]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_mplsvpn.c
bgpd: Replace bgp_flag_* to [UN]SET/CHECK_FLAG macros
[mirror_frr.git] / bgpd / bgp_mplsvpn.c
index 355bc93320f1e110f1f2df0695f0f729151306ba..86c04b71f07429b0eea345a2a913525fa8ab3ebf 100644 (file)
@@ -109,7 +109,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
        uint16_t type;
        struct rd_as rd_as;
        struct rd_ip rd_ip;
-       struct prefix_rd prd;
+       struct prefix_rd prd = {0};
        mpls_label_t label = {0};
        afi_t afi;
        safi_t safi;
@@ -142,7 +142,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr,
                        if (pnt + BGP_ADDPATH_ID_LEN > lim)
                                return BGP_NLRI_PARSE_ERROR_PACKET_OVERFLOW;
 
-                       addpath_id = ntohl(*((uint32_t *)pnt));
+                       memcpy(&addpath_id, pnt, BGP_ADDPATH_ID_LEN);
+                       addpath_id = ntohl(addpath_id);
                        pnt += BGP_ADDPATH_ID_LEN;
                }
 
@@ -699,7 +700,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,      /* to */
                return;
        }
 
-       bgp_attr_dup(&static_attr, path_vrf->attr); /* shallow copy */
+       /* shallow copy */
+       static_attr = *path_vrf->attr;
 
        /*
         * route map handling
@@ -781,12 +783,12 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,            /* to */
                        static_attr.nexthop.s_addr = nexthop->u.prefix4.s_addr;
 
                        static_attr.mp_nexthop_global_in = nexthop->u.prefix4;
-                       static_attr.mp_nexthop_len = 4;
+                       static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
                        break;
 
                case AF_INET6:
                        static_attr.mp_nexthop_global = nexthop->u.prefix6;
-                       static_attr.mp_nexthop_len = 16;
+                       static_attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV6_GLOBAL;
                        break;
 
                default:
@@ -802,7 +804,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,      /* to */
                                 */
                                static_attr.mp_nexthop_global_in =
                                        static_attr.nexthop;
-                               static_attr.mp_nexthop_len = 4;
+                               static_attr.mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_IPV4;
                                /*
                                 * XXX Leave static_attr.nexthop
                                 * intact for NHT
@@ -821,7 +824,8 @@ void vpn_leak_from_vrf_update(struct bgp *bgp_vpn,      /* to */
                            && !BGP_ATTR_NEXTHOP_AFI_IP6(path_vrf->attr)) {
                                static_attr.mp_nexthop_global_in.s_addr =
                                        static_attr.nexthop.s_addr;
-                               static_attr.mp_nexthop_len = 4;
+                               static_attr.mp_nexthop_len =
+                                       BGP_ATTR_NHLEN_IPV4;
                                static_attr.flag |=
                                        ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP);
                        }
@@ -1080,7 +1084,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf,            /* to */
                                buf_prefix, bgp_vrf->name_pretty);
        }
 
-       bgp_attr_dup(&static_attr, path_vpn->attr); /* shallow copy */
+       /* shallow copy */
+       static_attr = *path_vpn->attr;
 
        /*
         * Nexthop: stash and clear
@@ -1614,11 +1619,13 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
 {
        const char *export_name;
        vpn_policy_direction_t idir, edir;
-       char *vname;
-       char buf[1000];
+       char *vname, *tmp_name;
+       char buf[RD_ADDRSTRLEN];
        struct ecommunity *ecom;
        bool first_export = false;
        int debug;
+       struct listnode *node;
+       bool is_inst_match = false;
 
        export_name = to_bgp->name ? to_bgp->name : VRF_DEFAULT_NAME;
        idir = BGP_VPN_POLICY_DIR_FROMVPN;
@@ -1634,13 +1641,41 @@ void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
        vname = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
                               : XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
 
-       listnode_add(to_bgp->vpn_policy[afi].import_vrf, vname);
+       /* Check the import_vrf list of destination vrf for the source vrf name,
+        * insert otherwise.
+        */
+       for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi].import_vrf,
+                                 node, tmp_name)) {
+               if (strcmp(vname, tmp_name) == 0) {
+                       is_inst_match = true;
+                       break;
+               }
+       }
+       if (!is_inst_match)
+               listnode_add(to_bgp->vpn_policy[afi].import_vrf,
+                                    vname);
 
