]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: evpn pip data struct and cli
authorChirag Shah <chirag@cumulusnetworks.com>
Thu, 18 Apr 2019 07:17:57 +0000 (10:17 +0300)
committerChirag Shah <chirag@cumulusnetworks.com>
Fri, 22 Nov 2019 15:53:28 +0000 (07:53 -0800)
Evpn Primary IP advertisement feature uses
individual system IP and system MAC for prefix (type-5)
and self type-2 routes.

The PIP knob is enabled by default for bgp vrf instance.

Configuration CLI for enable/disable PIP feature knob.
User can configure PIP system IP and MAC to retain as
permanent values.

For the PIP IP, the default behavior is to accept bgp default
instance's router-id. When the default instance router-id change,
reflect PIP IP assignment.

Reflect type-5 to use system-IP and system MAC as nexthop and RMAC
values.

Ticket:CM-26190

Signed-off-by: Chirag Shah <chirag@cumulusnetworks.com>
bgpd/bgp_evpn.c
bgpd/bgp_evpn.h
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c

index f3c514fb15f659f0cfce470eccc5cff41058d051..5824a1cb56c049b8d73fbef1876acb00e1ab00e2 100644 (file)
@@ -1543,11 +1543,44 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf, struct prefix_evpn *evp,
                memset(&attr, 0, sizeof(struct attr));
                bgp_attr_default_set(&attr, BGP_ORIGIN_IGP);
        }
-       /* Set nexthop to ourselves and fill in the Router MAC. */
-       attr.nexthop = bgp_vrf->originator_ip;
-       attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
+
+       /* copy sys rmac */
+       memcpy(&attr.rmac, &bgp_vrf->evpn_info->pip_rmac, ETH_ALEN);
+       /* Advertise Primary IP (PIP) is enabled, send individual
+        * IP (default instance router-id) as nexthop.
+        * PIP is disabled or vrr interface is not present
+        * use anycast-IP as nexthop.
+        */
+       if (!bgp_vrf->evpn_info->advertise_pip ||
+           (!bgp_vrf->evpn_info->is_anycast_mac)) {
+               attr.nexthop = bgp_vrf->originator_ip;
+               attr.mp_nexthop_global_in = bgp_vrf->originator_ip;
+       } else {
+               if (bgp_vrf->evpn_info->pip_ip.s_addr != INADDR_ANY) {
+                       attr.nexthop = bgp_vrf->evpn_info->pip_ip;
+                       attr.mp_nexthop_global_in = bgp_vrf->evpn_info->pip_ip;
+               } else if (bgp_vrf->evpn_info->pip_ip.s_addr == INADDR_ANY)
+                       if (bgp_debug_zebra(NULL)) {
+                               char buf1[PREFIX_STRLEN];
+
+                               zlog_debug("VRF %s evp %s advertise-pip primary ip is not configured",
+                                          vrf_id_to_name(bgp_vrf->vrf_id),
+                                          prefix2str(evp, buf1, sizeof(buf1)));
+                       }
+       }
+
+       if (bgp_debug_zebra(NULL)) {
+               char buf[ETHER_ADDR_STRLEN];
+               char buf1[PREFIX_STRLEN];
+
+               zlog_debug("VRF %s type-5 route evp %s RMAC %s nexthop %s",
+                          vrf_id_to_name(bgp_vrf->vrf_id),
+                          prefix2str(evp, buf1, sizeof(buf1)),
+                          prefix_mac2str(&attr.rmac, buf, sizeof(buf)),
+                          inet_ntoa(attr.nexthop));
+       }
+
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
-       memcpy(&attr.rmac, &bgp_vrf->rmac, sizeof(struct ethaddr));
 
        /* Setup RT and encap extended community */
        build_evpn_type5_route_extcomm(bgp_vrf, &attr);
@@ -3527,8 +3560,14 @@ static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
  * update and advertise all ipv4 and ipv6 routes in thr vrf table as type-5
  * routes
  */
