From ce78a6fbbe90381cef3cca8582082e6a5124f6fa Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 6 Jun 2017 22:12:39 -0700 Subject: [PATCH 01/32] bgpd: Fix nexthop for labeled-unicast A prior change broke the nexthop setting for labeled-unicast address-family in a RFC-5549 scenario (IPv4 prefixes exchanged with IPv6 next hops). This commit fixes the issue. Fixes: "bgpd: Fix next hop setting for EVPN" Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr.c | 81 +++++++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index dd18797637..b03b408f7d 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2606,10 +2606,9 @@ size_t bgp_packet_mpattr_start(struct stream *s, struct peer *peer, afi_t afi, stream_putc(s, pkt_safi); /* SAFI */ /* Nexthop AFI */ - if (afi == AFI_IP && safi == SAFI_UNICAST) { + if (afi == AFI_IP + && (safi == SAFI_UNICAST || safi == SAFI_LABELED_UNICAST)) nh_afi = peer_cap_enhe(peer, afi, safi) ? AFI_IP6 : AFI_IP; - } else if (safi == SAFI_LABELED_UNICAST) - nh_afi = afi; else nh_afi = BGP_NEXTHOP_AFI_FROM_NHLEN(attr->mp_nexthop_len); @@ -2800,9 +2799,8 @@ static void bgp_packet_mpattr_tea(struct bgp *bgp, struct peer *peer, if (attrlenfield > 0xff) { /* 2-octet length field */ - stream_putc(s, - BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, attrtype); stream_putw(s, attrlenfield & 0xffff); } else { @@ -3040,15 +3038,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SEND_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))) { if (attr->community->size * 4 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putw(s, attr->community->size * 4); } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, attr->community->size * 4); } @@ -3062,15 +3059,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, PEER_FLAG_SEND_LARGE_COMMUNITY) && (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES))) { if (attr->lcommunity->size * 12 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putw(s, attr->lcommunity->size * 12); } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, attr->lcommunity->size * 12); } @@ -3122,16 +3118,14 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED) { if (attr->ecommunity->size * 8 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); stream_putw(s, attr->ecommunity->size * 8); } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_EXT_COMMUNITIES); stream_putc(s, attr->ecommunity->size * 8); } @@ -3197,9 +3191,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, label_index = attr->label_index; if (label_index != BGP_INVALID_LABEL_INDEX) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_PREFIX_SID); stream_putc(s, 10); stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX); @@ -3227,9 +3220,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, */ aspath = aspath_delete_confed_seq(aspath); - stream_putc(s, - BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_TRANS | BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_AS4_PATH); aspath_sizep = stream_get_endp(s); stream_putw(s, 0); @@ -3414,15 +3406,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, /* Community attribute. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) { if (attr->community->size * 4 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putw(s, attr->community->size * 4); } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_COMMUNITIES); stream_putc(s, attr->community->size * 4); } @@ -3432,15 +3423,14 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, /* Large Community attribute. */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_LARGE_COMMUNITIES)) { if (attr->lcommunity->size * 12 > 255) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS - | BGP_ATTR_FLAG_EXTLEN); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS + | BGP_ATTR_FLAG_EXTLEN); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putw(s, attr->lcommunity->size * 12); } else { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_LARGE_COMMUNITIES); stream_putc(s, attr->lcommunity->size * 12); } @@ -3485,9 +3475,8 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr, /* Prefix SID */ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_PREFIX_SID)) { if (attr->label_index != BGP_INVALID_LABEL_INDEX) { - stream_putc(s, - BGP_ATTR_FLAG_OPTIONAL - | BGP_ATTR_FLAG_TRANS); + stream_putc(s, BGP_ATTR_FLAG_OPTIONAL + | BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_PREFIX_SID); stream_putc(s, 10); stream_putc(s, BGP_PREFIX_SID_LABEL_INDEX); From f2d622627bf3e2326d909f0fb4519beb4499d61d Mon Sep 17 00:00:00 2001 From: vivek Date: Wed, 7 Jun 2017 22:43:19 -0700 Subject: [PATCH 02/32] bgpd: Update EVPN operational commands Make EVPN operational commands follow the " " syntax. The relevant commands are: - show bgp l2vpn evpn summary - show bgp l2vpn evpn vni ... - show bgp l2vpn evpn route ... - show bgp l2vpn evpn route vni ... - show bgp l2vpn evpn import-rt Signed-off-by: Vivek Venkatraman --- bgpd/bgp_evpn_vty.c | 280 +++++++++++++++++++++++++++----------------- 1 file changed, 170 insertions(+), 110 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 1225354c0a..c3eb32b91d 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1739,56 +1739,54 @@ DEFUN (no_bgp_evpn_advertise_all_vni, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_vni, - show_bgp_evpn_vni_cmd, - "show bgp evpn vni", +/* + * Display VNI information - for all or a specific VNI + */ +DEFUN (show_bgp_l2vpn_evpn_vni, + show_bgp_l2vpn_evpn_vni_cmd, + "show bgp l2vpn evpn vni [(1-16777215)]", SHOW_STR BGP_STR + L2VPN_HELP_STR EVPN_HELP_STR - "Show VNI\n") -{ - struct bgp *bgp; - - bgp = bgp_get_default(); - if (!bgp) - return CMD_WARNING; - - vty_out(vty, "Advertise All VNI flag: %s\n", - bgp->advertise_all_vni ? "Enabled" : "Disabled"); - - evpn_show_all_vnis(vty, bgp); - return CMD_SUCCESS; -} - -DEFUN (show_bgp_evpn_vni_num, - show_bgp_evpn_vni_num_cmd, - "show bgp evpn vni (1-16777215)", - SHOW_STR - BGP_STR - "Address family modifier\n" "Show VNI\n" "VNI number\n") { - vni_t vni; struct bgp *bgp; + vni_t vni; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - vni = strtoul(argv[4]->arg, NULL, 10); + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + if (argc == ((idx + 1) + 1)) { + /* Display all VNIs */ + vty_out(vty, "Advertise All VNI flag: %s\n", + bgp->advertise_all_vni ? "Enabled" : "Disabled"); + evpn_show_all_vnis(vty, bgp); + } else { + /* Display specific VNI */ + vni = strtoul(argv[argc - 1]->arg, NULL, 10); + evpn_show_vni(vty, bgp, vni); + } - evpn_show_vni(vty, bgp, vni); return CMD_SUCCESS; } -/* `show bgp evpn summary' commands. */ -DEFUN (show_bgp_evpn_summary, - show_bgp_evpn_summary_cmd, - "show bgp evpn summary [json]", +/* + * Display EVPN neighbor summary. + */ +DEFUN (show_bgp_l2vpn_evpn_summary, + show_bgp_l2vpn_evpn_summary_cmd, + "show bgp l2vpn evpn summary [json]", SHOW_STR BGP_STR - "EVPN\n" + L2VPN_HELP_STR + EVPN_HELP_STR "Summary of BGP neighbor status\n" "JavaScript Object Notation\n") { @@ -1796,29 +1794,37 @@ DEFUN (show_bgp_evpn_summary, return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj); } -/* Show bgp evpn route */ -DEFUN (show_bgp_evpn_route, - show_bgp_evpn_route_cmd, - "show bgp evpn route [type ]", +/* + * Display global EVPN routing table. + */ +DEFUN (show_bgp_l2vpn_evpn_route, + show_bgp_l2vpn_evpn_route_cmd, + "show bgp l2vpn evpn route [type ]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "Specify Route type\n" "MAC-IP (Type-2) route\n" "Multicast (Type-3) route\n") { struct bgp *bgp; + int idx = 0; int type = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - if (argc == 6) { - if (strncmp(argv[5]->arg, "ma", 2) == 0) + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + if (argc == ((idx + 1) + 3)) { + /* Specific type is requested */ + if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; - else if (strncmp(argv[5]->arg, "mu", 2) == 0) + else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; else return CMD_WARNING; @@ -1828,13 +1834,17 @@ DEFUN (show_bgp_evpn_route, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_rd, - show_bgp_evpn_route_rd_cmd, - "show bgp evpn route rd ASN:nn_or_IP-address:nn [type ]", +/* + * Display global EVPN routing table for specific RD. + */ +DEFUN (show_bgp_l2vpn_evpn_route_rd, + show_bgp_l2vpn_evpn_route_rd_cmd, + "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn [type ]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "Route Distinguisher\n" "ASN:XX or A.B.C.D:XX\n" "Specify Route type\n" @@ -1844,22 +1854,27 @@ DEFUN (show_bgp_evpn_route_rd, struct bgp *bgp; int ret; struct prefix_rd prd; + int idx = 0; int type = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - ret = str2prefix_rd(argv[5]->arg, &prd); + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + ret = str2prefix_rd(argv[idx + 3]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } - if (argc == 8) { - if (strncmp(argv[7]->arg, "ma", 2) == 0) + if (argc == ((idx + 1) + 5)) { + /* Specific type is requested */ + if (strncmp(argv[argc - 1]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; - else if (strncmp(argv[7]->arg, "mu", 2) == 0) + else if (strncmp(argv[argc - 1]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; else return CMD_WARNING; @@ -1869,13 +1884,17 @@ DEFUN (show_bgp_evpn_route_rd, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_rd_macip, - show_bgp_evpn_route_rd_macip_cmd, - "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", +/* + * Display global EVPN routing table for specific RD and MACIP. + */ +DEFUN (show_bgp_l2vpn_evpn_route_rd_macip, + show_bgp_l2vpn_evpn_route_rd_macip_cmd, + "show bgp l2vpn evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "Route Distinguisher\n" "ASN:XX or A.B.C.D:XX\n" "MAC\n" @@ -1888,23 +1907,28 @@ DEFUN (show_bgp_evpn_route_rd_macip, struct prefix_rd prd; struct ethaddr mac; struct ipaddr ip; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - ret = str2prefix_rd(argv[5]->arg, &prd); + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + ret = str2prefix_rd(argv[idx + 3]->arg, &prd); if (!ret) { vty_out(vty, "%% Malformed Route Distinguisher\n"); return CMD_WARNING; } - if (!prefix_str2mac(argv[7]->arg, &mac)) { + if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) { vty_out(vty, "%% Malformed MAC address\n"); return CMD_WARNING; } memset(&ip, 0, sizeof(ip)); - if (argc == 10 && argv[9]->arg != NULL) { - if (str2ipaddr(argv[9]->arg, &ip) != 0) { + if (argc == (idx + 1 + 7) && argv[argc - 1]->arg != NULL) { + /* Specific MAC+IP requested */ + if (str2ipaddr(argv[argc - 1]->arg, &ip) != 0) { vty_out(vty, "%% Malformed IP address\n"); return CMD_WARNING; } @@ -1914,13 +1938,17 @@ DEFUN (show_bgp_evpn_route_rd_macip, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_vni, - show_bgp_evpn_route_vni_cmd, - "show bgp evpn route vni (1-16777215) [ | vtep A.B.C.D>]", +/* + * Display per-VNI EVPN routing table. + */ +DEFUN (show_bgp_l2vpn_evpn_route_vni, + show_bgp_l2vpn_evpn_route_vni_cmd, + "show bgp l2vpn evpn route vni (1-16777215) [ | vtep A.B.C.D>]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "VXLAN Network Identifier\n" "VNI number\n" "Specify Route type\n" @@ -1933,25 +1961,29 @@ DEFUN (show_bgp_evpn_route_vni, struct bgp *bgp; struct in_addr vtep_ip; int type = 0; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + vtep_ip.s_addr = 0; - vni = strtoul(argv[5]->arg, NULL, 10); + vni = strtoul(argv[idx + 3]->arg, NULL, 10); - if (argc == 8 && argv[6]->arg) { - if (strncmp(argv[6]->arg, "type", 4) == 0) { - if (strncmp(argv[7]->arg, "ma", 2) == 0) + if (argc == (idx + 1 + 5) && argv[idx + 4]->arg) { + if (strncmp(argv[idx + 4]->arg, "type", 4) == 0) { + if (strncmp(argv[idx + 5]->arg, "ma", 2) == 0) type = BGP_EVPN_MAC_IP_ROUTE; - else if (strncmp(argv[7]->arg, "mu", 2) == 0) + else if (strncmp(argv[idx + 5]->arg, "mu", 2) == 0) type = BGP_EVPN_IMET_ROUTE; else return CMD_WARNING; - } else if (strncmp(argv[6]->arg, "vtep", 4) == 0) { - if (!inet_aton(argv[7]->arg, &vtep_ip)) { + } else if (strncmp(argv[idx + 4]->arg, "vtep", 4) == 0) { + if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) { vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } @@ -1963,13 +1995,17 @@ DEFUN (show_bgp_evpn_route_vni, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_vni_macip, - show_bgp_evpn_route_vni_macip_cmd, - "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", +/* + * Display per-VNI EVPN routing table for specific MACIP. + */ +DEFUN (show_bgp_l2vpn_evpn_route_vni_macip, + show_bgp_l2vpn_evpn_route_vni_macip_cmd, + "show bgp l2vpn evpn route vni (1-16777215) mac WORD [ip WORD]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "VXLAN Network Identifier\n" "VNI number\n" "MAC\n" @@ -1981,19 +2017,23 @@ DEFUN (show_bgp_evpn_route_vni_macip, struct bgp *bgp; struct ethaddr mac; struct ipaddr ip; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - vni = strtoul(argv[5]->arg, NULL, 10); - if (!prefix_str2mac(argv[7]->arg, &mac)) { + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + vni = strtoul(argv[idx + 3]->arg, NULL, 10); + if (!prefix_str2mac(argv[idx + 5]->arg, &mac)) { vty_out(vty, "%% Malformed MAC address\n"); return CMD_WARNING; } memset(&ip, 0, sizeof(ip)); - if (argc == 10 && argv[9]->arg != NULL) { - if (str2ipaddr(argv[9]->arg, &ip) != 0) { + if (argc == (idx + 1 + 7) && argv[idx + 7]->arg != NULL) { + if (str2ipaddr(argv[idx + 7]->arg, &ip) != 0) { vty_out(vty, "%% Malformed IP address\n"); return CMD_WARNING; } @@ -2003,13 +2043,17 @@ DEFUN (show_bgp_evpn_route_vni_macip, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_vni_multicast, - show_bgp_evpn_route_vni_multicast_cmd, - "show bgp evpn route vni (1-16777215) multicast A.B.C.D", +/* + * Display per-VNI EVPN routing table for specific multicast IP (remote VTEP). + */ +DEFUN (show_bgp_l2vpn_evpn_route_vni_multicast, + show_bgp_l2vpn_evpn_route_vni_multicast_cmd, + "show bgp l2vpn evpn route vni (1-16777215) multicast A.B.C.D", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "VXLAN Network Identifier\n" "VNI number\n" "Multicast (Type-3) route\n" @@ -2019,13 +2063,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast, struct bgp *bgp; int ret; struct in_addr orig_ip; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; - vni = strtoul(argv[5]->arg, NULL, 10); - ret = inet_aton(argv[7]->arg, &orig_ip); + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + + vni = strtoul(argv[idx + 3]->arg, NULL, 10); + ret = inet_aton(argv[idx + 5]->arg, &orig_ip); if (!ret) { vty_out(vty, "%% Malformed Originating Router IP address\n"); return CMD_WARNING; @@ -2035,13 +2083,17 @@ DEFUN (show_bgp_evpn_route_vni_multicast, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_route_vni_all, - show_bgp_evpn_route_vni_all_cmd, - "show bgp evpn route vni all [vtep A.B.C.D]", +/* + * Display per-VNI EVPN routing table - for all VNIs. + */ +DEFUN (show_bgp_l2vpn_evpn_route_vni_all, + show_bgp_l2vpn_evpn_route_vni_all_cmd, + "show bgp l2vpn evpn route vni all [vtep A.B.C.D]", SHOW_STR BGP_STR - "Address Family Modifier\n" - "Display EVPN route information\n" + L2VPN_HELP_STR + EVPN_HELP_STR + "EVPN route information\n" "VXLAN Network Identifier\n" "All VNIs\n" "Remote VTEP\n" @@ -2049,14 +2101,18 @@ DEFUN (show_bgp_evpn_route_vni_all, { struct bgp *bgp; struct in_addr vtep_ip; + int idx = 0; bgp = bgp_get_default(); if (!bgp) return CMD_WARNING; + if (!argv_find(argv, argc, "evpn", &idx)) + return CMD_WARNING; + vtep_ip.s_addr = 0; - if (argc == 8 && argv[7]->arg) { - if (!inet_aton(argv[7]->arg, &vtep_ip)) { + if (argc == (idx + 1 + 5) && argv[idx + 5]->arg) { + if (!inet_aton(argv[idx + 5]->arg, &vtep_ip)) { vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } @@ -2066,12 +2122,16 @@ DEFUN (show_bgp_evpn_route_vni_all, return CMD_SUCCESS; } -DEFUN (show_bgp_evpn_import_rt, - show_bgp_evpn_import_rt_cmd, - "show bgp evpn import-rt", +/* + * Display EVPN import route-target hash table + */ +DEFUN (show_bgp_l2vpn_evpn_import_rt, + show_bgp_l2vpn_evpn_import_rt_cmd, + "show bgp l2vpn evpn import-rt", SHOW_STR BGP_STR - "Address family modifier\n" + L2VPN_HELP_STR + EVPN_HELP_STR "Show import route target\n") { struct bgp *bgp; @@ -2510,18 +2570,18 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); - /* "show bgp evpn" commands. */ - install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_vni_num_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_rd_macip_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_vni_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_vni_multicast_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd); - install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd); + /* "show bgp l2vpn evpn" commands. */ + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_summary_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_rd_macip_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_cmd); + install_element(VIEW_NODE, + &show_bgp_l2vpn_evpn_route_vni_multicast_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_macip_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd); + install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd); install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd); From ba0fcaf6df38668b2b77d22a5780d2c631405b81 Mon Sep 17 00:00:00 2001 From: vivek Date: Tue, 13 Jun 2017 19:12:10 -0700 Subject: [PATCH 03/32] bgpd: Fix incorrect AFI reference Fixes: "bgpd: Fixes related to use of L2VPN/EVPN" Signed-off-by: Vivek Venkatraman --- bgpd/bgpd.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 208a4e4b4e..7992075af1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1488,7 +1488,8 @@ static inline int peer_group_af_configured(struct peer_group *group) || peer->afc[AFI_IP6][SAFI_MULTICAST] || peer->afc[AFI_IP6][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP6][SAFI_MPLS_VPN] - || peer->afc[AFI_IP6][SAFI_ENCAP] || peer->afc[AFI_IP6][SAFI_EVPN]) + || peer->afc[AFI_IP6][SAFI_ENCAP] + || peer->afc[AFI_L2VPN][SAFI_EVPN]) return 1; return 0; } From d37ba5499ec01284c91250db0c17016c37f13a84 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 21 Jun 2017 01:02:46 -0700 Subject: [PATCH 04/32] bgpd, lib, vtysh: Added support for mac filtering in route-maps 1. Added support to create mac filters 2. Enabled route-map commands for EVPN address family 3. Provision to add mac filters under match clause in route-maps Ticket: CM-16349 Review: CCR-6190 Unit-test: Manual (logs attached to ticket) Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_route.c | 1 + bgpd/bgp_routemap.c | 78 +++++ bgpd/bgp_vty.c | 2 + lib/command.c | 1 + lib/command.h | 1 + lib/filter.c | 267 ++++++++++++++++-- lib/prefix.c | 658 ++++++++++++++++++------------------------- lib/prefix.h | 2 + vtysh/vtysh_config.c | 11 +- 9 files changed, 605 insertions(+), 416 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index e4e421510f..4f21232191 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1584,6 +1584,7 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, info.peer = peer; info.attr = attr; + /* don't confuse inbound and outbound setting */ RESET_FLAG(attr->rmap_change_flags); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 285bb9a80c..811ff619a3 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -54,6 +54,8 @@ #include "bgpd/bgp_lcommunity.h" #include "bgpd/bgp_vty.h" #include "bgpd/bgp_debug.h" +#include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -572,6 +574,52 @@ struct route_map_rule_cmd route_match_ip_route_source_prefix_list_cmd = { route_match_ip_route_source_prefix_list_compile, route_match_ip_route_source_prefix_list_free}; +/* `match mac address MAC_ACCESS_LIST' */ + +/* Match function should return 1 if match is success else return + zero. */ +static route_map_result_t route_match_mac_address(void *rule, + struct prefix *prefix, + route_map_object_t type, + void *object) +{ + struct access_list *alist; + + if (type == RMAP_BGP) { + alist = access_list_lookup(AFI_L2VPN, (char *)rule); + if (alist == NULL) + return RMAP_NOMATCH; + + if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE) + return RMAP_NOMATCH; + + return (access_list_apply(alist, &(prefix->u.prefix_evpn.mac)) + == FILTER_DENY + ? RMAP_NOMATCH + : RMAP_MATCH); + } + + return RMAP_NOMATCH; +} + +/* Route map `mac address' match statement. `arg' should be + access-list name. */ +static void *route_match_mac_address_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +/* Free route map's compiled `ip address' value. */ +static void route_match_mac_address_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for mac address matching. */ +struct route_map_rule_cmd route_match_mac_address_cmd = { + "mac address", route_match_mac_address, route_match_mac_address_compile, + route_match_mac_address_free}; + /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -2994,6 +3042,33 @@ static void bgp_route_map_event(route_map_event_t event, const char *rmap_name) route_map_notify_dependencies(rmap_name, RMAP_EVENT_MATCH_ADDED); } +DEFUN (match_mac_address, + match_mac_address_cmd, + "match mac address WORD", + MATCH_STR + "mac address\n" + "Match address of route\n" + "MAC Access-list name\n") +{ + return bgp_route_match_add(vty, "mac address", argv[3]->arg, + RMAP_EVENT_FILTER_ADDED); +} + +DEFUN (no_match_mac_address, + no_match_mac_address_cmd, + "no match mac address", + NO_STR + MATCH_STR + "mac\n" + "Match address of route\n") +{ + if (argc == 0) + return bgp_route_match_delete(vty, "mac address", NULL, + RMAP_EVENT_FILTER_DELETED); + + return bgp_route_match_delete(vty, "mac address", argv[4]->arg, + RMAP_EVENT_FILTER_DELETED); +} DEFUN (match_peer, match_peer_cmd, @@ -4351,6 +4426,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_probability_cmd); route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_tag_cmd); + route_map_install_match(&route_match_mac_address_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -4381,6 +4457,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_ip_route_source_cmd); install_element(RMAP_NODE, &match_ip_route_source_prefix_list_cmd); install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd); + install_element(RMAP_NODE, &match_mac_address_cmd); + install_element(RMAP_NODE, &no_match_mac_address_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 0220a7e55d..01c27920f5 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -12047,6 +12047,8 @@ void bgp_vty_init(void) install_element(BGP_VPNV4_NODE, &no_neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &neighbor_route_map_cmd); install_element(BGP_VPNV6_NODE, &no_neighbor_route_map_cmd); + install_element(BGP_EVPN_NODE, &neighbor_route_map_cmd); + install_element(BGP_EVPN_NODE, &no_neighbor_route_map_cmd); /* "neighbor unsuppress-map" commands. */ install_element(BGP_NODE, &neighbor_unsuppress_map_hidden_cmd); diff --git a/lib/command.c b/lib/command.c index f28a55ec6d..c25743324a 100644 --- a/lib/command.c +++ b/lib/command.c @@ -101,6 +101,7 @@ const char *node_names[] = { "ipv4 access list", // ACCESS_NODE, "ipv4 prefix list", // PREFIX_NODE, "ipv6 access list", // ACCESS_IPV6_NODE, + "MAC access list", // ACCESS_MAC_NODE, "ipv6 prefix list", // PREFIX_IPV6_NODE, "as list", // AS_LIST_NODE, "community list", // COMMUNITY_LIST_NODE, diff --git a/lib/command.h b/lib/command.h index 5184b53a9f..e53b70f7ad 100644 --- a/lib/command.h +++ b/lib/command.h @@ -123,6 +123,7 @@ enum node_type { ACCESS_NODE, /* Access list node. */ PREFIX_NODE, /* Prefix list node. */ ACCESS_IPV6_NODE, /* Access list node. */ + ACCESS_MAC_NODE, /* MAC access list node*/ PREFIX_IPV6_NODE, /* Prefix list node. */ AS_LIST_NODE, /* AS list node. */ COMMUNITY_LIST_NODE, /* Community list node. */ diff --git a/lib/filter.c b/lib/filter.c index 0262234c78..186b32bbba 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -90,6 +90,14 @@ struct access_master { void (*delete_hook)(struct access_list *); }; +/* Static structure for IPv4 access_list's master. */ +static struct access_master access_master_mac = { + {NULL, NULL}, + {NULL, NULL}, + NULL, + NULL, +}; + /* Static structure for IPv4 access_list's master. */ static struct access_master access_master_ipv4 = { {NULL, NULL}, @@ -112,6 +120,8 @@ static struct access_master *access_master_get(afi_t afi) return &access_master_ipv4; else if (afi == AFI_IP6) return &access_master_ipv6; + else if (afi == AFI_L2VPN) + return &access_master_mac; return NULL; } @@ -146,6 +156,25 @@ static const char *filter_type_str(struct filter *filter) } } +/* + * mac filter match + * n is of type struct prefix_eth + * p can be of type struct ethaddr + */ +static int mac_filter_match(struct prefix *n, struct ethaddr *p) +{ + if (!n && !p) + return 1; + + if (!n || !p) + return 0; + + if (memcmp(&(n->u.prefix), p, sizeof(struct ethaddr)) == 0) + return 1; + + return 0; +} + /* If filter match to the prefix then return 1. */ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) { @@ -171,22 +200,37 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) } /* If filter match to the prefix then return 1. */ -static int filter_match_zebra(struct filter *mfilter, struct prefix *p) +static int filter_match_zebra(struct filter *mfilter, void *obj) { - struct filter_zebra *filter; + struct filter_zebra *filter = NULL; filter = &mfilter->u.zfilter; - if (filter->prefix.family == p->family) { - if (filter->exact) { - if (filter->prefix.prefixlen == p->prefixlen) + if (filter->prefix.family == AF_ETHERNET) { + struct ethaddr *p = NULL; + + p = (struct ethaddr *)obj; + return mac_filter_match(&filter->prefix, p); + } + + if (filter->prefix.family == AF_INET + || filter->prefix.family == AF_INET6) { + struct prefix *p = NULL; + + p = (struct prefix *)obj; + if (filter->prefix.family == p->family) { + if (filter->exact) { + if (filter->prefix.prefixlen == p->prefixlen) + return prefix_match(&filter->prefix, p); + else + return 0; + } else return prefix_match(&filter->prefix, p); - else - return 0; } else - return prefix_match(&filter->prefix, p); - } else - return 0; + return 0; + } + + return 0; } /* Allocate new access list structure. */ @@ -377,7 +421,7 @@ enum filter_type access_list_apply(struct access_list *access, void *object) if (filter_match_cisco(filter, p)) return filter->type; } else { - if (filter_match_zebra(filter, p)) + if (filter_match_zebra(filter, object)) return filter->type; } } @@ -390,6 +434,7 @@ void access_list_add_hook(void (*func)(struct access_list *access)) { access_master_ipv4.add_hook = func; access_master_ipv6.add_hook = func; + access_master_mac.add_hook = func; } /* Delete hook function. */ @@ -397,6 +442,7 @@ void access_list_delete_hook(void (*func)(struct access_list *access)) { access_master_ipv4.delete_hook = func; access_master_ipv6.delete_hook = func; + access_master_mac.delete_hook = func; } /* Add new filter to the end of specified access_list. */ @@ -515,10 +561,18 @@ static struct filter *filter_lookup_zebra(struct access_list *access, filter = &mfilter->u.zfilter; if (filter->exact == new->exact - && mfilter->type - == mnew->type &&prefix_same(&filter->prefix, - &new->prefix)) - return mfilter; + && mfilter->type == mnew->type) { + if (new->prefix.family == AF_ETHERNET) { + if (prefix_eth_same( + (struct prefix_eth *)&filter + ->prefix, + (struct prefix_eth *)&new->prefix)) + return mfilter; + } else { + if (prefix_same(&filter->prefix, &new->prefix)) + return mfilter; + } + } } return NULL; } @@ -1252,6 +1306,12 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, "IPv6 address prefix/prefixlen is malformed\n"); return CMD_WARNING_CONFIG_FAILED; } + } else if (afi == AFI_L2VPN) { + ret = str2prefix_eth(prefix_str, (struct prefix_eth *)&p); + if (ret <= 0) { + vty_out(vty, "MAC address is malformed\n"); + return CMD_WARNING; + } } else return CMD_WARNING_CONFIG_FAILED; @@ -1274,7 +1334,6 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, access_list_filter_add(access, mfilter); } else { struct filter *delete_filter; - delete_filter = filter_lookup_zebra(access, mfilter); if (delete_filter) access_list_filter_delete(access, delete_filter); @@ -1285,6 +1344,64 @@ static int filter_set_zebra(struct vty *vty, const char *name_str, return CMD_SUCCESS; } +DEFUN (mac_access_list, + mac_access_list_cmd, + "mac access-list WORD MAC", + "Add a mac access-list\n" + "Add an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + argv[4]->arg, 0, 1); +} + +DEFUN (no_mac_access_list, + no_mac_access_list_cmd, + "no mac access-list WORD MAC", + NO_STR + "Remove a mac access-list\n" + "Remove an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, + argv[5]->arg, 0, 0); +} + +DEFUN (mac_access_list_any, + mac_access_list_any_cmd, + "mac access-list WORD any", + "Add a mac access-list\n" + "Add an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + "00:00:00:00:00:00", 0, 1); +} + +DEFUN (no_mac_access_list_any, + no_mac_access_list_any_cmd, + "no mac access-list WORD any", + NO_STR + "Remove a mac access-list\n" + "Remove an access list entry\n" + "MAC zebra access-list name\n" + "Specify packets to reject\n" + "Specify packets to forward\n" + "MAC address to match. e.g. 00:01:00:01:00:01\n") +{ + return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + "00:00:00:00:00:00", 0, 0); +} + DEFUN (access_list_exact, access_list_exact_cmd, "access-list WORD A.B.C.D/M [exact-match]", @@ -1666,12 +1783,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) filter = &mfilter->u.cfilter; if (write) { - vty_out(vty, "%s IP%s access list %s\n", + vty_out(vty, "%s %s access list %s\n", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", - afi == AFI_IP6 ? "v6" : "", + (afi == AFI_IP) + ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), access->name); write = 0; } @@ -1710,12 +1830,15 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) filter = &mfilter->u.cfilter; if (write) { - vty_out(vty, "%s IP%s access list %s\n", + vty_out(vty, "%s %s access list %s\n", mfilter->cisco ? (filter->extended ? "Extended" : "Standard") : "Zebra", - afi == AFI_IP6 ? "v6" : "", + (afi == AFI_IP) + ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), access->name); write = 0; } @@ -1746,6 +1869,29 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) return CMD_SUCCESS; } +/* show MAC access list - this only has MAC filters for now*/ +DEFUN (show_mac_access_list, + show_mac_access_list_cmd, + "show mac access-list", + SHOW_STR + "mac access lists\n" + "List mac access lists\n") +{ + return filter_show(vty, NULL, AFI_L2VPN); +} + +DEFUN (show_mac_access_list_name, + show_mac_access_list_name_cmd, + "show mac access-list WORD", + SHOW_STR + "mac\n" + "List mac access lists\n" + "mac zebra access-list\n" + "mac address") +{ + return filter_show(vty, argv[3]->arg, AFI_L2VPN); +} + DEFUN (show_ip_access_list, show_ip_access_list_cmd, "show ip access-list", @@ -1844,10 +1990,13 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter) if (p->prefixlen == 0 && !filter->exact) vty_out(vty, " any"); - else + else if (p->family == AF_INET6 || p->family == AF_INET) vty_out(vty, " %s/%d%s", inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, filter->exact ? " exact-match" : ""); + else + vty_out(vty, " %s", + prefix_mac2str(&(p->u.prefix_eth), buf, sizeof(buf))); vty_out(vty, "\n"); } @@ -1866,15 +2015,19 @@ static int config_write_access(struct vty *vty, afi_t afi) for (access = master->num.head; access; access = access->next) { if (access->remark) { vty_out(vty, "%saccess-list %s remark %s\n", - afi == AFI_IP ? "" : "ipv6 ", access->name, - access->remark); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, access->remark); write++; } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { vty_out(vty, "%saccess-list %s %s", - afi == AFI_IP ? "" : "ipv6 ", access->name, - filter_type_str(mfilter)); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); @@ -1888,15 +2041,19 @@ static int config_write_access(struct vty *vty, afi_t afi) for (access = master->str.head; access; access = access->next) { if (access->remark) { vty_out(vty, "%saccess-list %s remark %s\n", - afi == AFI_IP ? "" : "ipv6 ", access->name, - access->remark); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, access->remark); write++; } for (mfilter = access->head; mfilter; mfilter = mfilter->next) { vty_out(vty, "%saccess-list %s %s", - afi == AFI_IP ? "" : "ipv6 ", access->name, - filter_type_str(mfilter)); + (afi == AFI_IP) ? ("") + : ((afi == AFI_IP6) ? ("ipv6 ") + : ("mac ")), + access->name, filter_type_str(mfilter)); if (mfilter->cisco) config_write_access_cisco(vty, mfilter); @@ -1909,6 +2066,56 @@ static int config_write_access(struct vty *vty, afi_t afi) return write; } +static struct cmd_node access_mac_node = { + ACCESS_MAC_NODE, "", /* Access list has no interface. */ + 1}; + +static int config_write_access_mac(struct vty *vty) +{ + return config_write_access(vty, AFI_L2VPN); +} + +static void access_list_reset_mac(void) +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get(AFI_L2VPN); + if (master == NULL) + return; + + for (access = master->num.head; access; access = next) { + next = access->next; + access_list_delete(access); + } + for (access = master->str.head; access; access = next) { + next = access->next; + access_list_delete(access); + } + + assert(master->num.head == NULL); + assert(master->num.tail == NULL); + + assert(master->str.head == NULL); + assert(master->str.tail == NULL); +} + +/* Install vty related command. */ +static void access_list_init_mac(void) +{ + install_node(&access_mac_node, config_write_access_mac); + + install_element(ENABLE_NODE, &show_mac_access_list_cmd); + install_element(ENABLE_NODE, &show_mac_access_list_name_cmd); + + /* Zebra access-list */ + install_element(CONFIG_NODE, &mac_access_list_cmd); + install_element(CONFIG_NODE, &no_mac_access_list_cmd); + install_element(CONFIG_NODE, &mac_access_list_any_cmd); + install_element(CONFIG_NODE, &no_mac_access_list_any_cmd); +} + /* Access-list node. */ static struct cmd_node access_node = {ACCESS_NODE, "", /* Access list has no interface. */ @@ -2050,10 +2257,12 @@ void access_list_init() { access_list_init_ipv4(); access_list_init_ipv6(); + access_list_init_mac(); } void access_list_reset() { access_list_reset_ipv4(); access_list_reset_ipv6(); + access_list_reset_mac(); } diff --git a/lib/prefix.c b/lib/prefix.c index 33b6ff1987..e67184f52b 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -37,390 +37,262 @@ static const u_char maskbit[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, static const struct in6_addr maskbytes6[] = { /* /0 */ {{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /1 */ - {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /2 */ - {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /3 */ - {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /4 */ - {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /5 */ - {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /6 */ - {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /7 */ - {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /8 */ - {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /9 */ - {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /10 */ - {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /11 */ - {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /12 */ - {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /13 */ - {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /14 */ - {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /15 */ - {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /16 */ - {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /17 */ - {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /18 */ - {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /19 */ - {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /20 */ - {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /21 */ - {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /22 */ - {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /23 */ - {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /24 */ - {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /25 */ - {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /26 */ - {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /27 */ - {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /28 */ - {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /29 */ - {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /30 */ - {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /31 */ - {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /32 */ - {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /33 */ - {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /34 */ - {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /35 */ - {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /36 */ - {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /37 */ - {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /38 */ - {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /39 */ - {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /40 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /41 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /42 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /43 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /44 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /45 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /46 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /47 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /48 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /49 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /50 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /51 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /52 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /53 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /54 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /55 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /56 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /57 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /58 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /59 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /60 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /61 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /62 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /63 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /64 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /65 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /66 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /67 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /68 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /69 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /70 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /71 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /72 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /73 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /74 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /75 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /76 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /77 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /78 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /79 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /80 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /81 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /82 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /83 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /84 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /85 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /86 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /87 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /88 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x00, 0x00, 0x00, 0x00, 0x00}}}, - /* /89 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0x80, 0x00, 0x00, 0x00, 0x00}}}, - /* /90 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xc0, 0x00, 0x00, 0x00, 0x00}}}, - /* /91 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xe0, 0x00, 0x00, 0x00, 0x00}}}, - /* /92 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf0, 0x00, 0x00, 0x00, 0x00}}}, - /* /93 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xf8, 0x00, 0x00, 0x00, 0x00}}}, - /* /94 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfc, 0x00, 0x00, 0x00, 0x00}}}, - /* /95 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xfe, 0x00, 0x00, 0x00, 0x00}}}, - /* /96 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00}}}, - /* /97 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x80, 0x00, 0x00, 0x00}}}, - /* /98 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x00, 0x00, 0x00}}}, - /* /99 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xe0, 0x00, 0x00, 0x00}}}, - /* /100 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf0, 0x00, 0x00, 0x00}}}, - /* /101 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xf8, 0x00, 0x00, 0x00}}}, - /* /102 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfc, 0x00, 0x00, 0x00}}}, - /* /103 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xfe, 0x00, 0x00, 0x00}}}, - /* /104 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x00, 0x00, 0x00}}}, - /* /105 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0x80, 0x00, 0x00}}}, - /* /106 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xc0, 0x00, 0x00}}}, - /* /107 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xe0, 0x00, 0x00}}}, - /* /108 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf0, 0x00, 0x00}}}, - /* /109 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xf8, 0x00, 0x00}}}, - /* /110 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfc, 0x00, 0x00}}}, - /* /111 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xfe, 0x00, 0x00}}}, - /* /112 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, 0x00}}}, - /* /113 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x80, 0x00}}}, - /* /114 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xc0, 0x00}}}, - /* /115 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xe0, 0x00}}}, - /* /116 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf0, 0x00}}}, - /* /117 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xf8, 0x00}}}, - /* /118 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfc, 0x00}}}, - /* /119 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xfe, 0x00}}}, - /* /120 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00}}}, - /* /121 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x80}}}, - /* /122 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xc0}}}, - /* /123 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xe0}}}, - /* /124 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf0}}}, - /* /125 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xf8}}}, - /* /126 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfc}}}, - /* /127 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xfe}}}, - /* /128 */ - {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff}}}}; + /* /1 */ {{{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /2 */ {{{0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /3 */ {{{0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /4 */ {{{0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /5 */ {{{0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /6 */ {{{0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /7 */ {{{0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /8 */ {{{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /9 */ {{{0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /10 */ {{{0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /11 */ {{{0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /12 */ {{{0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /13 */ {{{0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /14 */ {{{0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /15 */ {{{0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /16 */ {{{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /17 */ {{{0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /18 */ {{{0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /19 */ {{{0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /20 */ {{{0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /21 */ {{{0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /22 */ {{{0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /23 */ {{{0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /24 */ {{{0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /25 */ {{{0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /26 */ {{{0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /27 */ {{{0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /28 */ {{{0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /29 */ {{{0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /30 */ {{{0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /31 */ {{{0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /32 */ {{{0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /33 */ {{{0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /34 */ {{{0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /35 */ {{{0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /36 */ {{{0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /37 */ {{{0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /38 */ {{{0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /39 */ {{{0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /40 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /41 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /42 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /43 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /44 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /45 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /46 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /47 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /48 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /49 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /50 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /51 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /52 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /53 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /54 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /55 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /56 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /57 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /58 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /59 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /60 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /61 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /62 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /63 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /64 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /65 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /66 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /67 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /68 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /69 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /70 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /71 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /72 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /73 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /74 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /75 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /76 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /77 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /78 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /79 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /80 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /81 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /82 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /83 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /84 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /85 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /86 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /87 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /88 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00}}}, + /* /89 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00}}}, + /* /90 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x00}}}, + /* /91 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00, 0x00}}}, + /* /92 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00}}}, + /* /93 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00, 0x00}}}, + /* /94 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00, 0x00}}}, + /* /95 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00}}}, + /* /96 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}}}, + /* /97 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x80, 0x00, 0x00, 0x00}}}, + /* /98 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00, 0x00}}}, + /* /99 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x00}}}, + /* /100 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x00}}}, + /* /101 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x00}}}, + /* /102 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x00}}}, + /* /103 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00}}}, + /* /104 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00}}}, + /* /105 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0x00}}}, + /* /106 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x00}}}, + /* /107 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00, 0x00}}}, + /* /108 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00}}}, + /* /109 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0x00}}}, + /* /110 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00}}}, + /* /111 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00, 0x00}}}, + /* /112 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00}}}, + /* /113 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00}}}, + /* /114 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00}}}, + /* /115 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x00}}}, + /* /116 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x00}}}, + /* /117 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00}}}, + /* /118 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x00}}}, + /* /119 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x00}}}, + /* /120 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00}}}, + /* /121 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80}}}, + /* /122 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0}}}, + /* /123 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0}}}, + /* /124 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0}}}, + /* /125 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8}}}, + /* /126 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc}}}, + /* /127 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}}}, + /* /128 */ {{{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}}}; /* Number of bits in prefix type. */ #ifndef PNBBY @@ -589,6 +461,24 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) } } +/* check if the two prefix_eth struct are same*/ +int prefix_eth_same(struct prefix_eth *p1, struct prefix_eth *p2) +{ + if (!p1 && !p2) + return 1; + + if (p1 && !p2) + return 0; + + if (!p1 && p2) + return 0; + + if (memcmp(p1, p2, sizeof(struct prefix_eth)) == 0) + return 1; + + return 0; +} + /* * Return 1 if the address/netmask contained in the prefix structure * is the same, and else return 0. For this routine, 'same' requires diff --git a/lib/prefix.h b/lib/prefix.h index 5f2b57ccce..0f3ad562d9 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -293,6 +293,7 @@ extern int prefix_cmp(const struct prefix *, const struct prefix *); extern int prefix_common_bits(const struct prefix *, const struct prefix *); extern void prefix_copy(struct prefix *dest, const struct prefix *src); extern void apply_mask(struct prefix *); +extern int prefix_eth_same(struct prefix_eth *p1, struct prefix_eth *p2); extern struct prefix *sockunion2prefix(const union sockunion *dest, const union sockunion *mask); @@ -356,6 +357,7 @@ static inline int ipv6_martian(struct in6_addr *addr) } extern int all_digit(const char *); +extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p); /* NOTE: This routine expects the address argument in network byte order. */ static inline int ipv4_martian(struct in_addr *addr) diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 74509d1ec8..d388b568ad 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -222,6 +222,10 @@ void vtysh_config_parse_line(void *arg, const char *line) strlen("ipv6 access-list")) == 0) config = config_get(ACCESS_IPV6_NODE, line); + else if (strncmp(line, "mac access-list", + strlen("mac access-list")) + == 0) + config = config_get(ACCESS_MAC_NODE, line); else if (strncmp(line, "ip prefix-list", strlen("ip prefix-list")) == 0) @@ -300,9 +304,10 @@ void vtysh_config_parse_line(void *arg, const char *line) #define NO_DELIMITER(I) \ ((I) == ACCESS_NODE || (I) == PREFIX_NODE || (I) == IP_NODE \ || (I) == AS_LIST_NODE || (I) == COMMUNITY_LIST_NODE \ - || (I) == ACCESS_IPV6_NODE || (I) == PREFIX_IPV6_NODE \ - || (I) == SERVICE_NODE || (I) == FORWARDING_NODE || (I) == DEBUG_NODE \ - || (I) == AAA_NODE || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE) + || (I) == ACCESS_IPV6_NODE || (I) == ACCESS_MAC_NODE \ + || (I) == PREFIX_IPV6_NODE || (I) == SERVICE_NODE \ + || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \ + || (I) == VRF_DEBUG_NODE || (I) == MPLS_NODE) /* Display configuration to file pointer. */ void vtysh_config_dump(FILE *fp) From 16f7ce2b1e88db5ef7f64fb79db3ca2784466e4b Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 21 Jun 2017 02:00:24 -0700 Subject: [PATCH 05/32] bgpd: Added support for vni filtering 1. provision to add match clause with a vni under route-map Ticket: CM-16349 Review: CCR-6190 Unit-test: Manual (logs attached to ticket) Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_route.c | 7 +++++ bgpd/bgp_routemap.c | 74 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 4f21232191..ac820fb34f 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -1580,11 +1580,18 @@ int subgroup_announce_check(struct bgp_node *rn, struct bgp_info *ri, /* Route map & unsuppress-map apply. */ if (ROUTE_MAP_OUT_NAME(filter) || (ri->extra && ri->extra->suppress)) { struct bgp_info info; + struct bgp_info_extra dummy_info_extra; struct attr dummy_attr; info.peer = peer; info.attr = attr; + if (ri->extra) { + memcpy(&dummy_info_extra, ri->extra, + sizeof(struct bgp_info_extra)); + info.extra = &dummy_info_extra; + } + /* don't confuse inbound and outbound setting */ RESET_FLAG(attr->rmap_change_flags); diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 811ff619a3..d360161cfe 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -620,6 +620,54 @@ struct route_map_rule_cmd route_match_mac_address_cmd = { "mac address", route_match_mac_address, route_match_mac_address_compile, route_match_mac_address_free}; +/* `match vni' */ + +/* Match function should return 1 if match is success else return + zero. */ +static route_map_result_t route_match_vni(void *rule, struct prefix *prefix, + route_map_object_t type, void *object) +{ + vni_t vni = 0; + struct bgp_info *bgp_info = NULL; + + if (type == RMAP_BGP) { + vni = *((vni_t *)rule); + bgp_info = (struct bgp_info *)object; + + if (vni == label2vni(&bgp_info->extra->label)) + return RMAP_MATCH; + } + + return RMAP_NOMATCH; +} + +/* Route map `vni' match statement. */ +static void *route_match_vni_compile(const char *arg) +{ + vni_t *vni = NULL; + char *end = NULL; + + vni = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(vni_t)); + if (!vni) + return NULL; + + *vni = strtoul(arg, &end, 10); + if (*end != '\0') + return NULL; + + return vni; +} + +/* Free route map's compiled `vni' value. */ +static void route_match_vni_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +/* Route map commands for vni matching. */ +struct route_map_rule_cmd route_match_evpn_vni_cmd = { + "vni", route_match_vni, route_match_vni_compile, route_match_vni_free}; + /* `match local-preference LOCAL-PREF' */ /* Match function return 1 if match is success else return zero. */ @@ -3070,6 +3118,29 @@ DEFUN (no_match_mac_address, RMAP_EVENT_FILTER_DELETED); } +DEFUN (match_evpn_vni, + match_evpn_vni_cmd, + "match evpn vni (1-16777215)", + MATCH_STR + "Match VNI\n" + "VNI ID\n") +{ + return bgp_route_match_add(vty, "evpn vni", argv[2]->arg, + RMAP_EVENT_MATCH_ADDED); +} + +DEFUN (no_match_evpn_vni, + no_match_evpn_vni_cmd, + "no match evpn vni (1-16777215)", + NO_STR + MATCH_STR + "Match VNI\n" + "VNI ID\n") +{ + return bgp_route_match_delete(vty, "evpn vni", argv[3]->arg, + RMAP_EVENT_MATCH_DELETED); +} + DEFUN (match_peer, match_peer_cmd, "match peer ", @@ -4427,6 +4498,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_interface_cmd); route_map_install_match(&route_match_tag_cmd); route_map_install_match(&route_match_mac_address_cmd); + route_map_install_match(&route_match_evpn_vni_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); @@ -4459,6 +4531,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_match_ip_route_source_prefix_list_cmd); install_element(RMAP_NODE, &match_mac_address_cmd); install_element(RMAP_NODE, &no_match_mac_address_cmd); + install_element(RMAP_NODE, &match_evpn_vni_cmd); + install_element(RMAP_NODE, &no_match_evpn_vni_cmd); install_element(RMAP_NODE, &match_aspath_cmd); install_element(RMAP_NODE, &no_match_aspath_cmd); From 62982d5a9d7b9e76d0e520f8145c369f090a1772 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 21 Jun 2017 11:14:24 -0400 Subject: [PATCH 06/32] bgpd: Fix evpn help strings Signed-off-by: Donald Sharp Reviewed-by: Daniel Walton --- bgpd/bgp_routemap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index d360161cfe..bde0363ae7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -56,6 +56,7 @@ #include "bgpd/bgp_debug.h" #include "bgpd/bgp_evpn.h" #include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_evpn_vty.h" #if ENABLE_BGP_VNC #include "bgpd/rfapi/bgp_rfapi_cfg.h" @@ -3122,6 +3123,7 @@ DEFUN (match_evpn_vni, match_evpn_vni_cmd, "match evpn vni (1-16777215)", MATCH_STR + EVPN_HELP_STR "Match VNI\n" "VNI ID\n") { @@ -3134,6 +3136,7 @@ DEFUN (no_match_evpn_vni, "no match evpn vni (1-16777215)", NO_STR MATCH_STR + EVPN_HELP_STR "Match VNI\n" "VNI ID\n") { From 421bb26a51b36cc7081aae7418cb932743bfc6d5 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 21 Jun 2017 12:55:29 -0700 Subject: [PATCH 07/32] bgpd/zebra: fix bgpd crash happening in mac mobility code path Ticket: CM-16216 Review: CCR-6210 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 26 +++++++++++++------------- zebra/zebra_vxlan.c | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index fe311832a2..7a5e370bcf 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -347,9 +347,9 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn, s = zclient->obuf; stream_reset(s); - zclient_create_header( - s, add ? ZEBRA_REMOTE_MACIP_ADD : ZEBRA_REMOTE_MACIP_DEL, - bgp->vrf_id); + zclient_create_header(s, add ? ZEBRA_REMOTE_MACIP_ADD + : ZEBRA_REMOTE_MACIP_DEL, + bgp->vrf_id); stream_putl(s, vpn->vni); stream_put(s, &p->prefix.mac.octet, ETH_ALEN); /* Mac Addr */ /* IP address length and IP address, if any. */ @@ -400,9 +400,9 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn, s = zclient->obuf; stream_reset(s); - zclient_create_header( - s, add ? ZEBRA_REMOTE_VTEP_ADD : ZEBRA_REMOTE_VTEP_DEL, - bgp->vrf_id); + zclient_create_header(s, add ? ZEBRA_REMOTE_VTEP_ADD + : ZEBRA_REMOTE_VTEP_DEL, + bgp->vrf_id); stream_putl(s, vpn->vni); if (IS_EVPN_PREFIX_IPADDR_V4(p)) stream_put_in_addr(s, &p->prefix.ip.ipaddr_v4); @@ -472,7 +472,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) { struct ecommunity ecom_tmp; struct ecommunity_val eval; - struct ecommunity *ecom_mm; + u_int8_t *ecom_val_ptr; int i; u_int8_t *pnt; int type = 0; @@ -482,7 +482,7 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) encode_mac_mobility_extcomm(0, seq_num, &eval); /* Find current MM ecommunity */ - ecom_mm = NULL; + ecom_val_ptr = NULL; if (attr->ecommunity) { for (i = 0; i < attr->ecommunity->size; i++) { @@ -493,17 +493,17 @@ static void add_mac_mobility_to_attr(u_int32_t seq_num, struct attr *attr) if (type == ECOMMUNITY_ENCODE_EVPN && sub_type == ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY) { - ecom_mm = (struct ecommunity *) - attr->ecommunity->val - + (i * 8); + ecom_val_ptr = + (u_int8_t *)(attr->ecommunity->val + + (i * 8)); break; } } } /* Update the existing MM ecommunity */ - if (ecom_mm) { - memcpy(ecom_mm->val, eval.val, sizeof(char) * ECOMMUNITY_SIZE); + if (ecom_val_ptr) { + memcpy(ecom_val_ptr, eval.val, sizeof(char) * ECOMMUNITY_SIZE); } /* Add MM to existing */ else { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 7d265af309..542b66898b 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2601,6 +2601,20 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, } add = 0; /* This is an update of local interface. */ + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + /* + * If we have already learned the MAC as a remote sticky + * MAC, + * this is a operator error and we must log a warning + */ + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) + zlog_warn( + "MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d", + prefix_mac2str(macaddr, buf, + sizeof(buf)), + inet_ntoa(mac->fwd_info.r_vtep_ip), + zvni->vni); + return 0; } } From b8ce75a5d3cca1519bf788db96379c162a3c9b7b Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 21 Jun 2017 14:25:39 -0700 Subject: [PATCH 08/32] zebra: update sticky mac attribute to BGP if necessary Ticket: CM-16732 Review: CCR-6368 Unit-test: Manual (logs attached to ticket) Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 542b66898b..029aefb0f7 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2584,6 +2584,12 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, ? 1 : 0; + /* + * return if nothing has changed. + * inform bgp if sticky flag has changed + * update locally and do not inform bgp if local + * parameters like interface has changed + */ if (mac_sticky == sticky && mac->fwd_info.local.ifindex == ifp->ifindex && mac->fwd_info.local.vid == vid) { @@ -2598,9 +2604,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, ifp->name, ifp->ifindex, vid, zvni->vni); return 0; - } - - add = 0; /* This is an update of local interface. */ + } else if (mac_sticky != sticky) + add = 1; + else + add = 0; /* This is an update of local + interface. */ } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { /* * If we have already learned the MAC as a remote sticky From 8f4b98eedbdf41d87b7228f81143a85d6ff2b09e Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Mon, 26 Jun 2017 17:55:55 -0700 Subject: [PATCH 09/32] zebra: fix mac mobility code path Ticket: CM-16928 Review: CCR-6210 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 029aefb0f7..523225bf36 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2615,14 +2615,15 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, * MAC, * this is a operator error and we must log a warning */ - if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY)) { zlog_warn( "MAC %s is already learnt as a remote sticky mac behind VTEP %s VNI %d", prefix_mac2str(macaddr, buf, sizeof(buf)), inet_ntoa(mac->fwd_info.r_vtep_ip), zvni->vni); - return 0; + return 0; + } } } From 1a98c08704e701740716f5bf0c51c68740e84708 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 28 Jun 2017 01:51:10 -0700 Subject: [PATCH 10/32] bgpd/zebra/lib: EVPN support for asymmetric VxLan routing 1. Advertise gateway mac-ip in EVPN 2. Advertise VRR mac-ip in EVPN 3. Ignore gateway mac-ip advertisements in case of distributed gateway 4. Config knob to enable/disable gateway mac-ip advertisements Ticket: CM-16456, CM-16543, CM-16555, CM-16778 Review: CCR-6283 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 39 ++- bgpd/bgp_evpn.h | 2 +- bgpd/bgp_evpn_private.h | 3 + bgpd/bgp_evpn_vty.c | 135 +++++++- bgpd/bgp_zebra.c | 36 ++- bgpd/bgp_zebra.h | 3 + bgpd/bgpd.h | 3 + lib/log.c | 1 + lib/zclient.h | 5 + zebra/if_netlink.c | 2 + zebra/interface.h | 14 +- zebra/redistribute.c | 5 + zebra/zebra_vrf.h | 5 + zebra/zebra_vxlan.c | 603 +++++++++++++++++++++++++++++++++--- zebra/zebra_vxlan.h | 5 + zebra/zebra_vxlan_private.h | 3 + zebra/zserv.c | 3 + 17 files changed, 801 insertions(+), 66 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 7a5e370bcf..ab3307a6a7 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -704,7 +704,7 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn) static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, afi_t afi, safi_t safi, struct bgp_node *rn, struct attr *attr, int add, int vni_table, - struct bgp_info **ri) + struct bgp_info **ri, u_char flags) { struct bgp_info *tmp_ri; struct bgp_info *local_ri, *remote_ri; @@ -751,8 +751,11 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * remote, we have to initiate appropriate MAC mobility steps. * This * is applicable when updating the VNI routing table. + * We need to skip mobility steps for g/w macs (local mac on g/w + * SVI) advertised in EVPN. + * This will ensure that local routes are preferred for g/w macs */ - if (remote_ri) { + if (remote_ri && !CHECK_FLAG(flags, ZEBRA_MAC_TYPE_GW)) { u_int32_t cur_seqnum; /* Add MM extended community to route. */ @@ -811,7 +814,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, * and schedule for processing. */ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, - struct prefix_evpn *p, u_char sticky) + struct prefix_evpn *p, u_char flags) { struct bgp_node *rn; struct attr attr; @@ -828,7 +831,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = sticky; + attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0; /* Set up RT and ENCAP extended community. */ build_evpn_route_extcomm(vpn, &attr); @@ -839,7 +842,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, /* Create or update route entry. */ route_change = update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, - 1, 1, &ri); + 1, 1, &ri, flags); assert(ri); attr_new = ri->attr; @@ -860,7 +863,7 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, (struct prefix *)p, &vpn->prd); update_evpn_route_entry(bgp, vpn, afi, safi, rn, attr_new, 1, 0, - &global_ri); + &global_ri, flags); /* Schedule for processing and unlock node. */ bgp_process(bgp, rn, afi, safi); @@ -998,10 +1001,10 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) if (evpn_route_is_sticky(bgp, rn)) update_evpn_route_entry(bgp, vpn, afi, safi, rn, - &attr_sticky, 0, 1, &ri); + &attr_sticky, 0, 1, &ri, 0); else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, - 0, 1, &ri); + 0, 1, &ri, 0); /* If a local route exists for this prefix, we need to update * the global routing table too. @@ -1022,7 +1025,7 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) (struct prefix *)evp, &vpn->prd); assert(rd_rn); update_evpn_route_entry(bgp, vpn, afi, safi, rd_rn, attr_new, 0, - 0, &global_ri); + 0, &global_ri, 0); /* Schedule for processing and unlock node. */ bgp_process(bgp, rd_rn, afi, safi); @@ -1631,8 +1634,8 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) global_rn = bgp_afi_node_get(bgp->rib[afi][safi], afi, safi, (struct prefix *)&p, &vpn->prd); - update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, - &ri); + update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, 0, &ri, + 0); /* Schedule for processing and unlock node. */ bgp_process(bgp, global_rn, afi, safi); @@ -1665,7 +1668,7 @@ static int update_advertise_vni_routes(struct bgp *bgp, struct bgpevpn *vpn) (struct prefix *)evp, &vpn->prd); assert(global_rn); update_evpn_route_entry(bgp, vpn, afi, safi, global_rn, attr, 1, - 0, &global_ri); + 0, &global_ri, 0); /* Schedule for processing and unlock node. */ bgp_process(bgp, global_rn, afi, safi); @@ -2586,7 +2589,7 @@ int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, * Handle add of a local MACIP. */ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, - struct ipaddr *ip, u_char sticky) + struct ipaddr *ip, u_char flags) { struct bgpevpn *vpn; struct prefix_evpn p; @@ -2606,13 +2609,17 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, /* Create EVPN type-2 route and schedule for processing. */ build_evpn_type2_prefix(&p, mac, ip); - if (update_evpn_route(bgp, vpn, &p, sticky)) { + if (update_evpn_route(bgp, vpn, &p, flags)) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; zlog_err( - "%u:Failed to create Type-2 route, VNI %u %sMAC %s IP %s", - bgp->vrf_id, vpn->vni, sticky ? "sticky" : "", + "%u:Failed to create Type-2 route, VNI %u %s %s MAC %s IP %s", + bgp->vrf_id, vpn->vni, + CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky " + : "", + CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "gateway " + : "", prefix_mac2str(mac, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2))); return -1; diff --git a/bgpd/bgp_evpn.h b/bgpd/bgp_evpn.h index f4c7e68a5d..e9b7857212 100644 --- a/bgpd/bgp_evpn.h +++ b/bgpd/bgp_evpn.h @@ -42,7 +42,7 @@ extern int bgp_evpn_local_macip_del(struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip); extern int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, struct ipaddr *ip, - u_char sticky); + u_char flags); extern int bgp_evpn_local_vni_del(struct bgp *bgp, vni_t vni); extern int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, struct in_addr originator_ip); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 095dfa1b15..e6f6301405 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -58,6 +58,9 @@ struct bgpevpn { #define VNI_FLAG_IMPRT_CFGD 0x8 /* Import RT is user configured */ #define VNI_FLAG_EXPRT_CFGD 0x10 /* Export RT is user configured */ + /* Flag to indicate if we are advertising the g/w mac ip for this VNI*/ + u_int8_t advertise_gw_macip; + /* Id for deriving the RD automatically for this VNI */ u_int16_t rd_id; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c3eb32b91d..b5c17cf9aa 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1641,6 +1641,51 @@ static void evpn_show_all_vnis(struct vty *vty, struct bgp *bgp) vty); } +/* + * evpn - enable advertisement of default g/w + */ +static void evpn_set_advertise_default_gw(struct bgp *bgp, struct bgpevpn *vpn) +{ + if (!vpn) { + if (bgp->advertise_gw_macip) + return; + + bgp->advertise_gw_macip = 1; + bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0); + } else { + if (vpn->advertise_gw_macip) + return; + + vpn->advertise_gw_macip = 1; + bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, + vpn->vni); + } + return; +} + +/* + * evpn - disable advertisement of default g/w + */ +static void evpn_unset_advertise_default_gw(struct bgp *bgp, + struct bgpevpn *vpn) +{ + if (!vpn) { + if (!bgp->advertise_gw_macip) + return; + + bgp->advertise_gw_macip = 0; + bgp_zebra_advertise_gw_macip(bgp, bgp->advertise_gw_macip, 0); + } else { + if (!vpn->advertise_gw_macip) + return; + + vpn->advertise_gw_macip = 0; + bgp_zebra_advertise_gw_macip(bgp, vpn->advertise_gw_macip, + vpn->vni); + } + return; +} + /* * EVPN (VNI advertisement) enabled. Register with zebra. */ @@ -1694,12 +1739,15 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write) ecom)) { ecom_str = ecommunity_ecom2str( ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out(vty, " route-target export %s\n", + vty_out(vty, " route-target export %s\n", ecom_str); XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } } + if (vpn->advertise_gw_macip) + vty_out(vty, " advertise-default-gw\n"); + vty_out(vty, " exit-vni\n"); } } @@ -1712,6 +1760,77 @@ static void write_vni_config_for_entry(struct hash_backet *backet, } #if defined(HAVE_CUMULUS) +DEFUN (bgp_evpn_advertise_default_gw_vni, + bgp_evpn_advertise_default_gw_vni_cmd, + "advertise-default-gw", + "Advertise defualt g/w mac-ip routes in EVPN for a VNI\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + evpn_set_advertise_default_gw(bgp, vpn); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_advertise_default_vni_gw, + no_bgp_evpn_advertise_default_gw_vni_cmd, + "no advertise-default-gw", + NO_STR + "Withdraw default g/w mac-ip routes from EVPN for a VNI\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + VTY_DECLVAR_CONTEXT_SUB(bgpevpn, vpn); + + if (!bgp) + return CMD_WARNING; + + if (!vpn) + return CMD_WARNING; + + evpn_unset_advertise_default_gw(bgp, vpn); + + return CMD_SUCCESS; +} + + +DEFUN (bgp_evpn_advertise_default_gw, + bgp_evpn_advertise_default_gw_cmd, + "advertise-default-gw", + "Advertise All defualt g/w mac-ip routes in EVPN\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + + evpn_set_advertise_default_gw(bgp, NULL); + + return CMD_SUCCESS; +} + +DEFUN (no_bgp_evpn_advertise_default_gw, + no_bgp_evpn_advertise_default_gw_cmd, + "no advertise-default-gw", + NO_STR + "Withdraw All default g/w mac-ip routes from EVPN\n") +{ + struct bgp *bgp = VTY_GET_CONTEXT(bgp); + + if (!bgp) + return CMD_WARNING; + + evpn_unset_advertise_default_gw(bgp, NULL); + + return CMD_SUCCESS; +} + DEFUN (bgp_evpn_advertise_all_vni, bgp_evpn_advertise_all_vni_cmd, "advertise-all-vni", @@ -1764,6 +1883,9 @@ DEFUN (show_bgp_l2vpn_evpn_vni, return CMD_WARNING; if (argc == ((idx + 1) + 1)) { + vty_out(vty, "Advertise gateway macip flag: %s\n", + bgp->advertise_gw_macip ? "Enabled" : "Disabled"); + /* Display all VNIs */ vty_out(vty, "Advertise All VNI flag: %s\n", bgp->advertise_all_vni ? "Enabled" : "Disabled"); @@ -2544,6 +2666,11 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi, bgp_config_write_family_header(vty, afi, safi, write); vty_out(vty, " advertise-all-vni\n"); } + + if (bgp->advertise_gw_macip) { + bgp_config_write_family_header(vty, afi, safi, write); + vty_out(vty, " advertise-default-gw\n"); + } } void bgp_ethernetvpn_init(void) @@ -2569,6 +2696,8 @@ void bgp_ethernetvpn_init(void) #if defined(HAVE_CUMULUS) install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_all_vni_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_all_vni_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_default_gw_cmd); + install_element(BGP_EVPN_NODE, &no_bgp_evpn_advertise_default_gw_cmd); /* "show bgp l2vpn evpn" commands. */ install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_vni_cmd); @@ -2592,5 +2721,9 @@ void bgp_ethernetvpn_init(void) install_element(BGP_EVPN_VNI_NODE, &bgp_evpn_vni_rt_cmd); install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_cmd); install_element(BGP_EVPN_VNI_NODE, &no_bgp_evpn_vni_rt_without_val_cmd); + install_element(BGP_EVPN_VNI_NODE, + &bgp_evpn_advertise_default_gw_vni_cmd); + install_element(BGP_EVPN_VNI_NODE, + &no_bgp_evpn_advertise_default_gw_vni_cmd); #endif } diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 5071be909e..2fc75ea5a2 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -2034,6 +2034,29 @@ void bgp_zebra_terminate_radv(struct bgp *bgp, struct peer *peer) zclient_send_interface_radv_req(zclient, bgp->vrf_id, peer->ifp, 0, 0); } +int bgp_zebra_advertise_gw_macip(struct bgp *bgp, int advertise, vni_t vni) +{ + struct stream *s = NULL; + + /* Check socket. */ + if (!zclient || zclient->sock < 0) + return 0; + + /* Don't try to register if Zebra doesn't know of this instance. */ + if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) + return 0; + + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_ADVERTISE_DEFAULT_GW, bgp->vrf_id); + stream_putc(s, advertise); + stream_put3(s, vni); + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise) { struct stream *s; @@ -2120,7 +2143,7 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, int ipa_len; char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; - u_char sticky; + u_char flags; memset(&ip, 0, sizeof(ip)); s = zclient->ibuf; @@ -2140,21 +2163,20 @@ static int bgp_zebra_process_local_macip(int command, struct zclient *zclient, (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6; stream_get(&ip.ip.addr, s, ipa_len); } - sticky = stream_getc(s); + flags = stream_getc(s); bgp = bgp_lookup_by_vrf_id(vrf_id); if (!bgp) return 0; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%u:Recv MACIP %s %sMAC %s IP %s VNI %u", vrf_id, - (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", - sticky ? "sticky " : "", - prefix_mac2str(&mac, buf, sizeof(buf)), + zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u", + vrf_id, (command == ZEBRA_MACIP_ADD) ? "Add" : "Del", + flags, prefix_mac2str(&mac, buf, sizeof(buf)), ipaddr2str(&ip, buf1, sizeof(buf1)), vni); if (command == ZEBRA_MACIP_ADD) - return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, sticky); + return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags); else return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip); } diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 8e55eb6d8d..11405d1c1b 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -21,6 +21,8 @@ #ifndef _QUAGGA_BGP_ZEBRA_H #define _QUAGGA_BGP_ZEBRA_H +#include "vxlan.h" + extern void bgp_zebra_init(struct thread_master *master); extern void bgp_zebra_destroy(void); extern int bgp_if_update_all(void); @@ -57,6 +59,7 @@ extern struct interface *if_lookup_by_ipv6(struct in6_addr *, ifindex_t, extern struct interface *if_lookup_by_ipv6_exact(struct in6_addr *, ifindex_t, vrf_id_t); +extern int bgp_zebra_advertise_gw_macip(struct bgp *, int, vni_t); extern int bgp_zebra_advertise_all_vni(struct bgp *, int); extern int bgp_zebra_num_connects(void); diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 7992075af1..bfdddc69b1 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -380,6 +380,9 @@ struct bgp { /* EVI hash table */ struct hash *vnihash; + /* EVPN enable - advertise gateway macip routes */ + int advertise_gw_macip; + /* EVPN enable - advertise local VNIs and their MACs etc. */ int advertise_all_vni; diff --git a/lib/log.c b/lib/log.c index 5adb06d28c..522aa9e7ac 100644 --- a/lib/log.c +++ b/lib/log.c @@ -908,6 +908,7 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_GET_LABEL_CHUNK), DESC_ENTRY(ZEBRA_RELEASE_LABEL_CHUNK), DESC_ENTRY(ZEBRA_ADVERTISE_ALL_VNI), + DESC_ENTRY(ZEBRA_ADVERTISE_DEFAULT_GW), DESC_ENTRY(ZEBRA_VNI_ADD), DESC_ENTRY(ZEBRA_VNI_DEL), DESC_ENTRY(ZEBRA_REMOTE_VTEP_ADD), diff --git a/lib/zclient.h b/lib/zclient.h index 435d26e2f9..67da45e13f 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -97,6 +97,7 @@ typedef enum { ZEBRA_FEC_REGISTER, ZEBRA_FEC_UNREGISTER, ZEBRA_FEC_UPDATE, + ZEBRA_ADVERTISE_DEFAULT_GW, ZEBRA_ADVERTISE_ALL_VNI, ZEBRA_VNI_ADD, ZEBRA_VNI_DEL, @@ -266,6 +267,10 @@ struct zapi_ipv4 { vrf_id_t vrf_id; }; +/* Zebra MAC types */ +#define ZEBRA_MAC_TYPE_STICKY 0x01 /* Sticky MAC*/ +#define ZEBRA_MAC_TYPE_GW 0x02 /* gateway (SVI) mac*/ + /* Prototypes of zebra client service functions. */ extern struct zclient *zclient_new(struct thread_master *); extern void zclient_init(struct zclient *, int, u_short); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index a46657dd2e..8064071c37 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -251,6 +251,8 @@ static void netlink_determine_zebra_iftype(char *kind, zebra_iftype_t *zif_type) *zif_type = ZEBRA_IF_VLAN; else if (strcmp(kind, "vxlan") == 0) *zif_type = ZEBRA_IF_VXLAN; + else if (strcmp(kind, "macvlan") == 0) + *zif_type = ZEBRA_IF_MACVLAN; } // Temporary Assignments to compile on older platforms. diff --git a/zebra/interface.h b/zebra/interface.h index ea72264696..970c3c5292 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -186,11 +186,12 @@ struct rtadvconf { /* Zebra interface type - ones of interest. */ typedef enum { - ZEBRA_IF_VXLAN, /* VxLAN interface */ - ZEBRA_IF_VRF, /* VRF device */ - ZEBRA_IF_BRIDGE, /* bridge device */ - ZEBRA_IF_VLAN, /* VLAN sub-interface */ - ZEBRA_IF_OTHER, /* Anything else */ + ZEBRA_IF_VXLAN, /* VxLAN interface */ + ZEBRA_IF_VRF, /* VRF device */ + ZEBRA_IF_BRIDGE, /* bridge device */ + ZEBRA_IF_VLAN, /* VLAN sub-interface */ + ZEBRA_IF_MACVLAN, /* MAC VLAN interface*/ + ZEBRA_IF_OTHER, /* Anything else */ } zebra_iftype_t; /* Zebra "slave" interface type */ @@ -295,6 +296,9 @@ static inline void zebra_if_set_ziftype(struct interface *ifp, #define IS_ZEBRA_IF_VXLAN(ifp) \ (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_VXLAN) +#define IS_ZEBRA_IF_MACVLAN(ifp) \ + (((struct zebra_if *)(ifp->info))->zif_type == ZEBRA_IF_MACVLAN) + #define IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) \ (((struct zebra_if *)(ifp->info))->zif_slave_type \ == ZEBRA_IF_SLAVE_BRIDGE) diff --git a/zebra/redistribute.c b/zebra/redistribute.c index c3bbf40b3f..92da5fe0ce 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -41,6 +41,7 @@ #include "zebra/debug.h" #include "zebra/router-id.h" #include "zebra/zebra_memory.h" +#include "zebra/zebra_vxlan.h" #define ZEBRA_PTM_SUPPORT @@ -402,6 +403,8 @@ void zebra_interface_address_add_update(struct interface *ifp, zlog_warn( "WARNING: advertising address to clients that is not yet usable."); + zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 1); + router_id_add_address(ifc); for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) @@ -428,6 +431,8 @@ void zebra_interface_address_delete_update(struct interface *ifp, prefix2str(p, buf, sizeof(buf)), ifc->ifp->name); } + zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0); + router_id_del_address(ifc); for (ALL_LIST_ELEMENTS(zebrad.client_list, node, nnode, client)) diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index eb0687bf8a..720268d360 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -102,6 +102,11 @@ struct zebra_vrf { */ int advertise_all_vni; + /* + * Whether we are advertising g/w macip in EVPN or not. + */ + int advertise_gw_macip; + /* Route Installs */ uint64_t installs; uint64_t removals; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 523225bf36..ee9a88c66c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -68,7 +68,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt); static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, - struct ipaddr *ip, u_char sticky, + struct ipaddr *ip, u_char flags, u_int16_t cmd); static unsigned int neigh_hash_keymake(void *p); static int neigh_cmp(const void *p1, const void *p2); @@ -83,10 +83,10 @@ static void zvni_neigh_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip); static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr); + struct ethaddr *macaddr, u_char flags); static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr); + struct ethaddr *macaddr, u_char flags); static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n); static int zvni_neigh_uninstall(zebra_vni_t *zvni, zebra_neigh_t *n); static zebra_vni_t *zvni_map_svi(struct interface *ifp, @@ -106,9 +106,9 @@ static void zvni_mac_del_all(struct zebra_vrf *zvrf, zebra_vni_t *zvni, int uninstall, int upd_client, u_int32_t flags); static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *macaddr); static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr, u_char sticky); + struct ethaddr *macaddr, u_char flags); static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr, u_char sticky); + struct ethaddr *macaddr, u_char flags); static zebra_vni_t *zvni_map_vlan(struct interface *ifp, struct interface *br_if, vlanid_t vid); static int zvni_mac_install(zebra_vni_t *zvni, zebra_mac_t *mac); @@ -131,10 +131,31 @@ static int zvni_vtep_del(zebra_vni_t *zvni, zebra_vtep_t *zvtep); static int zvni_vtep_del_all(zebra_vni_t *zvni, int uninstall); static int zvni_vtep_install(zebra_vni_t *zvni, struct in_addr *vtep_ip); static int zvni_vtep_uninstall(zebra_vni_t *zvni, struct in_addr *vtep_ip); - +static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); +static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni); +static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, + struct ethaddr *macaddr, struct ipaddr *ip); +static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, + struct ipaddr *ip); +struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp); +static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, + zebra_vni_t *zvni); +static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac, + int uninstall); /* Private functions */ +static int advertise_gw_macip_enabled(struct zebra_vrf *zvrf, zebra_vni_t *zvni) +{ + if (zvrf && zvrf->advertise_gw_macip) + return 1; + + if (zvni && zvni->advertise_gw_macip) + return 1; + + return 0; +} + /* * Helper function to determine maximum width of neighbor IP address for * display - just because we're dealing with IPv6 addresses that can @@ -450,7 +471,7 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt) */ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, - struct ipaddr *ip, u_char sticky, + struct ipaddr *ip, u_char flags, u_int16_t cmd) { struct zserv *client; @@ -483,19 +504,18 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, } else stream_putl(s, 0); /* Just MAC. */ - stream_putc(s, sticky); /* Sticky MAC? */ + stream_putc(s, flags); /* sticky mac/gateway mac */ /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("%u:Send MACIP %s %sMAC %s IP %s VNI %u to %s", - zvrf_id(zvrf), - (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", - sticky ? "sticky " : "", - prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2)), vni, - zebra_route_string(client->proto)); + zlog_debug( + "%u:Send MACIP %s flags 0x%x MAC %s IP %s VNI %u to %s", + zvrf_id(zvrf), (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del", + flags, prefix_mac2str(macaddr, buf, sizeof(buf)), + ipaddr2str(ip, buf2, sizeof(buf2)), vni, + zebra_route_string(client->proto)); if (cmd == ZEBRA_MACIP_ADD) client->macipadd_cnt++; @@ -597,8 +617,9 @@ static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg) && (n->flags & ZEBRA_NEIGH_REMOTE) && IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip))) { if (wctx->upd_client && (n->flags & ZEBRA_NEIGH_LOCAL)) - zvni_neigh_send_del_to_client( - wctx->zvrf, wctx->zvni->vni, &n->ip, &n->emac); + zvni_neigh_send_del_to_client(wctx->zvrf, + wctx->zvni->vni, &n->ip, + &n->emac, 0); if (wctx->uninstall) zvni_neigh_uninstall(wctx->zvni, n); @@ -676,9 +697,9 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip) */ static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr) + struct ethaddr *macaddr, u_char flags) { - return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0, + return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags, ZEBRA_MACIP_ADD); } @@ -687,9 +708,9 @@ static int zvni_neigh_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, */ static int zvni_neigh_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ipaddr *ip, - struct ethaddr *macaddr) + struct ethaddr *macaddr, u_char flags) { - return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, 0, + return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, ip, flags, ZEBRA_MACIP_DEL); } @@ -770,6 +791,309 @@ static void zvni_install_neigh_hash(struct hash_backet *backet, void *ctxt) zvni_neigh_install(wctx->zvni, n); } +/* Get the VRR interface for SVI if any */ +struct interface *zebra_get_vrr_intf_for_svi(struct interface *ifp) +{ + struct zebra_vrf *zvrf = NULL; + struct interface *tmp_if = NULL; + struct zebra_if *zif = NULL; + struct listnode *node; + + zvrf = vrf_info_lookup(ifp->vrf_id); + assert(zvrf); + + for (ALL_LIST_ELEMENTS_RO(vrf_iflist(zvrf_id(zvrf)), node, tmp_if)) { + zif = tmp_if->info; + if (!zif) + continue; + + if (!IS_ZEBRA_IF_MACVLAN(tmp_if)) + continue; + + if (zif->link == ifp) + return tmp_if; + } + + return NULL; +} + +static int zvni_del_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) +{ + struct zebra_vrf *zvrf = NULL; + struct listnode *cnode = NULL, *cnnode = NULL; + struct connected *c = NULL; + struct ethaddr macaddr; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) + return -1; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + + for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + struct ipaddr ip; + + memset(&ip, 0, sizeof(struct ipaddr)); + if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) + continue; + + if (c->address->family == AF_INET) { + ip.ipa_type = IPADDR_V4; + memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), + sizeof(struct in_addr)); + } else if (c->address->family == AF_INET6) { + ip.ipa_type = IPADDR_V6; + memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), + sizeof(struct in6_addr)); + } else { + continue; + } + + zvni_gw_macip_del(ifp, zvni, &ip); + } + + return 0; +} + +static int zvni_add_macip_for_intf(struct interface *ifp, zebra_vni_t *zvni) +{ + struct zebra_vrf *zvrf = NULL; + struct listnode *cnode = NULL, *cnnode = NULL; + struct connected *c = NULL; + struct ethaddr macaddr; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) + return -1; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + + for (ALL_LIST_ELEMENTS(ifp->connected, cnode, cnnode, c)) { + struct ipaddr ip; + + memset(&ip, 0, sizeof(struct ipaddr)); + if (!CHECK_FLAG(c->conf, ZEBRA_IFC_REAL)) + continue; + + if (c->address->family == AF_INET) { + ip.ipa_type = IPADDR_V4; + memcpy(&(ip.ipaddr_v4), &(c->address->u.prefix4), + sizeof(struct in_addr)); + } else if (c->address->family == AF_INET6) { + ip.ipa_type = IPADDR_V6; + memcpy(&(ip.ipaddr_v6), &(c->address->u.prefix6), + sizeof(struct in6_addr)); + } else { + continue; + } + + zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); + } + + return 0; +} + +/* + * zvni_gw_macip_add_to_client + */ +static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, + struct ethaddr *macaddr, struct ipaddr *ip) +{ + struct zebra_vrf *zvrf = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan *vxl = NULL; + zebra_neigh_t *n = NULL; + zebra_mac_t *mac = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) + return -1; + + zif = zvni->vxlan_if->info; + if (!zif) + return -1; + + vxl = &zif->l2info.vxl; + + mac = zvni_mac_lookup(zvni, macaddr); + if (!mac) { + mac = zvni_mac_add(zvni, macaddr); + if (!mac) { + zlog_err("%u:Failed to add MAC %s intf %s(%u) VID %u", + ifp->vrf_id, + prefix_mac2str(macaddr, buf, sizeof(buf)), + ifp->name, ifp->ifindex, vxl->access_vlan); + return -1; + } + } + + /* Set "local" forwarding info. */ + SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + mac->fwd_info.local.ifindex = ifp->ifindex; + mac->fwd_info.local.vid = vxl->access_vlan; + + n = zvni_neigh_lookup(zvni, ip); + if (!n) { + n = zvni_neigh_add(zvni, ip); + if (!n) { + zlog_err( + "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", + ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), + prefix_mac2str(macaddr, NULL, + ETHER_ADDR_STRLEN), + ifp->name, ifp->ifindex, zvni->vni); + return -1; + } + } + + /* Set "local" forwarding info. */ + SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); + memcpy(&n->emac, macaddr, ETH_ALEN); + n->ifindex = ifp->ifindex; + + /* We have a neigh associated to mac increment the refcnt*/ + mac->neigh_refcnt++; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s add to BGP", + ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, + prefix_mac2str(macaddr, NULL, ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); + + zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, + ZEBRA_MAC_TYPE_GW); + + return 0; +} + +/* + * zvni_gw_macip_del_from_client + */ +static int zvni_gw_macip_del(struct interface *ifp, zebra_vni_t *zvni, + struct ipaddr *ip) +{ + struct zebra_vrf *zvrf = NULL; + zebra_neigh_t *n = NULL; + zebra_mac_t *mac = NULL; + char buf2[INET6_ADDRSTRLEN]; + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) + return -1; + + /* If the neigh entry is not present nothing to do*/ + n = zvni_neigh_lookup(zvni, ip); + if (!n) + return 0; + + /* mac entry should be present */ + mac = zvni_mac_lookup(zvni, &n->emac); + if (!mac) + zlog_err("%u: MAC %s doesnt exsists for neigh %s on VNI %u", + ifp->vrf_id, + prefix_mac2str(&n->emac, NULL, ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); + + /* If the entry is not local nothing to do*/ + if (!CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) + return -1; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u:SVI %s(%u) VNI %u, sending GW MAC %s IP %s del to BGP", + ifp->vrf_id, ifp->name, ifp->ifindex, zvni->vni, + prefix_mac2str(&(n->emac), NULL, ETHER_ADDR_STRLEN), + ipaddr2str(ip, buf2, sizeof(buf2))); + + /* Remove neighbor from BGP. */ + zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, + ZEBRA_MAC_TYPE_GW); + + /* Delete this neighbor entry. */ + zvni_neigh_del(zvni, n); + + /* see if the mac needs to be deleted as well*/ + zvni_deref_ip2mac(zvni, mac, 0); + + return 0; +} + +static void zvni_gw_macip_del_for_vni_hash(struct hash_backet *backet, + void *zvrf) +{ + zebra_vni_t *zvni = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + struct interface *vrr_if = NULL; + + /* Add primary SVI MAC*/ + zvni = (zebra_vni_t *)backet->data; + if (!zvni) + return; + + zif = zvni->vxlan_if->info; + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); + + /* Del VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_del_macip_for_intf(vrr_if, zvni); + + return; +} + +static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, + void *zvrf) +{ + zebra_vni_t *zvni = NULL; + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + struct interface *vrr_if = NULL; + + zvni = (zebra_vni_t *)backet->data; + if (!zvni) + return; + + if (!advertise_gw_macip_enabled(zvrf, zvni)) + return; + + zif = zvni->vxlan_if->info; + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return; + + if (!advertise_gw_macip_enabled(zvrf, zvni)) + return; + + /* Add primary SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); + + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); + + return; +} + /* * Make hash key for MAC. */ @@ -864,8 +1188,9 @@ static int zvni_mac_del_hash_entry(struct hash_backet *backet, void *arg) if (wctx->upd_client && (mac->flags & ZEBRA_MAC_LOCAL)) { sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(wctx->zvrf, wctx->zvni->vni, - &mac->macaddr, sticky); + zvni_mac_send_del_to_client( + wctx->zvrf, wctx->zvni->vni, &mac->macaddr, + (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); } if (wctx->uninstall) @@ -941,9 +1266,9 @@ static zebra_mac_t *zvni_mac_lookup(zebra_vni_t *zvni, struct ethaddr *mac) * Inform BGP about local MAC addition. */ static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr, u_char sticky) + struct ethaddr *macaddr, u_char flags) { - return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky, + return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags, ZEBRA_MACIP_ADD); } @@ -951,9 +1276,9 @@ static int zvni_mac_send_add_to_client(struct zebra_vrf *zvrf, vni_t vni, * Inform BGP about local MAC deletion. */ static int zvni_mac_send_del_to_client(struct zebra_vrf *zvrf, vni_t vni, - struct ethaddr *macaddr, u_char sticky) + struct ethaddr *macaddr, u_char flags) { - return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, sticky, + return zvni_macip_send_msg_to_client(zvrf, vni, macaddr, NULL, flags, ZEBRA_MACIP_DEL); } @@ -1234,6 +1559,7 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni, struct zebra_if *zif; struct interface *vlan_if; struct zebra_l2info_vxlan *vxl; + struct interface *vrr_if; zif = ifp->info; vxl = &zif->l2info.vxl; @@ -1247,8 +1573,20 @@ static void zvni_read_mac_neigh(struct zebra_vrf *zvrf, zebra_vni_t *zvni, macfdb_read_for_bridge(zvrf->zns, ifp, zif->brslave_info.br_if); vlan_if = zvni_map_to_svi(zvrf, vxl->access_vlan, zif->brslave_info.br_if); - if (vlan_if) + if (vlan_if) { + + if (advertise_gw_macip_enabled(zvrf, zvni)) { + /* Add SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); + + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); + } + neigh_read_for_vlan(zvrf->zns, vlan_if); + } } /* @@ -1915,7 +2253,7 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, assert(zvrf); /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac); + zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, 0); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); @@ -2008,8 +2346,8 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* Issue delete for older info, if needed. */ if (send_del) - zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, - &n->emac); + zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, + 0); /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); @@ -2019,7 +2357,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* Inform BGP if required. */ if (send_upd) return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, - macaddr); + macaddr, 0); return 0; } @@ -2419,7 +2757,8 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, /* Remove MAC from BGP. */ sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky); + zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, + (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); /* Delete this MAC entry. */ zvni_mac_del(zvni, mac); @@ -2526,7 +2865,8 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, /* Remove MAC from BGP. */ sticky = CHECK_FLAG(mac->flags, ZEBRA_MAC_STICKY) ? 1 : 0; - zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, sticky); + zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, + (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); /* Delete this MAC entry. */ zvni_mac_del(zvni, mac); @@ -2656,8 +2996,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, /* Inform BGP if required. */ if (add) - return zvni_mac_send_add_to_client(zvrf, zvni->vni, macaddr, - sticky); + return zvni_mac_send_add_to_client( + zvrf, zvni->vni, macaddr, + (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); return 0; } @@ -2788,6 +3129,100 @@ int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, return 0; } +/* + * Add/Del gateway macip to evpn + * g/w can be: + * 1. SVI interface on a vlan aware bridge + * 2. SVI interface on a vlan unaware bridge + * 3. vrr interface (MACVLAN) associated to a SVI + * We advertise macip routes for an interface if it is associated to VxLan vlan + */ +int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, + int add) +{ + struct ipaddr ip; + struct ethaddr macaddr; + zebra_vni_t *zvni = NULL; + struct zebra_vrf *zvrf = NULL; + + memset(&ip, 0, sizeof(struct ipaddr)); + memset(&macaddr, 0, sizeof(struct ethaddr)); + + if (IS_ZEBRA_IF_MACVLAN(ifp)) { + struct interface *svi_if = + NULL; /* SVI corresponding to the MACVLAN */ + struct zebra_if *ifp_zif = + NULL; /* Zebra daemon specific info for MACVLAN */ + struct zebra_if *svi_if_zif = + NULL; /* Zebra daemon specific info for SVI*/ + + ifp_zif = ifp->info; + if (!ifp_zif) + return -1; + + svi_if = ifp_zif->link; + if (!svi_if) { + zlog_err("%u:MACVLAN %s(%u) without link information", + ifp->vrf_id, ifp->name, ifp->ifindex); + return -1; + } + + if (IS_ZEBRA_IF_VLAN(svi_if)) { + svi_if_zif = svi_if->info; + if (svi_if_zif) + zvni = zvni_map_svi(svi_if, svi_if_zif->link); + } else if (IS_ZEBRA_IF_BRIDGE(svi_if)) { + zvni = zvni_map_svi(svi_if, svi_if); + } + } else if (IS_ZEBRA_IF_VLAN(ifp)) { + struct zebra_if *svi_if_zif = + NULL; /* Zebra daemon specific info for SVI*/ + + svi_if_zif = ifp->info; + if (svi_if_zif) + zvni = zvni_map_svi(ifp, svi_if_zif->link); + } else if (IS_ZEBRA_IF_BRIDGE(ifp)) { + zvni = zvni_map_svi(ifp, ifp); + } + + if (!zvni) + return 0; + + if (!zvni->vxlan_if) { + zlog_err("VNI %u hash %p doesn't have intf upon MACVLAN up", + zvni->vni, zvni); + return -1; + } + + zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); + if (!zvrf) + return -1; + + /* check if we are advertising gw macip routes */ + if (!advertise_gw_macip_enabled(zvrf, zvni)) + return 0; + + memcpy(&macaddr.octet, ifp->hw_addr, ETH_ALEN); + + if (p->family == AF_INET) { + ip.ipa_type = IPADDR_V4; + memcpy(&(ip.ipaddr_v4), &(p->u.prefix4), + sizeof(struct in_addr)); + } else if (p->family == AF_INET6) { + ip.ipa_type = IPADDR_V6; + memcpy(&(ip.ipaddr_v6), &(p->u.prefix6), + sizeof(struct in6_addr)); + } + + + if (add) + zvni_gw_macip_add(ifp, zvni, &macaddr, &ip); + else + zvni_gw_macip_del(ifp, zvni, &ip); + + return 0; +} + /* * Handle SVI interface going down. At this point, this is a NOP since * the kernel deletes the neighbor entries on this SVI (if any). @@ -3146,6 +3581,98 @@ int zebra_vxlan_if_add(struct interface *ifp) return 0; } +/* + * Handle message from client to enable/disable advertisement of g/w macip + * routes + */ +int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, + u_short length, struct zebra_vrf *zvrf) +{ + struct stream *s; + int advertise; + vni_t vni = 0; + zebra_vni_t *zvni = NULL; + + s = client->ibuf; + advertise = stream_getc(s); + vni = stream_get3(s); + + if (!vni) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug("%u:EVPN gateway macip Adv %s, currently %s", + zvrf_id(zvrf), + advertise ? "enabled" : "disabled", + advertise_gw_macip_enabled(zvrf, NULL) + ? "enabled" + : "disabled"); + + if (zvrf->advertise_gw_macip == advertise) + return 0; + + zvrf->advertise_gw_macip = advertise; + + if (advertise_gw_macip_enabled(zvrf, zvni)) + hash_iterate(zvrf->vni_table, + zvni_gw_macip_add_for_vni_hash, zvrf); + else + hash_iterate(zvrf->vni_table, + zvni_gw_macip_del_for_vni_hash, zvrf); + + } else { + struct zebra_if *zif = NULL; + struct zebra_l2info_vxlan zl2_info; + struct interface *vlan_if = NULL; + struct interface *vrr_if = NULL; + + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u:EVPN gateway macip Adv %s on VNI %d , currently %s", + zvrf_id(zvrf), + advertise ? "enabled" : "disabled", vni, + advertise_gw_macip_enabled(zvrf, zvni) + ? "enabled" + : "disabled"); + + zvni = zvni_lookup(zvrf, vni); + if (!zvni) + return 0; + + if (zvni->advertise_gw_macip == advertise) + return 0; + + zvni->advertise_gw_macip = advertise; + + zif = zvni->vxlan_if->info; + zl2_info = zif->l2info.vxl; + + vlan_if = zvni_map_to_svi(zvrf, zl2_info.access_vlan, + zif->brslave_info.br_if); + if (!vlan_if) + return 0; + + if (advertise_gw_macip_enabled(zvrf, zvni)) { + /* Add primary SVI MAC-IP */ + zvni_add_macip_for_intf(vlan_if, zvni); + + /* Add VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_add_macip_for_intf(vrr_if, zvni); + } else { + /* Del primary MAC-IP */ + zvni_del_macip_for_intf(vlan_if, zvni); + + /* Del VRR MAC-IP - if any*/ + vrr_if = zebra_get_vrr_intf_for_svi(vlan_if); + if (vrr_if) + zvni_del_macip_for_intf(vrr_if, zvni); + } + } + + return 0; +} + + /* * Handle message from client to learn (or stop learning) about VNIs and MACs. * When enabled, the VNI hash table will be built and MAC FDB table read; @@ -3174,6 +3701,10 @@ int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock, /* Build VNI hash table and inform BGP. */ zvni_build_hash_table(zvrf); + /* Add all SVI (L3 GW) MACs to BGP*/ + hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash, + zvrf); + /* Read the MAC FDB */ macfdb_read(zvrf->zns); diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index f9ecd8333d..dca8006033 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -68,6 +68,8 @@ extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni); extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf); +extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, + int add); extern int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if); @@ -104,6 +106,9 @@ extern int zebra_vxlan_remote_vtep_add(struct zserv *client, int sock, u_short length, struct zebra_vrf *zvrf); extern int zebra_vxlan_remote_vtep_del(struct zserv *client, int sock, u_short length, struct zebra_vrf *zvrf); +extern int zebra_vxlan_advertise_gw_macip(struct zserv *client, int sock, + u_short length, + struct zebra_vrf *zvrf); extern int zebra_vxlan_advertise_all_vni(struct zserv *client, int sock, u_short length, struct zebra_vrf *zvrf); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index fbde722927..2e5943a75c 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -63,6 +63,9 @@ struct zebra_vni_t_ { /* VNI - key */ vni_t vni; + /* Flag for advertising gw macip */ + u_int8_t advertise_gw_macip; + /* Corresponding VxLAN interface. */ struct interface *vxlan_if; diff --git a/zebra/zserv.c b/zebra/zserv.c index 97f7122774..0f90939a0b 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -2418,6 +2418,9 @@ static int zebra_client_read(struct thread *thread) case ZEBRA_FEC_UNREGISTER: zserv_fec_unregister(client, sock, length); break; + case ZEBRA_ADVERTISE_DEFAULT_GW: + zebra_vxlan_advertise_gw_macip(client, sock, length, zvrf); + break; case ZEBRA_ADVERTISE_ALL_VNI: zebra_vxlan_advertise_all_vni(client, sock, length, zvrf); break; From 5014d96f0f02d3005bf41be2db343cb230cd9fdc Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Wed, 28 Jun 2017 11:30:36 -0700 Subject: [PATCH 11/32] bgpd, tools, vtysh: Handle config migration from 'address-family evpn' to 'address-family l2vpn evpn' Ticket: CM-16747 Signed-off-by: Daniel Walton Reviewed-by: Quentin Young --- bgpd/bgp_evpn_vty.c | 103 ++++++++++++++++++++++++++++++++++++++++++++ tools/frr-reload.py | 40 +++++++++++++++++ vtysh/vtysh.c | 8 ++-- 3 files changed, 147 insertions(+), 4 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index b5c17cf9aa..be88fcd273 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2266,6 +2266,97 @@ DEFUN (show_bgp_l2vpn_evpn_import_rt, return CMD_SUCCESS; } +#if defined(HAVE_CUMULUS) +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd, + "show bgp evpn vni [(1-16777215)]", SHOW_STR BGP_STR EVPN_HELP_STR + "Show VNI\n" + "VNI number\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd, + "show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR + "Summary of BGP neighbor status\n" + "JavaScript Object Notation\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd, + "show bgp evpn route [type ]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n") + +ALIAS_HIDDEN( + show_bgp_l2vpn_evpn_route_rd, show_bgp_evpn_route_rd_cmd, + "show bgp evpn route rd ASN:nn_or_IP-address:nn [type ]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n") + +ALIAS_HIDDEN( + show_bgp_l2vpn_evpn_route_rd_macip, show_bgp_evpn_route_rd_macip_cmd, + "show bgp evpn route rd ASN:nn_or_IP-address:nn mac WORD [ip WORD]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "Route Distinguisher\n" + "ASN:XX or A.B.C.D:XX\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n") + +ALIAS_HIDDEN( + show_bgp_l2vpn_evpn_route_vni, show_bgp_evpn_route_vni_cmd, + "show bgp evpn route vni (1-16777215) [ | vtep A.B.C.D>]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Specify Route type\n" + "MAC-IP (Type-2) route\n" + "Multicast (Type-3) route\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_macip, + show_bgp_evpn_route_vni_macip_cmd, + "show bgp evpn route vni (1-16777215) mac WORD [ip WORD]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_multicast, + show_bgp_evpn_route_vni_multicast_cmd, + "show bgp evpn route vni (1-16777215) multicast A.B.C.D", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "VNI number\n" + "Multicast (Type-3) route\n" + "Originating Router IP address\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route_vni_all, show_bgp_evpn_route_vni_all_cmd, + "show bgp evpn route vni all [vtep A.B.C.D]", + SHOW_STR BGP_STR EVPN_HELP_STR + "EVPN route information\n" + "VXLAN Network Identifier\n" + "All VNIs\n" + "Remote VTEP\n" + "Remote VTEP IP address\n") + +ALIAS_HIDDEN(show_bgp_l2vpn_evpn_import_rt, show_bgp_evpn_import_rt_cmd, + "show bgp evpn import-rt", + SHOW_STR BGP_STR EVPN_HELP_STR "Show import route target\n") +#endif + DEFUN_NOSH (bgp_evpn_vni, bgp_evpn_vni_cmd, "vni (1-16777215)", @@ -2712,6 +2803,18 @@ void bgp_ethernetvpn_init(void) install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_route_vni_all_cmd); install_element(VIEW_NODE, &show_bgp_l2vpn_evpn_import_rt_cmd); + /* "show bgp evpn" commands. */ + install_element(VIEW_NODE, &show_bgp_evpn_vni_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_summary_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_rd_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_rd_macip_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_vni_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_vni_multicast_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_vni_macip_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_route_vni_all_cmd); + install_element(VIEW_NODE, &show_bgp_evpn_import_rt_cmd); + install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_NODE, &no_bgp_evpn_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); diff --git a/tools/frr-reload.py b/tools/frr-reload.py index bfdc08ab4c..43496d4cbf 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -432,6 +432,8 @@ end ctx_keys.append("address-family ipv6 unicast") elif line == "address-family ipv4": ctx_keys.append("address-family ipv4 unicast") + elif line == "address-family evpn": + ctx_keys.append("address-family l2vpn evpn") else: ctx_keys.append(line) @@ -745,6 +747,37 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, None)) lines_to_add_to_del.append(((tmpline,), None)) + if (len(ctx_keys) == 3 and + ctx_keys[0].startswith('router bgp') and + ctx_keys[1] == 'address-family l2vpn evpn' and + ctx_keys[2].startswith('vni')): + + re_route_target = re.search('^route-target import (.*)$', line) if line is not None else False + + if re_route_target: + rt = re_route_target.group(1).strip() + route_target_import_line = line + route_target_export_line = "route-target export %s" % rt + route_target_both_line = "route-target both %s" % rt + + found_route_target_export_line = line_exist(lines_to_del, ctx_keys, route_target_export_line) + found_route_target_both_line = line_exist(lines_to_add, ctx_keys, route_target_both_line) + + ''' + If the running configs has + route-target import 1:1 + route-target export 1:1 + + and the config we are reloading against has + route-target both 1:1 + + then we can ignore deleting the import/export and ignore adding the 'both' + ''' + if found_route_target_export_line and found_route_target_both_line: + lines_to_del_to_del.append((ctx_keys, route_target_import_line)) + lines_to_del_to_del.append((ctx_keys, route_target_export_line)) + lines_to_add_to_del.append((ctx_keys, route_target_both_line)) + if not deleted: found_add_line = line_exist(lines_to_add, ctx_keys, line) @@ -822,6 +855,13 @@ def compare_context_objects(newconf, running): elif "router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and delete_bgpd: continue + # Delete an entire vni sub-context under "address-family l2vpn evpn" + elif ("router bgp" in running_ctx_keys[0] and + len(running_ctx_keys) > 2 and + running_ctx_keys[1].startswith('address-family l2vpn evpn') and + running_ctx_keys[2].startswith('vni ')): + lines_to_del.append((running_ctx_keys, None)) + elif ("router bgp" in running_ctx_keys[0] and len(running_ctx_keys) > 1 and running_ctx_keys[1].startswith('address-family')): diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 5886d39c19..736c8f1825 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1160,10 +1160,10 @@ DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, } #if defined(HAVE_CUMULUS) -DEFUNSH(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, - "address-family evpn", - "Enter Address Family command mode\n" - "EVPN Address family\n") +DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, + "address-family evpn", + "Enter Address Family command mode\n" + "EVPN Address family\n") { vty->node = BGP_EVPN_NODE; return CMD_SUCCESS; From 9b67b5147486be9b754c9c9a6c82bcac49505eb1 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 29 Jun 2017 09:45:18 -0400 Subject: [PATCH 12/32] zebra: Fix some memory leaks on shutdown Signed-off-by: Donald Sharp --- zebra/zebra_mpls.c | 8 +++++--- zebra/zebra_vxlan.c | 1 + 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index e44e5d2e6b..b1edb7d960 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -1321,9 +1321,9 @@ static void nhlfe_print(zebra_nhlfe_t *nhlfe, struct vty *vty) default: break; } - vty_out(vty, "%s", - CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) ? " (installed)" - : ""); + vty_out(vty, "%s", CHECK_FLAG(nhlfe->flags, NHLFE_FLAG_INSTALLED) + ? " (installed)" + : ""); vty_out(vty, "\n"); } @@ -2807,6 +2807,8 @@ void zebra_mpls_close_tables(struct zebra_vrf *zvrf) hash_free(zvrf->lsp_table); hash_clean(zvrf->slsp_table, NULL); hash_free(zvrf->slsp_table); + route_table_finish(zvrf->fec_table[AFI_IP]); + route_table_finish(zvrf->fec_table[AFI_IP6]); } /* diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index ee9a88c66c..dc8e6e9c0e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3736,4 +3736,5 @@ void zebra_vxlan_init_tables(struct zebra_vrf *zvrf) void zebra_vxlan_close_tables(struct zebra_vrf *zvrf) { hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf); + hash_free(zvrf->vni_table); } From cd233079064f4b0fa8eacaf60d9fbd454ad47e30 Mon Sep 17 00:00:00 2001 From: Chirag Shah Date: Wed, 21 Jun 2017 16:37:51 -0700 Subject: [PATCH 13/32] zebra: Enable JSON for EVPN show cmds Ticket: CM-16959 Reviewed By: CCR-6401 Testing Done: Execute 'show evpn .... json' form of outputs with local/remote vteps Signed-off-by: Chirag Shah --- zebra/zebra_vty.c | 92 ++++-- zebra/zebra_vxlan.c | 613 +++++++++++++++++++++++++++++------- zebra/zebra_vxlan.h | 29 +- zebra/zebra_vxlan_private.h | 12 +- 4 files changed, 582 insertions(+), 164 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 13c4429d6a..61fe171cff 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2300,89 +2300,100 @@ DEFUN (show_vrf, DEFUN (show_evpn_vni, show_evpn_vni_cmd, - "show evpn vni", + "show evpn vni [json]", SHOW_STR "EVPN\n" - "VxLAN information\n") + "VxLAN information\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; + u_char uj = use_json(argc, argv); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_vnis(vty, zvrf); + zebra_vxlan_print_vnis(vty, zvrf, uj); return CMD_SUCCESS; } DEFUN (show_evpn_vni_vni, show_evpn_vni_vni_cmd, - "show evpn vni " CMD_VNI_RANGE, + "show evpn vni " CMD_VNI_RANGE "[json]", SHOW_STR "EVPN\n" "VxLAN Network Identifier\n" - "VNI number\n") + "VNI number\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; + u_char uj = use_json(argc, argv); vni = strtoul(argv[3]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_vni(vty, zvrf, vni); + zebra_vxlan_print_vni(vty, zvrf, vni, uj); return CMD_SUCCESS; } DEFUN (show_evpn_mac_vni, show_evpn_mac_vni_cmd, - "show evpn mac vni " CMD_VNI_RANGE, + "show evpn mac vni " CMD_VNI_RANGE "[json]", SHOW_STR "EVPN\n" "MAC addresses\n" "VxLAN Network Identifier\n" - "VNI number\n") + "VNI number\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; + u_char uj = use_json(argc, argv); vni = strtoul(argv[4]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_macs_vni(vty, zvrf, vni); + zebra_vxlan_print_macs_vni(vty, zvrf, vni, uj); return CMD_SUCCESS; } DEFUN (show_evpn_mac_vni_all, show_evpn_mac_vni_all_cmd, - "show evpn mac vni all", + "show evpn mac vni all [json]", SHOW_STR "EVPN\n" "MAC addresses\n" "VxLAN Network Identifier\n" - "All VNIs\n") + "All VNIs\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; + u_char uj = use_json(argc, argv); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_macs_all_vni(vty, zvrf); + zebra_vxlan_print_macs_all_vni(vty, zvrf, uj); return CMD_SUCCESS; } DEFUN (show_evpn_mac_vni_all_vtep, show_evpn_mac_vni_all_vtep_cmd, - "show evpn mac vni all vtep A.B.C.D", + "show evpn mac vni all vtep A.B.C.D [json]", SHOW_STR "EVPN\n" "MAC addresses\n" "VxLAN Network Identifier\n" "All VNIs\n" "Remote VTEP\n" - "Remote VTEP IP address\n") + "Remote VTEP IP address\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; struct in_addr vtep_ip; + u_char uj = use_json(argc, argv); if (!inet_aton(argv[6]->arg, &vtep_ip)) { - vty_out(vty, "%% Malformed VTEP IP address\n"); + if (!uj) + vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip); + zebra_vxlan_print_macs_all_vni_vtep(vty, zvrf, vtep_ip, uj); return CMD_SUCCESS; } @@ -2415,112 +2426,125 @@ DEFUN (show_evpn_mac_vni_mac, DEFUN (show_evpn_mac_vni_vtep, show_evpn_mac_vni_vtep_cmd, - "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D", + "show evpn mac vni " CMD_VNI_RANGE " vtep A.B.C.D" "[json]", SHOW_STR "EVPN\n" "MAC addresses\n" "VxLAN Network Identifier\n" "VNI number\n" "Remote VTEP\n" - "Remote VTEP IP address\n") + "Remote VTEP IP address\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; struct in_addr vtep_ip; + u_char uj = use_json(argc, argv); vni = strtoul(argv[4]->arg, NULL, 10); if (!inet_aton(argv[6]->arg, &vtep_ip)) { - vty_out(vty, "%% Malformed VTEP IP address\n"); + if (!uj) + vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip); + zebra_vxlan_print_macs_vni_vtep(vty, zvrf, vni, vtep_ip, uj); return CMD_SUCCESS; } DEFUN (show_evpn_neigh_vni, show_evpn_neigh_vni_cmd, - "show evpn arp-cache vni " CMD_VNI_RANGE, + "show evpn arp-cache vni " CMD_VNI_RANGE "[json]", SHOW_STR "EVPN\n" "ARP and ND cache\n" "VxLAN Network Identifier\n" - "VNI number\n") + "VNI number\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; + u_char uj = use_json(argc, argv); vni = strtoul(argv[4]->arg, NULL, 10); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_neigh_vni(vty, zvrf, vni); + zebra_vxlan_print_neigh_vni(vty, zvrf, vni, uj); return CMD_SUCCESS; } DEFUN (show_evpn_neigh_vni_all, show_evpn_neigh_vni_all_cmd, - "show evpn arp-cache vni all", + "show evpn arp-cache vni all [json]", SHOW_STR "EVPN\n" "ARP and ND cache\n" "VxLAN Network Identifier\n" - "All VNIs\n") + "All VNIs\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; + u_char uj = use_json(argc, argv); zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_neigh_all_vni(vty, zvrf); + zebra_vxlan_print_neigh_all_vni(vty, zvrf, uj); return CMD_SUCCESS; } DEFUN (show_evpn_neigh_vni_neigh, show_evpn_neigh_vni_neigh_cmd, - "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD", + "show evpn arp-cache vni " CMD_VNI_RANGE " ip WORD [json]", SHOW_STR "EVPN\n" "ARP and ND cache\n" "VxLAN Network Identifier\n" "VNI number\n" "Neighbor\n" - "Neighbor address (IPv4 or IPv6 address)\n") + "Neighbor address (IPv4 or IPv6 address)\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; struct ipaddr ip; + u_char uj = use_json(argc, argv); vni = strtoul(argv[4]->arg, NULL, 10); if (str2ipaddr(argv[6]->arg, &ip) != 0) { - vty_out(vty, "%% Malformed Neighbor address\n"); + if (!uj) + vty_out(vty, "%% Malformed Neighbor address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip); + zebra_vxlan_print_specific_neigh_vni(vty, zvrf, vni, &ip, uj); return CMD_SUCCESS; } DEFUN (show_evpn_neigh_vni_vtep, show_evpn_neigh_vni_vtep_cmd, - "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D", + "show evpn arp-cache vni " CMD_VNI_RANGE " vtep A.B.C.D [json]", SHOW_STR "EVPN\n" "ARP and ND cache\n" "VxLAN Network Identifier\n" "VNI number\n" "Remote VTEP\n" - "Remote VTEP IP address\n") + "Remote VTEP IP address\n" + "JavaScript Object Notation\n") { struct zebra_vrf *zvrf; vni_t vni; struct in_addr vtep_ip; + u_char uj = use_json(argc, argv); vni = strtoul(argv[4]->arg, NULL, 10); if (!inet_aton(argv[6]->arg, &vtep_ip)) { - vty_out(vty, "%% Malformed VTEP IP address\n"); + if (!uj) + vty_out(vty, "%% Malformed VTEP IP address\n"); return CMD_WARNING; } zvrf = vrf_info_lookup(VRF_DEFAULT); - zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip); + zebra_vxlan_print_neigh_vni_vtep(vty, zvrf, vni, vtep_ip, uj); return CMD_SUCCESS; } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index dc8e6e9c0e..cb555ff1ee 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -46,6 +46,7 @@ #include "zebra/zebra_vxlan.h" #include "zebra/zebra_memory.h" #include "zebra/zebra_l2.h" +#include "lib/json.h" DEFINE_MTYPE_STATIC(ZEBRA, ZVNI, "VNI hash"); DEFINE_MTYPE_STATIC(ZEBRA, ZVNI_VTEP, "VNI remote VTEP"); @@ -56,15 +57,15 @@ DEFINE_MTYPE_STATIC(ZEBRA, NEIGH, "VNI Neighbor"); /* static function declarations */ -static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt); +static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json); static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt); static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, - void *ctxt); + void **args); static void zvni_print_mac(zebra_mac_t *mac, void *ctxt); static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt); static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt); -static void zvni_print(zebra_vni_t *zvni, void *ctxt); -static void zvni_print_hash(struct hash_backet *backet, void *ctxt); +static void zvni_print(zebra_vni_t *zvni, void **ctxt); +static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]); static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *macaddr, @@ -180,18 +181,34 @@ static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) /* * Print a specific neighbor entry. */ -static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt) +static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) { struct vty *vty; char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - ipaddr2str(&n->ip, buf2, sizeof(buf2)), vty = (struct vty *)ctxt; - vty_out(vty, "IP: %s\n", ipaddr2str(&n->ip, buf2, sizeof(buf2))); - vty_out(vty, " MAC: %s", prefix_mac2str(&n->emac, buf1, sizeof(buf1))); - if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) - vty_out(vty, " Remote VTEP: %s", inet_ntoa(n->r_vtep_ip)); - vty_out(vty, "\n"); + ipaddr2str(&n->ip, buf2, sizeof(buf2)); + prefix_mac2str(&n->emac, buf1, sizeof(buf1)); + vty = (struct vty *)ctxt; + if (json == NULL) { + vty_out(vty, "IP: %s\n", + ipaddr2str(&n->ip, buf2, sizeof(buf2))); + vty_out(vty, " MAC: %s", + prefix_mac2str(&n->emac, buf1, sizeof(buf1))); + } else { + json_object_string_add(json, "ip", buf2); + json_object_string_add(json, "mac", buf1); + } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { + if (json == NULL) + vty_out(vty, " Remote VTEP: %s", + inet_ntoa(n->r_vtep_ip)); + else + json_object_string_add(json, "remoteVtep", + inet_ntoa(n->r_vtep_ip)); + } + if (json == NULL) + vty_out(vty, "\n"); } /* @@ -200,65 +217,115 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt) static void zvni_print_neigh_hash(struct hash_backet *backet, void *ctxt) { struct vty *vty; + json_object *json_vni = NULL, *json_row = NULL; zebra_neigh_t *n; char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; struct neigh_walk_ctx *wctx = ctxt; vty = wctx->vty; + json_vni = wctx->json; n = (zebra_neigh_t *)backet->data; if (!n) return; + if (json_vni) + json_row = json_object_new_object(); + prefix_mac2str(&n->emac, buf1, sizeof(buf1)); ipaddr2str(&n->ip, buf2, sizeof(buf2)); if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL) && !(wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP)) { - vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width, buf2, - "local", buf1); + if (json_vni == NULL) { + vty_out(vty, "%*s %-6s %-17s\n", -wctx->addr_width, + buf2, "local", buf1); + } else { + json_object_string_add(json_row, "type", "local"); + json_object_string_add(json_row, "mac", buf1); + } wctx->count++; } else { if (wctx->flags & SHOW_REMOTE_NEIGH_FROM_VTEP) { if (IPV4_ADDR_SAME(&n->r_vtep_ip, &wctx->r_vtep_ip)) { - if (wctx->count == 0) + if (json_vni == NULL) { + if (wctx->count == 0) + vty_out(vty, + "%*s %-6s %-17s %-21s\n", + -wctx->addr_width, + "Neighbor", "Type", + "MAC", "Remote VTEP"); vty_out(vty, "%*s %-6s %-17s %-21s\n", - -wctx->addr_width, "Neighbor", - "Type", "MAC", "Remote VTEP"); - vty_out(vty, "%*s %-6s %-17s %-21s\n", - -wctx->addr_width, buf2, "remote", buf1, - inet_ntoa(n->r_vtep_ip)); + -wctx->addr_width, buf2, + "remote", buf1, + inet_ntoa(n->r_vtep_ip)); + } else { + json_object_string_add(json_row, "type", + "remote"); + json_object_string_add(json_row, "mac", + buf1); + json_object_string_add( + json_row, "remoteVtep", + inet_ntoa(n->r_vtep_ip)); + } wctx->count++; } } else { - vty_out(vty, "%*s %-6s %-17s %-21s\n", - -wctx->addr_width, buf2, "remote", buf1, - inet_ntoa(n->r_vtep_ip)); + if (json_vni == NULL) { + vty_out(vty, "%*s %-6s %-17s %-21s\n", + -wctx->addr_width, buf2, "remote", buf1, + inet_ntoa(n->r_vtep_ip)); + } else { + json_object_string_add(json_row, "type", + "remote"); + json_object_string_add(json_row, "mac", buf1); + json_object_string_add(json_row, "remoteVtep", + inet_ntoa(n->r_vtep_ip)); + } wctx->count++; } } + + if (json_vni) + json_object_object_add(json_vni, buf2, json_row); } /* * Print neighbors for all VNI. */ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, - void *ctxt) + void **args) { struct vty *vty; + json_object *json = NULL, *json_vni = NULL; zebra_vni_t *zvni; u_int32_t num_neigh; struct neigh_walk_ctx wctx; + char vni_str[VNI_STR_LEN]; + + vty = (struct vty *)args[0]; + json = (json_object *)args[1]; - vty = (struct vty *)ctxt; zvni = (zebra_vni_t *)backet->data; - if (!zvni) + if (!zvni) { + if (json) + vty_out(vty, "{}\n"); return; - + } num_neigh = hashcount(zvni->neigh_table); - vty_out(vty, "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", - zvni->vni, num_neigh); - if (!num_neigh) + if (json == NULL) + vty_out(vty, + "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", + zvni->vni, num_neigh); + else { + json_vni = json_object_new_object(); + json_object_int_add(json_vni, "numArpNd", num_neigh); + snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); + } + if (!num_neigh) { + if (json) + json_object_object_add(json, vni_str, json_vni); return; + } /* Since we have IPv6 addresses to deal with which can vary widely in * size, we try to be a bit more elegant in display by first computing @@ -268,11 +335,16 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, wctx.zvni = zvni; wctx.vty = vty; wctx.addr_width = 15; + wctx.json = json_vni; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type", - "MAC", "Remote VTEP"); + if (json == NULL) + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", + "Type", "MAC", "Remote VTEP"); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); + + if (json) + json_object_object_add(json, vni_str, json_vni); } /* @@ -313,16 +385,22 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) { struct vty *vty; + json_object *json_mac_hdr = NULL, *json_mac = NULL; zebra_mac_t *mac; char buf1[20]; struct mac_walk_ctx *wctx = ctxt; vty = wctx->vty; + json_mac_hdr = wctx->json; mac = (zebra_mac_t *)backet->data; if (!mac) return; prefix_mac2str(&mac->macaddr, buf1, sizeof(buf1)); + + if (json_mac_hdr) + json_mac = json_object_new_object(); + if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) && !(wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)) { struct zebra_ns *zns; @@ -336,29 +414,70 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) if (!ifp) // unexpected return; vid = mac->fwd_info.local.vid; - vty_out(vty, "%-17s %-6s %-21s", buf1, "local", ifp->name); - if (vid) - vty_out(vty, " %-5u", vid); - vty_out(vty, "\n"); + if (json_mac_hdr == NULL) + vty_out(vty, "%-17s %-6s %-21s", buf1, "local", + ifp->name); + else { + json_object_string_add(json_mac, "type", "local"); + json_object_string_add(json_mac, "intf", ifp->name); + } + if (vid) { + if (json_mac_hdr == NULL) + vty_out(vty, " %-5u", vid); + else + json_object_int_add(json_mac, "vlan", vid); + } + if (json_mac_hdr == NULL) + vty_out(vty, "\n"); + else + json_object_object_add(json_mac_hdr, buf1, json_mac); wctx->count++; } else { if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) { if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) { if (wctx->count == 0) { - vty_out(vty, "\nVNI %u", - wctx->zvni->vni); - vty_out(vty, "%-17s %-6s %-21s %-5s", - "MAC", "Type", - "Intf/Remote VTEP", "VLAN"); + if (json_mac_hdr == NULL) { + vty_out(vty, "\nVNI %u\n\n", + wctx->zvni->vni); + vty_out(vty, + "%-17s %-6s %-21s %-5s\n", + "MAC", "Type", + "Intf/Remote VTEP", + "VLAN"); + } + } + if (json_mac_hdr == NULL) + vty_out(vty, "%-17s %-6s %-21s\n", buf1, + "remote", + inet_ntoa(mac->fwd_info + .r_vtep_ip)); + else { + json_object_string_add(json_mac, "type", + "remote"); + json_object_string_add( + json_mac, "remoteVtep", + inet_ntoa(mac->fwd_info + .r_vtep_ip)); + json_object_object_add(json_mac_hdr, + buf1, json_mac); } - vty_out(vty, "%-17s %-6s %-21s", buf1, "remote", - inet_ntoa(mac->fwd_info.r_vtep_ip)); wctx->count++; } } else { - vty_out(vty, "%-17s %-6s %-21s", buf1, "remote", - inet_ntoa(mac->fwd_info.r_vtep_ip)); + if (json_mac_hdr == NULL) + vty_out(vty, "%-17s %-6s %-21s\n", buf1, + "remote", + inet_ntoa(mac->fwd_info.r_vtep_ip)); + else { + json_object_string_add(json_mac, "type", + "remote"); + json_object_string_add( + json_mac, "remoteVtep", + inet_ntoa(mac->fwd_info.r_vtep_ip)); + json_object_object_add(json_mac_hdr, buf1, + json_mac); + } wctx->count++; } } @@ -370,15 +489,22 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) { struct vty *vty; + json_object *json = NULL, *json_vni = NULL; + json_object *json_mac = NULL; zebra_vni_t *zvni; u_int32_t num_macs; struct mac_walk_ctx *wctx = ctxt; + char vni_str[VNI_STR_LEN]; vty = (struct vty *)wctx->vty; + json = (struct json_object *)wctx->json; zvni = (zebra_vni_t *)backet->data; - if (!zvni) + if (!zvni) { + if (json) + vty_out(vty, "{}\n"); return; + } wctx->zvni = zvni; /*We are iterating over a new VNI, set the count to 0*/ @@ -387,59 +513,115 @@ static void zvni_print_mac_hash_all_vni(struct hash_backet *backet, void *ctxt) num_macs = hashcount(zvni->mac_table); if (!num_macs) return; - if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { - vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", - zvni->vni, num_macs); - vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", - "Intf/Remote VTEP", "VLAN"); + + if (json) { + json_vni = json_object_new_object(); + json_mac = json_object_new_object(); + snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); } + if (!CHECK_FLAG(wctx->flags, SHOW_REMOTE_MAC_FROM_VTEP)) { + if (json == NULL) { + vty_out(vty, "\nVNI %u #MACs (local and remote) %u\n\n", + zvni->vni, num_macs); + vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", + "Intf/Remote VTEP", "VLAN"); + } else + json_object_int_add(json_vni, "numMacs", num_macs); + } + /* assign per-vni to wctx->json object to fill macs + * under the vni. Re-assign primary json object to fill + * next vni information. + */ + wctx->json = json_mac; hash_iterate(zvni->mac_table, zvni_print_mac_hash, wctx); + wctx->json = json; + if (json) { + if (wctx->count) + json_object_object_add(json_vni, "macs", json_mac); + json_object_object_add(json, vni_str, json_vni); + } } /* * Print a specific VNI entry. */ -static void zvni_print(zebra_vni_t *zvni, void *ctxt) +static void zvni_print(zebra_vni_t *zvni, void **ctxt) { struct vty *vty; zebra_vtep_t *zvtep; u_int32_t num_macs; u_int32_t num_neigh; + json_object *json = NULL; + json_object *json_vtep_list = NULL; + json_object *json_ip_str = NULL; - vty = (struct vty *)ctxt; + vty = ctxt[0]; + json = ctxt[1]; + + if (json == NULL) + vty_out(vty, "VNI: %u\n", zvni->vni); + else + json_object_int_add(json, "vni", zvni->vni); - vty_out(vty, "VNI: %u\n", zvni->vni); if (!zvni->vxlan_if) { // unexpected - vty_out(vty, " VxLAN interface: unknown\n"); + if (json == NULL) + vty_out(vty, " VxLAN interface: unknown\n"); return; } - vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n", - zvni->vxlan_if->name, zvni->vxlan_if->ifindex, - inet_ntoa(zvni->local_vtep_ip)); - - if (!zvni->vteps) { - vty_out(vty, " No remote VTEPs known for this VNI\n"); - } else { - vty_out(vty, " Remote VTEPs for this VNI:\n"); - for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) - vty_out(vty, " %s\n", inet_ntoa(zvtep->vtep_ip)); - } num_macs = hashcount(zvni->mac_table); - vty_out(vty, - " Number of MACs (local and remote) known for this VNI: %u\n", - num_macs); num_neigh = hashcount(zvni->neigh_table); - vty_out(vty, - " Number of ARPs (IPv4 and IPv6, local and remote) " - "known for this VNI: %u", - num_neigh); + if (json == NULL) + vty_out(vty, " VxLAN interface: %s ifIndex: %u VTEP IP: %s\n", + zvni->vxlan_if->name, zvni->vxlan_if->ifindex, + inet_ntoa(zvni->local_vtep_ip)); + else { + json_object_string_add(json, "vxlanInterface", + zvni->vxlan_if->name); + json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); + json_object_string_add(json, "vtepIp", + inet_ntoa(zvni->local_vtep_ip)); + json_object_int_add(json, "numMacs", num_macs); + json_object_int_add(json, "numArpNd", num_neigh); + } + if (!zvni->vteps) { + if (json == NULL) + vty_out(vty, " No remote VTEPs known for this VNI\n"); + } else { + if (json == NULL) + vty_out(vty, " Remote VTEPs for this VNI:\n"); + else + json_vtep_list = json_object_new_array(); + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { + if (json == NULL) + vty_out(vty, " %s\n", + inet_ntoa(zvtep->vtep_ip)); + else { + json_ip_str = json_object_new_string( + inet_ntoa(zvtep->vtep_ip)); + json_object_array_add(json_vtep_list, + json_ip_str); + } + } + if (json) + json_object_object_add(json, "numRemoteVteps", + json_vtep_list); + } + if (json == NULL) { + vty_out(vty, + " Number of MACs (local and remote) known for this VNI: %u\n", + num_macs); + vty_out(vty, + " Number of ARPs (IPv4 and IPv6, local and remote) " + "known for this VNI: %u\n", + num_neigh); + } } /* * Print a VNI hash entry - called for display of all VNIs. */ -static void zvni_print_hash(struct hash_backet *backet, void *ctxt) +static void zvni_print_hash(struct hash_backet *backet, void *ctxt[]) { struct vty *vty; zebra_vni_t *zvni; @@ -447,8 +629,14 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt) u_int32_t num_vteps = 0; u_int32_t num_macs = 0; u_int32_t num_neigh = 0; + json_object *json = NULL; + json_object *json_vni = NULL; + json_object *json_ip_str = NULL; + json_object *json_vtep_list = NULL; + + vty = ctxt[0]; + json = ctxt[1]; - vty = (struct vty *)ctxt; zvni = (zebra_vni_t *)backet->data; if (!zvni) return; @@ -461,9 +649,36 @@ static void zvni_print_hash(struct hash_backet *backet, void *ctxt) num_macs = hashcount(zvni->mac_table); num_neigh = hashcount(zvni->neigh_table); - vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni, - zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", - inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, num_vteps); + if (json == NULL) + vty_out(vty, "%-10u %-21s %-15s %-8u %-8u %-15u\n", zvni->vni, + zvni->vxlan_if ? zvni->vxlan_if->name : "unknown", + inet_ntoa(zvni->local_vtep_ip), num_macs, num_neigh, + num_vteps); + else { + char vni_str[VNI_STR_LEN]; + snprintf(vni_str, VNI_STR_LEN, "%u", zvni->vni); + json_vni = json_object_new_object(); + json_object_string_add(json_vni, "vxlanIf", + zvni->vxlan_if ? zvni->vxlan_if->name + : "unknown"); + json_object_string_add(json_vni, "vtepIp", + inet_ntoa(zvni->local_vtep_ip)); + json_object_int_add(json_vni, "numMacs", num_macs); + json_object_int_add(json_vni, "numArpNd", num_neigh); + json_object_int_add(json_vni, "numRemoteVteps", num_vteps); + if (num_vteps) { + json_vtep_list = json_object_new_array(); + for (zvtep = zvni->vteps; zvtep; zvtep = zvtep->next) { + json_ip_str = json_object_new_string( + inet_ntoa(zvtep->vtep_ip)); + json_object_array_add(json_vtep_list, + json_ip_str); + } + json_object_object_add(json_vni, "remoteVteps", + json_vtep_list); + } + json_object_object_add(json, vni_str, json_vni); + } } /* @@ -1943,23 +2158,30 @@ static void zvni_cleanup_all(struct hash_backet *backet, void *zvrf) * Display Neighbors for a VNI (VTY command handler). */ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni) + vni_t vni, u_char use_json) { zebra_vni_t *zvni; u_int32_t num_neigh; struct neigh_walk_ctx wctx; + json_object *json = NULL; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_neigh = hashcount(zvni->neigh_table); if (!num_neigh) return; + if (use_json) + json = json_object_new_object(); + /* Since we have IPv6 addresses to deal with which can vary widely in * size, we try to be a bit more elegant in display by first computing * the maximum width. @@ -1968,25 +2190,52 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, wctx.zvni = zvni; wctx.vty = vty; wctx.addr_width = 15; + wctx.json = json; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - vty_out(vty, - "Number of ARPs (local and remote) known for this VNI: %u\n", - num_neigh); - vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", "Type", - "MAC", "Remote VTEP"); + if (!use_json) { + vty_out(vty, + "Number of ARPs (local and remote) known for this VNI: %u\n", + num_neigh); + vty_out(vty, "%*s %-6s %-17s %-21s\n", -wctx.addr_width, "IP", + "Type", "MAC", "Remote VTEP"); + } else + json_object_int_add(json, "numArpNd", num_neigh); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* * Display neighbors across all VNIs (VTY command handler). */ -void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf) +void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json) { + json_object *json = NULL; + void *args[2]; + if (!EVPN_ENABLED(zvrf)) return; - hash_iterate(zvrf->vni_table, zvni_print_neigh_hash_all_vni, vty); + + if (use_json) + json = json_object_new_object(); + + args[0] = vty; + args[1] = json; + hash_iterate(zvrf->vni_table, + (void (*)(struct hash_backet *, + void *))zvni_print_neigh_hash_all_vni, + args); + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* @@ -1994,26 +2243,40 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf) */ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, - struct ipaddr *ip) + struct ipaddr *ip, u_char use_json) { zebra_vni_t *zvni; zebra_neigh_t *n; + json_object *json = NULL; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } n = zvni_neigh_lookup(zvni, ip); if (!n) { - vty_out(vty, "%% Requested neighbor does not exist in VNI %u\n", - vni); + if (!use_json) + vty_out(vty, + "%% Requested neighbor does not exist in VNI %u\n", + vni); return; } + if (use_json) + json = json_object_new_object(); - zvni_print_neigh(n, vty); + zvni_print_neigh(n, vty, json); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* @@ -2021,17 +2284,22 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, * By definition, these are remote neighbors. */ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni, struct in_addr vtep_ip) + vni_t vni, struct in_addr vtep_ip, + u_char use_json) { zebra_vni_t *zvni; u_int32_t num_neigh; struct neigh_walk_ctx wctx; + json_object *json = NULL; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_neigh = hashcount(zvni->neigh_table); @@ -2043,56 +2311,98 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, wctx.vty = vty; wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; wctx.r_vtep_ip = vtep_ip; - + wctx.json = json; hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* * Display MACs for a VNI (VTY command handler). */ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni) + vni_t vni, u_char use_json) { zebra_vni_t *zvni; u_int32_t num_macs; struct mac_walk_ctx wctx; + json_object *json = NULL; + json_object *json_mac = NULL; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = hashcount(zvni->mac_table); if (!num_macs) return; + if (use_json) { + json = json_object_new_object(); + json_mac = json_object_new_object(); + } + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); wctx.zvni = zvni; wctx.vty = vty; + wctx.json = json_mac; - vty_out(vty, - "Number of MACs (local and remote) known for this VNI: %u\n", - num_macs); - vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", - "Intf/Remote VTEP", "VLAN"); + if (!use_json) { + vty_out(vty, + "Number of MACs (local and remote) known for this VNI: %u\n", + num_macs); + vty_out(vty, "%-17s %-6s %-21s %-5s\n", "MAC", "Type", + "Intf/Remote VTEP", "VLAN"); + } else + json_object_int_add(json, "numMacs", num_macs); hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); + + if (use_json) { + json_object_object_add(json, "macs", json_mac); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* * Display MACs for all VNIs (VTY command handler). */ -void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf) +void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json) { struct mac_walk_ctx wctx; + json_object *json = NULL; - if (!EVPN_ENABLED(zvrf)) + if (!EVPN_ENABLED(zvrf)) { + if (use_json) + vty_out(vty, "{}\n"); return; + } + if (use_json) + json = json_object_new_object(); + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); wctx.vty = vty; + wctx.json = json; hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* @@ -2100,17 +2410,30 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf) */ void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, - struct in_addr vtep_ip) + struct in_addr vtep_ip, + u_char use_json) { struct mac_walk_ctx wctx; + json_object *json = NULL; if (!EVPN_ENABLED(zvrf)) return; + + if (use_json) + json = json_object_new_object(); + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); wctx.vty = vty; wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; wctx.r_vtep_ip = vtep_ip; + wctx.json = json; hash_iterate(zvrf->vni_table, zvni_print_mac_hash_all_vni, &wctx); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* @@ -2143,64 +2466,124 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, * Display MACs for a VNI from specific VTEP (VTY command handler). */ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni, struct in_addr vtep_ip) + vni_t vni, struct in_addr vtep_ip, + u_char use_json) { zebra_vni_t *zvni; u_int32_t num_macs; struct mac_walk_ctx wctx; + json_object *json = NULL; + json_object *json_mac = NULL; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } num_macs = hashcount(zvni->mac_table); if (!num_macs) return; + + if (use_json) { + json = json_object_new_object(); + json_mac = json_object_new_object(); + } + memset(&wctx, 0, sizeof(struct mac_walk_ctx)); wctx.zvni = zvni; wctx.vty = vty; wctx.flags = SHOW_REMOTE_MAC_FROM_VTEP; wctx.r_vtep_ip = vtep_ip; + wctx.json = json_mac; hash_iterate(zvni->mac_table, zvni_print_mac_hash, &wctx); + + if (use_json) { + json_object_int_add(json, "numMacs", wctx.count); + if (wctx.count) + json_object_object_add(json, "macs", json_mac); + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* * Display VNI information (VTY command handler). */ -void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni) +void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, + u_char use_json) { zebra_vni_t *zvni; + json_object *json = NULL; + void *args[2]; if (!EVPN_ENABLED(zvrf)) return; zvni = zvni_lookup(zvrf, vni); if (!zvni) { - vty_out(vty, "%% VNI %u does not exist\n", vni); + if (use_json) + vty_out(vty, "{}\n"); + else + vty_out(vty, "%% VNI %u does not exist\n", vni); return; } - zvni_print(zvni, (void *)vty); + if (use_json) + json = json_object_new_object(); + args[0] = vty; + args[1] = json; + zvni_print(zvni, (void *)args); + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* * Display VNI hash table (VTY command handler). */ -void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf) +void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json) { u_int32_t num_vnis; + json_object *json = NULL; + void *args[2]; if (!EVPN_ENABLED(zvrf)) return; num_vnis = hashcount(zvrf->vni_table); - if (!num_vnis) + if (!num_vnis) { + if (use_json) + vty_out(vty, "{}\n"); return; - vty_out(vty, "Number of VNIs: %u\n", num_vnis); - vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", "VxLAN IF", - "VTEP IP", "# MACs", "# ARPs", "# Remote VTEPs"); - hash_iterate(zvrf->vni_table, zvni_print_hash, vty); + } + if (use_json) { + json = json_object_new_object(); + json_object_int_add(json, "numVnis", num_vnis); + } else { + vty_out(vty, "Number of VNIs: %u\n", num_vnis); + vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", + "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", + "# Remote VTEPs"); + } + args[0] = vty; + args[1] = json; + + hash_iterate(zvrf->vni_table, + (void (*)(struct hash_backet *, void *))zvni_print_hash, + args); + + if (use_json) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } } /* diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index dca8006033..f7c1afc959 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -41,32 +41,41 @@ #define ZEBRA_VXLIF_MASTER_CHANGE 0x2 #define ZEBRA_VXLIF_VLAN_CHANGE 0x4 +#define VNI_STR_LEN 32 + extern void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni); + vni_t vni, u_char use_json); extern void zebra_vxlan_print_macs_all_vni(struct vty *vty, - struct zebra_vrf *zvrf); + struct zebra_vrf *zvrf, + u_char use_json); extern void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, - struct in_addr vtep_ip); + struct in_addr vtep_ip, + u_char use_json); extern void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, struct ethaddr *mac); extern void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, - struct in_addr vtep_ip); + struct in_addr vtep_ip, + u_char use_json); extern void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni); + vni_t vni, u_char use_json); extern void zebra_vxlan_print_neigh_all_vni(struct vty *vty, - struct zebra_vrf *zvrf); + struct zebra_vrf *zvrf, + u_char use_json); extern void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni, struct ipaddr *ip); + vni_t vni, struct ipaddr *ip, + u_char use_json); extern void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, - struct in_addr vtep_ip); + struct in_addr vtep_ip, + u_char use_json); extern void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, - vni_t vni); -extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf); + vni_t vni, u_char use_json); +extern void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, + u_char use_json); extern int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, int add); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 2e5943a75c..2bf00291e7 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -135,8 +135,9 @@ struct mac_walk_ctx { struct in_addr r_vtep_ip; /* To walk MACs from specific VTEP */ - struct vty *vty; /* Used by VTY handlers */ - u_int32_t count; /* Used by VTY handlers */ + struct vty *vty; /* Used by VTY handlers */ + u_int32_t count; /* Used by VTY handlers */ + struct json_object *json; /* Used for JSON Output */ }; /* @@ -186,9 +187,10 @@ struct neigh_walk_ctx { struct in_addr r_vtep_ip; /* To walk neighbors from specific VTEP */ - struct vty *vty; /* Used by VTY handlers */ - u_int32_t count; /* Used by VTY handlers */ - u_char addr_width; /* Used by VTY handlers */ + struct vty *vty; /* Used by VTY handlers */ + u_int32_t count; /* Used by VTY handlers */ + u_char addr_width; /* Used by VTY handlers */ + struct json_object *json; /* Used for JSON Output */ }; #endif /* _ZEBRA_VXLAN_PRIVATE_H */ From 5bc2ed52f0b55615a24d788e9529ddb630fd9bc8 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 29 Jun 2017 14:16:49 -0700 Subject: [PATCH 14/32] bgpd: fix crash while configuring rt Ticket: CM-16410 Review: CCR-6409 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn_vty.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index be88fcd273..886d2a02c6 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -2563,11 +2563,11 @@ DEFUN (bgp_evpn_vni_rt, if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) { ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0); - ecommunity_str(ecomadd); if (!ecomadd) { vty_out(vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } + ecommunity_str(ecomadd); /* Do nothing if we already have this import route-target */ if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomadd)) @@ -2578,11 +2578,11 @@ DEFUN (bgp_evpn_vni_rt, if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) { ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0); - ecommunity_str(ecomadd); if (!ecomadd) { vty_out(vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } + ecommunity_str(ecomadd); /* Do nothing if we already have this export route-target */ if (!bgp_evpn_rt_matches_existing(vpn->export_rtl, ecomadd)) @@ -2645,11 +2645,11 @@ DEFUN (no_bgp_evpn_vni_rt, } ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0); - ecommunity_str(ecomdel); if (!ecomdel) { vty_out(vty, "%% Malformed Route Target list\n"); return CMD_WARNING; } + ecommunity_str(ecomdel); if (rt_type == RT_TYPE_IMPORT) { if (!bgp_evpn_rt_matches_existing(vpn->import_rtl, ecomdel)) { From 640751c7acc8ea2236a0d46d9663849573e56e3f Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Fri, 30 Jun 2017 13:29:37 +0000 Subject: [PATCH 15/32] EVPN: Indentation is off for route-target export Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-16967 --- bgpd/bgp_evpn_vty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 886d2a02c6..a6f5e168c9 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1739,7 +1739,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn, int *write) ecom)) { ecom_str = ecommunity_ecom2str( ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0); - vty_out(vty, " route-target export %s\n", + vty_out(vty, " route-target export %s\n", ecom_str); XFREE(MTYPE_ECOMMUNITY_STR, ecom_str); } From b6938a74e5f73a2f29df12efb46e7121e79d3b86 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 5 Jul 2017 15:03:14 -0700 Subject: [PATCH 16/32] zebra: Provide neigh-mac tie-in in zebra Currently, FRR does not do any linking between local MACs and neighbors. We found this necessary when dealing with centralized GW. A neigh is considered local only when the mac is learnt locally as well. Ticket: CM-16544 Review: CCR-6388 Unit-test: Manual/Evpn-Smoke Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 331 +++++++++++++++++++++++++++++++++--- zebra/zebra_vxlan_private.h | 19 ++- 2 files changed, 323 insertions(+), 27 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index cb555ff1ee..393ac997b3 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -74,7 +74,8 @@ static int zvni_macip_send_msg_to_client(struct zebra_vrf *zvrf, vni_t vni, static unsigned int neigh_hash_keymake(void *p); static int neigh_cmp(const void *p1, const void *p2); static void *zvni_neigh_alloc(void *p); -static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip); +static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, + struct ethaddr *mac); static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n); static int zvni_neigh_del_hash_entry(struct hash_backet *backet, void *arg); static void zvni_neigh_del_from_vtep(zebra_vni_t *zvni, int uninstall, @@ -200,10 +201,13 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) json_object_string_add(json, "mac", buf1); } if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { - if (json == NULL) + if (json == NULL) { vty_out(vty, " Remote VTEP: %s", inet_ntoa(n->r_vtep_ip)); - else + vty_out(vty, " State: %s", IS_ZEBRA_NEIGH_ACTIVE(n) + ? "Active" + : "Inactive"); + } else json_object_string_add(json, "remoteVtep", inet_ntoa(n->r_vtep_ip)); } @@ -353,7 +357,10 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) { struct vty *vty; + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; char buf1[20]; + char buf2[INET6_ADDRSTRLEN]; vty = (struct vty *)ctxt; vty_out(vty, "MAC: %s", @@ -371,11 +378,30 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt) vty_out(vty, " Intf: %s(%u)", ifp->name, ifindex); if (mac->fwd_info.local.vid) vty_out(vty, " VLAN: %u", mac->fwd_info.local.vid); - } else { + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { vty_out(vty, " Remote VTEP: %s", inet_ntoa(mac->fwd_info.r_vtep_ip)); + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) { + vty_out(vty, " Auto Mac "); } - vty_out(vty, " ARP ref: %u", mac->neigh_refcnt); + vty_out(vty, " ARP ref: %u\n", mac->neigh_refcnt); + + /* print all the associated neigh */ + vty_out(vty, " Neighbors:\n"); + if (!listcount(mac->neigh_list)) + vty_out(vty, " No Neighbors\n"); + else { + for (ALL_LIST_ELEMENTS_RO(mac->neigh_list, node, n)) { + vty_out(vty, " %s %s\n", + ipaddr2str(&n->ip, buf2, sizeof(buf2)), + CHECK_FLAG(n->flags, ZEBRA_MAC_LOCAL) + ? (IS_ZEBRA_NEIGH_ACTIVE(n) + ? "Active" + : "Inactive") + : ""); + } + } + vty_out(vty, "\n"); } @@ -432,7 +458,7 @@ static void zvni_print_mac_hash(struct hash_backet *backet, void *ctxt) else json_object_object_add(json_mac_hdr, buf1, json_mac); wctx->count++; - } else { + } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP) { if (IPV4_ADDR_SAME(&mac->fwd_info.r_vtep_ip, &wctx->r_vtep_ip)) { @@ -789,16 +815,26 @@ static void *zvni_neigh_alloc(void *p) /* * Add neighbor entry. */ -static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip) +static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip, + struct ethaddr *mac) { zebra_neigh_t tmp_n; zebra_neigh_t *n = NULL; + zebra_mac_t *zmac = NULL; memset(&tmp_n, 0, sizeof(zebra_neigh_t)); memcpy(&tmp_n.ip, ip, sizeof(struct ipaddr)); n = hash_get(zvni->neigh_table, &tmp_n, zvni_neigh_alloc); assert(n); + memcpy(&n->emac, mac, ETH_ALEN); + n->state = ZEBRA_NEIGH_INACTIVE; + + /* Associate the neigh to mac */ + zmac = zvni_mac_lookup(zvni, mac); + if (zmac) + listnode_add_sort(zmac->neigh_list, n); + return n; } @@ -808,6 +844,11 @@ static zebra_neigh_t *zvni_neigh_add(zebra_vni_t *zvni, struct ipaddr *ip) static int zvni_neigh_del(zebra_vni_t *zvni, zebra_neigh_t *n) { zebra_neigh_t *tmp_n; + zebra_mac_t *zmac = NULL; + + zmac = zvni_mac_lookup(zvni, &n->emac); + if (zmac) + listnode_delete(zmac->neigh_list, n); /* Free the VNI hash entry and allocated memory. */ tmp_n = hash_release(zvni->neigh_table, n); @@ -907,6 +948,146 @@ static zebra_neigh_t *zvni_neigh_lookup(zebra_vni_t *zvni, struct ipaddr *ip) return n; } +/* Process all neigh associated to a mac upon local mac add event */ +static void zvni_process_neigh_on_local_mac_add(struct zebra_vrf *zvrf, + zebra_vni_t *zvni, + zebra_mac_t *zmac) +{ + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + /* MAC is learnt locally, program all inactive neigh + * pointing to this mac */ + if (IS_ZEBRA_NEIGH_INACTIVE(n)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: neigh %s (MAC %s) on VNI %u is now ACTIVE", + zvrf_id(zvrf), + ipaddr2str(&n->ip, buf2, + sizeof(buf2)), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni); + + ZEBRA_NEIGH_SET_ACTIVE(n); + zvni_neigh_send_add_to_client( + zvrf, zvni->vni, &n->ip, &n->emac, 0); + } else { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: neigh %s (MAC %s) on VNI %u should NOT be ACTIVE", + zvrf_id(zvrf), + ipaddr2str(&n->ip, buf2, + sizeof(buf2)), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni); + } + } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { + /* TODO: assume the neigh has moved too ?? */ + } + } +} + +/* Process all neigh associated to a mac upon local mac del event */ +static void zvni_process_neigh_on_local_mac_del(struct zebra_vrf *zvrf, + zebra_vni_t *zvni, + zebra_mac_t *zmac) +{ + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + if (IS_ZEBRA_NEIGH_ACTIVE(n)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: neigh %s (MAC %s) on VNI %u is now INACTIVE", + zvrf_id(zvrf), + ipaddr2str(&n->ip, buf2, + sizeof(buf2)), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni); + + ZEBRA_NEIGH_SET_INACTIVE(n); + zvni_neigh_send_del_to_client( + zvrf, zvni->vni, &n->ip, &n->emac, 0); + } + } else if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_REMOTE)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_err( + "%u: local MAC %s getting deleted on VNI %u has remote neigh %s", + zvrf_id(zvrf), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni, + ipaddr2str(&n->ip, buf2, sizeof(buf2))); + } + } +} + +/* process all neigh associated to a mac entry upon remote mac add */ +static void zvni_process_neigh_on_remote_mac_add(struct zebra_vrf *zvrf, + zebra_vni_t *zvni, + zebra_mac_t *zmac) +{ + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + if (IS_ZEBRA_NEIGH_ACTIVE(n)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: neigh %s (MAC %s) on VNI %u INACTIVE", + zvrf_id(zvrf), + ipaddr2str(&n->ip, buf2, + sizeof(buf2)), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni); + + ZEBRA_NEIGH_SET_INACTIVE(n); + zvni_neigh_send_del_to_client( + zvrf, zvni->vni, &n->ip, &n->emac, 0); + } + } + } +} + +/* process all neigh associated to mac entry upon remote mac del */ +static void zvni_process_neigh_on_remote_mac_del(struct zebra_vrf *zvrf, + zebra_vni_t *zvni, + zebra_mac_t *zmac) +{ + zebra_neigh_t *n = NULL; + struct listnode *node = NULL; + char buf[ETHER_ADDR_STRLEN]; + char buf2[INET6_ADDRSTRLEN]; + + for (ALL_LIST_ELEMENTS_RO(zmac->neigh_list, node, n)) { + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_LOCAL)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_err( + "%u: remote MAC %s getting deleted on VNI %u has local neigh %s", + zvrf_id(zvrf), + prefix_mac2str(&n->emac, buf, + sizeof(buf)), + zvni->vni, + ipaddr2str(&n->ip, buf2, sizeof(buf2))); + } + } +} + /* * Inform BGP about local neighbor addition. */ @@ -1153,7 +1334,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, n = zvni_neigh_lookup(zvni, ip); if (!n) { - n = zvni_neigh_add(zvni, ip); + n = zvni_neigh_add(zvni, ip, macaddr); if (!n) { zlog_err( "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", @@ -1366,6 +1547,9 @@ static zebra_mac_t *zvni_mac_add(zebra_vni_t *zvni, struct ethaddr *macaddr) mac = hash_get(zvni->mac_table, &tmp_mac, zvni_mac_alloc); assert(mac); + mac->neigh_list = list_new(); + mac->neigh_list->cmp = (int (*)(void *, void *))neigh_cmp; + return mac; } @@ -1376,6 +1560,8 @@ static int zvni_mac_del(zebra_vni_t *zvni, zebra_mac_t *mac) { zebra_mac_t *tmp_mac; + list_delete(mac->neigh_list); + /* Free the VNI hash entry and allocated memory. */ tmp_mac = hash_release(zvni->mac_table, mac); if (tmp_mac) @@ -2599,6 +2785,8 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, zebra_neigh_t *n; struct zebra_vrf *zvrf; char buf[INET6_ADDRSTRLEN]; + char buf2[ETHER_ADDR_STRLEN]; + zebra_mac_t *zmac; /* We are only interested in neighbors on an SVI that resides on top * of a VxLAN bridge. @@ -2623,6 +2811,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, if (!n) return 0; + zmac = zvni_mac_lookup(zvni, &n->emac); + if (!zmac) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_err( + "%u: trying to del a neigh %s without a mac %s on VNI %u", + ifp->vrf_id, ipaddr2str(ip, buf, sizeof(buf)), + prefix_mac2str(&n->emac, buf2, sizeof(buf2)), + zvni->vni); + + return 0; + } + /* If it is a remote entry, the kernel has aged this out or someone has * deleted it, it needs to be re-installed as Quagga is the owner. */ @@ -2636,11 +2836,18 @@ int zebra_vxlan_local_neigh_del(struct interface *ifp, assert(zvrf); /* Remove neighbor from BGP. */ - zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, 0); + if (IS_ZEBRA_NEIGH_ACTIVE(n)) + zvni_neigh_send_del_to_client(zvrf, zvni->vni, &n->ip, &n->emac, + 0); /* Delete this neighbor entry. */ zvni_neigh_del(zvni, n); + /* see if the AUTO mac needs to be deleted */ + if (CHECK_FLAG(zmac->flags, ZEBRA_MAC_AUTO) + || !listcount(zmac->neigh_list)) + zvni_mac_del(zvni, zmac); + return 0; } @@ -2657,6 +2864,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, zebra_vni_t *zvni; zebra_neigh_t *n; struct zebra_vrf *zvrf; + zebra_mac_t *zmac; char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; int send_upd = 1, send_del = 0; @@ -2681,6 +2889,30 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, ifp->ifindex, state, ext_learned ? "ext-learned " : "", zvni->vni); + /* create a dummy MAC if the MAC is not already present */ + zmac = zvni_mac_lookup(zvni, macaddr); + if (!zmac) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: AUTO MAC %s created for neigh %s on VNI %u", + ifp->vrf_id, + prefix_mac2str(macaddr, buf, sizeof(buf)), + ipaddr2str(ip, buf2, sizeof(buf2)), zvni->vni); + + zmac = zvni_mac_add(zvni, macaddr); + if (!zmac) { + zlog_warn("%u:Failed to add MAC %s VNI %u", + zvrf_id(zvrf), + prefix_mac2str(macaddr, buf, sizeof(buf)), + zvni->vni); + return -1; + } + + memset(&zmac->fwd_info, 0, sizeof(zmac->fwd_info)); + memset(&zmac->flags, 0, sizeof(u_int32_t)); + SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); + } + /* If same entry already exists, it might be a change or it might be a * move from remote to local. */ @@ -2716,7 +2948,7 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, n->r_vtep_ip.s_addr = 0; } } else { - n = zvni_neigh_add(zvni, ip); + n = zvni_neigh_add(zvni, ip, macaddr); if (!n) { zlog_err( "%u:Failed to add neighbor %s MAC %s intf %s(%u) -> VNI %u", @@ -2734,13 +2966,34 @@ int zebra_vxlan_local_neigh_add_update(struct interface *ifp, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); - memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; + /* Before we program this in BGP, we need to check if MAC is locally + * learnt as well */ + if (!CHECK_FLAG(zmac->flags, ZEBRA_MAC_LOCAL)) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: Skipping neigh %s add to client as MAC %s is not local on VNI %u", + ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), + prefix_mac2str(macaddr, buf, sizeof(buf)), + zvni->vni); + + return 0; + } + /* Inform BGP if required. */ - if (send_upd) + if (send_upd) { + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "%u: neigh %s (MAC %s) is now ACTIVE on VNI %u", + ifp->vrf_id, ipaddr2str(ip, buf2, sizeof(buf2)), + prefix_mac2str(macaddr, buf, sizeof(buf)), + zvni->vni); + + ZEBRA_NEIGH_SET_ACTIVE(n); return zvni_neigh_send_add_to_client(zvrf, zvni->vni, ip, macaddr, 0); + } return 0; } @@ -2868,6 +3121,9 @@ int zebra_vxlan_remote_macip_del(struct zserv *client, int sock, u_short length, } } else { if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { + zvni_process_neigh_on_remote_mac_del(zvrf, zvni, + mac); + if (!mac->neigh_refcnt) { zvni_mac_uninstall(zvni, mac, 0); zvni_mac_del(zvni, mac); @@ -3024,6 +3280,8 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, else UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); + zvni_process_neigh_on_remote_mac_add(zvrf, zvni, mac); + /* Install the entry. */ zvni_mac_install(zvni, mac); } @@ -3047,7 +3305,7 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, if (update_neigh) { if (!n) { - n = zvni_neigh_add(zvni, &ip); + n = zvni_neigh_add(zvni, &ip, &macaddr); if (!n) { zlog_warn( "%u:Failed to add Neigh %s MAC %s VNI %u Remote VTEP %s", @@ -3070,12 +3328,12 @@ int zebra_vxlan_remote_macip_add(struct zserv *client, int sock, u_short length, if (old_mac) zvni_deref_ip2mac(zvni, old_mac, 1); mac->neigh_refcnt++; + memcpy(&n->emac, &macaddr, ETH_ALEN); } /* Set "remote" forwarding info. */ UNSET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); /* TODO: Handle MAC change. */ - memcpy(&n->emac, &macaddr, ETH_ALEN); n->r_vtep_ip = vtep_ip; SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); @@ -3143,8 +3401,16 @@ int zebra_vxlan_check_del_local_mac(struct interface *ifp, zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); - /* Delete this MAC entry. */ - zvni_mac_del(zvni, mac); + /* + * If there are no neigh associated with the mac delete the mac + * else mark it as AUTO for forward reference + */ + if (!listcount(mac->neigh_list)) { + zvni_mac_del(zvni, mac); + } else { + UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + } return 0; } @@ -3251,8 +3517,19 @@ int zebra_vxlan_local_mac_del(struct interface *ifp, struct interface *br_if, zvni_mac_send_del_to_client(zvrf, zvni->vni, macaddr, (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); - /* Delete this MAC entry. */ - zvni_mac_del(zvni, mac); + /* Update all the neigh entries associated with this mac */ + zvni_process_neigh_on_local_mac_del(zvrf, zvni, mac); + + /* + * If there are no neigh associated with the mac delete the mac + * else mark it as AUTO for forward reference + */ + if (!listcount(mac->neigh_list)) { + zvni_mac_del(zvni, mac); + } else { + UNSET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + SET_FLAG(mac->flags, ZEBRA_MAC_AUTO); + } return 0; } @@ -3307,6 +3584,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, ? 1 : 0; + /* * return if nothing has changed. * inform bgp if sticky flag has changed @@ -3327,11 +3605,12 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, ifp->name, ifp->ifindex, vid, zvni->vni); return 0; - } else if (mac_sticky != sticky) + } else if (mac_sticky != sticky) { add = 1; - else + } else { add = 0; /* This is an update of local interface. */ + } } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { /* * If we have already learned the MAC as a remote sticky @@ -3367,8 +3646,9 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, /* Set "local" forwarding info. */ UNSET_FLAG(mac->flags, ZEBRA_MAC_REMOTE); - memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); + UNSET_FLAG(mac->flags, ZEBRA_MAC_AUTO); SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); + memset(&mac->fwd_info, 0, sizeof(mac->fwd_info)); mac->fwd_info.local.ifindex = ifp->ifindex; mac->fwd_info.local.vid = vid; @@ -3378,10 +3658,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp, UNSET_FLAG(mac->flags, ZEBRA_MAC_STICKY); /* Inform BGP if required. */ - if (add) - return zvni_mac_send_add_to_client( - zvrf, zvni->vni, macaddr, - (sticky ? ZEBRA_MAC_TYPE_STICKY : 0)); + if (add) { + zvni_process_neigh_on_local_mac_add(zvrf, zvni, mac); + return zvni_mac_send_add_to_client(zvrf, zvni->vni, macaddr, + sticky); + } return 0; } diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 2bf00291e7..8539311eab 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -115,6 +115,9 @@ struct zebra_mac_t_ { } fwd_info; u_int32_t neigh_refcnt; + + /* List of neigh associated with this mac */ + struct list *neigh_list; }; /* @@ -140,6 +143,16 @@ struct mac_walk_ctx { struct json_object *json; /* Used for JSON Output */ }; +enum zebra_neigh_state { ZEBRA_NEIGH_INACTIVE = 0, ZEBRA_NEIGH_ACTIVE = 1 }; + +#define IS_ZEBRA_NEIGH_ACTIVE(n) n->state == ZEBRA_NEIGH_ACTIVE + +#define IS_ZEBRA_NEIGH_INACTIVE(n) n->state == ZEBRA_NEIGH_INACTIVE + +#define ZEBRA_NEIGH_SET_ACTIVE(n) n->state = ZEBRA_NEIGH_ACTIVE + +#define ZEBRA_NEIGH_SET_INACTIVE(n) n->state = ZEBRA_NEIGH_INACTIVE + /* * Neighbor hash table. * @@ -162,8 +175,10 @@ struct zebra_neigh_t_ { ifindex_t ifindex; u_int32_t flags; -#define ZEBRA_NEIGH_LOCAL 0x01 -#define ZEBRA_NEIGH_REMOTE 0x02 +#define ZEBRA_NEIGH_LOCAL 0x01 +#define ZEBRA_NEIGH_REMOTE 0x02 + + enum zebra_neigh_state state; /* Remote VTEP IP - applicable only for remote neighbors. */ struct in_addr r_vtep_ip; From ddd16ed5f274863ca23401f1f7bf628feb610b11 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Thu, 6 Jul 2017 16:33:50 -0700 Subject: [PATCH 17/32] bgpd/zebra: honor tunnel ip change in bgp regardless of vni readiness Ticket: CM-17014 Review: CCR-6432 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 14 ++++++++++++-- bgpd/bgp_evpn_vty.c | 2 ++ zebra/zebra_vxlan.c | 8 ++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ab3307a6a7..110ff3a17b 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1193,6 +1193,12 @@ static int handle_tunnel_ip_change(struct bgp *bgp, struct bgpevpn *vpn, { struct prefix_evpn p; + /* If VNI is not live, we only need to update the originator ip */ + if (!is_vni_live(vpn)) { + vpn->originator_ip = originator_ip; + return 0; + } + /* Need to withdraw type-3 route as the originator IP is part * of the key. */ @@ -2678,14 +2684,14 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, /* Lookup VNI. If present and no change, exit. */ vpn = bgp_evpn_lookup_vni(bgp, vni); - if (vpn && is_vni_live(vpn)) { + if (vpn) { if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) /* Probably some other param has changed that we don't * care about. */ return 0; /* Local tunnel endpoint IP address has changed */ - return handle_tunnel_ip_change(bgp, vpn, originator_ip); + handle_tunnel_ip_change(bgp, vpn, originator_ip); } /* Create or update as appropriate. */ @@ -2699,6 +2705,10 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, } } + /* if the VNI is live already, there is nothibng more to do */ + if (is_vni_live(vpn)) + return 0; + /* Mark as "live" */ SET_FLAG(vpn->flags, VNI_FLAG_LIVE); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index a6f5e168c9..8a583a74d8 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -195,6 +195,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn) vty_out(vty, " RD: %s\n", prefix_rd2str(&vpn->prd, buf1, RD_ADDRSTRLEN)); vty_out(vty, " Originator IP: %s\n", inet_ntoa(vpn->originator_ip)); + vty_out(vty, " Advertise-gw-macip : %s\n", + vpn->advertise_gw_macip ? "Yes" : "No"); vty_out(vty, " Import Route Target:\n"); for (ALL_LIST_ELEMENTS(vpn->import_rtl, node, nnode, ecom)) { diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 393ac997b3..52886bd7f0 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -607,6 +607,8 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) json_object_int_add(json, "ifindex", zvni->vxlan_if->ifindex); json_object_string_add(json, "vtepIp", inet_ntoa(zvni->local_vtep_ip)); + json_object_string_add(json, "advertiseGatewayMacip", + zvni->advertise_gw_macip ? "Yes" : "No"); json_object_int_add(json, "numMacs", num_macs); json_object_int_add(json, "numArpNd", num_neigh); } @@ -641,6 +643,8 @@ static void zvni_print(zebra_vni_t *zvni, void **ctxt) " Number of ARPs (IPv4 and IPv6, local and remote) " "known for this VNI: %u\n", num_neigh); + vty_out(vty, " Advertise-gw-macip: %s\n", + zvni->advertise_gw_macip ? "Yes" : "No"); } } @@ -2751,8 +2755,12 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, } if (use_json) { json = json_object_new_object(); + json_object_string_add(json, "advertiseGatewayMacip", + zvrf->advertise_gw_macip ? "Yes" : "No"); json_object_int_add(json, "numVnis", num_vnis); } else { + vty_out(vty, "Advertise gateway mac-ip: %s\n", + zvrf->advertise_gw_macip ? "Yes" : "No"); vty_out(vty, "Number of VNIs: %u\n", num_vnis); vty_out(vty, "%-10s %-21s %-15s %-8s %-8s %-15s\n", "VNI", "VxLAN IF", "VTEP IP", "# MACs", "# ARPs", From 8a893163781c618620c25372638d7c80eb80595b Mon Sep 17 00:00:00 2001 From: Daniel Walton Date: Thu, 6 Jul 2017 23:47:15 +0000 Subject: [PATCH 18/32] bgpd: show bgp ipv4 label-unicast does not provide any output Signed-off-by: Daniel Walton Reviewed-by: Donald Sharp Ticket: CM-16957 --- bgpd/bgp_route.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index ac820fb34f..44e5af578d 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -10240,6 +10240,10 @@ static int bgp_show_neighbor_route(struct vty *vty, struct peer *peer, afi_t afi, safi_t safi, enum bgp_show_type type, u_char use_json) { + /* labeled-unicast routes live in the unicast table */ + if (safi == SAFI_LABELED_UNICAST) + safi = SAFI_UNICAST; + if (!peer || !peer->afc[afi][safi]) { if (use_json) { json_object *json_no = NULL; From 4192df64c9185b48d60deefac81927a25fb688a9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 7 Jul 2017 09:08:25 -0400 Subject: [PATCH 19/32] bgpd: Fix output of interface based 'show bgp ..' commands When issuing a 'show ip bgp' command and the nexthop is a interface, if the interface name was greater than 7 characters we would arbitrarily start a new-line and setup the next line to start at the wrong spot. Modify the interface field to allow 16 characters than 7( to match v6 display ), and if the interface name is greater than 16 characters properly setup the next line for display Signed-off-by: Donald Sharp --- bgpd/bgp_route.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 44e5af578d..bce54ab2d0 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6513,15 +6513,14 @@ void route_vty_out(struct vty *vty, struct prefix *p, struct bgp_info *binfo, len = vty_out( vty, "%s", binfo->peer->conf_if); - len = - 7 - len; /* len of IPv6 - addr + max - len of def - ifname */ + len = 16 - len; /* len of IPv6 + addr + max + len of def + ifname */ if (len < 1) vty_out(vty, "\n%*s", - 45, " "); + 36, " "); else vty_out(vty, "%*s", len, " "); From bd7d02999f1d1c2a4aaa484c24738d31f80aab82 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 7 Jul 2017 09:45:15 -0400 Subject: [PATCH 20/32] zebra: Guard debugs in interface speed check Not being able to get the interface speed is a common occurrence for some interface types. Convert this these outputs to a guarded debug. Signed-off-by: Donald Sharp --- zebra/if_netlink.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8064071c37..0d08155178 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -403,16 +403,19 @@ static int get_iflink_speed(const char *ifname) /* use ioctl to get IP address of an interface */ sd = socket(PF_INET, SOCK_DGRAM, IPPROTO_IP); if (sd < 0) { - zlog_debug("Failure to read interface %s speed: %d %s", ifname, - errno, safe_strerror(errno)); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("Failure to read interface %s speed: %d %s", + ifname, errno, safe_strerror(errno)); return 0; } /* Get the current link state for the interface */ rc = ioctl(sd, SIOCETHTOOL, (char *)&ifdata); if (rc < 0) { - zlog_debug("IOCTL failure to read interface %s speed: %d %s", - ifname, errno, safe_strerror(errno)); + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug( + "IOCTL failure to read interface %s speed: %d %s", + ifname, errno, safe_strerror(errno)); ecmd.speed_hi = 0; ecmd.speed = 0; } From 2f1ac16a7e683970a9025ad29572f54137e31d3e Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 12 Jul 2017 13:44:02 -0700 Subject: [PATCH 21/32] bgpd: BGP should not ignore the VNI add notification if it is not live currently Ticket: CM-17053 Review: CCR-6446 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_evpn.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 110ff3a17b..ff861a7324 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2685,7 +2685,8 @@ int bgp_evpn_local_vni_add(struct bgp *bgp, vni_t vni, /* Lookup VNI. If present and no change, exit. */ vpn = bgp_evpn_lookup_vni(bgp, vni); if (vpn) { - if (IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) + if (is_vni_live(vpn) + && IPV4_ADDR_SAME(&vpn->originator_ip, &originator_ip)) /* Probably some other param has changed that we don't * care about. */ return 0; From 297a21b66b885710f752a2fd42d2fa66db854259 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 12 Jul 2017 14:09:36 -0700 Subject: [PATCH 22/32] zebra: zebra should not try and advertise gateway macip if EVPN is disabled Ticket: CM-17050 Review: CCR-6447 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- zebra/zebra_vxlan.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 52886bd7f0..f99c16ae91 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -3820,6 +3820,13 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, memset(&ip, 0, sizeof(struct ipaddr)); memset(&macaddr, 0, sizeof(struct ethaddr)); + zvrf = vrf_info_lookup(ifp->vrf_id); + if (!zvrf) + return -1; + + if (!EVPN_ENABLED(zvrf)) + return 0; + if (IS_ZEBRA_IF_MACVLAN(ifp)) { struct interface *svi_if = NULL; /* SVI corresponding to the MACVLAN */ @@ -3866,9 +3873,6 @@ int zebra_vxlan_add_del_gw_macip(struct interface *ifp, struct prefix *p, return -1; } - zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id); - if (!zvrf) - return -1; /* check if we are advertising gw macip routes */ if (!advertise_gw_macip_enabled(zvrf, zvni)) From 69b61704b8c125b34d3b8efe8fb6d1477c895eef Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 12 Jul 2017 14:27:24 -0700 Subject: [PATCH 23/32] lib: changes needed for mac access-list any command Ticket: CM-17074 Review: CCR-6453 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- lib/filter.c | 16 ++++++++++++---- lib/prefix.c | 12 ++++++++++++ lib/prefix.h | 1 + 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/filter.c b/lib/filter.c index 186b32bbba..c01ee4ee10 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -169,6 +169,10 @@ static int mac_filter_match(struct prefix *n, struct ethaddr *p) if (!n || !p) return 0; + /* check if we are matching on any mac */ + if (is_zero_mac(&(n->u.prefix_eth))) + return 1; + if (memcmp(&(n->u.prefix), p, sizeof(struct ethaddr)) == 0) return 1; @@ -1398,7 +1402,7 @@ DEFUN (no_mac_access_list_any, "Specify packets to forward\n" "MAC address to match. e.g. 00:01:00:01:00:01\n") { - return filter_set_zebra(vty, argv[2]->arg, argv[3]->arg, AFI_L2VPN, + return filter_set_zebra(vty, argv[3]->arg, argv[4]->arg, AFI_L2VPN, "00:00:00:00:00:00", 0, 0); } @@ -1994,9 +1998,13 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter) vty_out(vty, " %s/%d%s", inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, filter->exact ? " exact-match" : ""); - else - vty_out(vty, " %s", - prefix_mac2str(&(p->u.prefix_eth), buf, sizeof(buf))); + else if (p->family == AF_ETHERNET) { + if (is_zero_mac(&(p->u.prefix_eth))) + vty_out(vty, " any"); + else + vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth), + buf, sizeof(buf))); + } vty_out(vty, "\n"); } diff --git a/lib/prefix.c b/lib/prefix.c index e67184f52b..edfc22fb42 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -301,6 +301,18 @@ static const struct in6_addr maskbytes6[] = { #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) +int is_zero_mac(struct ethaddr *mac) +{ + int i = 0; + + for (i = 0; i < ETH_ALEN; i++) { + if (mac->octet[i]) + return 0; + } + + return 1; +} + unsigned int prefix_bit(const u_char *prefix, const u_char prefixlen) { unsigned int offset = prefixlen / 8; diff --git a/lib/prefix.h b/lib/prefix.h index 0f3ad562d9..f665f55dfd 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -265,6 +265,7 @@ union prefixconstptr { #endif /*s6_addr32*/ /* Prototypes. */ +extern int is_zero_mac(struct ethaddr *mac); extern int str2family(const char *); extern int afi2family(afi_t); extern afi_t family2afi(int); From 646050e57af95df01ee0aea7fad2cc10230e41e1 Mon Sep 17 00:00:00 2001 From: Mitesh Kanjariya Date: Wed, 12 Jul 2017 14:55:22 -0700 Subject: [PATCH 24/32] bgp: fix match mac address/match evpn vni commands Ticket: CM-17071 Review: CCR-6454 Unit-test: Manual Signed-off-by: Mitesh Kanjariya --- bgpd/bgp_routemap.c | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index bde0363ae7..69b798a01c 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -667,7 +667,8 @@ static void route_match_vni_free(void *rule) /* Route map commands for vni matching. */ struct route_map_rule_cmd route_match_evpn_vni_cmd = { - "vni", route_match_vni, route_match_vni_compile, route_match_vni_free}; + "evpn vni", route_match_vni, route_match_vni_compile, + route_match_vni_free}; /* `match local-preference LOCAL-PREF' */ @@ -3105,16 +3106,13 @@ DEFUN (match_mac_address, DEFUN (no_match_mac_address, no_match_mac_address_cmd, - "no match mac address", + "no match mac address WORD", NO_STR MATCH_STR "mac\n" - "Match address of route\n") + "Match address of route\n" + "MAC acess-list name\n") { - if (argc == 0) - return bgp_route_match_delete(vty, "mac address", NULL, - RMAP_EVENT_FILTER_DELETED); - return bgp_route_match_delete(vty, "mac address", argv[4]->arg, RMAP_EVENT_FILTER_DELETED); } @@ -3127,7 +3125,7 @@ DEFUN (match_evpn_vni, "Match VNI\n" "VNI ID\n") { - return bgp_route_match_add(vty, "evpn vni", argv[2]->arg, + return bgp_route_match_add(vty, "evpn vni", argv[3]->arg, RMAP_EVENT_MATCH_ADDED); } @@ -3140,7 +3138,7 @@ DEFUN (no_match_evpn_vni, "Match VNI\n" "VNI ID\n") { - return bgp_route_match_delete(vty, "evpn vni", argv[3]->arg, + return bgp_route_match_delete(vty, "evpn vni", argv[4]->arg, RMAP_EVENT_MATCH_DELETED); } From 1667fc4097c9d9fbc4f2d01d920da7fa10e59cf9 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Sat, 15 Jul 2017 14:15:13 -0400 Subject: [PATCH 25/32] lib: Fix extra doc string Signed-off-by: Donald Sharp --- lib/filter.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/filter.c b/lib/filter.c index c01ee4ee10..3eb874728d 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -1888,10 +1888,9 @@ DEFUN (show_mac_access_list_name, show_mac_access_list_name_cmd, "show mac access-list WORD", SHOW_STR - "mac\n" + "mac access lists\n" "List mac access lists\n" - "mac zebra access-list\n" - "mac address") + "mac address\n") { return filter_show(vty, argv[3]->arg, AFI_L2VPN); } From bd592158eff8742929b37b9c068d43d3bf30d3c5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 25 Jul 2017 08:17:31 -0400 Subject: [PATCH 26/32] zebra: Use JSON_STR Signed-off-by: Donald Sharp --- zebra/zebra_vty.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 61fe171cff..780a71b7c7 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -2304,7 +2304,7 @@ DEFUN (show_evpn_vni, SHOW_STR "EVPN\n" "VxLAN information\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; u_char uj = use_json(argc, argv); @@ -2321,7 +2321,7 @@ DEFUN (show_evpn_vni_vni, "EVPN\n" "VxLAN Network Identifier\n" "VNI number\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; @@ -2341,7 +2341,7 @@ DEFUN (show_evpn_mac_vni, "MAC addresses\n" "VxLAN Network Identifier\n" "VNI number\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; @@ -2361,7 +2361,7 @@ DEFUN (show_evpn_mac_vni_all, "MAC addresses\n" "VxLAN Network Identifier\n" "All VNIs\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; u_char uj = use_json(argc, argv); @@ -2381,7 +2381,7 @@ DEFUN (show_evpn_mac_vni_all_vtep, "All VNIs\n" "Remote VTEP\n" "Remote VTEP IP address\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; struct in_addr vtep_ip; @@ -2434,7 +2434,7 @@ DEFUN (show_evpn_mac_vni_vtep, "VNI number\n" "Remote VTEP\n" "Remote VTEP IP address\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; @@ -2461,7 +2461,7 @@ DEFUN (show_evpn_neigh_vni, "ARP and ND cache\n" "VxLAN Network Identifier\n" "VNI number\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; @@ -2481,7 +2481,7 @@ DEFUN (show_evpn_neigh_vni_all, "ARP and ND cache\n" "VxLAN Network Identifier\n" "All VNIs\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; u_char uj = use_json(argc, argv); @@ -2501,7 +2501,7 @@ DEFUN (show_evpn_neigh_vni_neigh, "VNI number\n" "Neighbor\n" "Neighbor address (IPv4 or IPv6 address)\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; @@ -2529,7 +2529,7 @@ DEFUN (show_evpn_neigh_vni_vtep, "VNI number\n" "Remote VTEP\n" "Remote VTEP IP address\n" - "JavaScript Object Notation\n") + JSON_STR) { struct zebra_vrf *zvrf; vni_t vni; From 6d53d24c86db4a80bf25295ac3bb5b05dbb4f3d5 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 25 Jul 2017 08:17:55 -0400 Subject: [PATCH 27/32] ldpd: Use JSON_STR Signed-off-by: Donald Sharp --- ldpd/ldp_vty_cmds.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index 3f39ad926c..db92b93628 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -21,6 +21,8 @@ #include "command.h" #include "vty.h" +#include "json.h" + #include "ldpd/ldpd.h" #include "ldpd/ldp_vty.h" #include "ldpd/ldp_vty_cmds_clippy.c" @@ -586,7 +588,7 @@ DEFPY (ldp_show_mpls_ldp_binding, "IPv6 Address Family\n" "Label Information Base (LIB) information\n" "Show detailed information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_binding(vty, af, detail, json)); } @@ -601,7 +603,7 @@ DEFPY (ldp_show_mpls_ldp_discovery, "IPv6 Address Family\n" "Discovery Hello Information\n" "Show detailed information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_discovery(vty, af, detail, json)); } @@ -615,7 +617,7 @@ DEFPY (ldp_show_mpls_ldp_interface, "IPv4 Address Family\n" "IPv6 Address Family\n" "interface information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_interface(vty, af, json)); } @@ -627,7 +629,7 @@ DEFPY (ldp_show_mpls_ldp_capabilities, "MPLS information\n" "Label Distribution Protocol\n" "Display LDP Capabilities information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_capabilities(vty, json)); } @@ -640,7 +642,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor, "Label Distribution Protocol\n" "Neighbor information\n" "Show detailed information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_neighbor(vty, 0, detail, json)); } @@ -653,7 +655,7 @@ DEFPY (ldp_show_mpls_ldp_neighbor_capabilities, "Label Distribution Protocol\n" "Neighbor information\n" "Display neighbor capability information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_neighbor(vty, 1, NULL, json)); } @@ -665,7 +667,7 @@ DEFPY (ldp_show_l2vpn_atom_binding, "Show information about Layer2 VPN\n" "Show Any Transport over MPLS information\n" "Show AToM label binding information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_atom_binding(vty, json)); } @@ -677,7 +679,7 @@ DEFPY (ldp_show_l2vpn_atom_vc, "Show information about Layer2 VPN\n" "Show Any Transport over MPLS information\n" "Show AToM virtual circuit information\n" - "JavaScript Object Notation\n") + JSON_STR) { return (ldp_vty_show_atom_vc(vty, json)); } From a85b24cc7f014466a78f2d4992efb0c379454f4a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 25 Jul 2017 08:18:20 -0400 Subject: [PATCH 28/32] bgpd: Use JSON_STR Signed-off-by: Donald Sharp --- bgpd/bgp_evpn_vty.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 8a583a74d8..948c7f50f2 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1912,7 +1912,7 @@ DEFUN (show_bgp_l2vpn_evpn_summary, L2VPN_HELP_STR EVPN_HELP_STR "Summary of BGP neighbor status\n" - "JavaScript Object Notation\n") + JSON_STR) { u_char uj = use_json(argc, argv); return bgp_show_summary_vty(vty, NULL, AFI_L2VPN, SAFI_EVPN, uj); @@ -2277,7 +2277,7 @@ ALIAS_HIDDEN(show_bgp_l2vpn_evpn_vni, show_bgp_evpn_vni_cmd, ALIAS_HIDDEN(show_bgp_l2vpn_evpn_summary, show_bgp_evpn_summary_cmd, "show bgp evpn summary [json]", SHOW_STR BGP_STR EVPN_HELP_STR "Summary of BGP neighbor status\n" - "JavaScript Object Notation\n") + JSON_STR) ALIAS_HIDDEN(show_bgp_l2vpn_evpn_route, show_bgp_evpn_route_cmd, "show bgp evpn route [type ]", From b34fd35d3ad5089ef2aecff06879d2f3ca471947 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Thu, 27 Jul 2017 12:31:54 -0400 Subject: [PATCH 29/32] lib, bgpd: Address Review comments. Signed-off-by: Donald Sharp --- bgpd/bgp_evpn.c | 6 ++---- lib/filter.c | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index ff861a7324..67484efe12 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -2620,11 +2620,9 @@ int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac, char buf2[INET6_ADDRSTRLEN]; zlog_err( - "%u:Failed to create Type-2 route, VNI %u %s %s MAC %s IP %s", + "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s", bgp->vrf_id, vpn->vni, - CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky " - : "", - CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "gateway " + CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? "sticky gateway" : "", prefix_mac2str(mac, buf, sizeof(buf)), ipaddr2str(ip, buf2, sizeof(buf2))); diff --git a/lib/filter.c b/lib/filter.c index 3eb874728d..fa52fed1c6 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -90,7 +90,7 @@ struct access_master { void (*delete_hook)(struct access_list *); }; -/* Static structure for IPv4 access_list's master. */ +/* Static structure for mac access_list's master. */ static struct access_master access_master_mac = { {NULL, NULL}, {NULL, NULL}, From b03b88986e529eeb0cd7de1ce9a07d8d2a83b6d3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Tue, 8 Aug 2017 10:16:12 -0400 Subject: [PATCH 30/32] lib, bgpd: Distinguish between AF_EVPN and AF_ETHERNET Create AF_EVPN for internal use and start using it. Signed-off-by: Vivek Venkatraman --- bgpd/bgp_attr_evpn.c | 2 +- bgpd/bgp_evpn.c | 10 +++++----- bgpd/bgp_evpn_private.h | 4 ++-- bgpd/bgp_route.c | 10 +++++++--- lib/prefix.c | 35 ++++++++++++++++++++++++++--------- lib/prefix.h | 15 +++++++++++++-- 6 files changed, 54 insertions(+), 22 deletions(-) diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 2f0b566ccf..6ead059261 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -169,7 +169,7 @@ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, prefix_copy(src, dst); memset(dst, 0, sizeof(struct prefix)); p_evpn_p = &(dst->u.prefix_evpn); - dst->family = AF_ETHERNET; + dst->family = AF_EVPN; p_evpn_p->route_type = evpn_type; if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { p_evpn_p->eth_tag = eth_tag; diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index 67484efe12..0560dc46f9 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1807,7 +1807,7 @@ static int process_type2_route(struct peer *peer, afi_t afi, safi_t safi, /* Make EVPN prefix. */ memset(&p, 0, sizeof(struct prefix_evpn)); - p.family = AF_ETHERNET; + p.family = AF_EVPN; p.prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p.prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; @@ -1896,7 +1896,7 @@ static int process_type3_route(struct peer *peer, afi_t afi, safi_t safi, /* Make EVPN prefix. */ memset(&p, 0, sizeof(struct prefix_evpn)); - p.family = AF_ETHERNET; + p.family = AF_EVPN; p.prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; p.prefix.route_type = BGP_EVPN_IMET_ROUTE; @@ -1961,7 +1961,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi, /* Make EVPN prefix. */ memset(&p, 0, sizeof(struct prefix_evpn)); - p.family = AF_ETHERNET; + p.family = AF_EVPN; p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE; /* Additional information outside of prefix - ESI and GW IP */ @@ -2030,7 +2030,7 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p, struct evpn_addr *p_evpn_p; memset(&temp, 0, 16); - if (p->family != AF_ETHERNET) + if (p->family != AF_EVPN) return; p_evpn_p = &(p->u.prefix_evpn); @@ -2213,7 +2213,7 @@ char *bgp_evpn_route2str(struct prefix_evpn *p, char *buf, int len) PREFIX2STR_BUFFER)); } } else { - /* Currently, this is to cater to other AF_ETHERNET code. */ + /* For EVPN route types not supported yet. */ } return (buf); diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index e6f6301405..9dc459cd4e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -174,7 +174,7 @@ static inline void build_evpn_type2_prefix(struct prefix_evpn *p, struct ipaddr *ip) { memset(p, 0, sizeof(struct prefix_evpn)); - p->family = AF_ETHERNET; + p->family = AF_EVPN; p->prefixlen = EVPN_TYPE_2_ROUTE_PREFIXLEN; p->prefix.route_type = BGP_EVPN_MAC_IP_ROUTE; memcpy(&p->prefix.mac.octet, mac->octet, ETH_ALEN); @@ -187,7 +187,7 @@ static inline void build_evpn_type3_prefix(struct prefix_evpn *p, struct in_addr originator_ip) { memset(p, 0, sizeof(struct prefix_evpn)); - p->family = AF_ETHERNET; + p->family = AF_EVPN; p->prefixlen = EVPN_TYPE_3_ROUTE_PREFIXLEN; p->prefix.route_type = BGP_EVPN_IMET_ROUTE; p->prefix.ip.ipa_type = IPADDR_V4; diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index bce54ab2d0..35f793f861 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -6246,6 +6246,9 @@ static void route_vty_out_route(struct prefix *p, struct vty *vty) } else len += vty_out(vty, "/%d", p->prefixlen); } else if (p->family == AF_ETHERNET) { + prefix2str(p, buf, PREFIX_STRLEN); + len = vty_out(vty, "%s", buf); + } else if (p->family == AF_EVPN) { #if defined(HAVE_CUMULUS) len = vty_out(vty, "%s", bgp_evpn_route2str((struct prefix_evpn *)p, buf, @@ -6808,7 +6811,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, if (attr) { if (((p->family == AF_INET) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) - || (safi == SAFI_EVPN && p->family == AF_ETHERNET + || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP @@ -6833,7 +6836,7 @@ void route_vty_out_tag(struct vty *vty, struct prefix *p, } } else if (((p->family == AF_INET6) && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) - || (safi == SAFI_EVPN && p->family == AF_ETHERNET + || (safi == SAFI_EVPN && BGP_ATTR_NEXTHOP_AFI_IP6(attr)) || (BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { char buf_a[BUFSIZ]; @@ -7333,7 +7336,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct prefix *p, /* Line2 display Next-hop, Neighbor, Router-id */ /* Display the nexthop */ - if ((p->family == AF_INET || p->family == AF_ETHERNET) + if ((p->family == AF_INET || p->family == AF_ETHERNET || + p->family == AF_EVPN) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { diff --git a/lib/prefix.c b/lib/prefix.c index edfc22fb42..df638b0fc8 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -334,6 +334,8 @@ int str2family(const char *string) return AF_INET6; else if (!strcmp("ethernet", string)) return AF_ETHERNET; + else if (!strcmp("evpn", string)) + return AF_EVPN; return -1; } @@ -346,6 +348,7 @@ int afi2family(afi_t afi) return AF_INET6; else if (afi == AFI_L2VPN) return AF_ETHERNET; + /* NOTE: EVPN code should NOT use this interface. */ return 0; } @@ -355,7 +358,7 @@ afi_t family2afi(int family) return AFI_IP; else if (family == AF_INET6) return AFI_IP6; - else if (family == AF_ETHERNET) + else if (family == AF_ETHERNET || family == AF_EVPN) return AFI_L2VPN; return 0; } @@ -461,6 +464,9 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) else if (src->family == AF_INET6) dest->u.prefix6 = src->u.prefix6; else if (src->family == AF_ETHERNET) { + memcpy(&dest->u.prefix_eth, &src->u.prefix_eth, + sizeof(struct ethaddr)); + } else if (src->family == AF_EVPN) { memcpy(&dest->u.prefix_evpn, &src->u.prefix_evpn, sizeof(struct evpn_addr)); } else if (src->family == AF_UNSPEC) { @@ -517,6 +523,10 @@ int prefix_same(const struct prefix *p1, const struct prefix *p2) &p2->u.prefix6.s6_addr)) return 1; if (p1->family == AF_ETHERNET) + if (!memcmp(&p1->u.prefix_eth, &p2->u.prefix_eth, + sizeof(struct ethaddr))) + return 1; + if (p1->family == AF_EVPN) if (!memcmp(&p1->u.prefix_evpn, &p2->u.prefix_evpn, sizeof(struct evpn_addr))) return 1; @@ -581,6 +591,8 @@ int prefix_common_bits(const struct prefix *p1, const struct prefix *p2) if (p1->family == AF_INET6) length = IPV6_MAX_BYTELEN; if (p1->family == AF_ETHERNET) + length = ETH_ALEN; + if (p1->family == AF_EVPN) length = 8 * sizeof(struct evpn_addr); if (p1->family != p2->family || !length) @@ -609,6 +621,8 @@ const char *prefix_family_str(const struct prefix *p) return "inet6"; if (p->family == AF_ETHERNET) return "ether"; + if (p->family == AF_EVPN) + return "evpn"; return "unspec"; } @@ -965,6 +979,7 @@ int prefix_blen(const struct prefix *p) break; case AF_ETHERNET: return ETH_ALEN; + break; } return 0; } @@ -992,7 +1007,7 @@ int str2prefix(const char *str, struct prefix *p) return 0; } -static const char *prefixeth2str(const struct prefix *p, char *str, int size) +static const char *prefixevpn2str(const struct prefix *p, char *str, int size) { u_char family; char buf[PREFIX2STR_BUFFER]; @@ -1036,12 +1051,8 @@ static const char *prefixeth2str(const struct prefix *p, char *str, int size) PREFIX2STR_BUFFER), p->prefixlen); } else { - sprintf(str, "UNK AF_ETHER prefix"); - snprintf(str, size, "%02x:%02x:%02x:%02x:%02x:%02x/%d", - p->u.prefix_eth.octet[0], p->u.prefix_eth.octet[1], - p->u.prefix_eth.octet[2], p->u.prefix_eth.octet[3], - p->u.prefix_eth.octet[4], p->u.prefix_eth.octet[5], - p->prefixlen); + sprintf(str, "Unsupported EVPN route type %d", + p->u.prefix_evpn.route_type); } return str; @@ -1061,7 +1072,13 @@ const char *prefix2str(union prefixconstptr pu, char *str, int size) break; case AF_ETHERNET: - prefixeth2str(p, str, size); + snprintf(str, size, "%s/%d", + prefix_mac2str(&p->u.prefix_eth, buf, sizeof(buf)), + p->prefixlen); + break; + + case AF_EVPN: + prefixevpn2str(p, str, size); break; default: diff --git a/lib/prefix.h b/lib/prefix.h index f665f55dfd..3ebf615468 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -116,7 +116,18 @@ struct evpn_addr { #endif #endif -/* IPv4 and IPv6 unified prefix structure. */ +/* The 'family' in the prefix structure is internal to FRR and need not + * map to standard OS AF_ definitions except where needed for interacting + * with the kernel. However, AF_ definitions are currently in use and + * prevalent across the code. Define a new FRR-specific AF for EVPN to + * distinguish between 'ethernet' (MAC-only) and 'evpn' prefixes and + * ensure it does not conflict with any OS AF_ definition. + */ +#if !defined(AF_EVPN) +#define AF_EVPN (AF_MAX + 1) +#endif + +/* FRR generic prefix structure. */ struct prefix { u_char family; u_char prefixlen; @@ -131,7 +142,7 @@ struct prefix { struct ethaddr prefix_eth; /* AF_ETHERNET */ u_char val[8]; uintptr_t ptr; - struct evpn_addr prefix_evpn; + struct evpn_addr prefix_evpn; /* AF_EVPN */ } u __attribute__((aligned(8))); }; From 0f6476ccc3dcd8d7bb3e254ef9e919f5163475fe Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 4 Aug 2017 15:55:44 -0400 Subject: [PATCH 31/32] lib, bgpd: Use 'struct prefix *' for filter matching There is no need for special casing of mac addresses, since the mac address is it's own type integrated into `struct prefix` now. Signed-off-by: Donald Sharp --- bgpd/bgp_routemap.c | 7 ++++++- lib/filter.c | 50 ++++++--------------------------------------- lib/prefix.c | 31 +++++++++++----------------- lib/prefix.h | 3 +-- 4 files changed, 25 insertions(+), 66 deletions(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 69b798a01c..a8e111d361 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -585,6 +585,7 @@ static route_map_result_t route_match_mac_address(void *rule, void *object) { struct access_list *alist; + struct prefix p; if (type == RMAP_BGP) { alist = access_list_lookup(AFI_L2VPN, (char *)rule); @@ -594,7 +595,11 @@ static route_map_result_t route_match_mac_address(void *rule, if (prefix->u.prefix_evpn.route_type != BGP_EVPN_MAC_IP_ROUTE) return RMAP_NOMATCH; - return (access_list_apply(alist, &(prefix->u.prefix_evpn.mac)) + p.family = AF_ETHERNET; + p.prefixlen = ETH_ALEN * 8; + p.u.prefix_eth = prefix->u.prefix_evpn.mac; + + return (access_list_apply(alist, &p) == FILTER_DENY ? RMAP_NOMATCH : RMAP_MATCH); diff --git a/lib/filter.c b/lib/filter.c index fa52fed1c6..9b983d26f2 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -156,29 +156,6 @@ static const char *filter_type_str(struct filter *filter) } } -/* - * mac filter match - * n is of type struct prefix_eth - * p can be of type struct ethaddr - */ -static int mac_filter_match(struct prefix *n, struct ethaddr *p) -{ - if (!n && !p) - return 1; - - if (!n || !p) - return 0; - - /* check if we are matching on any mac */ - if (is_zero_mac(&(n->u.prefix_eth))) - return 1; - - if (memcmp(&(n->u.prefix), p, sizeof(struct ethaddr)) == 0) - return 1; - - return 0; -} - /* If filter match to the prefix then return 1. */ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) { @@ -204,24 +181,19 @@ static int filter_match_cisco(struct filter *mfilter, struct prefix *p) } /* If filter match to the prefix then return 1. */ -static int filter_match_zebra(struct filter *mfilter, void *obj) +static int filter_match_zebra(struct filter *mfilter, struct prefix *p) { struct filter_zebra *filter = NULL; filter = &mfilter->u.zfilter; if (filter->prefix.family == AF_ETHERNET) { - struct ethaddr *p = NULL; - - p = (struct ethaddr *)obj; - return mac_filter_match(&filter->prefix, p); + return prefix_match(&filter->prefix, p); } if (filter->prefix.family == AF_INET || filter->prefix.family == AF_INET6) { - struct prefix *p = NULL; - p = (struct prefix *)obj; if (filter->prefix.family == p->family) { if (filter->exact) { if (filter->prefix.prefixlen == p->prefixlen) @@ -413,9 +385,7 @@ static struct access_list *access_list_get(afi_t afi, const char *name) enum filter_type access_list_apply(struct access_list *access, void *object) { struct filter *filter; - struct prefix *p; - - p = (struct prefix *)object; + struct prefix *p = (struct prefix *)object; if (access == NULL) return FILTER_DENY; @@ -425,7 +395,7 @@ enum filter_type access_list_apply(struct access_list *access, void *object) if (filter_match_cisco(filter, p)) return filter->type; } else { - if (filter_match_zebra(filter, object)) + if (filter_match_zebra(filter, p)) return filter->type; } } @@ -566,16 +536,8 @@ static struct filter *filter_lookup_zebra(struct access_list *access, if (filter->exact == new->exact && mfilter->type == mnew->type) { - if (new->prefix.family == AF_ETHERNET) { - if (prefix_eth_same( - (struct prefix_eth *)&filter - ->prefix, - (struct prefix_eth *)&new->prefix)) - return mfilter; - } else { - if (prefix_same(&filter->prefix, &new->prefix)) - return mfilter; - } + if (prefix_same(&filter->prefix, &new->prefix)) + return mfilter; } } return NULL; diff --git a/lib/prefix.c b/lib/prefix.c index df638b0fc8..d12999067c 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -301,7 +301,7 @@ static const struct in6_addr maskbytes6[] = { #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) -int is_zero_mac(struct ethaddr *mac) +int is_zero_mac(const struct ethaddr *mac) { int i = 0; @@ -479,24 +479,6 @@ void prefix_copy(struct prefix *dest, const struct prefix *src) } } -/* check if the two prefix_eth struct are same*/ -int prefix_eth_same(struct prefix_eth *p1, struct prefix_eth *p2) -{ - if (!p1 && !p2) - return 1; - - if (p1 && !p2) - return 0; - - if (!p1 && p2) - return 0; - - if (memcmp(p1, p2, sizeof(struct prefix_eth)) == 0) - return 1; - - return 0; -} - /* * Return 1 if the address/netmask contained in the prefix structure * is the same, and else return 0. For this routine, 'same' requires @@ -699,6 +681,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) const char *str_addr = str; unsigned int a[6]; int i; + bool slash = false; /* Find slash inside string. */ pnt = strchr(str, '/'); @@ -716,6 +699,7 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) *(cp + (pnt - str)) = '\0'; str_addr = cp; + slash = true; } /* Convert string to prefix. */ @@ -730,6 +714,15 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) } p->prefixlen = plen; p->family = AF_ETHERNET; + + /* + * special case to allow old configurations to work + * Since all zero's is implicitly meant to allow + * a comparison to zero, let's assume + */ + if (!slash && is_zero_mac(&(p->eth_addr))) + p->prefixlen = 0; + ret = 1; done: diff --git a/lib/prefix.h b/lib/prefix.h index 3ebf615468..ddd01af766 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -276,7 +276,7 @@ union prefixconstptr { #endif /*s6_addr32*/ /* Prototypes. */ -extern int is_zero_mac(struct ethaddr *mac); +extern int is_zero_mac(const struct ethaddr *mac); extern int str2family(const char *); extern int afi2family(afi_t); extern afi_t family2afi(int); @@ -305,7 +305,6 @@ extern int prefix_cmp(const struct prefix *, const struct prefix *); extern int prefix_common_bits(const struct prefix *, const struct prefix *); extern void prefix_copy(struct prefix *dest, const struct prefix *src); extern void apply_mask(struct prefix *); -extern int prefix_eth_same(struct prefix_eth *p1, struct prefix_eth *p2); extern struct prefix *sockunion2prefix(const union sockunion *dest, const union sockunion *mask); From 3b0f6068a83da9aeb46e42c430afc7b9c8e79393 Mon Sep 17 00:00:00 2001 From: David Lamparter Date: Wed, 9 Aug 2017 20:30:34 +0200 Subject: [PATCH 32/32] lib: some final MAC access-list fixes - couldn't load back written configs because it was trying to parse "any" as MAC address - don't need special-casing in filter_match_zebra(), exact is going to be 0 for AF_ETHERNET anyway - some vty formatting was slightly different - is_zero_mac now static to prefix.c Signed-off-by: David Lamparter --- lib/filter.c | 40 +++++++++++++++------------------------- lib/prefix.c | 8 +++++++- lib/prefix.h | 1 - 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/lib/filter.c b/lib/filter.c index 9b983d26f2..cb6f743c01 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -187,26 +187,16 @@ static int filter_match_zebra(struct filter *mfilter, struct prefix *p) filter = &mfilter->u.zfilter; - if (filter->prefix.family == AF_ETHERNET) { - return prefix_match(&filter->prefix, p); - } - - if (filter->prefix.family == AF_INET - || filter->prefix.family == AF_INET6) { - - if (filter->prefix.family == p->family) { - if (filter->exact) { - if (filter->prefix.prefixlen == p->prefixlen) - return prefix_match(&filter->prefix, p); - else - return 0; - } else + if (filter->prefix.family == p->family) { + if (filter->exact) { + if (filter->prefix.prefixlen == p->prefixlen) return prefix_match(&filter->prefix, p); + else + return 0; } else - return 0; - } - - return 0; + return prefix_match(&filter->prefix, p); + } else + return 0; } /* Allocate new access list structure. */ @@ -1755,9 +1745,9 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) : "Standard") : "Zebra", (afi == AFI_IP) - ? ("") - : ((afi == AFI_IP6) ? ("ipv6 ") - : ("mac ")), + ? ("IP") + : ((afi == AFI_IP6) ? ("IPv6 ") + : ("MAC ")), access->name); write = 0; } @@ -1802,9 +1792,9 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi) : "Standard") : "Zebra", (afi == AFI_IP) - ? ("") - : ((afi == AFI_IP6) ? ("ipv6 ") - : ("mac ")), + ? ("IP") + : ((afi == AFI_IP6) ? ("IPv6 ") + : ("MAC ")), access->name); write = 0; } @@ -1960,7 +1950,7 @@ void config_write_access_zebra(struct vty *vty, struct filter *mfilter) inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen, filter->exact ? " exact-match" : ""); else if (p->family == AF_ETHERNET) { - if (is_zero_mac(&(p->u.prefix_eth))) + if (p->prefixlen == 0) vty_out(vty, " any"); else vty_out(vty, " %s", prefix_mac2str(&(p->u.prefix_eth), diff --git a/lib/prefix.c b/lib/prefix.c index d12999067c..de521b2e3e 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -301,7 +301,7 @@ static const struct in6_addr maskbytes6[] = { #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff) -int is_zero_mac(const struct ethaddr *mac) +static int is_zero_mac(const struct ethaddr *mac) { int i = 0; @@ -683,6 +683,12 @@ int str2prefix_eth(const char *str, struct prefix_eth *p) int i; bool slash = false; + if (!strcmp(str, "any")) { + memset(p, 0, sizeof(*p)); + p->family = AF_ETHERNET; + return 1; + } + /* Find slash inside string. */ pnt = strchr(str, '/'); diff --git a/lib/prefix.h b/lib/prefix.h index ddd01af766..f0644ea88e 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -276,7 +276,6 @@ union prefixconstptr { #endif /*s6_addr32*/ /* Prototypes. */ -extern int is_zero_mac(const struct ethaddr *mac); extern int str2family(const char *); extern int afi2family(afi_t); extern afi_t family2afi(int);