diff options
| -rw-r--r-- | bgpd/Makefile.am | 1 | ||||
| -rw-r--r-- | bgpd/bgp_attr.c | 10 | ||||
| -rw-r--r-- | bgpd/bgp_attr.h | 3 | ||||
| -rw-r--r-- | bgpd/bgp_attr_evpn.c | 33 | ||||
| -rw-r--r-- | bgpd/bgp_attr_evpn.h | 2 | ||||
| -rw-r--r-- | bgpd/bgp_debug.c | 337 | ||||
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 3 | ||||
| -rw-r--r-- | bgpd/bgp_evpn.c | 30 | ||||
| -rw-r--r-- | bgpd/bgp_evpn_private.h | 10 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 5 | ||||
| -rw-r--r-- | lib/zclient.h | 2 | ||||
| -rw-r--r-- | zebra/if_netlink.c | 12 | ||||
| -rw-r--r-- | zebra/rt.h | 2 | ||||
| -rw-r--r-- | zebra/rt_netlink.c | 58 | ||||
| -rw-r--r-- | zebra/rt_socket.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_rib.c | 4 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 73 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.h | 3 | ||||
| -rw-r--r-- | zebra/zebra_vxlan_private.h | 1 | ||||
| -rw-r--r-- | zebra/zserv.c | 1 |
20 files changed, 514 insertions, 78 deletions
diff --git a/bgpd/Makefile.am b/bgpd/Makefile.am index 3880d2020d..2f19bbbd73 100644 --- a/bgpd/Makefile.am +++ b/bgpd/Makefile.am @@ -134,6 +134,7 @@ dist_examples_DATA = bgpd.conf.sample bgpd.conf.sample2 \ bgp_vty.o: bgp_vty_clippy.c bgp_route.o: bgp_route_clippy.c +bgp_debug.o: bgp_debug_clippy.c EXTRA_DIST = BGP4-MIB.txt diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 6596e7cfa2..e5ad5e2338 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1890,6 +1890,16 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) /* Check if this is a Gateway MAC-IP advertisement */ attr->default_gw = bgp_attr_default_gw(attr); + /* Handle scenario where router flag ecommunity is not + * set but default gw ext community is present. + * Use default gateway, set and propogate R-bit. + */ + if (attr->default_gw) + attr->router_flag = 1; + + /* Check EVPN Neighbor advertisement flags, R-bit */ + bgp_attr_evpn_na_flag(attr, &attr->router_flag); + /* Extract the Rmac, if any */ bgp_attr_rmac(attr, &attr->rmac); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f17c2a68e4..883b129136 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -185,6 +185,9 @@ struct attr { /* Flag for default gateway extended community in EVPN */ uint8_t default_gw; + /* NA router flag (R-bit) support in EVPN */ + uint8_t router_flag; + /* route tag */ route_tag_t tag; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index 14ff01ada5..88e520fdc5 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -210,6 +210,39 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) return 0; } +/* + * return true if attr contains router flag extended community + */ +void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag) +{ + struct ecommunity *ecom; + int i; + uint8_t val; + + ecom = attr->ecommunity; + if (!ecom || !ecom->size) + return; + + /* If there is a evpn na extendd community set router_flag */ + for (i = 0; i < ecom->size; i++) { + uint8_t *pnt; + uint8_t type, sub_type; + + pnt = (ecom->val + (i * ECOMMUNITY_SIZE)); + type = *pnt++; + sub_type = *pnt++; + + if (type == ECOMMUNITY_ENCODE_EVPN && + sub_type == ECOMMUNITY_EVPN_SUBTYPE_ND) { + val = *pnt++; + if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) { + *router_flag = 1; + break; + } + } + } +} + /* dst prefix must be AF_INET or AF_INET6 prefix, to forge EVPN prefix */ extern int bgp_build_evpn_prefix(int evpn_type, uint32_t eth_tag, struct prefix *dst) diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index 7454b81b96..b036702151 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -65,4 +65,6 @@ extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky); extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag); + #endif /* _QUAGGA_BGP_ATTR_EVPN_H */ diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index a4ded57c25..1e95a887bc 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -42,6 +42,8 @@ #include "bgpd/bgp_ecommunity.h" #include "bgpd/bgp_label.h" #include "bgpd/bgp_evpn.h" +#include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_vty.h" #include "bgpd/bgp_flowspec.h" unsigned long conf_bgp_debug_as4; @@ -169,6 +171,8 @@ static const struct message bgp_notify_capability_msg[] = { const char *bgp_origin_str[] = {"i", "e", "?"}; const char *bgp_origin_long_str[] = {"IGP", "EGP", "incomplete"}; +static int bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p); /* Given a string return a pointer the corresponding peer structure */ static struct peer *bgp_find_peer(struct vty *vty, const char *peer_str) { @@ -216,11 +220,11 @@ static void bgp_debug_list_free(struct list *list) /* Print the desc along with a list of peers/prefixes this debug is * enabled for */ static void bgp_debug_list_print(struct vty *vty, const char *desc, - struct list *list) + struct list *list, uint8_t evpn_dbg) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; vty_out(vty, "%s", desc); @@ -230,12 +234,17 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, if (filter->host) vty_out(vty, " %s", filter->host); - if (filter->p) - vty_out(vty, " %s/%d", - inet_ntop(filter->p->family, - &filter->p->u.prefix, buf, - INET6_ADDRSTRLEN), - filter->p->prefixlen); + if (filter->p) { + if (!evpn_dbg) { + vty_out(vty, " %s", + prefix2str(filter->p, buf, + sizeof(buf))); + } else { + if (filter->p->family == AF_EVPN) + bgp_debug_print_evpn_prefix(vty, + "", filter->p); + } + } } } @@ -246,11 +255,11 @@ static void bgp_debug_list_print(struct vty *vty, const char *desc, * enabled for */ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, - struct list *list) + struct list *list, uint8_t evpn_dbg) { struct bgp_debug_filter *filter; struct listnode *node, *nnode; - char buf[INET6_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; int write = 0; if (list && !list_isempty(list)) { @@ -262,12 +271,17 @@ static int bgp_debug_list_conf_print(struct vty *vty, const char *desc, if (filter->p) { - vty_out(vty, "%s %s/%d\n", desc, - inet_ntop(filter->p->family, - &filter->p->u.prefix, buf, - INET6_ADDRSTRLEN), - filter->p->prefixlen); - write++; + if (!evpn_dbg) { + vty_out(vty, "%s %s\n", desc, + prefix2str(filter->p, buf, + sizeof(buf))); + write++; + } else { + if (filter->p->family == AF_EVPN) + bgp_debug_print_evpn_prefix(vty, + desc, filter->p); + write++; + } } } } @@ -543,6 +557,118 @@ static void bgp_debug_clear_updgrp_update_dbg(struct bgp *bgp) update_group_walk(bgp, update_group_clear_update_dbg, NULL); } +static int bgp_debug_print_evpn_prefix(struct vty *vty, const char *desc, + struct prefix *p) +{ + char evpn_desc[PREFIX2STR_BUFFER + INET_ADDRSTRLEN]; + char buf[PREFIX2STR_BUFFER]; + char buf2[ETHER_ADDR_STRLEN]; + + if (p->u.prefix_evpn.route_type == BGP_EVPN_MAC_IP_ROUTE) { + if (is_evpn_prefix_ipaddr_none((struct prefix_evpn *)p)) { + sprintf(evpn_desc, "l2vpn evpn type macip mac %s", + prefix_mac2str( + &p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2))); + } else { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? + AF_INET : AF_INET6; + sprintf(evpn_desc, "l2vpn evpn type macip mac %s ip %s", + prefix_mac2str( + &p->u.prefix_evpn.macip_addr.mac, + buf2, sizeof(buf2)), + inet_ntop(family, + &p->u.prefix_evpn.macip_addr.ip.ip.addr, + buf, PREFIX2STR_BUFFER)); + } + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IMET_ROUTE) { + sprintf(evpn_desc, "l2vpn evpn type multicast ip %s", + inet_ntoa(p->u.prefix_evpn.imet_addr.ip.ipaddr_v4)); + } else if (p->u.prefix_evpn.route_type == BGP_EVPN_IP_PREFIX_ROUTE) { + uint8_t family = is_evpn_prefix_ipaddr_v4( + (struct prefix_evpn *)p) ? AF_INET + : AF_INET6; + sprintf(evpn_desc, "l2vpn evpn type prefix ip %s/%d", + inet_ntop(family, + &p->u.prefix_evpn.prefix_addr.ip.ip.addr, buf, + PREFIX2STR_BUFFER), + p->u.prefix_evpn.prefix_addr.ip_prefix_length); + } + + vty_out(vty, "%s %s\n", desc, evpn_desc); + + return 0; +} + +static int bgp_debug_parse_evpn_prefix(struct vty *vty, struct cmd_token **argv, + int argc, struct prefix **argv_pp) +{ + struct prefix *argv_p; + struct ethaddr mac; + struct ipaddr ip; + int evpn_type; + int type_idx = 0; + int mac_idx = 0; + int ip_idx = 0; + + argv_p = *argv_pp; + + if (argv_find(argv, argc, "type", &type_idx) == 0) + return CMD_WARNING; + + if (strncmp(argv[type_idx + 1]->arg, "ma", 2) == 0) + evpn_type = BGP_EVPN_MAC_IP_ROUTE; + else if (strncmp(argv[type_idx + 1]->arg, "mu", 2) == 0) + evpn_type = BGP_EVPN_IMET_ROUTE; + else if (strncmp(argv[type_idx + 1]->arg, "pr", 2) == 0) + evpn_type = BGP_EVPN_IP_PREFIX_ROUTE; + else + evpn_type = 0; + + if (evpn_type == BGP_EVPN_MAC_IP_ROUTE) { + memset(&ip, 0, sizeof(struct ipaddr)); + /* get the ip if specified */ + if (argv_find(argv, argc, "ip", &ip_idx)) { + if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) { + vty_out(vty, "%% Malformed IP address\n"); + return CMD_WARNING; + } + } + argv_find(argv, argc, "mac", &mac_idx); + if (!prefix_str2mac(argv[mac_idx + 1]->arg, &mac)) { + vty_out(vty, "%% Malformed MAC address\n"); + return CMD_WARNING; + } + + build_evpn_type2_prefix((struct prefix_evpn *)argv_p, + &mac, &ip); + } else if (evpn_type == BGP_EVPN_IMET_ROUTE) { + memset(&ip, 0, sizeof(struct ipaddr)); + /* get the ip if specified */ + if (argv_find(argv, argc, "ip", &ip_idx)) { + if (str2ipaddr(argv[ip_idx + 1]->arg, &ip) != 0) { + vty_out(vty, "%% Malformed IP address\n"); + return CMD_WARNING; + } + } + build_evpn_type3_prefix((struct prefix_evpn *)argv_p, + ip.ipaddr_v4); + } else if (evpn_type == BGP_EVPN_IP_PREFIX_ROUTE) { + struct prefix ip_prefix; + + memset(&ip_prefix, 0, sizeof(struct prefix)); + if (argv_find(argv, argc, "ip", &ip_idx)) { + (void)str2prefix(argv[ip_idx + 1]->arg, &ip_prefix); + apply_mask(&ip_prefix); + } + build_type5_prefix_from_ip_prefix( + (struct prefix_evpn *)argv_p, + &ip_prefix); + } + + return CMD_SUCCESS; +} /* Debug option setting interface. */ unsigned long bgp_debug_option = 0; @@ -1266,6 +1392,148 @@ DEFUN (no_debug_bgp_update_direct_peer, return CMD_SUCCESS; } +#ifndef VTYSH_EXTRACT_PL +#include "bgpd/bgp_debug_clippy.c" +#endif + +DEFPY (debug_bgp_update_prefix_afi_safi, + debug_bgp_update_prefix_afi_safi_cmd, + "debug bgp updates prefix <l2vpn>$afi <evpn>$safi type <macip mac WORD [ip WORD]|multicast ip WORD |prefix ip WORD>", + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + "l2vpn\n" + "evpn\n" + "Specify EVPN Route type\n" + "MAC-IP (Type-2) route\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + "Multicast (Type-3) route\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + "Prefix (Type-5) route\n" + "IP\n" + "Prefix route\n") +{ + int idx_ipv4_ipv6_prefixlen = 4; + struct prefix *argv_p; + int ret = CMD_SUCCESS; + afi_t afiz; + safi_t safiz; + + argv_p = prefix_new(); + + afiz = bgp_vty_afi_from_str(afi); + safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST; + + /* check for evpn route type */ + if (afiz == AFI_L2VPN && safiz == SAFI_EVPN) { + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) + return ret; + } else { + (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); + apply_mask(argv_p); + } + + if (!bgp_debug_update_prefixes) + bgp_debug_update_prefixes = list_new(); + + if (bgp_debug_list_has_entry(bgp_debug_update_prefixes, NULL, argv_p)) { + vty_out(vty, + "BGP updates debugging is already enabled for %s\n", + argv[idx_ipv4_ipv6_prefixlen]->arg); + return CMD_SUCCESS; + } + + bgp_debug_list_add_entry(bgp_debug_update_prefixes, NULL, argv_p); + + if (vty->node == CONFIG_NODE) { + DEBUG_ON(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_ON(update, UPDATE_PREFIX); + vty_out(vty, "BGP updates debugging is on for %s\n", + argv[idx_ipv4_ipv6_prefixlen]->arg); + } + + return CMD_SUCCESS; +} + +DEFPY (no_debug_bgp_update_prefix_afi_safi, + no_debug_bgp_update_prefix_afi_safi_cmd, + "no debug bgp updates prefix <l2vpn>$afi <evpn>$safi type <macip mac WORD [ip WORD]|multicast ip WORD |prefix ip WORD>", + NO_STR + DEBUG_STR + BGP_STR + "BGP updates\n" + "Specify a prefix to debug\n" + "l2vpn\n" + "evpn\n" + "Specify EVPN Route type\n" + "MAC-IP (Type-2) route\n" + "MAC\n" + "MAC address (e.g., 00:e0:ec:20:12:62)\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + "Multicast (Type-3) route\n" + "IP\n" + "IP address (IPv4 or IPv6)\n" + "Prefix (Type-5) route\n" + "IP\n" + "Prefix route\n") +{ + int idx_ipv4_ipv6_prefixlen = 5; + struct prefix *argv_p; + int found_prefix = 0; + int ret = CMD_SUCCESS; + afi_t afiz; + safi_t safiz; + + argv_p = prefix_new(); + + afiz = bgp_vty_afi_from_str(afi); + safiz = safi ? bgp_vty_safi_from_str(safi) : SAFI_UNICAST; + + /* check for evpn route type */ + if (afiz == AFI_L2VPN && safiz == SAFI_EVPN) { + ret = bgp_debug_parse_evpn_prefix(vty, argv, argc, &argv_p); + if (ret != CMD_SUCCESS) + return ret; + } else { + (void)str2prefix(argv[idx_ipv4_ipv6_prefixlen]->arg, argv_p); + apply_mask(argv_p); + } + + if (bgp_debug_update_prefixes + && !list_isempty(bgp_debug_update_prefixes)) { + found_prefix = bgp_debug_list_remove_entry( + bgp_debug_update_prefixes, NULL, argv_p); + + if (list_isempty(bgp_debug_update_prefixes)) { + if (vty->node == CONFIG_NODE) { + DEBUG_OFF(update, UPDATE_PREFIX); + } else { + TERM_DEBUG_OFF(update, UPDATE_PREFIX); + vty_out(vty, + "BGP updates debugging (per prefix) is off\n"); + } + } + } + + if (found_prefix) + vty_out(vty, "BGP updates debugging is off for %s\n", + argv[idx_ipv4_ipv6_prefixlen]->arg); + else + vty_out(vty, "BGP updates debugging was not enabled for %s\n", + argv[idx_ipv4_ipv6_prefixlen]->arg); + + return CMD_SUCCESS; +} + + DEFUN (debug_bgp_update_prefix, debug_bgp_update_prefix_cmd, "debug bgp updates prefix <A.B.C.D/M|X:X::X:X/M>", @@ -1816,16 +2084,16 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(bestpath, BESTPATH)) bgp_debug_list_print(vty, " BGP bestpath debugging is on", - bgp_debug_bestpath_prefixes); + bgp_debug_bestpath_prefixes, 0); if (BGP_DEBUG(keepalive, KEEPALIVE)) bgp_debug_list_print(vty, " BGP keepalives debugging is on", - bgp_debug_keepalive_peers); + bgp_debug_keepalive_peers, 0); if (BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) bgp_debug_list_print(vty, " BGP neighbor-events debugging is on", - bgp_debug_neighbor_events_peers); + bgp_debug_neighbor_events_peers, 0); if (BGP_DEBUG(nht, NHT)) vty_out(vty, " BGP next-hop tracking debugging is on\n"); @@ -1835,21 +2103,21 @@ DEFUN_NOSH (show_debugging_bgp, if (BGP_DEBUG(update, UPDATE_PREFIX)) bgp_debug_list_print(vty, " BGP updates debugging is on", - bgp_debug_update_prefixes); + bgp_debug_update_prefixes, 1); if (BGP_DEBUG(update, UPDATE_IN)) bgp_debug_list_print(vty, " BGP updates debugging is on (inbound)", - bgp_debug_update_in_peers); + bgp_debug_update_in_peers, 0); if (BGP_DEBUG(update, UPDATE_OUT)) bgp_debug_list_print(vty, " BGP updates debugging is on (outbound)", - bgp_debug_update_out_peers); + bgp_debug_update_out_peers, 0); if (BGP_DEBUG(zebra, ZEBRA)) bgp_debug_list_print(vty, " BGP zebra debugging is on", - bgp_debug_zebra_prefixes); + bgp_debug_zebra_prefixes, 0); if (BGP_DEBUG(allow_martians, ALLOW_MARTIANS)) vty_out(vty, " BGP allow martian next hop debugging is on\n"); @@ -1955,18 +2223,20 @@ static int bgp_config_write_debug(struct vty *vty) if (CONF_BGP_DEBUG(bestpath, BESTPATH)) { write += bgp_debug_list_conf_print(vty, "debug bgp bestpath", - bgp_debug_bestpath_prefixes); + bgp_debug_bestpath_prefixes, + 0); } if (CONF_BGP_DEBUG(keepalive, KEEPALIVE)) { write += bgp_debug_list_conf_print(vty, "debug bgp keepalives", - bgp_debug_keepalive_peers); + bgp_debug_keepalive_peers, + 0); } if (CONF_BGP_DEBUG(neighbor_events, NEIGHBOR_EVENTS)) { write += bgp_debug_list_conf_print( vty, "debug bgp neighbor-events", - bgp_debug_neighbor_events_peers); + bgp_debug_neighbor_events_peers, 0); } if (CONF_BGP_DEBUG(nht, NHT)) { @@ -1982,17 +2252,20 @@ static int bgp_config_write_debug(struct vty *vty) if (CONF_BGP_DEBUG(update, UPDATE_PREFIX)) { write += bgp_debug_list_conf_print(vty, "debug bgp updates prefix", - bgp_debug_update_prefixes); + bgp_debug_update_prefixes, + 1); } if (CONF_BGP_DEBUG(update, UPDATE_IN)) { write += bgp_debug_list_conf_print(vty, "debug bgp updates in", - bgp_debug_update_in_peers); + bgp_debug_update_in_peers, + 0); } if (CONF_BGP_DEBUG(update, UPDATE_OUT)) { write += bgp_debug_list_conf_print(vty, "debug bgp updates out", - bgp_debug_update_out_peers); + bgp_debug_update_out_peers, + 0); } if (CONF_BGP_DEBUG(zebra, ZEBRA)) { @@ -2003,7 +2276,7 @@ static int bgp_config_write_debug(struct vty *vty) } else { write += bgp_debug_list_conf_print( vty, "debug bgp zebra prefix", - bgp_debug_zebra_prefixes); + bgp_debug_zebra_prefixes, 0); } } @@ -2095,6 +2368,10 @@ void bgp_debug_init(void) install_element(CONFIG_NODE, &debug_bgp_update_prefix_cmd); install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_cmd); install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_cmd); + install_element(ENABLE_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &debug_bgp_update_prefix_afi_safi_cmd); + install_element(ENABLE_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); + install_element(CONFIG_NODE, &no_debug_bgp_update_prefix_afi_safi_cmd); /* debug bgp zebra prefix A.B.C.D/M */ install_element(ENABLE_NODE, &debug_bgp_zebra_prefix_cmd); diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 2f59308d65..c71f371a97 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -48,8 +48,11 @@ #define ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT 0x02 #define ECOMMUNITY_EVPN_SUBTYPE_ROUTERMAC 0x03 #define ECOMMUNITY_EVPN_SUBTYPE_DEF_GW 0x0d +#define ECOMMUNITY_EVPN_SUBTYPE_ND 0x08 #define ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG 0x01 +#define ECOMMUNITY_EVPN_SUBTYPE_ND_OVERRIDE_FLAG 0x02 /* Low-order octet of the Extended Communities type field for OPAQUE types */ #define ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP 0x0c diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index a026df59a0..73f225784c 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -730,10 +730,13 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, struct ecommunity ecom_sticky; struct ecommunity ecom_default_gw; struct ecommunity ecom_rmac; + struct ecommunity ecom_na; struct ecommunity_val eval; struct ecommunity_val eval_sticky; struct ecommunity_val eval_default_gw; struct ecommunity_val eval_rmac; + struct ecommunity_val eval_na; + bgp_encap_types tnl_type; struct listnode *node, *nnode; struct ecommunity *ecom; @@ -798,6 +801,15 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, ecommunity_merge(attr->ecommunity, &ecom_default_gw); } + if (attr->router_flag) { + memset(&ecom_na, 0, sizeof(ecom_na)); + encode_na_flag_extcomm(&eval_na, attr->router_flag); + ecom_na.size = 1; + ecom_na.val = (uint8_t *)eval_na.val; + attr->ecommunity = ecommunity_merge(attr->ecommunity, + &ecom_na); + } + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES); } @@ -1089,6 +1101,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, { struct bgp_info *old_select, *new_select; struct bgp_info_pair old_and_new; + struct prefix_evpn *evp; afi_t afi = AFI_L2VPN; safi_t safi = SAFI_EVPN; int ret = 0; @@ -1100,6 +1113,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, old_select = old_and_new.old; new_select = old_and_new.new; + evp = (struct prefix_evpn *)&rn->p; /* If the best path hasn't changed - see if there is still something to * update * to zebra RIB. @@ -1115,6 +1129,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); if (old_select->attr->default_gw) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + if (is_evpn_prefix_ipaddr_v6(evp) && + old_select->attr->router_flag) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + ret = evpn_zebra_install( bgp, vpn, (struct prefix_evpn *)&rn->p, old_select->attr->nexthop, flags); @@ -1148,6 +1166,10 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn, SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); if (new_select->attr->default_gw) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + if (is_evpn_prefix_ipaddr_v6(evp) && + new_select->attr->router_flag) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); + ret = evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p, new_select->attr->nexthop, flags); /* If an old best existed and it was a "local" route, the only @@ -1695,6 +1717,8 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; + attr.router_flag = CHECK_FLAG(flags, + ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; /* PMSI is only needed for type-3 routes */ if (p->prefix.route_type == BGP_EVPN_IMET_ROUTE) @@ -1993,11 +2017,13 @@ static int update_all_type2_routes(struct bgp *bgp, struct bgpevpn *vpn) update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_sticky, 0, 1, &ri, 0); - else if (evpn_route_is_def_gw(bgp, rn)) + else if (evpn_route_is_def_gw(bgp, rn)) { + if (is_evpn_prefix_ipaddr_v6(evp)) + attr_def_gw.router_flag = 1; update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr_def_gw, 0, 1, &ri, 0); - else + } else update_evpn_route_entry(bgp, vpn, afi, safi, rn, &attr, 0, 1, &ri, 0); } diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index e4e0511147..8d71c3123e 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -311,6 +311,16 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, eval->val[7] = seq & 0xff; } +static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, + uint8_t na_flag) +{ + memset(eval, 0, sizeof(*eval)); + eval->val[0] = ECOMMUNITY_ENCODE_EVPN; + eval->val[1] = ECOMMUNITY_EVPN_SUBTYPE_ND; + if (na_flag) + eval->val[2] |= ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG; +} + static inline void ip_prefix_from_type5_prefix(struct prefix_evpn *evp, struct prefix *ip) { diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f63d591d6f..33f5180bd3 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -184,6 +184,7 @@ safi_t bgp_node_safi(struct vty *vty) * @param afi string, one of * - "ipv4" * - "ipv6" + * - "l2vpn" * @return the corresponding afi_t */ afi_t bgp_vty_afi_from_str(const char *afi_str) @@ -193,6 +194,8 @@ afi_t bgp_vty_afi_from_str(const char *afi_str) afi = AFI_IP; else if (strmatch(afi_str, "ipv6")) afi = AFI_IP6; + else if (strmatch(afi_str, "l2vpn")) + afi = AFI_L2VPN; return afi; } @@ -222,6 +225,8 @@ safi_t bgp_vty_safi_from_str(const char *safi_str) safi = SAFI_UNICAST; else if (strmatch(safi_str, "vpn")) safi = SAFI_MPLS_VPN; + else if (strmatch(safi_str, "evpn")) + safi = SAFI_EVPN; else if (strmatch(safi_str, "labeled-unicast")) safi = SAFI_LABELED_UNICAST; else if (strmatch(safi_str, "flowspec")) diff --git a/lib/zclient.h b/lib/zclient.h index 10a1723010..49419b3df3 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -448,6 +448,8 @@ enum zapi_iptable_notify_owner { /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ +#define ZEBRA_MACIP_TYPE_ROUTER_FLAG 0x04 /* Router Flag - proxy NA */ +#define ZEBRA_MACIP_TYPE_OVERRIDE_FLAG 0x08 /* Override Flag */ struct zclient_options { bool receive_notify; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 2743f34cb4..8943b434d7 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1230,6 +1230,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update interface information. */ set_ifindex(ifp, ifi->ifi_index, zns); ifp->flags = ifi->ifi_flags & 0x0000fffff; + if (!tb[IFLA_MTU]) { + zlog_warn( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + return 0; + } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; ifp->ptm_status = ZEBRA_PTM_STATUS_UNKNOWN; @@ -1279,6 +1285,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) bridge_ifindex, ifi->ifi_flags); set_ifindex(ifp, ifi->ifi_index, zns); + if (!tb[IFLA_MTU]) { + zlog_warn( + "RTM_NEWLINK for interface %s(%u) without MTU set", + name, ifi->ifi_index); + return 0; + } ifp->mtu6 = ifp->mtu = *(int *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; diff --git a/zebra/rt.h b/zebra/rt.h index 57e62e4f6e..e40bae3a3e 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -122,7 +122,7 @@ extern int kernel_del_mac(struct interface *ifp, vlanid_t vid, int local); extern int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac); + struct ethaddr *mac, uint8_t flags); extern int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip); /* diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index b346247d4b..80841b6ac1 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -387,8 +387,15 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, memcpy(&p.u.prefix4, dest, 4); p.prefixlen = rtm->rtm_dst_len; - src_p.prefixlen = - 0; // Forces debug below to not display anything + if (rtm->rtm_src_len != 0) { + char buf[PREFIX_STRLEN]; + zlog_warn("unsupported IPv4 sourcedest route (dest %s vrf %u)", + prefix2str(&p, buf, sizeof(buf)), vrf_id); + return 0; + } + + /* Force debug below to not display anything for source */ + src_p.prefixlen = 0; } else if (rtm->rtm_family == AF_INET6) { p.family = AF_INET6; memcpy(&p.u.prefix6, dest, 16); @@ -399,14 +406,6 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, src_p.prefixlen = rtm->rtm_src_len; } - if (rtm->rtm_src_len != 0) { - char buf[PREFIX_STRLEN]; - zlog_warn( - "unsupported IPv[4|6] sourcedest route (dest %s vrf %u)", - prefix2str(&p, buf, sizeof(buf)), vrf_id); - return 0; - } - /* * For ZEBRA_ROUTE_KERNEL types: * @@ -492,7 +491,7 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, nh.vrf_id = nh_vrf_id; rib_add(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, &p, - NULL, &nh, table, metric, mtu, distance, tag); + &src_p, &nh, table, metric, mtu, distance, tag); } else { /* This is a multipath route */ @@ -581,6 +580,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, route_entry_nexthop_ifindex_add( re, index, nh_vrf_id); + if (rtnh->rtnh_len == 0) + break; + len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } @@ -591,8 +593,8 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (re->nexthop_num == 0) XFREE(MTYPE_RE, re); else - rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, - re); + rib_add_multipath(afi, SAFI_UNICAST, &p, + &src_p, re); } } else { if (!tb[RTA_MULTIPATH]) { @@ -624,12 +626,12 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id, if (gate) memcpy(&nh.gate, gate, sz); rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, &nh, table, metric, true); + &p, &src_p, &nh, table, metric, true); } else { /* XXX: need to compare the entire list of nexthops * here for NLM_F_APPEND stupidity */ rib_delete(afi, SAFI_UNICAST, vrf_id, proto, 0, flags, - &p, NULL, NULL, table, metric, true); + &p, &src_p, NULL, table, metric, true); } } @@ -701,6 +703,9 @@ static int netlink_route_change_read_multicast(struct nlmsghdr *h, oif[oif_count] = rtnh->rtnh_ifindex; oif_count++; + if (rtnh->rtnh_len == 0) + break; + len -= NLMSG_ALIGN(rtnh->rtnh_len); rtnh = RTNH_NEXT(rtnh); } @@ -2160,6 +2165,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) char buf2[INET6_ADDRSTRLEN]; int mac_present = 0; uint8_t ext_learned; + uint8_t router_flag; ndm = NLMSG_DATA(h); @@ -2250,6 +2256,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) } ext_learned = (ndm->ndm_flags & NTF_EXT_LEARNED) ? 1 : 0; + router_flag = (ndm->ndm_flags & NTF_ROUTER) ? 1 : 0; if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( @@ -2272,7 +2279,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (ndm->ndm_state & NUD_VALID) return zebra_vxlan_handle_kernel_neigh_update( ifp, link_if, &ip, &mac, ndm->ndm_state, - ext_learned); + ext_learned, router_flag); return zebra_vxlan_handle_kernel_neigh_del(ifp, link_if, &ip); } @@ -2406,7 +2413,8 @@ int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id) } static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac, uint32_t flags, int cmd) + struct ethaddr *mac, uint8_t flags, + uint16_t state, int cmd) { struct { struct nlmsghdr n; @@ -2429,11 +2437,10 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, req.n.nlmsg_flags |= (NLM_F_CREATE | NLM_F_REPLACE); req.n.nlmsg_type = cmd; // RTM_NEWNEIGH or RTM_DELNEIGH req.ndm.ndm_family = IS_IPADDR_V4(ip) ? AF_INET : AF_INET6; - req.ndm.ndm_state = flags; + req.ndm.ndm_state = state; req.ndm.ndm_ifindex = ifp->ifindex; req.ndm.ndm_type = RTN_UNICAST; - req.ndm.ndm_flags = NTF_EXT_LEARNED; - + req.ndm.ndm_flags = flags; ipa_len = IS_IPADDR_V4(ip) ? IPV4_MAX_BYTELEN : IPV6_MAX_BYTELEN; addattr_l(&req.n, sizeof(req), NDA_DST, &ip->ip.addr, ipa_len); @@ -2441,12 +2448,12 @@ static int netlink_neigh_update2(struct interface *ifp, struct ipaddr *ip, addattr_l(&req.n, sizeof(req), NDA_LLADDR, mac, 6); if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s", + zlog_debug("Tx %s family %s IF %s(%u) Neigh %s MAC %s flags 0x%x", nl_msg_type_to_str(cmd), nl_family_to_str(req.ndm.ndm_family), ifp->name, ifp->ifindex, ipaddr2str(ip, buf, sizeof(buf)), mac ? prefix_mac2str(mac, buf2, sizeof(buf2)) - : "null"); + : "null", flags); return netlink_talk(netlink_talk_filter, &req.n, &zns->netlink_cmd, zns, 0); @@ -2467,14 +2474,15 @@ int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac) + struct ethaddr *mac, uint8_t flags) { - return netlink_neigh_update2(ifp, ip, mac, NUD_NOARP, RTM_NEWNEIGH); + return netlink_neigh_update2(ifp, ip, mac, flags, + NUD_NOARP, RTM_NEWNEIGH); } int kernel_del_neigh(struct interface *ifp, struct ipaddr *ip) { - return netlink_neigh_update2(ifp, ip, NULL, 0, RTM_DELNEIGH); + return netlink_neigh_update2(ifp, ip, NULL, 0, 0, RTM_DELNEIGH); } /* diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 1cba28496d..346699198f 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -462,7 +462,7 @@ int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, } int kernel_add_neigh(struct interface *ifp, struct ipaddr *ip, - struct ethaddr *mac) + struct ethaddr *mac, uint8_t flags) { return 0; } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9bf6bfa22f..71d48632c1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2331,7 +2331,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, if (!re) return 0; - assert(!src_p || afi == AFI_IP6); + assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, re->vrf_id, re->table); @@ -2421,7 +2421,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, char buf2[INET6_ADDRSTRLEN]; rib_dest_t *dest; - assert(!src_p || afi == AFI_IP6); + assert(!src_p || !src_p->prefixlen || afi == AFI_IP6); /* Lookup table. */ table = zebra_vrf_table_with_table_id(afi, safi, vrf_id, table_id); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index a3b1c7d62e..06d1b3618c 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -33,6 +33,9 @@ #include "jhash.h" #include "vlan.h" #include "vxlan.h" +#ifdef GNU_LINUX +#include <linux/neighbour.h> +#endif #include "zebra/rib.h" #include "zebra/rt.h" @@ -282,6 +285,7 @@ static void zvni_find_neigh_addr_width(struct hash_backet *backet, void *ctxt) ipaddr2str(&n->ip, buf, sizeof(buf)), width = strlen(buf); if (width > wctx->addr_width) wctx->addr_width = width; + } /* @@ -327,6 +331,10 @@ static void zvni_print_neigh(zebra_neigh_t *n, void *ctxt, json_object *json) else json_object_boolean_true_add(json, "defaultGateway"); } + if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG)) { + if (!json) + vty_out(vty, " Router"); + } if (json == NULL) vty_out(vty, "\n"); } @@ -432,11 +440,11 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, return; } num_neigh = hashcount(zvni->neigh_table); - if (json == NULL) + if (json == NULL) { vty_out(vty, "\nVNI %u #ARP (IPv4 and IPv6, local and remote) %u\n\n", zvni->vni, num_neigh); - else { + } 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); @@ -458,9 +466,10 @@ static void zvni_print_neigh_hash_all_vni(struct hash_backet *backet, wctx.json = json_vni; hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); - if (json == NULL) + 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) @@ -1556,6 +1565,9 @@ static int zvni_neigh_send_add_to_client(vni_t vni, struct ipaddr *ip, if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_DEF_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); + /* Set router flag (R-bit) based on local neigh entry add */ + if (CHECK_FLAG(neigh_flags, ZEBRA_NEIGH_ROUTER_FLAG)) + SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); return zvni_macip_send_msg_to_client(vni, macaddr, ip, flags, ZEBRA_MACIP_ADD); @@ -1579,6 +1591,8 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) struct zebra_if *zif; struct zebra_l2info_vxlan *vxl; struct interface *vlan_if; + uint8_t flags; + int ret = 0; if (!(n->flags & ZEBRA_NEIGH_REMOTE)) return 0; @@ -1591,8 +1605,13 @@ static int zvni_neigh_install(zebra_vni_t *zvni, zebra_neigh_t *n) vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (!vlan_if) return -1; - - return kernel_add_neigh(vlan_if, &n->ip, &n->emac); +#ifdef GNU_LINUX + flags = NTF_EXT_LEARNED; + if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) + flags |= NTF_ROUTER; + ret = kernel_add_neigh(vlan_if, &n->ip, &n->emac, flags); +#endif + return ret; } /* @@ -1814,6 +1833,9 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, /* Set "local" forwarding info. */ SET_FLAG(n->flags, ZEBRA_NEIGH_LOCAL); SET_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW); + /* Set Router flag (R-bit) */ + if (ip->ipa_type == IPADDR_V6) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); memcpy(&n->emac, macaddr, ETH_ALEN); n->ifindex = ifp->ifindex; @@ -1823,10 +1845,10 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( - "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP", + "SVI %s(%u) L2-VNI %u, sending GW MAC %s IP %s add to BGP with flags 0x%x", ifp->name, ifp->ifindex, zvni->vni, prefix_mac2str(macaddr, buf, sizeof(buf)), - ipaddr2str(ip, buf2, sizeof(buf2))); + ipaddr2str(ip, buf2, sizeof(buf2)), n->flags); zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); @@ -1969,7 +1991,8 @@ static void zvni_gw_macip_add_for_vni_hash(struct hash_backet *backet, static int zvni_local_neigh_update(zebra_vni_t *zvni, struct interface *ifp, struct ipaddr *ip, - struct ethaddr *macaddr) + struct ethaddr *macaddr, + uint8_t router_flag) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -2087,15 +2110,19 @@ static int zvni_local_neigh_update(zebra_vni_t *zvni, return 0; } + /*Set router flag (R-bit) */ + if (router_flag) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + /* Inform BGP. */ if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u", + zlog_debug("Neigh %s (MAC %s) is now ACTIVE on L2-VNI %u with flags 0x%x", ipaddr2str(ip, buf2, sizeof(buf2)), prefix_mac2str(macaddr, buf, sizeof(buf)), - zvni->vni); + zvni->vni, n->flags); ZEBRA_NEIGH_SET_ACTIVE(n); - return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, 0); + return zvni_neigh_send_add_to_client(zvni->vni, ip, macaddr, n->flags); } static int zvni_remote_neigh_update(zebra_vni_t *zvni, @@ -3366,14 +3393,22 @@ static int zl3vni_nh_del(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) */ static int zl3vni_nh_install(zebra_l3vni_t *zl3vni, zebra_neigh_t *n) { + uint8_t flags; + int ret = 0; + if (!is_l3vni_oper_up(zl3vni)) return -1; if (!(n->flags & ZEBRA_NEIGH_REMOTE) || !(n->flags & ZEBRA_NEIGH_REMOTE_NH)) return 0; - - return kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac); +#ifdef GNU_LINUX + flags = NTF_EXT_LEARNED; + if (n->flags & ZEBRA_NEIGH_ROUTER_FLAG) + flags |= NTF_ROUTER; + ret = kernel_add_neigh(zl3vni->svi_if, &n->ip, &n->emac, flags); +#endif + return ret; } /* @@ -4517,9 +4552,11 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, memset(&wctx, 0, sizeof(struct neigh_walk_ctx)); wctx.zvni = zvni; wctx.vty = vty; + wctx.addr_width = 15; wctx.flags = SHOW_REMOTE_NEIGH_FROM_VTEP; wctx.r_vtep_ip = vtep_ip; wctx.json = json; + hash_iterate(zvni->neigh_table, zvni_find_neigh_addr_width, &wctx); hash_iterate(zvni->neigh_table, zvni_print_neigh_hash, &wctx); if (use_json) { @@ -4948,7 +4985,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, struct ipaddr *ip, struct ethaddr *macaddr, uint16_t state, - uint8_t ext_learned) + uint8_t ext_learned, + uint8_t router_flag) { char buf[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; @@ -4979,7 +5017,8 @@ int zebra_vxlan_handle_kernel_neigh_update(struct interface *ifp, /* Is this about a local neighbor or a remote one? */ if (!ext_learned) - return zvni_local_neigh_update(zvni, ifp, ip, macaddr); + return zvni_local_neigh_update(zvni, ifp, ip, macaddr, + router_flag); return zvni_remote_neigh_update(zvni, ifp, ip, macaddr, state); } @@ -5366,6 +5405,10 @@ void zebra_vxlan_remote_macip_add(ZAPI_HANDLER_ARGS) n->r_vtep_ip = vtep_ip; SET_FLAG(n->flags, ZEBRA_NEIGH_REMOTE); + /* Set router flag (R-bit) to this Neighbor entry */ + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(n->flags, ZEBRA_NEIGH_ROUTER_FLAG); + /* Install the entry. */ zvni_neigh_install(zvni, n); } diff --git a/zebra/zebra_vxlan.h b/zebra/zebra_vxlan.h index 34d1152751..2732ef72ed 100644 --- a/zebra/zebra_vxlan.h +++ b/zebra/zebra_vxlan.h @@ -124,7 +124,8 @@ extern int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if); extern int zebra_vxlan_handle_kernel_neigh_update( struct interface *ifp, struct interface *link_if, struct ipaddr *ip, - struct ethaddr *macaddr, uint16_t state, uint8_t ext_learned); + struct ethaddr *macaddr, uint16_t state, uint8_t ext_learned, + uint8_t router_flag); extern int zebra_vxlan_handle_kernel_neigh_del(struct interface *ifp, struct interface *link_if, struct ipaddr *ip); diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h index 354126ca5d..e86967041b 100644 --- a/zebra/zebra_vxlan_private.h +++ b/zebra/zebra_vxlan_private.h @@ -331,6 +331,7 @@ struct zebra_neigh_t_ { #define ZEBRA_NEIGH_REMOTE 0x02 #define ZEBRA_NEIGH_REMOTE_NH 0x04 /* neigh entry for remote vtep */ #define ZEBRA_NEIGH_DEF_GW 0x08 +#define ZEBRA_NEIGH_ROUTER_FLAG 0x10 enum zebra_neigh_state state; diff --git a/zebra/zserv.c b/zebra/zserv.c index 4c90757d70..725cc9229c 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1024,7 +1024,6 @@ DEFUN (show_zebra_client_summary, void zserv_read_file(char *input) { int fd; - struct zserv *client = NULL; struct thread t; fd = open(input, O_RDONLY | O_NONBLOCK); |
