Mailing List Archive

[PATCH 41/57] lib: add new prefix macip
Acording to RFC7432 , part 7.2 MAC/IP Advertisement Route ( Route Type 2)
enlarges the definition of prefix as quoted below:
"the Ethernet Tag ID, MAC Address Length, MAC Address, IP Address
Length, and IP Address fields are considered to be part of the prefix in the
NLRI"
This new kind of route prefix is added by this patch, and it is build
using all data mentionned above.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
Signed-off-by: Julien Courtat <julien.courtat@6wind.com>
---
lib/prefix.c | 65 ++++++++++++++++++++++++++++++++++++++++++++----
lib/prefix.h | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 137 insertions(+), 8 deletions(-)

diff --git a/lib/prefix.c b/lib/prefix.c
index 354890dd0400..5e2ebdea3ba7 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -196,7 +196,10 @@ str2family(const char *string)
return AF_INET6;
else if (!strcmp("ethernet", string))
return AF_ETHERNET;
- return -1;
+ else if (!strcmp("l2vpn", string))
+ return AF_L2VPN;
+ else
+ return -1;
}

/* Address Famiy Identifier to Address Family converter. */
@@ -211,6 +214,8 @@ afi2family (afi_t afi)
#endif /* HAVE_IPV6 */
else if (afi == AFI_ETHER)
return AF_ETHERNET;
+ else if (afi == AFI_INTERNAL_L2VPN)
+ return AF_L2VPN;
return 0;
}

@@ -225,6 +230,8 @@ family2afi (int family)
#endif /* HAVE_IPV6 */
else if (family == AF_ETHERNET)
return AFI_ETHER;
+ else if (family == AF_L2VPN)
+ return AFI_INTERNAL_L2VPN;
return 0;
}

@@ -257,6 +264,8 @@ safi2str(safi_t safi)
return "encap";
case SAFI_MPLS_VPN:
return "vpn";
+ case SAFI_INTERNAL_EVPN:
+ return "evpn";
}
return NULL;
}
@@ -312,6 +321,17 @@ prefix_copy (struct prefix *dest, const struct prefix *src)
{
dest->u.prefix_eth = src->u.prefix_eth;
}
+ else if (src->family == AF_L2VPN)
+ {
+ dest->u.prefix_macip.eth_tag_id = src->u.prefix_macip.eth_tag_id;
+ memcpy(&dest->u.prefix_macip.mac, &src->u.prefix_macip.mac, sizeof(dest->u.prefix_macip.mac));
+ dest->u.prefix_macip.mac_len = src->u.prefix_macip.mac_len;
+ dest->u.prefix_macip.ip_len = src->u.prefix_macip.ip_len;
+ if (dest->u.prefix_macip.ip_len == 32)
+ memcpy(&dest->u.prefix_macip.ip.in4, &src->u.prefix_macip.ip.in4, sizeof(dest->u.prefix_macip.ip.in4));
+ else
+ memcpy(&dest->u.prefix_macip.ip.in6, &src->u.prefix_macip.ip.in6, sizeof(dest->u.prefix_macip.ip.in6));
+ }
else
{
zlog (NULL, LOG_ERR, "prefix_copy(): Unknown address family %d",
@@ -341,10 +361,15 @@ prefix_same (const struct prefix *p1, const struct prefix *p2)
if (IPV6_ADDR_SAME (&p1->u.prefix6.s6_addr, &p2->u.prefix6.s6_addr))
return 1;
#endif /* HAVE_IPV6 */
- if (p1->family == AF_ETHERNET) {
- if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
- return 1;
- }
+ if (p1->family == AF_ETHERNET)
+ if (!memcmp(p1->u.prefix_eth.octet, p2->u.prefix_eth.octet, ETHER_ADDR_LEN))
+ return 1;
+ if (p1->family == AF_L2VPN)
+ if ( (p1->u.prefix_macip.eth_tag_id == p2->u.prefix_macip.eth_tag_id)
+ && (!memcmp(p1->u.prefix_macip.mac.octet, p2->u.prefix_macip.mac.octet, ETHER_ADDR_LEN))
+ && (p1->u.prefix_macip.ip_len == p2->u.prefix_macip.ip_len)
+ && (!memcmp(&p1->u.prefix_macip.ip, &p2->u.prefix_macip.ip, p2->u.prefix_macip.ip_len/8)))
+ return 1;
}
return 0;
}
@@ -438,6 +463,8 @@ prefix_family_str (const struct prefix *p)
#endif /* HAVE_IPV6 */
if (p->family == AF_ETHERNET)
return "ether";
+ if (p->family == AF_L2VPN)
+ return "l2vpn";
return "unspec";
}

