diff options
Diffstat (limited to 'bgpd/bgp_rd.c')
-rw-r--r-- | bgpd/bgp_rd.c | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/bgpd/bgp_rd.c b/bgpd/bgp_rd.c new file mode 100644 index 0000000..bb9f76b --- /dev/null +++ b/bgpd/bgp_rd.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* BGP RD definitions for BGP-based VPNs (IP/EVPN) + * -- brought over from bgpd/bgp_mplsvpn.c + * Copyright (C) 2000 Kunihiro Ishiguro <kunihiro@zebra.org> + */ + +#include <zebra.h> +#include "command.h" +#include "log.h" +#include "prefix.h" +#include "memory.h" +#include "stream.h" +#include "filter.h" +#include "frrstr.h" + +#include "lib/printfrr.h" + +#include "bgpd/bgpd.h" +#include "bgpd/bgp_rd.h" +#include "bgpd/bgp_attr.h" + +#ifdef ENABLE_BGP_VNC +#include "bgpd/rfapi/rfapi_backend.h" +#endif + +uint16_t decode_rd_type(const uint8_t *pnt) +{ + uint16_t v; + + v = ((uint16_t)*pnt++ << 8); +#ifdef ENABLE_BGP_VNC + /* + * VNC L2 stores LHI in lower byte, so omit it + */ + if (v != RD_TYPE_VNC_ETH) + v |= (uint16_t)*pnt; +#else /* duplicate code for clarity */ + v |= (uint16_t)*pnt; +#endif + return v; +} + +void encode_rd_type(uint16_t v, uint8_t *pnt) +{ + *((uint16_t *)pnt) = htons(v); +} + +/* type == RD_TYPE_AS */ +void decode_rd_as(const uint8_t *pnt, struct rd_as *rd_as) +{ + rd_as->as = (uint16_t)*pnt++ << 8; + rd_as->as |= (uint16_t)*pnt++; + ptr_get_be32(pnt, &rd_as->val); +} + +/* type == RD_TYPE_AS4 */ +void decode_rd_as4(const uint8_t *pnt, struct rd_as *rd_as) +{ + pnt = ptr_get_be32(pnt, &rd_as->as); + rd_as->val = ((uint16_t)*pnt++ << 8); + rd_as->val |= (uint16_t)*pnt; +} + +/* type == RD_TYPE_IP */ +void decode_rd_ip(const uint8_t *pnt, struct rd_ip *rd_ip) +{ + memcpy(&rd_ip->ip, pnt, 4); + pnt += 4; + + rd_ip->val = ((uint16_t)*pnt++ << 8); + rd_ip->val |= (uint16_t)*pnt; +} + +#ifdef ENABLE_BGP_VNC +/* type == RD_TYPE_VNC_ETH */ +void decode_rd_vnc_eth(const uint8_t *pnt, struct rd_vnc_eth *rd_vnc_eth) +{ + rd_vnc_eth->type = RD_TYPE_VNC_ETH; + rd_vnc_eth->local_nve_id = pnt[1]; + memcpy(rd_vnc_eth->macaddr.octet, pnt + 2, ETH_ALEN); +} +#endif + +int str2prefix_rd(const char *str, struct prefix_rd *prd) +{ + int ret = 0, type = RD_TYPE_UNDEFINED; + char *p, *p2; + struct stream *s = NULL; + char *half = NULL; + struct in_addr addr; + as_t as_val; + + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + + p = strchr(str, ':'); + if (!p) + goto out; + + /* a second ':' is accepted */ + p2 = strchr(p + 1, ':'); + if (p2) { + /* type is in first part */ + half = XMALLOC(MTYPE_TMP, (p - str) + 1); + memcpy(half, str, (p - str)); + half[p - str] = '\0'; + type = atoi(half); + if (type != RD_TYPE_AS && type != RD_TYPE_IP && + type != RD_TYPE_AS4) + goto out; + XFREE(MTYPE_TMP, half); + half = XMALLOC(MTYPE_TMP, (p2 - p)); + memcpy(half, p + 1, (p2 - p - 1)); + half[p2 - p - 1] = '\0'; + p = p2 + 1; + } else { + half = XMALLOC(MTYPE_TMP, (p - str) + 1); + memcpy(half, str, (p - str)); + half[p - str] = '\0'; + } + if (!all_digit(p + 1)) + goto out; + + s = stream_new(RD_BYTES); + + /* if it is an AS format or an IP */ + if (asn_str2asn(half, &as_val)) { + if (as_val > UINT16_MAX) { + stream_putw(s, RD_TYPE_AS4); + stream_putl(s, as_val); + stream_putw(s, atol(p + 1)); + if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS4) + goto out; + } else { + stream_putw(s, RD_TYPE_AS); + stream_putw(s, as_val); + stream_putl(s, atol(p + 1)); + if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_AS) + goto out; + } + } else if (inet_aton(half, &addr)) { + stream_putw(s, RD_TYPE_IP); + stream_put_in_addr(s, &addr); + stream_putw(s, atol(p + 1)); + if (type != RD_TYPE_UNDEFINED && type != RD_TYPE_IP) + goto out; + } else + goto out; + memcpy(prd->val, s->data, 8); + ret = 1; + +out: + if (s) + stream_free(s); + XFREE(MTYPE_TMP, half); + return ret; +} + +char *prefix_rd2str(const struct prefix_rd *prd, char *buf, size_t size, + enum asnotation_mode asnotation) +{ + const uint8_t *pnt; + uint16_t type; + struct rd_as rd_as; + struct rd_ip rd_ip; + int len = 0; + + assert(size >= RD_ADDRSTRLEN); + + pnt = prd->val; + + type = decode_rd_type(pnt); + + if (type == RD_TYPE_AS) { + decode_rd_as(pnt + 2, &rd_as); + len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation), + &rd_as.as); + snprintfrr(buf + len, size - len, ":%u", rd_as.val); + return buf; + } else if (type == RD_TYPE_AS4) { + decode_rd_as4(pnt + 2, &rd_as); + len += snprintfrr(buf + len, size - len, ASN_FORMAT(asnotation), + &rd_as.as); + snprintfrr(buf + len, size - len, ":%u", rd_as.val); + return buf; + } else if (type == RD_TYPE_IP) { + decode_rd_ip(pnt + 2, &rd_ip); + snprintfrr(buf, size, "%pI4:%hu", &rd_ip.ip, rd_ip.val); + return buf; + } +#ifdef ENABLE_BGP_VNC + else if (type == RD_TYPE_VNC_ETH) { + snprintf(buf, size, "LHI:%d, %02x:%02x:%02x:%02x:%02x:%02x", + *(pnt + 1), /* LHI */ + *(pnt + 2), /* MAC[0] */ + *(pnt + 3), *(pnt + 4), *(pnt + 5), *(pnt + 6), + *(pnt + 7)); + + return buf; + } +#endif + + snprintf(buf, size, "Unknown Type: %d", type); + return buf; +} + +void form_auto_rd(struct in_addr router_id, + uint16_t rd_id, + struct prefix_rd *prd) +{ + char buf[100]; + + prd->family = AF_UNSPEC; + prd->prefixlen = 64; + snprintfrr(buf, sizeof(buf), "%pI4:%hu", &router_id, rd_id); + (void)str2prefix_rd(buf, prd); +} + +static ssize_t printfrr_prd_asnotation(struct fbuf *buf, + struct printfrr_eargs *ea, + const void *ptr, + enum asnotation_mode asnotation) +{ + char rd_buf[RD_ADDRSTRLEN]; + + if (!ptr) + return bputs(buf, "(null)"); + + prefix_rd2str(ptr, rd_buf, sizeof(rd_buf), asnotation); + + return bputs(buf, rd_buf); +} + +printfrr_ext_autoreg_p("RDP", printfrr_prd); +static ssize_t printfrr_prd(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_PLAIN); +} + +printfrr_ext_autoreg_p("RDD", printfrr_prd_dot); +static ssize_t printfrr_prd_dot(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOT); +} + +printfrr_ext_autoreg_p("RDE", printfrr_prd_dotplus); +static ssize_t printfrr_prd_dotplus(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_prd_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS); +} |