-static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
+void update_advertise_vrf_routes(struct bgp *bgp_vrf)
 {
+       struct bgp *bgp_evpn = NULL; /* EVPN bgp instance */
+
+       bgp_evpn = bgp_get_evpn();
+       if (!bgp_evpn)
+               return;
+
        /* update all ipv4 routes */
        if (advertise_type5_routes(bgp_vrf, AFI_IP))
                bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
@@ -4586,6 +4625,9 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
  */
 void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
 {
+       struct listnode *node;
+       struct bgp *bgp_vrf;
+
        if (withdraw) {
 
                /* delete and withdraw all the type-5 routes
@@ -4600,8 +4642,34 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
                             (void (*)(struct hash_bucket *,
                                       void *))withdraw_router_id_vni,
                             bgp);
+
+               if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+                       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+                               if (bgp_vrf->evpn_info->advertise_pip &&
+                                   (bgp_vrf->evpn_info->pip_ip_static.s_addr
+                                    == INADDR_ANY))
+                                       bgp_vrf->evpn_info->pip_ip.s_addr
+                                               = INADDR_ANY;
+                       }
+               }
        } else {
 
+               /* Assign new default instance router-id */
+               if (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
+                       for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp_vrf)) {
+                               if (bgp_vrf->evpn_info->advertise_pip &&
+                                   (bgp_vrf->evpn_info->pip_ip_static.s_addr
+                                    == INADDR_ANY)) {
+                                       bgp_vrf->evpn_info->pip_ip =
+                                               bgp->router_id;
+                                       /* advertise type-5 routes with
+                                        * new nexthop
+                                        */
+                                       update_advertise_vrf_routes(bgp_vrf);
+                               }
+                       }
+               }
+
                /* advertise all routes in the vrf as type-5 routes with the new
                 * RD
                 */
@@ -6005,6 +6073,15 @@ void bgp_evpn_init(struct bgp *bgp)
                bgp->evpn_info->dad_freeze_time = 0;
                /* Initialize zebra vxlan */
                bgp_zebra_dup_addr_detection(bgp);
+               /* Enable PIP feature by default for bgp vrf instance */
+               if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+                       struct bgp *bgp_default;
+
+                       bgp->evpn_info->advertise_pip = true;
+                       bgp_default = bgp_get_default();
+                       if (bgp_default)
+                               bgp->evpn_info->pip_ip = bgp_default->router_id;
+               }
        }
 
        /* Default BUM handling is to do head-end replication. */
index 798c3e59bcba193beacbc5b69a4880d59f43a8a4..f9927067e538ea0133e7ba0443a9387a773a4f90 100644 (file)
@@ -192,5 +192,6 @@ extern void bgp_evpn_cleanup(struct bgp *bgp);
 extern void bgp_evpn_init(struct bgp *bgp);
 extern int bgp_evpn_get_type5_prefixlen(struct prefix *pfx);
 extern bool bgp_evpn_is_prefix_nht_supported(struct prefix *pfx);
+extern void update_advertise_vrf_routes(struct bgp *bgp_vrf);
 
 #endif /* _QUAGGA_BGP_EVPN_H */
index f6bde2e9fa3c837c9b195f68ac272b45475cc566..a0c05e34f8cf71bbd402df7046b286b76b92dead 100644 (file)
@@ -188,6 +188,16 @@ struct bgp_evpn_info {
        /* EVPN enable - advertise svi macip routes */
        int advertise_svi_macip;
 
+       /* PIP feature knob */
+       bool advertise_pip;
+       /* PIP IP (sys ip) */
+       struct in_addr pip_ip;
+       struct in_addr pip_ip_static;
+       /* PIP MAC (sys MAC) */
+       struct ethaddr pip_rmac;
+       struct ethaddr pip_rmac_static;
+       struct ethaddr pip_rmac_zebra;
+       bool is_anycast_mac;
 };
 
 static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
