]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_evpn.c
Merge pull request #3409 from opensourcerouting/feature/cleanup-topotest-docker-docs
[mirror_frr.git] / bgpd / bgp_evpn.c
index 9e71f1855c1a5941a46e52e6649474bc18a8ba64..7be79377866a7f82824434a3e23f055efbb73f27 100644 (file)
@@ -47,6 +47,7 @@
 #include "bgpd/bgp_aspath.h"
 #include "bgpd/bgp_zebra.h"
 #include "bgpd/bgp_nexthop.h"
+#include "bgpd/bgp_addpath.h"
 
 /*
  * Definitions and external declarations.
@@ -70,16 +71,12 @@ static int delete_all_vni_routes(struct bgp *bgp, struct bgpevpn *vpn);
  */
 
 /* compare two IPV4 VTEP IPs */
-static int evpn_vtep_ip_cmp(const void *p1, const void *p2)
+static int evpn_vtep_ip_cmp(void *p1, void *p2)
 {
        const struct in_addr *ip1 = p1;
        const struct in_addr *ip2 = p2;
 
-       if (!ip1 && !ip2)
-               return 1;
-       if (!ip1 || !ip2)
-               return 0;
-       return (ip1->s_addr == ip2->s_addr);
+       return ip1->s_addr - ip2->s_addr;
 }
 
 /*
@@ -96,16 +93,16 @@ static unsigned int esi_hash_keymake(void *p)
 /*
  * Compare two ESIs.
  */
-static int esi_cmp(const void *p1, const void *p2)
+static bool esi_cmp(const void *p1, const void *p2)
 {
        const struct evpnes *pes1 = p1;
        const struct evpnes *pes2 = p2;
 
        if (pes1 == NULL && pes2 == NULL)
-               return 1;
+               return true;
 
        if (pes1 == NULL || pes2 == NULL)
-               return 0;
+               return false;
 
        return (memcmp(pes1->esi.val, pes2->esi.val, ESI_BYTES) == 0);
 }
@@ -122,18 +119,26 @@ static unsigned int vni_hash_key_make(void *p)
 /*
  * Comparison function for vni hash
  */
-static int vni_hash_cmp(const void *p1, const void *p2)
+static bool vni_hash_cmp(const void *p1, const void *p2)
 {
        const struct bgpevpn *vpn1 = p1;
        const struct bgpevpn *vpn2 = p2;
 
        if (!vpn1 && !vpn2)
-               return 1;
+               return true;
        if (!vpn1 || !vpn2)
-               return 0;
+               return false;
        return (vpn1->vni == vpn2->vni);
 }
 
+static int vni_list_cmp(void *p1, void *p2)
+{
+       const struct bgpevpn *vpn1 = p1;
+       const struct bgpevpn *vpn2 = p2;
+
+       return vpn1->vni - vpn2->vni;
+}
+
 /*
  * Make vrf import route target hash key.
  */
@@ -148,16 +153,16 @@ static unsigned int vrf_import_rt_hash_key_make(void *p)
 /*
  * Comparison function for vrf import rt hash
  */
-static int vrf_import_rt_hash_cmp(const void *p1, const void *p2)
+static bool vrf_import_rt_hash_cmp(const void *p1, const void *p2)
 {
        const struct vrf_irt_node *irt1 = p1;
        const struct vrf_irt_node *irt2 = p2;
 
        if (irt1 == NULL && irt2 == NULL)
-               return 1;
+               return true;
 
        if (irt1 == NULL || irt2 == NULL)
-               return 0;
+               return false;
 
        return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
 }
@@ -265,16 +270,16 @@ static unsigned int import_rt_hash_key_make(void *p)
 /*
  * Comparison function for import rt hash
  */