@@ -850,6 +877,8 @@ prefix_blen (const struct prefix *p)
#endif /* HAVE_IPV6 */
case AF_ETHERNET:
return ETHER_ADDR_LEN;
+ case AF_L2VPN:
+ return L2VPN_MAX_BYTELEN;
}
return 0;
}
@@ -904,6 +933,32 @@ prefix2str (union prefix46constptr pu, char *str, int size)
return 0;
}

+ if (p->family == AF_L2VPN)
+ {
+ char *s = str;
+
+ assert(size >= PREFIX_STRLEN);
+
+ if (L2VPN_PREFIX_HAS_IPV4(p))
+ inet_ntop (AF_INET, &p->u.prefix_macip.ip.in4, buf, BUFSIZ);
+ else if (L2VPN_PREFIX_HAS_IPV6(p))
+ inet_ntop (AF_INET6, &p->u.prefix_macip.ip.in6, buf, BUFSIZ);
+ else if (L2VPN_PREFIX_HAS_NOIP(p))
+ strcpy(buf, "none");
+ snprintf (s, BUFSIZ, "[%u][%02x:%02x:%02x:%02x:%02x:%02x/%d][%s/%d]",
+ p->u.prefix_macip.eth_tag_id,
+ p->u.prefix_macip.mac.octet[0],
+ p->u.prefix_macip.mac.octet[1],
+ p->u.prefix_macip.mac.octet[2],
+ p->u.prefix_macip.mac.octet[3],
+ p->u.prefix_macip.mac.octet[4],
+ p->u.prefix_macip.mac.octet[5],
+ p->u.prefix_macip.mac_len,
+ buf,
+ p->u.prefix_macip.ip_len);
+ return 0;
+ }
+
inet_ntop (p->family, &p->u.prefix, buf, BUFSIZ);
snprintf (str, size, "%s/%d", buf, p->prefixlen);
return str;
diff --git a/lib/prefix.h b/lib/prefix.h
index 0075cce43de3..fcc633648c31 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -46,6 +46,38 @@ struct ethaddr {
u_char octet[ETHER_ADDR_LEN];
} __attribute__ ((packed));

+/*
+ * RFC7432 , part 7.2 MAC/IP Advertisement Route ( Route Type 2)
+ * enlarges the definition of prefix as quoted below:
+ * "the Ethernet Tag ID, MAC Address Length, MAC Address, IP Address Length,
+ * and IP Address fields are considered to be part of the prefix in the NLRI"
+ */
+struct macipaddr {
+ u_int32_t eth_tag_id;
+ u_int8_t mac_len;
+ struct ethaddr mac;
+ u_int8_t ip_len;
+ union
+ {
+ struct in_addr in4; /* AF_INET */
+#ifdef HAVE_IPV6
+ struct in6_addr in6; /* AF_INET6 */
+#endif /* HAVE_IPV6 */
+ } ip __attribute__ ((packed));
+};
+
+struct ipvrfaddr {
+ u_int32_t eth_tag_id;
+ u_int8_t ip_len;
+ union
+ {
+ struct in_addr in4; /* AF_INET */
+#ifdef HAVE_IPV6
+ struct in6_addr in6; /* AF_INET6 */
+#endif /* HAVE_IPV6 */
+ } ip __attribute__ ((packed));
+};
+

/*
* A struct prefix contains an address family, a prefix length, and an
@@ -65,6 +97,14 @@ struct ethaddr {
#endif
#endif

+/* arbitrarily defined using unused value from kernel
+ * include/linux/socket.h
+ */
+#define AF_L2VPN 44
+#define L2VPN_NOIP_PREFIX_LEN ((ETHER_ADDR_LEN + 4 /*ethtag*/+ 2 /*mac len + ip len*/) * 8)
+#define L2VPN_IPV4_PREFIX_LEN ((ETHER_ADDR_LEN + 4 /*ethtag*/+ 4 /*IP address*/ + 2 /*mac len + ip len*/) * 8)
+#define L2VPN_IPV6_PREFIX_LEN ((ETHER_ADDR_LEN + 4 /*ethtag*/+ 16 /*IP address*/ + 2 /*mac len + ip len*/) * 8)
+
/* IPv4 and IPv6 unified prefix structure. */
struct prefix
{
@@ -82,12 +122,15 @@ struct prefix
struct in_addr id;
struct in_addr adv_router;
} lp;
- struct ethaddr prefix_eth; /* AF_ETHERNET */
+ struct ethaddr prefix_eth; /* AF_ETHERNET */
+ struct macipaddr prefix_macip; /* AF_L2VPN */
+ struct macipaddr prefix_ipvrf; /* AF_L2VPN */
u_char val[8];
uintptr_t ptr;
} u __attribute__ ((aligned (8)));
};

