summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/Makefile.am1
-rw-r--r--bgpd/bgp_attr.c10
-rw-r--r--bgpd/bgp_attr.h3
-rw-r--r--bgpd/bgp_attr_evpn.c33
-rw-r--r--bgpd/bgp_attr_evpn.h2
-rw-r--r--bgpd/bgp_debug.c337
-rw-r--r--bgpd/bgp_ecommunity.h3
-rw-r--r--bgpd/bgp_evpn.c30
-rw-r--r--bgpd/bgp_evpn_private.h10
-rw-r--r--bgpd/bgp_vty.c5
-rw-r--r--lib/zclient.h2
-rw-r--r--zebra/if_netlink.c12
-rw-r--r--zebra/rt.h2
-rw-r--r--zebra/rt_netlink.c58
-rw-r--r--zebra/rt_socket.c2
-rw-r--r--zebra/zebra_rib.c4
-rw-r--r--zebra/zebra_vxlan.c73
-rw-r--r--zebra/zebra_vxlan.h3
-rw-r--r--zebra/zebra_vxlan_private.h1
-rw-r--r--zebra/zserv.c1
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);