summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_rd.c
diff options
context:
space:
mode:
Diffstat (limited to 'bgpd/bgp_rd.c')
-rw-r--r--bgpd/bgp_rd.c253
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);
+}