-static int import_rt_hash_cmp(const void *p1, const void *p2)
+static bool import_rt_hash_cmp(const void *p1, const void *p2)
 {
        const struct irt_node *irt1 = p1;
        const struct irt_node *irt2 = p2;
 
        if (irt1 == NULL && irt2 == NULL)
-               return 1;
+               return true;
 
        if (irt1 == NULL || irt2 == NULL)
-               return 0;
+               return false;
 
        return (memcmp(irt1->rt.val, irt2->rt.val, ECOMMUNITY_SIZE) == 0);
 }
@@ -554,9 +559,12 @@ static int bgp_zebra_send_remote_macip(struct bgp *bgp, struct bgpevpn *vpn,
                return 0;
 
        /* Don't try to register if Zebra doesn't know of this instance. */
-       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("%s: No zebra instance to talk to, not installing remote macip",
+                                  __PRETTY_FUNCTION__);
                return 0;
-
+       }
        s = zclient->obuf;
        stream_reset(s);
 
@@ -612,8 +620,12 @@ static int bgp_zebra_send_remote_vtep(struct bgp *bgp, struct bgpevpn *vpn,
                return 0;
 
        /* Don't try to register if Zebra doesn't know of this instance. */
-       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
+       if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp)) {
+               if (BGP_DEBUG(zebra, ZEBRA))
+                       zlog_debug("%s: No zebra instance to talk to, not installing remote vtep",
+                                  __PRETTY_FUNCTION__);
                return 0;
+       }
 
        s = zclient->obuf;
        stream_reset(s);