-       if (!listcount(from_bgp->vpn_policy[afi].export_vrf))
-               first_export = true;
+       /* Check if the source vrf already exports to any vrf,
+        * first time export requires to setup auto derived RD/RT values.
+        * Add the destination vrf name to export vrf list if it is
+        * not present.
+        */
+       is_inst_match = false;
        vname = XSTRDUP(MTYPE_TMP, export_name);
-       listnode_add(from_bgp->vpn_policy[afi].export_vrf, vname);
-
+       if (!listcount(from_bgp->vpn_policy[afi].export_vrf)) {
+               first_export = true;
+       } else {
+               for (ALL_LIST_ELEMENTS_RO(from_bgp->vpn_policy[afi].export_vrf,
+                                         node, tmp_name)) {
+                       if (strcmp(vname, tmp_name) == 0) {
+                               is_inst_match = true;
+                               break;
+                       }
+               }
+       }
+       if (!is_inst_match)
+               listnode_add(from_bgp->vpn_policy[afi].export_vrf,
+                            vname);
        /* Update import RT for current VRF using export RT of the VRF we're
         * importing from. First though, make sure "import_vrf" has that
         * set.
@@ -1702,7 +1737,7 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
        const char *export_name, *tmp_name;
        vpn_policy_direction_t idir, edir;
        char *vname;
-       struct ecommunity *ecom;
+       struct ecommunity *ecom = NULL;
        struct listnode *node;
        int debug;
 
@@ -1747,10 +1782,12 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
        if (to_bgp->vpn_policy[afi].import_vrf->count == 0) {
                UNSET_FLAG(to_bgp->af_flags[afi][safi],
                           BGP_CONFIG_VRF_TO_VRF_IMPORT);
-               ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
+               if (to_bgp->vpn_policy[afi].rtlist[idir])
+                       ecommunity_free(&to_bgp->vpn_policy[afi].rtlist[idir]);
        } else {
                ecom = from_bgp->vpn_policy[afi].rtlist[edir];
-               ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
+               if (ecom)
+                       ecommunity_del_val(to_bgp->vpn_policy[afi].rtlist[idir],
                                   (struct ecommunity_val *)ecom->val);
                vpn_leak_postchange(idir, afi, bgp_get_default(), to_bgp);
        }
@@ -1783,8 +1820,11 @@ void vrf_unimport_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
         *
         * import_vrf and export_vrf must match in having
         * the in/out names as appropriate.
+        * export_vrf list could have been cleaned up
+        * as part of no router bgp source instnace.
         */
-       assert(vname);
+       if (!vname)
+               return;
 
        listnode_delete(from_bgp->vpn_policy[afi].export_vrf, vname);
        XFREE(MTYPE_TMP, vname);
@@ -2471,3 +2511,167 @@ void vpn_leak_postchange_all(void)
                        bgp);
        }
 }