index 3bc8345140381b86170948ea82ca33aabe3ec68d..882716cf37bd3aa5a8e8624327c65b6b1f7915f4 100644 (file)
@@ -3650,6 +3650,129 @@ DEFUN (no_bgp_evpn_advertise_type5,
        return CMD_SUCCESS;
 }
 
+DEFPY (bgp_evpn_advertise_pip_ip_mac,
+       bgp_evpn_advertise_pip_ip_mac_cmd,
+       "[no$no] advertise-pip [ip <A.B.C.D> [mac <X:X:X:X:X:X|X:X:X:X:X:X/M>]]",
+       NO_STR
+       "evpn system primary IP\n"
+       IP_STR
+       "ip address\n"
+       MAC_STR MAC_STR MAC_STR)
+{
+       struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
+       struct bgp *bgp_evpn = NULL;
+
+       if (EVPN_ENABLED(bgp_vrf)) {
+               vty_out(vty,
+                       "This command is supported under L3VNI BGP EVPN VRF\n");
+               return CMD_WARNING;
+       }
+       bgp_evpn = bgp_get_evpn();
+
+       if (!no) {
+               /* pip is already enabled */
+               if (argc == 1 && bgp_vrf->evpn_info->advertise_pip)
+                       return CMD_SUCCESS;
+
+               bgp_vrf->evpn_info->advertise_pip = true;
+               if (ip.s_addr != INADDR_ANY) {
+                       /* Already configured with same IP */
+                       if (IPV4_ADDR_SAME(&ip,
+                                       &bgp_vrf->evpn_info->pip_ip_static))
+                               return CMD_SUCCESS;
+
+                       bgp_vrf->evpn_info->pip_ip_static = ip;
+                       bgp_vrf->evpn_info->pip_ip = ip;
+               } else {
+                       bgp_vrf->evpn_info->pip_ip_static.s_addr
+                               = INADDR_ANY;
+                       /* default instance router-id assignemt */
+                       if (bgp_evpn)
+                               bgp_vrf->evpn_info->pip_ip =
+                                       bgp_evpn->router_id;
+               }
+               /* parse sys mac */
+               if (!is_zero_mac(&mac->eth_addr)) {
+                       /* Already configured with same MAC */
+                       if (memcmp(&bgp_vrf->evpn_info->pip_rmac_static,
+                                  &mac->eth_addr, ETH_ALEN) == 0)
+                               return CMD_SUCCESS;
+
+                       memcpy(&bgp_vrf->evpn_info->pip_rmac_static,
+                              &mac->eth_addr, ETH_ALEN);
+                       memcpy(&bgp_vrf->evpn_info->pip_rmac,
+                              &bgp_vrf->evpn_info->pip_rmac_static,
+                              ETH_ALEN);
+               } else {
+                       /* Copy zebra sys mac */
+                       if (!is_zero_mac(&bgp_vrf->evpn_info->pip_rmac_zebra))
+                               memcpy(&bgp_vrf->evpn_info->pip_rmac,
+                                      &bgp_vrf->evpn_info->pip_rmac_zebra,
+                                      ETH_ALEN);
+               }
+       } else {
+               if (argc == 2) {
+                       if (!bgp_vrf->evpn_info->advertise_pip)
+                               return CMD_SUCCESS;
+                       /* Disable PIP feature */
+                       bgp_vrf->evpn_info->advertise_pip = false;
+                       /* copy anycast mac */
+                       memcpy(&bgp_vrf->evpn_info->pip_rmac,
+                              &bgp_vrf->rmac, ETH_ALEN);
+               } else {
+                       /* remove MAC-IP option retain PIP knob. */
+                       if ((ip.s_addr != INADDR_ANY) &&
+                           !IPV4_ADDR_SAME(&ip,
+                                       &bgp_vrf->evpn_info->pip_ip_static)) {
+                               vty_out(vty,
+                                       "%% BGP EVPN PIP IP does not match\n");
+                               return CMD_WARNING_CONFIG_FAILED;
+                       }
+
+                       if (!is_zero_mac(&mac->eth_addr) &&
+                           memcmp(&bgp_vrf->evpn_info->pip_rmac_static,
+                                  &mac->eth_addr, ETH_ALEN) != 0) {
+                               vty_out(vty,
+                                       "%% BGP EVPN PIP MAC does not match\n");
+                               return CMD_WARNING_CONFIG_FAILED;
+                       }
+                       /* pip_rmac can carry vrr_rmac reset only if it matches
+                        * with static value.
+                        */
+                       if (memcmp(&bgp_vrf->evpn_info->pip_rmac,
+                                  &bgp_vrf->evpn_info->pip_rmac_static,
+                                  ETH_ALEN) == 0) {
+                               /* Copy zebra sys mac */
+                               if (!is_zero_mac(
+                                       &bgp_vrf->evpn_info->pip_rmac_zebra))
+                                       memcpy(&bgp_vrf->evpn_info->pip_rmac,
+                                       &bgp_vrf->evpn_info->pip_rmac_zebra,
+                                              ETH_ALEN);
+                               else {
+                                       /* copy anycast mac */
+                                       memcpy(&bgp_vrf->evpn_info->pip_rmac,
+                                              &bgp_vrf->rmac, ETH_ALEN);
+                               }
+                       }
+               }
+               /* reset user configured sys MAC */
+               memset(&bgp_vrf->evpn_info->pip_rmac_static, 0, ETH_ALEN);
+               /* reset user configured sys IP */
+               bgp_vrf->evpn_info->pip_ip_static.s_addr = INADDR_ANY;
+               /* Assign default PIP IP (bgp instance router-id) */
+               if (bgp_evpn)
+                       bgp_vrf->evpn_info->pip_ip = bgp_evpn->router_id;
+               else
+                       bgp_vrf->evpn_info->pip_ip.s_addr = INADDR_ANY;
+       }
+
+       if (is_evpn_enabled()) {
+               update_advertise_vrf_routes(bgp_vrf);
+       }
+
+       return CMD_SUCCESS;
+}
+
 /*
  * Display VNI information - for all or a specific VNI
  */
