Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add decoder for BGP EVPN routes (RFC 7432) #1233

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 226 additions & 0 deletions print-bgp.c
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,11 @@ static const struct tok bgp_graceful_restart_comm_flag_values[] = {
#define BGP_EXT_COM_VRF_RT_IMP 0x010b /* RFC-ietf-l3vpn-2547bis-mcast-bgp-08.txt */
#define BGP_EXT_COM_L2VPN_RT_0 0x000a /* L2VPN Identifier,Format AS(2bytes):AN(4bytes) */
#define BGP_EXT_COM_L2VPN_RT_1 0xF10a /* L2VPN Identifier,Format IP address:AN(2bytes) */
/* rfc7432 */
#define BGP_EXT_COM_DEF_GATEWAY 0x030d /* Default gateway */
#define BGP_EXT_COM_EVPN_MMOB 0x0600 /* EVPN MAC Mobility */
#define BGP_EXT_COM_EVPN_ESI 0x0601 /* EVPN ESI Label */
#define BGP_EXT_COM_EVPN_ES_IMP 0x0602 /* EVPN ES-Import Route Target */

/* https://www.cisco.com/en/US/tech/tk436/tk428/technologies_tech_note09186a00801eb09a.shtml */
#define BGP_EXT_COM_EIGRP_GEN 0x8800
Expand Down Expand Up @@ -560,6 +565,10 @@ static const struct tok bgp_extd_comm_subtype_values[] = {
{ BGP_EXT_COM_VRF_RT_IMP, "vrf-route-import"},
{ BGP_EXT_COM_L2VPN_RT_0, "l2vpn-id"},
{ BGP_EXT_COM_L2VPN_RT_1, "l2vpn-id"},
{ BGP_EXT_COM_DEF_GATEWAY, "default-gateway" },
{ BGP_EXT_COM_EVPN_MMOB, "mac-mobility" },
{ BGP_EXT_COM_EVPN_ESI, "esi-label" },
{ BGP_EXT_COM_EVPN_ES_IMP, "es-import-target" },
{ 0, NULL},
};

Expand Down Expand Up @@ -884,6 +893,28 @@ bgp_vpn_rd_print(netdissect_options *ndo, const u_char *pptr)
return (rd);
}

/* Print an RFC 7432 Ethernet Segment Identifier */
static const char *
bgp_evpn_esi_print(netdissect_options *ndo, const u_char *pptr)
{
static char esi[sizeof("01:23:45:67:89:01:23:45:67:89")];

snprintf(esi, sizeof(esi),
"%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
GET_U_1(pptr),
GET_U_1(pptr + 1),
GET_U_1(pptr + 2),
GET_U_1(pptr + 3),
GET_U_1(pptr + 4),
GET_U_1(pptr + 5),
GET_U_1(pptr + 6),
GET_U_1(pptr + 7),
GET_U_1(pptr + 8),
GET_U_1(pptr + 9));

return esi;
}

/*
* Print an RFC 4360 Extended Community.
*/
Expand Down Expand Up @@ -982,6 +1013,39 @@ bgp_extended_community_print(netdissect_options *ndo,
GET_BE_U_2(pptr + 6)));
break;

case BGP_EXT_COM_DEF_GATEWAY:
/* Empty payload */
ND_PRINT("(empty)");
break;

case BGP_EXT_COM_EVPN_MMOB:
{
uint8_t flag = GET_U_1(pptr + 2);
ND_PRINT("Sequence number: %u%s",
GET_BE_U_4(pptr + 4),
flag == 0x1 ? " (static)" : "");
}
break;

case BGP_EXT_COM_EVPN_ESI:
{
uint8_t flag = GET_U_1(pptr + 2);
ND_PRINT("%u %s",
GET_BE_U_3(pptr + 5),
flag == 1 ? "(Single-Active)" : "(All-Active)");
}
break;

case BGP_EXT_COM_EVPN_ES_IMP:
ND_PRINT("%02x:%02x:%02x:%02x:%02x:%02x",
GET_U_1(pptr + 2),
GET_U_1(pptr + 3),
GET_U_1(pptr + 4),
GET_U_1(pptr + 5),
GET_U_1(pptr + 6),
GET_U_1(pptr + 7));
break;

default:
ND_PRINT("%02x%02x%02x%02x%02x%02x",
GET_U_1(pptr + 2),
Expand Down Expand Up @@ -1428,6 +1492,139 @@ print_labeled_vpn_l2(netdissect_options *ndo, const u_char *pptr)
return -2;
}

