]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #2704 from sworleys/Netlink-Nexthop-Hang
authorRuss White <russ@riw.us>
Tue, 24 Jul 2018 23:42:11 +0000 (19:42 -0400)
committerGitHub <noreply@github.com>
Tue, 24 Jul 2018 23:42:11 +0000 (19:42 -0400)
zebra: Add check for nexthop loop to prevent hanging

25 files changed:
bgpd/Makefile.am
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_attr_evpn.c
bgpd/bgp_attr_evpn.h
bgpd/bgp_debug.c
bgpd/bgp_ecommunity.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_vty.c
doc/Makefile.am
doc/extra/spelling_wordlist.txt
doc/user/index.rst
doc/user/ldpd.rst [new file with mode: 0644]
ldpd/ldp_vty_cmds.c
lib/zclient.h
zebra/if_netlink.c
zebra/rt.h
zebra/rt_netlink.c
zebra/rt_socket.c
zebra/zebra_rib.c
zebra/zebra_vxlan.c
zebra/zebra_vxlan.h
zebra/zebra_vxlan_private.h
zebra/zserv.c

index 3880d2020da26da4ac1f29915de2dfdd613d750e..2f19bbbd739cb28f0f09fbdb71bb538a0fd51906 100644 (file)
@@ -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
 
index 6596e7cfa2643d1e4b650ecdeb4d5705d3762230..e5ad5e23387ab3fa2bc348f0afd9bb050292ce0c 100644 (file)
@@ -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);
 
index f17c2a68e4533780614a99586205adfb62667412..883b129136220645e80aa1d63947e4dbda0170c3 100644 (file)
@@ -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;
 
index 14ff01ada54c09eb56466857557959c30f71d90d..88e520fdc508c24de4fdd1014124cd9cf3dee105 100644 (file)
@@ -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)
index 7454b81b966870903f72b4ce05365aebef73fa8d..b036702151d0e01957bec7d693bd765a1374dd6d 100644 (file)
@@ -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 */
index a4ded57c25630d2008103bbcbb5a3e5a2bd62e43..1e95a887bc5bf63e928c4f8b06d3a435e343bd0b 100644 (file)
@@ -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);
index 2f59308d65fd1f0f0eedfbfa9637c61ea0e3da25..c71f371a9738e2c91171c6cc8c789b4f9acf93ad 100644 (file)
 #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
index a026df59a06f717fb0cf05e630c1439d491f62e8..73f225784cb903827577b4727a74d9a042732fe8 100644 (file)
@@ -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);
                }
