diff options
author | denis <denis@cvs.openbsd.org> | 2018-12-30 13:53:08 +0000 |
---|---|---|
committer | denis <denis@cvs.openbsd.org> | 2018-12-30 13:53:08 +0000 |
commit | a824537c7c90146373b79b2f57f5027a586cf979 (patch) | |
tree | 614696296938fbaf4389866bbb417c11158eaa6c /usr.sbin/bgpd/util.c | |
parent | d6ba61a601290d0dffba4585b85e02442086b8a4 (diff) |
add support for IPv6 VPN routes
The kernel bits are missing as of now. With input from claudio@ and kn@
OK claudio@
Diffstat (limited to 'usr.sbin/bgpd/util.c')
-rw-r--r-- | usr.sbin/bgpd/util.c | 109 |
1 files changed, 105 insertions, 4 deletions
diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index 4e70d2a9aac..3c24500e750 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.41 2018/12/11 09:02:14 claudio Exp $ */ +/* $OpenBSD: util.c,v 1.42 2018/12/30 13:53:07 denis Exp $ */ /* * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> @@ -39,8 +39,8 @@ const char *aspath_delim(u_int8_t, int); const char * log_addr(const struct bgpd_addr *addr) { - static char buf[48]; - char tbuf[16]; + static char buf[74]; + char tbuf[40]; switch (addr->aid) { case AID_INET: @@ -56,6 +56,13 @@ log_addr(const struct bgpd_addr *addr) snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), tbuf); return (buf); + case AID_VPN_IPv6: + if (inet_ntop(aid2af(addr->aid), &addr->vpn6.addr, tbuf, + sizeof(tbuf)) == NULL) + return ("?"); + snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn6.rd), + tbuf); + return (buf); } return ("???"); } @@ -575,9 +582,77 @@ nlri_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix, return (plen + rv); } +int +nlri_get_vpn6(u_char *p, u_int16_t len, struct bgpd_addr *prefix, + u_int8_t *prefixlen, int withdraw) +{ + int rv, done = 0; + u_int8_t pfxlen; + u_int16_t plen; + + if (len < 1) + return (-1); + + memcpy(&pfxlen, p, 1); + p += 1; + plen = 1; + + memset(prefix, 0, sizeof(struct bgpd_addr)); + + /* label stack */ + do { + if (len - plen < 3 || pfxlen < 3 * 8) + return (-1); + if (prefix->vpn6.labellen + 3U > + sizeof(prefix->vpn6.labelstack)) + return (-1); + if (withdraw) { + /* on withdraw ignore the labelstack all together */ + plen += 3; + pfxlen -= 3 * 8; + break; + } + + prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++; + prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++; + prefix->vpn6.labelstack[prefix->vpn6.labellen] = *p++; + if (prefix->vpn6.labelstack[prefix->vpn6.labellen] & + BGP_MPLS_BOS) + done = 1; + prefix->vpn6.labellen++; + plen += 3; + pfxlen -= 3 * 8; + } while (!done); + + /* RD */ + if (len - plen < (int)sizeof(u_int64_t) || + pfxlen < sizeof(u_int64_t) * 8) + return (-1); + + memcpy(&prefix->vpn6.rd, p, sizeof(u_int64_t)); + pfxlen -= sizeof(u_int64_t) * 8; + p += sizeof(u_int64_t); + plen += sizeof(u_int64_t); + + /* prefix */ + prefix->aid = AID_VPN_IPv6; + *prefixlen = pfxlen; + + if (pfxlen > 128) + return (-1); + + if ((rv = extract_prefix(p, len, &prefix->vpn6.addr, + pfxlen, sizeof(prefix->vpn6.addr))) == -1) + return (-1); + + return (plen + rv); +} + + + /* * This function will have undefined behaviour if the passed in prefixlen is - * to large for the respective bgpd_addr address family. + * too large for the respective bgpd_addr address family. */ int prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, @@ -637,6 +712,32 @@ prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, return (-1); return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, a->vpn4.labellen)); + case AID_VPN_IPv6: + if (prefixlen > 128) + return (-1); + if (betoh64(a->vpn6.rd) > betoh64(b->vpn6.rd)) + return (1); + if (betoh64(a->vpn6.rd) < betoh64(b->vpn6.rd)) + return (-1); + for (i = 0; i < prefixlen / 8; i++) + if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i]) + return (a->vpn6.addr.s6_addr[i] - + b->vpn6.addr.s6_addr[i]); + i = prefixlen % 8; + if (i) { + m = 0xff00 >> i; + if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) != + (b->vpn6.addr.s6_addr[prefixlen / 8] & m)) + return ((a->vpn6.addr.s6_addr[prefixlen / 8] & + m) - (b->vpn6.addr.s6_addr[prefixlen / 8] & + m)); + } + if (a->vpn6.labellen > b->vpn6.labellen) + return (1); + if (a->vpn6.labellen < b->vpn6.labellen) + return (-1); + return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack, + a->vpn6.labellen)); } return (-1); } |