static int
print_evpn_prefix(netdissect_options *ndo, const u_char *pptr, u_int itemlen)
{
u_int ptype, plen, tlen, iplen, maclen;

if (itemlen < 2)
goto trunc;

ptype = GET_U_1(pptr);
plen = GET_U_1(pptr + 1);
tlen = plen + 2;
pptr += 2;

if (itemlen < tlen) {
ND_PRINT("\n\t (ran past the end)");
goto trunc;
}

ND_PRINT("\n\t EVPN Route-Type: %u", ptype);

switch (ptype) {
case 1: /* Ethernet auto-discovery route */
ND_PRINT("\n\t\tRD: %s", bgp_vpn_rd_print(ndo, pptr));
ND_PRINT("\n\t\tEthernet Segment ID: %s", bgp_evpn_esi_print(ndo, pptr + 8));
ND_PRINT("\n\t\tEthernet Tag: 0x%08x", GET_BE_U_4(pptr + 18));
ND_PRINT("\n\t\tMPLS Label: %u", GET_BE_U_3(pptr + 22));
break;
case 2: /* MAC/IP advertisement route */
ND_PRINT("\n\t\tRD: %s", bgp_vpn_rd_print(ndo, pptr));
ND_PRINT("\n\t\tEthernet Segment ID: %s", bgp_evpn_esi_print(ndo, pptr + 8));
ND_PRINT("\n\t\tEthernet Tag: 0x%08x", GET_BE_U_4(pptr + 18));
pptr += 22;
plen -= 22;

maclen = GET_U_1(pptr);
pptr++;
plen--;

ND_PRINT("\n\t\tMAC Address: ");

if ((plen * 8) < maclen) { /* maclen is in bits */
ND_PRINT("(ran past the end)");
break;
} else if (maclen == (sizeof(nd_mac48) * 8)) {
ND_PRINT("%s", GET_MAC48_STRING(pptr));
} else {
ND_PRINT("(illegal address length)");
}

pptr += maclen / 8;
plen -= maclen / 8;

iplen = GET_U_1(pptr);
pptr++;
plen--;

if (iplen != 0) {
ND_PRINT("\n\t\tIP Address: ");

if ((plen * 8) < iplen) { /* iplen is in bits */
ND_PRINT("(ran past the end)");
break;
} else if (iplen == (sizeof(nd_ipv4) * 8)) {
ND_PRINT("%s", GET_IPADDR_STRING(pptr));
} else if (iplen == (sizeof(nd_ipv6) * 8)) {
ND_PRINT("%s", GET_IP6ADDR_STRING(pptr));
} else {
ND_PRINT("(illegal address length)");
}

pptr += iplen / 8;
plen -= iplen / 8;
}

ND_PRINT("\n\t\tMPLS Label 1: %u", GET_BE_U_3(pptr));
pptr += 3;
plen -= 3;

if (plen > 0) {
ND_PRINT("\n\t\tMPLS Label 2: ");

if (plen < 3) {
ND_PRINT("(ran past the end)");
} else {
ND_PRINT("%u", GET_BE_U_3(pptr));
}
}

break;
case 3: /* Inclusive multicast ethernet tag route */
case 4: /* Ethernet segment route */
ND_PRINT("\n\t\tRD: %s", bgp_vpn_rd_print(ndo, pptr));
pptr += 8;
plen -= 8;

if (ptype == 3) {
ND_PRINT("\n\t\tEthernet Tag: 0x%08x", GET_BE_U_4(pptr));
pptr += 4;
plen -= 4;
} else if (ptype == 4) {
ND_PRINT("\n\t\tEthernet Segment ID: %s", bgp_evpn_esi_print(ndo, pptr));
pptr += 10;
plen -= 10;
}

iplen = GET_U_1(pptr);
pptr++;
plen--;

ND_PRINT("\n\t\tOriginating Router: ");

if ((plen * 8) < iplen) { /* iplen is in bits */
ND_PRINT("(ran past the end)");
} else if (iplen == (sizeof(nd_ipv4) * 8)) {
ND_PRINT("%s", GET_IPADDR_STRING(pptr));
} else if (iplen == (sizeof(nd_ipv6) * 8)) {
ND_PRINT("%s", GET_IP6ADDR_STRING(pptr));
} else {
ND_PRINT("(illegal address length)");
}

break;
default:
ND_PRINT(" (no decoder)");
break;
}

return tlen;

trunc:
return -2;
}

