]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/zebra_vrf.c
Merge pull request #1654 from mkanjari/evpn-symm-routing-enhancements
[mirror_frr.git] / zebra / zebra_vrf.c
index 246a7e7e4c597ce5ab315e102ae3c13da39d1a8b..b9b3048486f7132b94d5dade28790c2a3624c77c 100644 (file)
 
 extern struct zebra_t zebrad;
 
+static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
+                                  safi_t safi);
+static void zebra_rnhtable_node_cleanup(struct route_table *table,
+                                       struct route_node *node);
+
 /* VRF information update. */
 static void zebra_vrf_add_update(struct zebra_vrf *zvrf)
 {
@@ -82,7 +87,7 @@ static int zebra_vrf_new(struct vrf *vrf)
        struct zebra_vrf *zvrf;
 
        if (IS_ZEBRA_DEBUG_EVENT)
-               zlog_info("ZVRF %s with id %u", vrf->name, vrf->vrf_id);
+               zlog_info("VRF %s created, id %u", vrf->name, vrf->vrf_id);
 
        zvrf = zebra_vrf_alloc();
        zvrf->zns = zebra_ns_lookup(
@@ -101,14 +106,36 @@ static int zebra_vrf_enable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
        struct interface *ifp;
        afi_t afi;
        safi_t safi;
 
        assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now active",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Inform clients that the VRF is now active. This is an
+        * add for the clients.
+        */
        zebra_vrf_add_update(zvrf);
 
+       /* Allocate tables */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       zebra_vrf_table_create(zvrf, afi, safi);
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->rnh_table[afi] = table;
+
+               table = route_table_init();
+               table->cleanup = zebra_rnhtable_node_cleanup;
+               zvrf->import_check_table[afi] = table;
+       }
+
+       /* Install any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -132,6 +159,9 @@ static int zebra_vrf_enable(struct vrf *vrf)
                                }
                }
 
+       /* Kick off any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_enable(zvrf);
+
        return 0;
 }
 
@@ -142,13 +172,19 @@ static int zebra_vrf_disable(struct vrf *vrf)
        struct route_table *stable;
        struct route_node *rn;
        struct static_route *si;
+       struct route_table *table;
+       struct interface *ifp;
+       u_int32_t table_id;
        afi_t afi;
        safi_t safi;
+       unsigned i;
 
-       if (IS_ZEBRA_DEBUG_KERNEL)
-               zlog_debug("VRF %s id %u is now disabled.", zvrf_name(zvrf),
-                          zvrf_id(zvrf));
+       assert(zvrf);
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u is now inactive",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
+       /* Uninstall any static routes configured for this VRF. */
        for (afi = AFI_IP; afi < AFI_MAX; afi++)
                for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
                        stable = zvrf->stable[afi][safi];
@@ -161,6 +197,84 @@ static int zebra_vrf_disable(struct vrf *vrf)
                                                afi, safi, &rn->p, NULL, si);
                }
 