index e4e0511147376b95abbe6c62a246f4ce0d38def5..8d71c3123e830af11eb70ac8877101f08bf46b4b 100644 (file)
@@ -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)
 {
index f63d591d6f89f86a1c54132633c48f25142593a1..33f5180bd365805ee1e02c018e798b60dd50f875 100644 (file)
@@ -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"))
index 62cb3c2edb452e7e859fe6eafef2d863c7ca4a08..19aab63ea3609a8db574cc3b43c00414d089ae6f 100644 (file)
@@ -193,6 +193,7 @@ EXTRA_DIST = frr-sphinx.mk \
        developer/workflow.rst \
        developer/zebra.rst \
        user/babeld.rst \
+       user/ldpd.rst \
        user/basic.rst \
        user/bgp.rst \
        user/bugs.rst \
index 4c9455e8e94409ede31b05856d6b7aaf90856de5..29445929625e68655d9685ec511e9591b390ba18 100644 (file)
@@ -83,6 +83,7 @@ IPv
 isis
 isisd
 lan
+ldpd
 le
 libc
 libcap
index a8109fe47970ebfbeff949f9307e08ae893cfbcb..746cc1c32dddafdfa01ce7898d3af69b01b135b4 100644 (file)
@@ -41,6 +41,7 @@ Protocols
    zebra
    bgp
    babeld
+   ldpd
    eigrpd
    isisd
    nhrpd
diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst
new file mode 100644 (file)
index 0000000..8d88ef1
--- /dev/null
@@ -0,0 +1,309 @@
+.. _ldp:
+
+***
+LDP
+***
+
+The *ldpd* daemon is a standardised protocol that permits exchanging MPLS label
+information between MPLS devices. The LDP protocol creates peering between
+devices, so as to exchange that label information. This information is stored in
+MPLS table of *zebra*, and it injects that MPLS information in the underlying
+system (Linux kernel or OpenBSD system for instance).
+*ldpd* provides necessary options to create a Layer 2 VPN across MPLS network.
+For instance, it is possible to interconnect several sites that share the same
+broadcast domain.
+
+FRR implements LDP as described in :rfc:`5036`; other LDP standard are the
+following ones: :rfc:`6720`, :rfc:`6667`, :rfc:`5919`, :rfc:`5561`, :rfc:`7552`,
+:rfc:`4447`.
+Because MPLS is already available, FRR also supports :rfc:`3031`.
+
+Running Ldpd
+============
+
+The *ldpd* daemon can be invoked with any of the common
+options (:ref:`common-invocation-options`).
+
+The *zebra* daemon must be running before *ldpd* is invoked.
+
+Configuration of *ldpd* is done in its configuration file
+:file:`ldpd.conf`.
+
+
+.. _understanding-ldp:
+
+Understanding LDP principles
+============================
+
+Let's first introduce some definitions that permit understand better the LDP
+protocol:
+
+- `LSR` : Labeled Switch Router. Networking devices handling labels used to
+  forward traffic between and through them.
+
+- `LER` : Labeled Edge Router. A Labeled edge router is located at the edge of
+   an MPLS network, generally between an IP network and an MPLS network.
+
+
+``LDP`` aims at sharing label information across devices. It tries to establish
+peering with remote LDP capable devices, first by discovering using UDP port 646
+, then by peering using TCP port 646. Once the TCP session is established, the
+label information is shared, through label advertisements.
+
+There are different methods to send label advertisement modes. The
+implementation actually supports the following : Liberal Label Retention +
+Downstream Unsolicited + Independent Control.
+The other advertising modes are depicted below, and compared with the current
+implementation.
+
+- Liberal label retention versus conservative mode
+  In liberal mode, every label sent by every LSR is stored in the MPLS table.
+  In conservative mode, only the label that was sent by the best next hop
+  (determined by the IGP metric) for that particular FEC is stored in the MPLS
+  table.
+
+- Independent LSP Control versus ordered LSP Control
+  MPLS has two ways of binding labels to FEC’s; either through ordered LSP
+  control, or independent LSP control.
+  Ordered LSP control only binds a label to a FEC if it is the egress LSR, or
+  the router received a label binding for a FEC from the next hop router. In
+  this mode, an MPLS router will create a label binding for each FEC and
+  distribute it to its neighbors so long as he has a entry in the RIB for the
+  destination.
+  In the other mode, label bindings are made without any dependencies on another
+  router advertising a label for a particular FEC. Each router makes it own
+  independent decision to create a label for each FEC.
+  By default IOS uses Independent LSP Control, while Juniper implements the
+  Ordered Control. Both modes are interoperable, the difference is that Ordered
+  Control prevent blackholing during the LDP convergence process, at cost of
+  slowing down the convergence itself
+
+- unsolicited downstream versus downstream on demand
+  Downstream on demand label distribution is where an LSR must explicitly
+  request that a label be sent from its downstream router for a particular FEC.
+  Unsolicited label distribution is where a label is sent from the downstream
+  router without the original router requesting it.
+
+.. _configuring-ldpd:
+
+.. _ldp-configuration:
+
+LDP Configuration
+===================
+
+.. index:: [no] mpls ldp
+.. clicmd:: [no] mpls ldp
+
+   Enable or disable LDP daemon
+
+.. index:: [no] router-id A.B.C.D
+.. clicmd:: [no] router-id A.B.C.D
+
+   The following command located under MPLS router node configures the MPLS
+   router-id of the local device.
+
+.. index:: [no] address-family [ipv4 | ipv6]
+.. clicmd:: [no] address-family [ipv4 | ipv6]
+
+   Configure LDP for IPv4 or IPv6 address-family. Located under MPLS route node,
+   this subnode permits configuring the LDP neighbors.
+
+.. index:: [no] interface IFACE
+.. clicmd:: [no] interface IFACE
+
+   Located under MPLS address-family node, use this command to enable or disable
+   LDP discovery per interface. IFACE stands for the interface name where LDP is
+   enabled. By default it is disabled. Once this command executed, the
+   address-family interface node is configured.
+
+.. index:: [no] discovery transport-address A.B.C.D | A:B::C:D
+.. clicmd:: [no] discovery transport-address A.B.C.D | A:B::C:D
+
+   Located under mpls address-family interface node, use this command to set
+   the IPv4 or IPv6 transport-address used by the LDP protocol to talk on this
+   interface.
+
+.. index:: [no] neighbor A.B.C.D password PASSWORD
+.. clicmd:: [no] neighbor A.B.C.D password PASSWORD
+
+   The following command located under MPLS router node configures the router
+   of a LDP device. This device, if found, will have to comply with the
+   configured password. PASSWORD is a clear text password wit its digest sent
+   through the network.
+
+.. index:: [no] neighbor A.B.C.D holdtime HOLDTIME
+.. clicmd:: [no] neighbor A.B.C.D holdtime HOLDTIME
+
+   The following command located under MPLS router node configures the holdtime
+   value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive
+   mechanism. That value can be configured between 15 and 65535 seconds. After
+   this time of non response, the LDP established session will be considered as
+   set to down. By default, no holdtime is configured for the LDP devices.
+
+.. index:: [no] discovery hello holdtime HOLDTIME
+.. clicmd:: [no] discovery hello holdtime HOLDTIME
+
+.. index:: [no] discovery hello interval INTERVAL
+.. clicmd:: [no] discovery hello interval INTERVAL
+
+   INTERVAL value ranges from 1 to 65535 seconds. Default value is 5 seconds.
+   This is the value between each hello timer message sent.
+   HOLDTIME value ranges from 1 to 65535 seconds. Default value is 15 seconds.
+   That value is added as a TLV in the LDP messages.
+
+.. _show-ldp-information:
+
+Show LDP Information
+====================
+
+These commands dump various parts of *ldpd*.
+
+.. index:: show mpls ldp neighbor [A.B.C.D]
+.. clicmd:: show mpls ldp neighbor [A.B.C.D]
+
+   This command dumps the various neighbors discovered. Below example shows that
+   local machine has an operation neighbor with ID set to 1.1.1.1.
+
+   ::
+
+      west-vm# show mpls ldp neighbor
+      AF   ID              State       Remote Address    Uptime
+      ipv4 1.1.1.1         OPERATIONAL 1.1.1.1         00:01:37
+      west-vm#
+
+.. index:: show mpls ldp neighbor [A.B.C.D] capabilities
+.. clicmd:: show mpls ldp neighbor [A.B.C.D] capabilities
+
+.. index:: show mpls ldp neighbor [A.B.C.D] detail
+.. clicmd:: show mpls ldp neighbor [A.B.C.D] detail
+
+   Above commands dump other neighbor information.
+
+.. index:: show mpls ldp discovery [detail]
+.. clicmd:: show mpls ldp discovery [detail]
+
+.. index:: show mpls ldp ipv4 discovery [detail]
+.. clicmd:: show mpls ldp ipv4 discovery [detail]
+
+.. index:: show mpls ldp ipv6 discovery [detail]
+.. clicmd:: show mpls ldp ipv6 discovery [detail]
+
+   Above commands dump discovery information.
+
+.. index:: show mpls ldp ipv4 interface
+.. clicmd:: show mpls ldp ipv4 interface
+
+.. index:: show mpls ldp ipv6 interface
+.. clicmd:: show mpls ldp ipv6 interface
+
+   Above command dumps the IPv4 or IPv6 interface per where LDP is enabled.
+   Below output illustrates what is dumped for IPv4.
+
+   ::
+
+      west-vm# show mpls ldp ipv4 interface
+      AF   Interface   State  Uptime   Hello Timers  ac
+      ipv4 eth1       ACTIVE 00:08:35 5/15           0
+      ipv4 eth3       ACTIVE 00:08:35 5/15           1
+
+
+.. index:: show mpls ldp ipv4|ipv6 binding
+.. clicmd:: show mpls ldp ipv4|ipv6 binding
+
+   Above command dumps the binding obtained through MPLS exchanges with LDP.
+
+   ::
+
+      west-vm# show mpls ldp ipv4 binding
+      AF   Destination          Nexthop         Local Label Remote Label  In Use
+      ipv4 1.1.1.1/32           1.1.1.1         16          imp-null         yes
+      ipv4 2.2.2.2/32           1.1.1.1         imp-null    16                no
+      ipv4 10.0.2.0/24          1.1.1.1         imp-null    imp-null          no
+      ipv4 10.115.0.0/24        1.1.1.1         imp-null    17                no
+      ipv4 10.135.0.0/24        1.1.1.1         imp-null    imp-null          no
+      ipv4 10.200.0.0/24        1.1.1.1         17          imp-null         yes
+      west-vm#
+
+LDP debugging commands
+========================
+
+.. index::
+   simple: debug mpls ldp KIND
+   simple: no debug mpls ldp KIND
+
+.. clicmd:: [no] debug mpls ldp KIND
+
+   Enable or disable debugging messages of a given kind. ``KIND`` can
+   be one of:
+
+   - ``discovery``
+   - ``errors``
+   - ``event``
+   - ``labels``
+   - ``messages``
+   - ``zebra``
+
+LDP Example Configuration
+=========================
+
+Below configuration gives a typical MPLS configuration of a device located in a
+MPLS backbone. LDP is enabled on two interfaces and will attempt to peer with
+two neighbors with router-id set to either 1.1.1.1 or 3.3.3.3.
+
+.. code-block:: frr
+
+   mpls ldp
+    router-id 2.2.2.2
+    neighbor 1.1.1.1 password test
+    neighbor 3.3.3.3 password test
+    !
+    address-family ipv4
+     discovery transport-address 2.2.2.2
+     !
+     interface eth1
+     !
+     interface eth3
+     !
+    exit-address-family
+    !
+
+
+Deploying LDP across a backbone generally is done in a full mesh configuration
+topology. LDP is typically deployed with an IGP like OSPF, that helps discover
+the remote IPs. Below example is an OSPF configuration extract that goes with
+LDP configuration
+
+.. code-block:: frr
+
+   router ospf
+    ospf router-id 2.2.2.2
+     network 0.0.0.0/0 area 0
+    !
+
+
+Below output shows the routing entry on the LER side. The OSPF routing entry
+(10.200.0.0) is associated with Label entry (17), and shows that MPLS push action
+that traffic to that destination will be applied.
+
+::
+
+   north-vm# show ip route
+   Codes: K - kernel route, C - connected, S - static, R - RIP,
+          O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,
+          T - Table, v - VNC, V - VNC-Direct, A - Babel, D - SHARP,
+          F - PBR,
+          > - selected route, * - FIB route
+
+   O>* 1.1.1.1/32 [110/120] via 10.115.0.1, eth2, label 16, 00:00:15
+   O>* 2.2.2.2/32 [110/20] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+   O   3.3.3.3/32 [110/10] via 0.0.0.0, loopback1 onlink, 00:01:19
+   C>* 3.3.3.3/32 is directly connected, loopback1, 00:01:29
+   O>* 10.0.2.0/24 [110/11] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+   O   10.100.0.0/24 [110/10] is directly connected, eth1, 00:00:32
+   C>* 10.100.0.0/24 is directly connected, eth1, 00:00:32
+   O   10.115.0.0/24 [110/10] is directly connected, eth2, 00:00:25
+   C>* 10.115.0.0/24 is directly connected, eth2, 00:00:32
+   O>* 10.135.0.0/24 [110/110] via 10.115.0.1, eth2, label implicit-null, 00:00:15
+   O>* 10.200.0.0/24 [110/210] via 10.115.0.1, eth2, label 17, 00:00:15
+   north-vm#
+
index 6c86582960365e956e8e6f741e9e1ebb1d9b5dda..d77a3e7e9351bd1b0775d1a7103859d2be82586b 100644 (file)
@@ -861,6 +861,7 @@ ldp_vty_init (void)
        install_element(LDP_IPV6_NODE, &ldp_label_remote_accept_cmd);
        install_element(LDP_IPV6_NODE, &ldp_ttl_security_disable_cmd);
        install_element(LDP_IPV6_NODE, &ldp_interface_cmd);
+       install_element(LDP_IPV6_NODE, &no_ldp_interface_cmd);
        install_element(LDP_IPV6_NODE, &ldp_session_holdtime_cmd);
        install_element(LDP_IPV6_NODE, &ldp_neighbor_ipv6_targeted_cmd);
        install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd);