@@ -5457,6 +5580,23 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
                       BGP_L2VPN_EVPN_DEFAULT_ORIGINATE_IPV6))
                vty_out(vty, "  default-originate ipv6\n");
 
+       if (bgp->inst_type == BGP_INSTANCE_TYPE_VRF) {
+               if (!bgp->evpn_info->advertise_pip)
+                       vty_out(vty, "  no advertise-pip\n");
+               if (bgp->evpn_info->advertise_pip) {
+                       if (bgp->evpn_info->pip_ip_static.s_addr != INADDR_ANY)
+                               vty_out(vty, "  advertise-pip ip %s",
+                               inet_ntoa(bgp->evpn_info->pip_ip_static));
+                       if (!is_zero_mac(&(bgp->evpn_info->pip_rmac_static))) {
+                               char buf[ETHER_ADDR_STRLEN];
+
+                               vty_out(vty, " mac %s",
+                               prefix_mac2str(&bgp->evpn_info->pip_rmac,
+                                                      buf, sizeof(buf)));
+                       }
+                       vty_out(vty, "\n");
+               }
+       }
        if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_RD_CFGD))
                vty_out(vty, "  rd %s\n",
                        prefix_rd2str(&bgp->vrf_prd, buf1, sizeof(buf1)));
@@ -5527,6 +5667,7 @@ void bgp_ethernetvpn_init(void)
        install_element(BGP_EVPN_NODE, &dup_addr_detection_auto_recovery_cmd);
        install_element(BGP_EVPN_NODE, &no_dup_addr_detection_cmd);
        install_element(BGP_EVPN_NODE, &bgp_evpn_flood_control_cmd);
+       install_element(BGP_EVPN_NODE, &bgp_evpn_advertise_pip_ip_mac_cmd);
 
        /* test commands */
        install_element(BGP_EVPN_NODE, &test_adv_evpn_type4_route_cmd);