int
decode_prefix6(netdissect_options *ndo,
const u_char *pd, u_int itemlen, char *buf, size_t buflen)
Expand Down Expand Up @@ -1777,6 +1974,7 @@ bgp_mp_af_print(netdissect_options *ndo,
case (AFNUM_L2VPN<<8 | SAFNUM_VPNMULTICAST):
case (AFNUM_L2VPN<<8 | SAFNUM_VPNUNIMULTICAST):
case (AFNUM_VPLS<<8 | SAFNUM_VPLS):
case (AFNUM_VPLS<<8 | SAFNUM_EVPN):
break;
default:
ND_TCHECK_LEN(tptr, tlen);
Expand Down Expand Up @@ -1881,6 +2079,11 @@ bgp_nlri_print(netdissect_options *ndo, uint16_t af, uint8_t safi,
if (advance == -2)
goto trunc;
break;
case (AFNUM_VPLS<<8 | SAFNUM_EVPN):
advance = print_evpn_prefix(ndo, tptr, len);
if (advance == -2)
goto trunc;
break;
case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
Expand Down Expand Up @@ -2130,6 +2333,11 @@ bgp_attr_print(netdissect_options *ndo,
tptr += tnhlen;
tlen -= tnhlen;
tnhlen = 0;
} else if (tnhlen >= sizeof(nd_ipv6)) {
ND_PRINT("%s",GET_IP6ADDR_STRING(tptr));
tptr += sizeof(nd_ipv6);
tnhlen -= sizeof(nd_ipv6);
tlen -= sizeof(nd_ipv6);
} else {
ND_PRINT("%s",GET_IPADDR_STRING(tptr));
tptr += sizeof(nd_ipv4);
Expand Down Expand Up @@ -2203,6 +2411,24 @@ bgp_attr_print(netdissect_options *ndo,
tnhlen -= (sizeof(nd_ipv4));
}
break;
case (AFNUM_VPLS<<8 | SAFNUM_EVPN):
if (tnhlen < sizeof(nd_ipv4)) {
ND_PRINT("invalid len");
tptr += tnhlen;
tlen -= tnhlen;
tnhlen = 0;
} else if (tnhlen >= sizeof(nd_ipv6)) {
ND_PRINT("%s",GET_IP6ADDR_STRING(tptr));
tptr += sizeof(nd_ipv6);
tnhlen -= sizeof(nd_ipv6);
tlen -= sizeof(nd_ipv6);
} else {
ND_PRINT("%s",GET_IPADDR_STRING(tptr));
tptr += sizeof(nd_ipv4);
tnhlen -= sizeof(nd_ipv4);
tlen -= sizeof(nd_ipv4);
}
break;
case (AFNUM_NSAP<<8 | SAFNUM_UNICAST):
case (AFNUM_NSAP<<8 | SAFNUM_MULTICAST):
case (AFNUM_NSAP<<8 | SAFNUM_UNIMULTICAST):
Expand Down
2 changes: 2 additions & 0 deletions tests/TESTLIST
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ bgp-4byte-asn bgp-4byte-asn.pcap bgp-4byte-asn.out -v
bgp-4byte-asdot bgp-4byte-asn.pcap bgp-4byte-asdot.out -vb
bgp-lu-multiple-labels bgp-lu-multiple-labels.pcap bgp-lu-multiple-labels.out -v
bgp-evpn bgp-evpn.pcap bgp-evpn.out -v
bgp-evpn-pkt-1 bgp-evpn-pkt-1.pcap bgp-evpn-pkt-1.out -v
bgp-evpn-pkt-2 bgp-evpn-pkt-2.pcap bgp-evpn-pkt-2.out -v
bgp-llgr bgp-evpn.pcap bgp-llgr.out -v
bgp-encap bgp-encap.pcap bgp-encap.out -v
bgp-rt-prefix bgp-rt-prefix.pcap bgp-rt-prefix.out -v
Expand Down
11 changes: 7 additions & 4 deletions tests/bgp-encap.out
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
encapsulation (0x030c), Flags [none]: Tunnel type: VXLAN
Multi-Protocol Reach NLRI (14), length: 44, Flags [OE]:
AFI: VPLS (25), SAFI: EVPN (70)
no AFI 25 / SAFI 70 decoder
0x0000: 0019 4604 0404 0404 0002 2100 0104 0404
0x0010: 0400 0400 0000 0000 0000 0000 0000 0000
0x0020: 0030 0206 0a0e faf3 0000 0065
nexthop: 4.4.4.4, nh-length: 4, no SNPA
EVPN Route-Type: 2
RD: 4.4.4.4:4
Ethernet Segment ID: 00:00:00:00:00:00:00:00:00:00
Ethernet Tag: 0x00000000
MAC Address: 02:06:0a:0e:fa:f3
MPLS Label 1: 101
Loading