+
+/* When a bgp vrf instance is unconfigured, remove its routes
+ * from the VPN table and this vrf could be importing routes from other
+ * bgp vrf instnaces, unimport them.
+ * VRF X and VRF Y are exporting routes to each other.
+ * When VRF X is deleted, unimport its routes from all target vrfs,
+ * also VRF Y should unimport its routes from VRF X table.
+ * This will ensure VPN table is cleaned up appropriately.
+ */
+int bgp_vpn_leak_unimport(struct bgp *from_bgp, struct vty *vty)
+{
+       struct bgp *to_bgp;
+       const char *tmp_name;
+       char *vname;
+       struct listnode *node, *next;
+       safi_t safi = SAFI_UNICAST;
+       afi_t afi;
+       bool is_vrf_leak_bind;
+       int debug;
+
+       if (from_bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+               return 0;
+
+       debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+                    BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
+       tmp_name = from_bgp->name ? from_bgp->name : VRF_DEFAULT_NAME;
+
+       for (afi = 0; afi < AFI_MAX; ++afi) {
+               /* vrf leak is for IPv4 and IPv6 Unicast only */
+               if (afi != AFI_IP && afi != AFI_IP6)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
+                       if (from_bgp == to_bgp)
+                               continue;
+
+                       /* Unimport and remove source vrf from the
+                        * other vrfs import list.
+                        */
+                       struct vpn_policy *to_vpolicy;
+
+                       is_vrf_leak_bind = false;
+                       to_vpolicy = &(to_bgp->vpn_policy[afi]);
+                       for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf, node,
+                                                 vname)) {
+                               if (strcmp(vname, tmp_name) == 0) {
+                                       is_vrf_leak_bind = true;
+                                       break;
+                               }
+                       }
+                       /* skip this bgp instance as there is no leak to this
+                        * vrf instance.
+                        */
+                       if (!is_vrf_leak_bind)
+                               continue;
+
+                       if (debug)
+                               zlog_debug("%s: unimport routes from %s to_bgp %s afi %s import vrfs count %u",
+                                          __func__, from_bgp->name_pretty,
+                                          to_bgp->name_pretty, afi2str(afi),
+                                          to_vpolicy->import_vrf->count);
+
+                       vrf_unimport_from_vrf(to_bgp, from_bgp, afi, safi);
+
+                       /* readd vrf name as unimport removes import vrf name
+                        * from the destination vrf's import list where the
+                        * `import vrf` configuration still exist.
+                        */
+                       vname = XSTRDUP(MTYPE_TMP, tmp_name);
+                       listnode_add(to_bgp->vpn_policy[afi].import_vrf,
+                                    vname);
+                       SET_FLAG(to_bgp->af_flags[afi][safi],
+                                BGP_CONFIG_VRF_TO_VRF_IMPORT);
+
+                       /* If to_bgp exports its routes to the bgp vrf
+                        * which is being deleted, un-import the
+                        * to_bgp routes from VPN.
+                        */
+                       for (ALL_LIST_ELEMENTS_RO(to_bgp->vpn_policy[afi]
+                                                 .export_vrf, node,
+                                                 vname)) {
+                               if (strcmp(vname, tmp_name) == 0) {
+                                       vrf_unimport_from_vrf(from_bgp, to_bgp,
+                                                     afi, safi);
+                                       break;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
+/* When a router bgp is configured, there could be a bgp vrf
+ * instance importing routes from this newly configured
+ * bgp vrf instance. Export routes from configured
+ * bgp vrf to VPN.
+ * VRF Y has import from bgp vrf x,
+ * when a bgp vrf x instance is created, export its routes
+ * to VRF Y instance.
+ */
+void bgp_vpn_leak_export(struct bgp *from_bgp)
+{
+       afi_t afi;
+       const char *export_name;
+       char *vname;
+       struct listnode *node, *next;
+       struct ecommunity *ecom;
+       vpn_policy_direction_t idir, edir;
+       safi_t safi = SAFI_UNICAST;
+       struct bgp *to_bgp;
+       int debug;
+
+       debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+                    BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
+       idir = BGP_VPN_POLICY_DIR_FROMVPN;
+       edir = BGP_VPN_POLICY_DIR_TOVPN;
+
+       export_name = (from_bgp->name ? XSTRDUP(MTYPE_TMP, from_bgp->name)
+                              : XSTRDUP(MTYPE_TMP, VRF_DEFAULT_NAME));
+
+       for (afi = 0; afi < AFI_MAX; ++afi) {
+               /* vrf leak is for IPv4 and IPv6 Unicast only */
+               if (afi != AFI_IP && afi != AFI_IP6)
+                       continue;
+
+               for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, to_bgp)) {
+                       if (from_bgp == to_bgp)
+                               continue;
+
+                       /* bgp instance has import list, check to see if newly
+                        * configured bgp instance is the list.
+                        */
+                       struct vpn_policy *to_vpolicy;
+
+                       to_vpolicy = &(to_bgp->vpn_policy[afi]);
+                       for (ALL_LIST_ELEMENTS_RO(to_vpolicy->import_vrf,
+                                                 node, vname)) {
+                               if (strcmp(vname, export_name) != 0)
+                                       continue;
+
+                               if (debug)
+                                       zlog_debug("%s: found from_bgp %s in to_bgp %s import list, import routes.",
+                                          __func__,
+                                          export_name, to_bgp->name_pretty);
+
+                               ecom = from_bgp->vpn_policy[afi].rtlist[edir];
+                               /* remove import rt, it will be readded
+                                * as part of import from vrf.
+                                */
+                               if (ecom)
+                                       ecommunity_del_val(
+                                               to_vpolicy->rtlist[idir],
+                                               (struct ecommunity_val *)
+                                                       ecom->val);
+                               vrf_import_from_vrf(to_bgp, from_bgp,
+                                                   afi, safi);
+                               break;
+
+                       }
+               }
+       }
+}