]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_evpn.c
Merge branch 'master' into evpn-symmetric-routing
[mirror_frr.git] / bgpd / bgp_evpn.c
index 1921a9553e10c64b2335f45627d805e7174df816..12cc425bd36e5d6d850db63c69ed2756a25a31c5 100644 (file)
@@ -687,7 +687,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
                attr->ecommunity = ecommunity_merge(attr->ecommunity, ecom);
 
        /* Add the export RTs for L3VNI - currently only supported for IPV4 host
-        * routes */
+        * routes
+        */
        if (afi == AFI_IP) {
                vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
                if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
@@ -956,7 +957,7 @@ static int evpn_route_is_sticky(struct bgp *bgp, struct bgp_node *rn)
 static int update_evpn_type5_route_entry(struct bgp *bgp_def,
                                         struct bgp *bgp_vrf, afi_t afi,
                                         safi_t safi, struct bgp_node *rn,
-                                        struct attr *attr)
+                                        struct attr *attr, int *route_changed)
 {
        struct attr *attr_new = NULL;
        struct bgp_info *ri = NULL;
@@ -964,7 +965,7 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
        struct bgp_info *local_ri = NULL;
        struct bgp_info *tmp_ri = NULL;
 
-
+       *route_changed = 0;
        /* locate the local route entry if any */
        for (tmp_ri = rn->info; tmp_ri; tmp_ri = tmp_ri->next) {
                if (tmp_ri->peer == bgp_def->peer_self
@@ -974,9 +975,13 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
        }
 
        /* create a new route entry if one doesnt exist.
-          Otherwise see if route attr has changed */
+          Otherwise see if route attr has changed
+        */
        if (!local_ri) {
 
+               /* route has changed as this is the first entry */
+               *route_changed = 1;
+
                /* Add (or update) attribute to hash. */
                attr_new = bgp_attr_intern(attr);
 
@@ -996,6 +1001,10 @@ static int update_evpn_type5_route_entry(struct bgp *bgp_def,
 
                tmp_ri = local_ri;
                if (!attrhash_cmp(tmp_ri->attr, attr)) {
+
+                       /* attribute changed */
+                       *route_changed = 1;
+
                        /* The attribute has changed. */
                        /* Add (or update) attribute to hash. */
                        attr_new = bgp_attr_intern(attr);
@@ -1023,6 +1032,7 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
        struct attr attr;
        struct bgp_node *rn = NULL;
        struct bgp *bgp_def = NULL;
+       int route_changed = 0;
 
        bgp_def = bgp_get_default();
        if (!bgp_def)
@@ -1048,11 +1058,13 @@ static int update_evpn_type5_route(struct bgp *bgp_vrf,
        /* create or update the route entry within the route node */
        update_evpn_type5_route_entry(bgp_def, bgp_vrf,
                                      afi, safi,
-                                     rn, &attr);
+                                     rn, &attr, &route_changed);
 
        /* schedule for processing and unlock node */
-       bgp_process(bgp_def, rn, afi, safi);
-       bgp_unlock_node(rn);
+       if (route_changed) {
+               bgp_process(bgp_def, rn, afi, safi);
+               bgp_unlock_node(rn);
+       }
 
        /* uninten temporary */
        aspath_unintern(&attr.aspath);
@@ -1194,7 +1206,9 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn,
        attr.mp_nexthop_global_in = vpn->originator_ip;
        attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
        attr.sticky = CHECK_FLAG(flags, ZEBRA_MAC_TYPE_STICKY) ? 1 : 0;
+  attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_PMSI_TUNNEL);
        bgpevpn_get_rmac(vpn, &attr.rmac);
+       vni2label(vpn->vni, &(attr.label));
 
        /* Set up RT and ENCAP extended community. */
        build_evpn_route_extcomm(vpn, &attr,
@@ -1684,7 +1698,10 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        char buf1[PREFIX_STRLEN];
 
        memset(pp, 0, sizeof(struct prefix));
-       ip_prefix_from_type2_prefix(evp, pp);
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+               ip_prefix_from_type2_prefix(evp, pp);
+       else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+               ip_prefix_from_type5_prefix(evp, pp);
 
        if (bgp_debug_zebra(NULL)) {
                zlog_debug("installing evpn prefix %s as ip prefix %s in vrf %s",
@@ -1841,7 +1858,10 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
        char buf1[PREFIX_STRLEN];
 
        memset(pp, 0, sizeof(struct prefix));
-       ip_prefix_from_type2_prefix(evp, pp);
+       if (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE)
+               ip_prefix_from_type2_prefix(evp, pp);
+       else if (evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+               ip_prefix_from_type5_prefix(evp, pp);
 
        if (bgp_debug_zebra(NULL)) {
                zlog_debug("uninstalling evpn prefix %s as ip prefix %s in vrf %s",
@@ -2095,7 +2115,8 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf,
                        struct prefix_evpn *evp = (struct prefix_evpn *)&rn->p;
 
                        /* if not mac-ip route skip this route */
-                       if (evp->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
+                       if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+                             evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
                                continue;
 
                        /* if not a mac+ip route skip this route */
@@ -2105,7 +2126,8 @@ static int install_uninstall_routes_for_vrf(struct bgp *bgp_vrf,
 
                        for (ri = rn->info; ri; ri = ri->next) {
                                /* Consider "valid" remote routes applicable for
-                                * this VRF. */
+                                * this VRF.
+                                */
                                if (!(CHECK_FLAG(ri->flags, BGP_INFO_VALID)
                                      && ri->type == ZEBRA_ROUTE_BGP
                                      && ri->sub_type == BGP_ROUTE_NORMAL))
@@ -2214,7 +2236,8 @@ static int install_uninstall_routes_for_vni(struct bgp *bgp,
 }
 
 /* Install any existing remote routes applicable for this VRF into VRF RIB. This
- * is invoked upon l3vni-add or l3vni import rt change */
+ * is invoked upon l3vni-add or l3vni import rt change
+ */
 static int install_routes_for_vrf(struct bgp *bgp_vrf)
 {
        install_uninstall_routes_for_vrf(bgp_vrf, 1);
@@ -2282,13 +2305,14 @@ static int install_uninstall_route_in_vrfs(struct bgp *bgp_def, afi_t afi,
        struct bgp *bgp_vrf;
        struct listnode *node, *nnode;
 
-       /* Only type-2 routes go into a VRF */
-       if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE))
+       /* Only type-2/type-5 routes go into a VRF */
+       if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+             evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
                return 0;
 
-       /* if not a mac+ip route skip this route */
-       if (!(IS_EVPN_PREFIX_IPADDR_V4(evp) ||
-             IS_EVPN_PREFIX_IPADDR_V6(evp)))
+       /* if it is type-2 route and not a mac+ip route skip this route */
+       if ((evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE) &&
+           !(IS_EVPN_PREFIX_IPADDR_V4(evp) || IS_EVPN_PREFIX_IPADDR_V6(evp)))
                return 0;
 
        for (ALL_LIST_ELEMENTS(vrfs, node, nnode, bgp_vrf)) {
@@ -2364,9 +2388,10 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
 
        assert(attr);
 
-       /* Only type-2 and type-3 routes go into a L2 VNI. */
+       /* Only type-2 and type-3 and type-5 are supported currently */
        if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
-             || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE))
+             || evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
+             || evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
                return 0;
 
        /* If we don't have Route Target, nothing much to do. */
@@ -2377,8 +2402,8 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
        if (!ecom || !ecom->size)
                return -1;
 
-       /* For each extended community RT, see which VNIs match and import
-        * the route into matching VNIs.
+       /* For each extended community RT, see which VNIs/VRFs match and import
+        * the route into matching VNIs/VRFs.
         */
        for (i = 0; i < ecom->size; i++) {
                u_char *pnt;
@@ -2397,22 +2422,26 @@ static int install_uninstall_evpn_route(struct bgp *bgp, afi_t afi, safi_t safi,
                if (sub_type != ECOMMUNITY_ROUTE_TARGET)
                        continue;
 
-               /* Import route into matching l2-vnis */
+               /* Import route into matching l2-vnis (type-2/type-3 routes go
+                * into l2vni table)
+                */
                irt = lookup_import_rt(bgp, eval);
                if (irt && irt->vnis)
                        install_uninstall_route_in_vnis(bgp, afi, safi, evp, ri,
                                                        irt->vnis, import);
 
-               /* Import route into matching l3-vnis (vrfs) */
+               /* Import route into matching l3-vnis (type-2/type-5 routes go
+                * into l3vni/vrf table)
+                */
                vrf_irt = lookup_vrf_import_rt(eval);
                if (vrf_irt && vrf_irt->vrfs)
                        install_uninstall_route_in_vrfs(bgp, afi, safi, evp, ri,
                                                        vrf_irt->vrfs, import);
 
-               /* Also check for non-exact match. In this, we mask out the AS
-                * and
-                * only check on the local-admin sub-field. This is to
-                * facilitate using
+               /* Also check for non-exact match. In this,
+                *  we mask out the AS and
+                * only check on the local-admin sub-field.
+                * This is to facilitate using
                 * VNI as the RT for EBGP peering too.
                 */
                irt = NULL;
@@ -2847,6 +2876,7 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
        /* Make EVPN prefix. */
        memset(&p, 0, sizeof(struct prefix_evpn));
        p.family = AF_EVPN;
+       p.prefixlen = EVPN_TYPE_5_ROUTE_PREFIXLEN;
        p.prefix.route_type = BGP_EVPN_IP_PREFIX_ROUTE;
 
        /* Additional information outside of prefix - ESI and GW IP */
@@ -2881,14 +2911,12 @@ static int process_type5_route(struct peer *peer, afi_t afi, safi_t safi,
                pfx += 4;
                memcpy(&evpn.gw_ip.ipv4, pfx, 4);
                pfx += 4;
-               p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV4;
        } else {
                SET_IPADDR_V6(&p.prefix.ip);
                memcpy(&p.prefix.ip.ipaddr_v6, pfx, 16);
                pfx += 16;
                memcpy(&evpn.gw_ip.ipv6, pfx, 16);
                pfx += 16;
-               p.prefixlen = PREFIX_LEN_ROUTE_TYPE_5_IPV6;
        }
 
        label_pnt = (mpls_label_t *)pfx;
@@ -2919,10 +2947,13 @@ static void evpn_mpattr_encode_type5(struct stream *s, struct prefix *p,
                return;
        p_evpn_p = &(p->u.prefix_evpn);
 
+       /* len denites the total len of IP and GW-IP in the route
+          IP and GW-IP have to be both ipv4 or ipv6
+        */
        if (IS_IPADDR_V4(&p_evpn_p->ip))
-               len = 8; /* ipv4 */
+               len = 8; /* IP and GWIP are both ipv4 */
        else
-               len = 32; /* ipv6 */
+               len = 32; /* IP and GWIP are both ipv6 */
        /* Prefix contains RD, ESI, EthTag, IP length, IP, GWIP and VNI */
        stream_putc(s, 8 + 10 + 4 + 1 + len + 3);
        stream_put(s, prd->val, 8);
@@ -3047,6 +3078,25 @@ static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
  * Public functions.
  */
 
+/* withdraw type-5 route corresponding to ip prefix */
+void bgp_evpn_withdraw_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+                                  afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       ret = delete_evpn_type5_route(bgp_vrf, &evp);
+       if (ret) {
+               zlog_err(
+                        "%u failed to delete type-5 route for prefix %s in vrf %s",
+                        bgp_vrf->vrf_id,
+                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        vrf_id_to_name(bgp_vrf->vrf_id));
+       }
+}
+
 /* withdraw all type-5 routes for an address family */
 void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
                                    afi_t afi, safi_t safi)
@@ -3058,21 +3108,37 @@ void bgp_evpn_withdraw_type5_routes(struct bgp *bgp_vrf,
                return;
 
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+               bgp_evpn_withdraw_type5_route(bgp_vrf, rn, afi, safi);
 
-               int ret = 0;
-               struct prefix_evpn evp;
-               char buf[PREFIX_STRLEN];
+}
 
-               build_type5_prefix_from_ip_prefix(&evp, &rn->p);
-               ret = delete_evpn_type5_route(bgp_vrf, &evp);
-               if (ret) {
-                       zlog_err(
-                                "%u failed to delete type-5 route for prefix %s in vrf %s",
-                                bgp_vrf->vrf_id,
-                                prefix2str(&rn->p, buf, sizeof(buf)),
-                                vrf_id_to_name(bgp_vrf->vrf_id));
-               }
+/* advertise ip prefix as type-5 route*/
+void bgp_evpn_advertise_type5_route(struct bgp *bgp_vrf, struct bgp_node *rn,
+                                   afi_t afi, safi_t safi)
+{
+       int ret = 0;
+       struct prefix_evpn evp;
+       char buf[PREFIX_STRLEN];
+
+       if (!advertise_type5_routes(bgp_vrf, afi))
+               return;
+
+       if (!rn->info)
+               return;
+
+       /* only advertise subnet routes as type-5 */
+       if (is_host_route(&rn->p))
+               return;
+
+       build_type5_prefix_from_ip_prefix(&evp, &rn->p);
+       ret = update_evpn_type5_route(bgp_vrf, &evp);
+       if (ret) {
+               zlog_err(
+                        "%u failed to create type-5 route for prefix %s in vrf %s",
+                        bgp_vrf->vrf_id,
+                        prefix2str(&rn->p, buf, sizeof(buf)),
+                        vrf_id_to_name(bgp_vrf->vrf_id));
        }
 }
 
@@ -3083,26 +3149,9 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf,
        struct bgp_table *table = NULL;
        struct bgp_node *rn = NULL;
 
-       if (!advertise_type5_routes(bgp_vrf, afi))
-               return;
-
        table = bgp_vrf->rib[afi][safi];
-       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn)) {
-
-               int ret = 0;
-               struct prefix_evpn evp;
-               char buf[PREFIX_STRLEN];
-
-               build_type5_prefix_from_ip_prefix(&evp, &rn->p);
-               ret = update_evpn_type5_route(bgp_vrf, &evp);
-               if (ret) {
-                       zlog_err(
-                                "%u failed to create type-5 route for prefix %s in vrf %s",
-                                bgp_vrf->vrf_id,
-                                prefix2str(&rn->p, buf, sizeof(buf)),
-                                vrf_id_to_name(bgp_vrf->vrf_id));
-               }
-       }
+       for (rn = bgp_table_top(table); rn; rn = bgp_route_next(rn))
+               bgp_evpn_advertise_type5_route(bgp_vrf, rn, afi, safi);
 }
 
 void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni,
@@ -3224,7 +3273,7 @@ void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
                list_delete_node(bgp_vrf->vrf_export_rtl, node_to_del);
 
        /* fall back to auto-generated RT if this was the last RT */
-       if (list_isempty(bgp_vrf->vrf_export_rtl)) {
+       if (bgp_vrf->vrf_export_rtl && list_isempty(bgp_vrf->vrf_export_rtl)) {
                UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
                evpn_auto_rt_export_add_for_vrf(bgp_vrf);
        }
@@ -3244,11 +3293,13 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
        if (withdraw) {
 
                /* delete and withdraw all the type-5 routes
-                  stored in the global table for this vrf */
+                  stored in the global table for this vrf
+                */
                withdraw_router_id_vrf(bgp);
 
                /* delete all the VNI routes (type-2/type-3) routes for all the
-                * L2-VNIs */
+                * L2-VNIs
+                */
                hash_iterate(bgp->vnihash,
                             (void (*)(struct hash_backet *,
                                       void *))withdraw_router_id_vni,
@@ -3256,11 +3307,13 @@ void bgp_evpn_handle_router_id_update(struct bgp *bgp, int withdraw)
        } else {
 
                /* advertise all routes in the vrf as type-5 routes with the new
-                * RD */
+                * RD
+                */
                update_router_id_vrf(bgp);
 
                /* advertise all the VNI routes (type-2/type-3) routes with the
-                * new RD*/
+                * new RD
+                */
                hash_iterate(bgp->vnihash,
                             (void (*)(struct hash_backet *,
                                       void *))update_router_id_vni,
@@ -4027,7 +4080,8 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni,
        as_t as = 0;
 
        /* get the default instamce - required to get the AS number for VRF
-        * auto-creation*/
+        * auto-creatio
+        */
        bgp_def = bgp_get_default();
        if (!bgp_def) {
                zlog_err("Cannot process L3VNI  %u ADD - default BGP instance not yet created",
@@ -4119,7 +4173,8 @@ int bgp_evpn_local_l3vni_del(vni_t l3vni,
        }
 
        /* unimport remote routes from VRF, if it is AUTO vrf bgp_delete will
-        * take care of uninstalling the routes from zebra */
+        * take care of uninstalling the routes from zebra
+        */
        if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_AUTO))
                uninstall_routes_for_vrf(bgp_vrf);
 
@@ -4308,13 +4363,10 @@ void bgp_evpn_cleanup(struct bgp *bgp)
        bgp->vnihash = NULL;
        if (bgp->vrf_import_rtl)
                list_delete_and_null(&bgp->vrf_import_rtl);
-       bgp->vrf_import_rtl = NULL;
        if (bgp->vrf_export_rtl)
                list_delete_and_null(&bgp->vrf_export_rtl);
-       bgp->vrf_export_rtl = NULL;
        if (bgp->l2vnis)
                list_delete_and_null(&bgp->l2vnis);
-       bgp->l2vnis = NULL;
        bf_release_index(bm->rd_idspace, bgp->vrf_rd_id);
 }