@@ -1048,7 +1060,7 @@ static int evpn_es_route_select_install(struct bgp *bgp,
            && old_select->sub_type == BGP_ROUTE_IMPORTED
            && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
            && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
-           && !bgp->addpath_tx_used[afi][safi]) {
+           && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
                if (bgp_zebra_has_route_changed(rn, old_select)) {
                        ret = evpn_es_install_vtep(bgp, es,
                                                   (struct prefix_evpn *)&rn->p,
@@ -1131,7 +1143,7 @@ static int evpn_route_select_install(struct bgp *bgp, struct bgpevpn *vpn,
            && old_select->sub_type == BGP_ROUTE_IMPORTED
            && !CHECK_FLAG(rn->flags, BGP_NODE_USER_CLEAR)
            && !CHECK_FLAG(old_select->flags, BGP_PATH_ATTR_CHANGED)
-           && !bgp->addpath_tx_used[afi][safi]) {
+           && !bgp_addpath_is_addpath_used(&bgp->tx_addpath, afi, safi)) {
                if (bgp_zebra_has_route_changed(rn, old_select)) {
                        if (old_select->attr->sticky)
                                SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
@@ -1445,7 +1457,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
        }
 
        /*
-        * create a new route entry if one doesnt exist.
+        * create a new route entry if one doesn't exist.
         * Otherwise see if route attr has changed
         */
        if (!local_pi) {
@@ -1681,6 +1693,58 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn,
        return route_change;
 }
 
+/*
+ * If the local route was not selected evict it and tell zebra to re-add
+ * the best remote dest.
+ *
+ * Typically a local path added by zebra is expected to be selected as
+ * best. In which case when a remote path wins as best (later)
+ * evpn_route_select_install itself evicts the older-local-best path.
+ *
+ * However if bgp's add and zebra's add cross paths (race condition) it
+ * is possible that the local path is no longer the "older" best path.
+ * It is a path that was never designated as best and hence requires
+ * additional handling to prevent bgp from injecting and holding on to a
+ * non-best local path.
+ */
+static void evpn_cleanup_local_non_best_route(struct bgp *bgp,
+                                             struct bgpevpn *vpn,
+                                             struct bgp_node *rn,
+                                             struct bgp_path_info *local_pi)
+{
+       struct bgp_path_info *tmp_pi;
+       struct bgp_path_info *curr_select = NULL;
+       uint8_t flags = 0;
+       char buf[PREFIX_STRLEN];
+
+       /* local path was not picked as the winner; kick it out */
+       if (bgp_debug_zebra(NULL)) {
+               zlog_debug("evicting local evpn prefix %s as remote won",
+                                       prefix2str(&rn->p, buf, sizeof(buf)));
+       }
+       evpn_delete_old_local_route(bgp, vpn, rn, local_pi);
+       bgp_path_info_reap(rn, local_pi);
+
+       /* tell zebra to re-add the best remote path */
+       for (tmp_pi = rn->info; tmp_pi; tmp_pi = tmp_pi->next) {
+               if (CHECK_FLAG(tmp_pi->flags, BGP_PATH_SELECTED)) {
+                       curr_select = tmp_pi;
+                       break;
+               }
+       }
+       if (curr_select &&
+           curr_select->type == ZEBRA_ROUTE_BGP
+           && curr_select->sub_type == BGP_ROUTE_IMPORTED) {
+               if (curr_select->attr->sticky)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY);
+               if (curr_select->attr->default_gw)
+                       SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW);
+               evpn_zebra_install(bgp, vpn, (struct prefix_evpn *)&rn->p,
+                                  curr_select->attr->nexthop, flags,
+                                  mac_mobility_seqnum(curr_select->attr));
+       }
+}
+
 /*
  * Create or update EVPN route (of type based on prefix) for specified VNI
  * and schedule for processing.
@@ -1743,10 +1807,23 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        assert(pi);
        attr_new = pi->attr;
 
+       /* lock ri to prevent freeing in evpn_route_select_install */
+       bgp_path_info_lock(pi);
        /* Perform route selection; this is just to set the flags correctly
         * as local route in the VNI always wins.
         */
        evpn_route_select_install(bgp, vpn, rn);
+       /*
+        * If the new local route was not selected evict it and tell zebra
+        * to re-add the best remote dest. BGP doesn't retain non-best local
+        * routes.
+        */
+       if (!CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
+               route_change = 0;
+               evpn_cleanup_local_non_best_route(bgp, vpn, rn, pi);
+       }
+       bgp_path_info_unlock(pi);
+
        bgp_unlock_node(rn);
 
        /* If this is a new route or some attribute has changed, export the
@@ -1917,8 +1994,10 @@ static int delete_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        /* Delete route entry in the VNI route table. This can just be removed.
         */
        delete_evpn_route_entry(bgp, afi, safi, rn, &pi);
-       if (pi)
+       if (pi) {
                bgp_path_info_reap(rn, pi);
+               evpn_route_select_install(bgp, vpn, rn);
+       }
        bgp_unlock_node(rn);
 
        return 0;
@@ -3317,10 +3396,20 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
  */
 static void delete_withdraw_vrf_routes(struct bgp *bgp_vrf)
 {
+       /* Delete ipv4 default route and withdraw from peers */
+       if (evpn_default_originate_set(bgp_vrf, AFI_IP, SAFI_UNICAST))
+               bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP,
+                                                        SAFI_UNICAST, false);
+
        /* delete all ipv4 routes and withdraw from peers */
        if (advertise_type5_routes(bgp_vrf, AFI_IP))
                bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
 
+       /* Delete ipv6 default route and withdraw from peers */
+       if (evpn_default_originate_set(bgp_vrf, AFI_IP6, SAFI_UNICAST))
+               bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP6,
+                                                        SAFI_UNICAST, false);
+
        /* delete all ipv6 routes and withdraw from peers */
        if (advertise_type5_routes(bgp_vrf, AFI_IP6))
                bgp_evpn_withdraw_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
@@ -3336,9 +3425,20 @@ static void update_advertise_vrf_routes(struct bgp *bgp_vrf)
        if (advertise_type5_routes(bgp_vrf, AFI_IP))
                bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP, SAFI_UNICAST);
 