+
/* IPv4 prefix structure. */
struct prefix_ipv4
{
@@ -138,6 +181,14 @@ struct prefix_ptr
uintptr_t prefix __attribute__ ((aligned (8)));
};

+/* L2VPN IP-VRF prefix structure. */
+struct prefix_macip
+{
+ u_char family;
+ u_char prefixlen;
+ struct ipvrfaddr prefix __attribute__ ((aligned (8)));
+};
+
/* helper to get type safety/avoid casts on calls
* (w/o this, functions accepting all prefix types need casts on the caller
* side, which strips type safety since the cast will accept any pointer
@@ -148,6 +199,7 @@ union prefix46ptr
struct prefix *p;
struct prefix_ipv4 *p4;
struct prefix_ipv6 *p6;
+ struct prefix_macip *pm;
} __attribute__ ((transparent_union));

union prefix46constptr
@@ -155,6 +207,7 @@ union prefix46constptr
const struct prefix *p;
const struct prefix_ipv4 *p4;
const struct prefix_ipv6 *p6;
+ const struct prefix_macip *pm;
} __attribute__ ((transparent_union));

#ifndef INET_ADDRSTRLEN
@@ -169,8 +222,13 @@ union prefix46constptr
#define INET6_BUFSIZ 51
#endif /* INET6_BUFSIZ */

-/* Maximum prefix string length (IPv6) */
-#define PREFIX_STRLEN 51
+/* [1a:2b:3c:4d:5e:6f/48][32.210.222.0/32] => ETH + Ethtag ID : 83 bytes */
+#ifndef L2VPN_BUFSIZ
+#define L2VPN_BUFSIZ 51+32
+#endif /* L2VPN_BUFSIZ */
+
+/* Maximum prefix string length (L2VPN) */
+#define PREFIX_STRLEN 51+32

/* Max bit/byte length of IPv4 address. */
#define IPV4_MAX_BYTELEN 4
@@ -193,11 +251,27 @@ union prefix46constptr
#define IPV6_ADDR_SAME(D,S) (memcmp ((D), (S), IPV6_MAX_BYTELEN) == 0)
#define IPV6_ADDR_COPY(D,S) memcpy ((D), (S), IPV6_MAX_BYTELEN)

+/* Max bit/byte length of l2vpn address. */
+#define L2VPN_PREFIX_ETHTAGLEN (8 * sizeof(u_int32_t))
+#define L2VPN_PREFIX_MACADDRLEN (8 * sizeof (u_int8_t) + 8 * sizeof(struct ethaddr))
+#define L2VPN_PREFIX_IPV4LEN (8 * sizeof (u_int8_t) + IPV4_MAX_BITLEN)
+#define L2VPN_PREFIX_IPV6LEN (8 * sizeof (u_int8_t) + IPV6_MAX_BITLEN)
+#define L2VPN_MAX_BYTELEN 28
+#define L2VPN_MAX_BITLEN ( L2VPN_PREFIX_ETHTAGLEN \
+ + L2VPN_PREFIX_MACADDRLEN \
+ + L2VPN_PREFIX_IPV6LEN)
+#define L2VPN_MAX_PREFIXLEN L2VPN_MAX_BITLEN
+#define L2VPN_PREFIX_IPLEN(p) ((p)->u.prefix_macip.ip_len)
+#define L2VPN_PREFIX_HAS_IPV4(p) ((p)->u.prefix_macip.ip_len == IPV4_MAX_PREFIXLEN)
+#define L2VPN_PREFIX_HAS_IPV6(p) ((p)->u.prefix_macip.ip_len == IPV6_MAX_PREFIXLEN)
+#define L2VPN_PREFIX_HAS_NOIP(p) ((p)->u.prefix_macip.ip_len == 0)
+
/* Count prefix size from mask length */
#define PSIZE(a) (((a) + 7) / (8))

/* Prefix's family member. */
#define PREFIX_FAMILY(p) ((p)->family)
+#define PREFIX_IS_L2VPN(p) ((p)->family == AF_L2VPN)

/* glibc defines s6_addr32 to __in6_u.__u6_addr32 if __USE_{MISC || GNU} */
#ifndef s6_addr32
--
2.1.4


_______________________________________________
Quagga-dev mailing list
Quagga-dev@lists.quagga.net
https://lists.quagga.net/mailman/listinfo/quagga-dev