+       /* Stop any VxLAN-EVPN processing. */
+       zebra_vxlan_vrf_disable(zvrf);
+
+       /* Inform clients that the VRF is now inactive. This is a
+        * delete for the clients.
+        */
+       zebra_vrf_delete_update(zvrf);
+
+       /* If asked to retain routes, there's nothing more to do. */
+       if (CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN))
+               return 0;
+
+       /* Remove all routes. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++)
+                       rib_close_table(zvrf->table[afi][safi]);
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id])
+                                       rib_close_table(zvrf->other_table[afi][table_id]);
+       }
+
+       /* Cleanup Vxlan, MPLS and PW tables. */
+       zebra_vxlan_cleanup_tables(zvrf);
+       zebra_mpls_cleanup_tables(zvrf);
+       zebra_pw_exit(zvrf);
+
+       /* Remove link-local IPv4 addresses created for BGP unnumbered peering. */
+       FOR_ALL_INTERFACES (vrf, ifp)
+               if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
+
+       /* clean-up work queues */
+       for (i = 0; i < MQ_SIZE; i++) {
+               struct listnode *lnode, *nnode;
+               struct route_node *rnode;
+               rib_dest_t *dest;
+
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
+                       dest = rib_dest_from_rnode(rnode);
+                       if (dest && rib_dest_vrf(dest) == zvrf) {
+                               route_unlock_node(rnode);
+                               list_delete_node(zebrad.mq->subq[i], lnode);
+                               zebrad.mq->size--;
+                       }
+               }
+       }
+
+       /* Cleanup (free) routing tables and NHT tables. */
+       for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
+               void *table_info;
+
+               for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
+                       table = zvrf->table[afi][safi];
+                       table_info = table->info;
+                       route_table_finish(table);
+                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       zvrf->table[afi][safi] = NULL;
+               }
+
+               if (vrf->vrf_id == VRF_DEFAULT)
+                       for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
+                            table_id++)
+                               if (zvrf->other_table[afi][table_id]) {
+                                       table = zvrf->other_table[afi][table_id];
+                                       table_info = table->info;
+                                       route_table_finish(table);
+                                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                                       zvrf->other_table[afi][table_id] = NULL;
+                               }
+
+               route_table_finish(zvrf->rnh_table[afi]);
+               zvrf->rnh_table[afi] = NULL;
+               route_table_finish(zvrf->import_check_table[afi]);
+               zvrf->import_check_table[afi] = NULL;
+       }
+
        return 0;
 }
 
@@ -174,38 +288,9 @@ static int zebra_vrf_delete(struct vrf *vrf)
        unsigned i;
 
        assert(zvrf);
-
-       zebra_vrf_delete_update(zvrf);
-
-       /* uninstall everything */
-       if (!CHECK_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN)) {
-               struct interface *ifp;
-
-               for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
-                       for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST;
-                            safi++)
-                               rib_close_table(zvrf->table[afi][safi]);
-
-                       if (vrf->vrf_id == VRF_DEFAULT)
-                               for (table_id = 0;
-                                    table_id < ZEBRA_KERNEL_TABLE_MAX;
-                                    table_id++)
-                                       if (zvrf->other_table[afi][table_id])
-                                               rib_close_table(
-                                                       zvrf->other_table
-                                                               [afi]
-                                                               [table_id]);
-               }
-
-               /* Cleanup Vxlan table and update kernel */
-               zebra_vxlan_close_tables(zvrf);
-
-               zebra_mpls_close_tables(zvrf);
-               zebra_pw_exit(zvrf);
-
-               FOR_ALL_INTERFACES (vrf, ifp)
-                       if_nbr_ipv6ll_to_ipv4ll_neigh_del_all(ifp);
-       }
+       if (IS_ZEBRA_DEBUG_EVENT)
+               zlog_debug("VRF %s id %u deleted",
+                          zvrf_name(zvrf), zvrf_id(zvrf));
 
        /* clean-up work queues */
        for (i = 0; i < MQ_SIZE; i++) {
@@ -213,8 +298,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                struct route_node *rnode;
                rib_dest_t *dest;
 
-               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode,
-                                      rnode)) {
+               for (ALL_LIST_ELEMENTS(zebrad.mq->subq[i], lnode, nnode, rnode)) {
                        dest = rib_dest_from_rnode(rnode);
                        if (dest && rib_dest_vrf(dest) == zvrf) {
                                route_unlock_node(rnode);
@@ -224,22 +308,27 @@ static int zebra_vrf_delete(struct vrf *vrf)
                }
        }
 
+       /* Free Vxlan and MPLS. */
+       zebra_vxlan_close_tables(zvrf);
+       zebra_mpls_close_tables(zvrf);
+
        /* release allocated memory */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                void *table_info;
 
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
                        table = zvrf->table[afi][safi];
-                       table_info = table->info;
-                       route_table_finish(table);
-                       XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       if (table) {
+                               table_info = table->info;
+                               route_table_finish(table);
+                               XFREE(MTYPE_RIB_TABLE_INFO, table_info);
+                       }
 
                        table = zvrf->stable[afi][safi];
                        route_table_finish(table);
                }
 