index 10a1723010ba4e4c893bbacc21ac5c299f131f1a..49419b3df33921eb225d375c1205789e9f520333 100644 (file)
@@ -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;
index 2743f34cb4fd2f57934f7ac3f3c0d461c30c3b95..8943b434d79af3dcff3e44903539389595deb587 100644 (file)
@@ -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;
 
index 57e62e4f6ee5cc9963ce6ab5ee8e719bc5abb6b2..e40bae3a3e475f37a271d21f988ae2106a938984 100644 (file)
@@ -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);
 
 /*
index ec84c4c622720f67f15cb18e3e4779aa5aa49e6f..80841b6ac1d6d352904718302c6075b9eb60d38c 100644 (file)
@@ -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 */
 
@@ -594,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]) {
@@ -627,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);
                }
        }
 
@@ -2166,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);
 
@@ -2256,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(
@@ -2278,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);
        }
@@ -2412,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;
@@ -2435,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);
@@ -2447,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);
@@ -2473,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);
 }
 
 /*
index 1cba28496de8404b8ed8c1d2337cb93165ef2ddf..346699198f9b8c15f22f724da4fdeead4fec6e22 100644 (file)
@@ -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;
 }
index 9bf6bfa22f08d949d19879a43408b744315e49f4..71d48632c14a434ec50c4f5abe61a8f42b7f40ec 100644 (file)
@@ -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);
index a3b1c7d62e79db11103efad2b859e827edfacfc9..06d1b3618c97f3cc99159ddded5d96dc1e92132f 100644 (file)
@@ -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);
                }
index 34d115275102ddab077e868e43cbcbd4661e69b7..2732ef72edfd9e8408af0b0b532a81388102cb43 100644 (file)
@@ -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);
index 354126ca5d0f5db8dbde4615ebb5eccfee7f671b..e86967041b2e6daeb72466182093d7c2b0e74da7 100644 (file)
@@ -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;
 
index 4c90757d70489e02ac6c42d0cb60fc8685c8b5f1..725cc9229c8e16e551b718870495742a56692841 100644 (file)
@@ -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);