+       /* update ipv4 default route and withdraw from peers */
+       if (evpn_default_originate_set(bgp_vrf, AFI_IP, SAFI_UNICAST))
+               bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP,
+                                                        SAFI_UNICAST, true);
+
        /* update all ipv6 routes */
        if (advertise_type5_routes(bgp_vrf, AFI_IP6))
                bgp_evpn_advertise_type5_routes(bgp_vrf, AFI_IP6, SAFI_UNICAST);
+
+       /* update ipv6 default route and withdraw from peers */
+       if (evpn_default_originate_set(bgp_vrf, AFI_IP6, SAFI_UNICAST))
+               bgp_evpn_install_uninstall_default_route(bgp_vrf, AFI_IP6,
+                                                        SAFI_UNICAST, true);
+
 }
 
 /*
@@ -4139,6 +4239,28 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf, afi_t afi, safi_t safi)
        }
 }
 
+/*
+ * evpn - enable advertisement of default g/w
+ */
+void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf, afi_t afi,
+                                             safi_t safi, bool add)
+{
+       struct prefix ip_prefix;
+
+       /* form the default prefix 0.0.0.0/0 */
+       memset(&ip_prefix, 0, sizeof(struct prefix));
+       ip_prefix.family = afi2family(afi);
+
+       if (add) {
+               bgp_evpn_advertise_type5_route(bgp_vrf, &ip_prefix,
+                                              NULL, afi, safi);
+       } else {
+               bgp_evpn_withdraw_type5_route(bgp_vrf, &ip_prefix,
+                                             afi, safi);
+       }
+}
+
+
 /*
  * Advertise IP prefix as type-5 route. The afi/safi and src_attr passed
  * to this function correspond to those of the source IP prefix (best
@@ -5065,7 +5187,7 @@ struct evpnes *bgp_evpn_es_new(struct bgp *bgp,
 
        /* Initialise the VTEP list */
        es->vtep_list = list_new();
-       es->vtep_list->cmp = (int (*)(void *, void *))evpn_vtep_ip_cmp;
+       es->vtep_list->cmp = evpn_vtep_ip_cmp;
 
        /* auto derive RD for this es */
        bf_assign_index(bm->rd_idspace, es->rd_id);
@@ -5284,7 +5406,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id, struct ethaddr *rmac,
        }
        as = bgp_def->as;
 
-       /* if the BGP vrf instance doesnt exist - create one */
+       /* if the BGP vrf instance doesn't exist - create one */
        bgp_vrf = bgp_lookup_by_name(vrf_id_to_name(vrf_id));
        if (!bgp_vrf) {
 
@@ -5722,7 +5844,22 @@ void bgp_evpn_init(struct bgp *bgp)
                (int (*)(void *, void *))evpn_route_target_cmp;
        bgp->vrf_export_rtl->del = evpn_xxport_delete_ecomm;
        bgp->l2vnis = list_new();
-       bgp->l2vnis->cmp = (int (*)(void *, void *))vni_hash_cmp;
+       bgp->l2vnis->cmp = vni_list_cmp;
+       /* By default Duplicate Address Dection is enabled.
+        * Max-moves (N) 5, detection time (M) 180
+        * default action is warning-only
+        * freeze action permanently freezes address,
+        * and freeze time (auto-recovery) is disabled.
+        */
+       if (bgp->evpn_info) {
+               bgp->evpn_info->dup_addr_detect = true;
+               bgp->evpn_info->dad_time = EVPN_DAD_DEFAULT_TIME;
+               bgp->evpn_info->dad_max_moves = EVPN_DAD_DEFAULT_MAX_MOVES;
+               bgp->evpn_info->dad_freeze = false;
+               bgp->evpn_info->dad_freeze_time = 0;
+               /* Initialize zebra vxlan */
+               bgp_zebra_dup_addr_detection(bgp);
+       }
 
        /* Default BUM handling is to do head-end replication. */
        bgp->vxlan_flood_ctrl = VXLAN_FLOOD_HEAD_END_REPL;