-               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX;
-                    table_id++)
+               for (table_id = 0; table_id < ZEBRA_KERNEL_TABLE_MAX; table_id++)
                        if (zvrf->other_table[afi][table_id]) {
                                table = zvrf->other_table[afi][table_id];
                                table_info = table->info;
@@ -251,7 +340,7 @@ static int zebra_vrf_delete(struct vrf *vrf)
                route_table_finish(zvrf->import_check_table[afi]);
        }
 
-       /* cleanup evpn states for vrf */
+       /* Cleanup EVPN states for vrf */
        zebra_vxlan_vrf_delete(zvrf);
 
        list_delete_all_node(zvrf->rid_all_sorted_list);
@@ -262,6 +351,37 @@ static int zebra_vrf_delete(struct vrf *vrf)
        return 0;
 }
 
+/* Return if this VRF has any FRR configuration or not.
+ * IMPORTANT: This function needs to be updated when additional configuration
+ * is added for a VRF.
+ */
+int zebra_vrf_has_config(struct zebra_vrf *zvrf)
+{
+       afi_t afi;
+       safi_t safi;
+       struct route_table *stable;
+
+       /* NOTE: This is a don't care for the default VRF, but we go through
+        * the motions to keep things consistent.
+        */
+       /* Any static routes? */
+       for (afi = AFI_IP; afi < AFI_MAX; afi++) {
+               for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
+                       stable = zvrf->stable[afi][safi];
+                       if (!stable)
+                               continue;
+                       if (route_table_count(stable))
+                               return 1;
+               }
+       }
+
+       /* EVPN L3-VNI? */
+       if (zvrf->l3vni)
+               return 1;
+
+       return 0;
+}
+
 /* Lookup the routing table in a VRF based on both VRF-Id and table-id.
  * NOTE: Table-id is relevant only in the Default VRF.
  */
@@ -354,9 +474,9 @@ struct zebra_vrf *zebra_vrf_alloc(void)
 
        zvrf = XCALLOC(MTYPE_ZEBRA_VRF, sizeof(struct zebra_vrf));
 
+       /* Allocate table for static route configuration. */
        for (afi = AFI_IP; afi <= AFI_IP6; afi++) {
                for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) {
-                       zebra_vrf_table_create(zvrf, afi, safi);
                        if (afi == AFI_IP6)
                                table = srcdest_table_init();
                        else
@@ -364,14 +484,6 @@ struct zebra_vrf *zebra_vrf_alloc(void)
                        table->cleanup = zebra_stable_node_cleanup;
                        zvrf->stable[afi][safi] = table;
                }
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->rnh_table[afi] = table;
-
-               table = route_table_init();
-               table->cleanup = zebra_rnhtable_node_cleanup;
-               zvrf->import_check_table[afi] = table;
        }
 
        zebra_vxlan_init_tables(zvrf);
@@ -477,16 +589,23 @@ static int vrf_config_write(struct vty *vty)
                if (!zvrf)
                        continue;
 
-               if (vrf->vrf_id != VRF_DEFAULT)
+               if (zvrf_id(zvrf) == VRF_DEFAULT) {
+                       if (zvrf->l3vni)
+                               vty_out(vty, "vni %u\n", zvrf->l3vni);
+                       vty_out(vty, "!\n");
+               }
+
+               if (vrf_is_user_cfged(vrf)) {
                        vty_out(vty, "vrf %s\n", zvrf_name(zvrf));
+                       if (zvrf->l3vni)
+                               vty_out(vty, " vni %u\n", zvrf->l3vni);
+                       vty_out(vty, "!\n");
+               }
 
                static_config(vty, zvrf, AFI_IP, SAFI_UNICAST, "ip route");
                static_config(vty, zvrf, AFI_IP, SAFI_MULTICAST, "ip mroute");
                static_config(vty, zvrf, AFI_IP6, SAFI_UNICAST, "ipv6 route");
 
-               if (vrf->vrf_id != VRF_DEFAULT && zvrf->l3vni)
-                       vty_out(vty, " vni %u\n", zvrf->l3vni);
-
                if (vrf->vrf_id != VRF_DEFAULT)
                        vty_out(vty, "!\n");
        }