]> git.proxmox.com Git - mirror_frr.git/commitdiff
ripd: add VRF support
authorRenato Westphal <renato@opensourcerouting.org>
Fri, 4 Jan 2019 21:08:10 +0000 (19:08 -0200)
committerRenato Westphal <renato@opensourcerouting.org>
Fri, 18 Jan 2019 18:15:41 +0000 (16:15 -0200)
* Turn the "instance" YANG presence-container into a YANG list keyed
  by the new "vrf" leaf. This is a backward incompatible change but
  this should be ok for now.

* RIP VRF instances can be configured even when the corresponding
  VRF doesn't exist. And a RIP VRF instance isn't deleted when
  the corresponding VRF is deleted. For this to work, implement the
  rip_instance_enable() and rip_instance_disable() functions that are
  called to enable/disable RIP routing instances when necessary. A
  RIP routing instance can be enabled only when the corresponding
  VRF is enabled (this information comes from zebra and depends on
  the underlying VRF backend). Routing instances are stored in the new
  rip_instances rb-tree (global variable).

* Add a vrf pointer to the rip structure instead of storing vrf_id
  only. This is much more convenient than using vrf_lookup_by_id()
  every time we need to get the vrf pointer from the VRF ID. The
  rip->vrf pointer is updated whenever the VRF enable/disable hooks
  are called.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
14 files changed:
ripd/rip_cli.c
ripd/rip_interface.c
ripd/rip_interface.h
ripd/rip_main.c
ripd/rip_memory.c
ripd/rip_memory.h
ripd/rip_northbound.c
ripd/rip_zebra.c
ripd/ripd.c
ripd/ripd.h
vtysh/vtysh.c
yang/example/ripd.json
yang/example/ripd.xml
yang/frr-ripd.yang

index 5bb81ef157c2f1a10da77634e89a7ab22cbebd1c..be24d04ff37eb4563803cb695fb7f62aed95fb19 100644 (file)
  */
 DEFPY_NOSH (router_rip,
        router_rip_cmd,
-       "router rip",
+       "router rip [vrf NAME]",
        "Enable a routing process\n"
-       "Routing Information Protocol (RIP)\n")
+       "Routing Information Protocol (RIP)\n"
+       VRF_CMD_HELP_STR)
 {
+       char xpath[XPATH_MAXLEN];
        int ret;
 
-       nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_CREATE,
-                             NULL);
+       /* Build RIP instance XPath. */
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
+       snprintf(xpath, sizeof(xpath), "/frr-ripd:ripd/instance[vrf='%s']",
+                vrf);
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
 
        ret = nb_cli_apply_changes(vty, NULL);
        if (ret == CMD_SUCCESS)
-               VTY_PUSH_XPATH(RIP_NODE, "/frr-ripd:ripd/instance");
+               VTY_PUSH_XPATH(RIP_NODE, xpath);
 
        return ret;
 }
 
 DEFPY (no_router_rip,
        no_router_rip_cmd,
-       "no router rip",
+       "no router rip [vrf NAME]",
        NO_STR
        "Enable a routing process\n"
-       "Routing Information Protocol (RIP)\n")
+       "Routing Information Protocol (RIP)\n"
+       VRF_CMD_HELP_STR)
 {
-       nb_cli_enqueue_change(vty, "/frr-ripd:ripd/instance", NB_OP_DELETE,
-                             NULL);
+       char xpath[XPATH_MAXLEN];
+
+       /* Build RIP instance XPath. */
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
+       snprintf(xpath, sizeof(xpath), "/frr-ripd:ripd/instance[vrf='%s']",
+                vrf);
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DELETE, NULL);
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -71,8 +86,15 @@ DEFPY (no_router_rip,
 void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode,
                         bool show_defaults)
 {
+       const char *vrf_name;
+
+       vrf_name = yang_dnode_get_string(dnode, "./vrf");
+
        vty_out(vty, "!\n");
-       vty_out(vty, "router rip\n");
+       vty_out(vty, "router rip");
+       if (!strmatch(vrf_name, VRF_DEFAULT_NAME))
+               vty_out(vty, " vrf %s", vrf_name);
+       vty_out(vty, "\n");
 }
 
 /*
index ca6dea1b374d5cf33be5acb2dfad8f1b370a254e..86fb2952dd810b26cae65df806f0b6354ec887f5 100644 (file)
@@ -94,17 +94,12 @@ static int ipv4_multicast_leave(int sock, struct in_addr group,
 static void rip_interface_reset(struct rip_interface *);
 
 /* Allocate new RIP's interface configuration. */
-static struct rip_interface *rip_interface_new(struct interface *ifp)
+static struct rip_interface *rip_interface_new(void)
 {
-       struct vrf *vrf;
        struct rip_interface *ri;
 
        ri = XCALLOC(MTYPE_RIP_INTERFACE, sizeof(struct rip_interface));
 
-       vrf = vrf_lookup_by_id(ifp->vrf_id);
-       if (vrf)
-               ri->rip = vrf->info;
-
        rip_interface_reset(ri);
 
        return ri;
@@ -327,10 +322,9 @@ static int rip_if_ipv4_address_check(struct interface *ifp)
 /* Does this address belongs to me ? */
 int if_check_address(struct rip *rip, struct in_addr addr)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                struct listnode *cnode;
                struct connected *connected;
 
@@ -365,13 +359,14 @@ int rip_interface_down(int command, struct zclient *zclient,
        if (ifp == NULL)
                return 0;
 
+       rip_interface_sync(ifp);
        rip_if_down(ifp);
 
        if (IS_RIP_DEBUG_ZEBRA)
                zlog_debug(
-                       "interface %s index %d flags %llx metric %d mtu %d is down",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu);
+                       "interface %s vrf %u index %d flags %llx metric %d mtu %d is down",
+                       ifp->name, ifp->vrf_id, ifp->ifindex,
+                       (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
 
        return 0;
 }
@@ -391,9 +386,11 @@ int rip_interface_up(int command, struct zclient *zclient, zebra_size_t length,
 
        if (IS_RIP_DEBUG_ZEBRA)
                zlog_debug(
-                       "interface %s index %d flags %#llx metric %d mtu %d is up",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu);
+                       "interface %s vrf %u index %d flags %#llx metric %d mtu %d is up",
+                       ifp->name, ifp->vrf_id, ifp->ifindex,
+                       (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
+
+       rip_interface_sync(ifp);
 
        /* Check if this interface is RIP enabled or not.*/
        rip_enable_apply(ifp);
@@ -414,12 +411,13 @@ int rip_interface_add(int command, struct zclient *zclient, zebra_size_t length,
        struct interface *ifp;
 
        ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
+       rip_interface_sync(ifp);
 
        if (IS_RIP_DEBUG_ZEBRA)
                zlog_debug(
-                       "interface add %s index %d flags %#llx metric %d mtu %d",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu);
+                       "interface add %s vrf %u index %d flags %#llx metric %d mtu %d",
+                       ifp->name, ifp->vrf_id, ifp->ifindex,
+                       (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
 
        /* Check if this interface is RIP enabled or not.*/
        rip_enable_apply(ifp);
@@ -452,13 +450,15 @@ int rip_interface_delete(int command, struct zclient *zclient,
        if (ifp == NULL)
                return 0;
 
+       rip_interface_sync(ifp);
        if (if_is_up(ifp)) {
                rip_if_down(ifp);
        }
 
-       zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d",
-                 ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                 ifp->metric, ifp->mtu);
+       zlog_info(
+               "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d",
+               ifp->name, ifp->vrf_id, ifp->ifindex,
+               (unsigned long long)ifp->flags, ifp->metric, ifp->mtu);
 
        /* To support pseudo interface do not free interface structure.  */
        /* if_delete(ifp); */
@@ -467,6 +467,28 @@ int rip_interface_delete(int command, struct zclient *zclient,
        return 0;
 }
 
+/* VRF update for an interface. */
+int rip_interface_vrf_update(int command, struct zclient *zclient,
+                            zebra_size_t length, vrf_id_t vrf_id)
+{
+       struct interface *ifp;
+       vrf_id_t new_vrf_id;
+
+       ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id,
+                                             &new_vrf_id);
+       if (!ifp)
+               return 0;
+
+       if (IS_RIP_DEBUG_ZEBRA)
+               zlog_debug("interface %s VRF change vrf_id %u new vrf id %u",
+                          ifp->name, vrf_id, new_vrf_id);
+
+       if_update_to_new_vrf(ifp, new_vrf_id);
+       rip_interface_sync(ifp);
+
+       return 0;
+}
+
 static void rip_interface_clean(struct rip_interface *ri)
 {
        ri->enable_network = 0;
@@ -481,10 +503,9 @@ static void rip_interface_clean(struct rip_interface *ri)
 
 void rip_interfaces_clean(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_interface_clean(ifp->info);
 }
 
@@ -972,11 +993,10 @@ void rip_enable_apply(struct interface *ifp)
 /* Apply network configuration to all interface. */
 static void rip_enable_apply_all(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct interface *ifp;
 
        /* Check each interface. */
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_enable_apply(ifp);
 }
 
@@ -1090,10 +1110,9 @@ static void rip_passive_interface_apply(struct interface *ifp)
 
 static void rip_passive_interface_apply_all(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_passive_interface_apply(ifp);
 }
 
@@ -1154,22 +1173,25 @@ void rip_passive_nondefault_clean(struct rip *rip)
 /* Write rip configuration of each interface. */
 static int rip_interface_config_write(struct vty *vty)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
-       struct interface *ifp;
+       struct vrf *vrf;
        int write = 0;
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
-               struct lyd_node *dnode;
+       RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+               struct interface *ifp;
 
-               dnode = yang_dnode_get(
-                       running_config->dnode,
-                       "/frr-interface:lib/interface[name='%s'][vrf='%s']",
-                       ifp->name, vrf->name);
-               if (dnode == NULL)
-                       continue;
+               FOR_ALL_INTERFACES (vrf, ifp) {
+                       struct lyd_node *dnode;
+
+                       dnode = yang_dnode_get(
+                               running_config->dnode,
+                               "/frr-interface:lib/interface[name='%s'][vrf='%s']",
+                               ifp->name, vrf->name);
+                       if (dnode == NULL)
+                               continue;
 
-               write = 1;
-               nb_cli_show_dnode_cmds(vty, dnode, false);
+                       write = 1;
+                       nb_cli_show_dnode_cmds(vty, dnode, false);
+               }
        }
 
        return write;
@@ -1206,10 +1228,26 @@ static struct cmd_node interface_node = {
        INTERFACE_NODE, "%s(config-if)# ", 1,
 };
 
+void rip_interface_sync(struct interface *ifp)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(ifp->vrf_id);
+       if (vrf) {
+               struct rip_interface *ri;
+
+               ri = ifp->info;
+               if (ri)
+                       ri->rip = vrf->info;
+       }
+}
+
 /* Called when interface structure allocated. */
 static int rip_interface_new_hook(struct interface *ifp)
 {
-       ifp->info = rip_interface_new(ifp);
+       ifp->info = rip_interface_new();
+       rip_interface_sync(ifp);
+
        return 0;
 }
 
index 8723388e75551208eda4f7b24856777938039a64..303be0315d96fd0c1b5d9b0260144fe313eea655 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _QUAGGA_RIP_INTERFACE_H
 #define _QUAGGA_RIP_INTERFACE_H
 
+#include "zclient.h"
+
 extern int rip_interface_down(int, struct zclient *, zebra_size_t, vrf_id_t);
 extern int rip_interface_up(int, struct zclient *, zebra_size_t, vrf_id_t);
 extern int rip_interface_add(int, struct zclient *, zebra_size_t, vrf_id_t);
@@ -28,5 +30,8 @@ extern int rip_interface_address_add(int, struct zclient *, zebra_size_t,
                                     vrf_id_t);
 extern int rip_interface_address_delete(int, struct zclient *, zebra_size_t,
                                        vrf_id_t);
+extern int rip_interface_vrf_update(int command, struct zclient *zclient,
+                                   zebra_size_t length, vrf_id_t vrf_id);
+extern void rip_interface_sync(struct interface *ifp);
 
 #endif /* _QUAGGA_RIP_INTERFACE_H */
index 46babe2e0b7504ddb7fb2514a8f1744b4a569f52..8b6e3a620a75f822ea9ba8ee5b01529d21123eac 100644 (file)
@@ -46,7 +46,7 @@
 static struct option longopts[] = {{"retain", no_argument, NULL, 'r'}, {0}};
 
 /* ripd privileges */
-zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND};
+zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN};
 
 struct zebra_privs_t ripd_privs = {
 #if defined(FRR_USER)
@@ -59,7 +59,7 @@ struct zebra_privs_t ripd_privs = {
        .vty_group = VTY_GROUP,
 #endif
        .caps_p = _caps_p,
-       .cap_num_p = 2,
+       .cap_num_p = array_size(_caps_p),
        .cap_num_i = 0};
 
 /* Master of threads. */
@@ -79,18 +79,9 @@ static void sighup(void)
 /* SIGINT handler. */
 static void sigint(void)
 {
-       struct vrf *vrf;
-
        zlog_notice("Terminating on signal");
 
-       RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
-               struct rip *rip;
-
-               rip = vrf->info;
-               if (rip)
-                       rip_clean(rip);
-       }
-
+       rip_vrf_terminate();
        rip_zclient_stop();
        frr_fini();
 
@@ -179,7 +170,7 @@ int main(int argc, char **argv)
        /* Library initialization. */
        rip_error_init();
        keychain_init();
-       vrf_init(NULL, NULL, NULL, NULL, NULL);
+       rip_vrf_init();
 
        /* RIP related initialization. */
        rip_init();
index 185241074349bd00c59d003d05b4849583297978..7d703a86db515ae1365f1876bb3739a339163211 100644 (file)
@@ -27,6 +27,7 @@
 
 DEFINE_MGROUP(RIPD, "ripd")
 DEFINE_MTYPE(RIPD, RIP, "RIP structure")
+DEFINE_MTYPE(RIPD, RIP_VRF_NAME, "RIP VRF name")
 DEFINE_MTYPE(RIPD, RIP_INFO, "RIP route info")
 DEFINE_MTYPE(RIPD, RIP_INTERFACE, "RIP interface")
 DEFINE_MTYPE(RIPD, RIP_INTERFACE_STRING, "RIP Interface String")
index 29013ecec30bb36182bce5d2df718e987183543d..1f9d8f500fbfc388a82f79a3c0c4b51d3a78cd63 100644 (file)
@@ -26,6 +26,7 @@
 
 DECLARE_MGROUP(RIPD)
 DECLARE_MTYPE(RIP)
+DECLARE_MTYPE(RIP_VRF_NAME)
 DECLARE_MTYPE(RIP_INFO)
 DECLARE_MTYPE(RIP_INTERFACE)
 DECLARE_MTYPE(RIP_INTERFACE_STRING)
index f5a75707e84aafd376a0ba2444d5221d9cf10aa2..8a8cbae1fa40974bef7efcf70c06d2ab0495a5b4 100644 (file)
@@ -42,25 +42,42 @@ static int ripd_instance_create(enum nb_event event,
 {
        struct rip *rip;
        struct vrf *vrf;
+       const char *vrf_name;
        int socket;
 
+       vrf_name = yang_dnode_get_string(dnode, "./vrf");
+       vrf = vrf_lookup_by_name(vrf_name);
+
+       /*
+        * Try to create a RIP socket only if the VRF is enabled, otherwise
+        * create a disabled RIP instance and wait for the VRF to be enabled.
+        */
        switch (event) {
        case NB_EV_VALIDATE:
                break;
        case NB_EV_PREPARE:
-               socket = rip_create_socket();
+               if (!vrf || !vrf_is_enabled(vrf))
+                       break;
+
+               socket = rip_create_socket(vrf);
                if (socket < 0)
                        return NB_ERR_RESOURCE;
                resource->fd = socket;
                break;
        case NB_EV_ABORT:
+               if (!vrf || !vrf_is_enabled(vrf))
+                       break;
+
                socket = resource->fd;
                close(socket);
                break;
        case NB_EV_APPLY:
-               vrf = vrf_lookup_by_id(VRF_DEFAULT);
-               socket = resource->fd;
-               rip = rip_create(vrf, socket);
+               if (vrf && vrf_is_enabled(vrf))
+                       socket = resource->fd;
+               else
+                       socket = -1;
+
+               rip = rip_create(vrf_name, vrf, socket);
                yang_dnode_set_entry(dnode, rip);
                break;
        }
index 6fbc170cb9b01296e9b45b6ab8e73cacad0da9a2..d8b35cf976c185227f1a7f01404ce3ad9927ed64 100644 (file)
@@ -47,7 +47,7 @@ static void rip_zebra_ipv4_send(struct rip *rip, struct route_node *rp,
        int count = 0;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = rip->vrf_id;
+       api.vrf_id = rip->vrf->vrf_id;
        api.type = ZEBRA_ROUTE_RIP;
        api.safi = SAFI_UNICAST;
 
@@ -56,7 +56,7 @@ static void rip_zebra_ipv4_send(struct rip *rip, struct route_node *rp,
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
-               api_nh->vrf_id = rip->vrf_id;
+               api_nh->vrf_id = rip->vrf->vrf_id;
                api_nh->gate = rinfo->nh.gate;
                api_nh->type = NEXTHOP_TYPE_IPV4;
                if (cmd == ZEBRA_ROUTE_ADD)
@@ -153,14 +153,14 @@ static int rip_zebra_read_route(int command, struct zclient *zclient,
 void rip_redistribute_conf_update(struct rip *rip, int type)
 {
        zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
-                            0, rip->vrf_id);
+                            0, rip->vrf->vrf_id);
 }
 
 void rip_redistribute_conf_delete(struct rip *rip, int type)
 {
        if (zclient->sock > 0)
                zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
-                                       AFI_IP, type, 0, rip->vrf_id);
+                                       AFI_IP, type, 0, rip->vrf->vrf_id);
 
        /* Remove the routes from RIP table. */
        rip_redistribute_withdraw(rip, type);
@@ -168,21 +168,23 @@ void rip_redistribute_conf_delete(struct rip *rip, int type)
 
 int rip_redistribute_check(struct rip *rip, int type)
 {
-       return vrf_bitmap_check(zclient->redist[AFI_IP][type], rip->vrf_id);
+       return vrf_bitmap_check(zclient->redist[AFI_IP][type],
+                               rip->vrf->vrf_id);
 }
 
 void rip_redistribute_clean(struct rip *rip)
 {
        for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-               if (!vrf_bitmap_check(zclient->redist[AFI_IP][i], rip->vrf_id))
+               if (!vrf_bitmap_check(zclient->redist[AFI_IP][i],
+                                     rip->vrf->vrf_id))
                        continue;
 
                if (zclient->sock > 0)
                        zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE,
                                                zclient, AFI_IP, i, 0,
-                                               rip->vrf_id);
+                                               rip->vrf->vrf_id);
 
-               vrf_bitmap_unset(zclient->redist[AFI_IP][i], rip->vrf_id);
+               vrf_bitmap_unset(zclient->redist[AFI_IP][i], rip->vrf->vrf_id);
        }
 }
 
@@ -191,13 +193,37 @@ void rip_show_redistribute_config(struct vty *vty, struct rip *rip)
        for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
                if (i == zclient->redist_default
                    || !vrf_bitmap_check(zclient->redist[AFI_IP][i],
-                                        rip->vrf_id))
+                                        rip->vrf->vrf_id))
                        continue;
 
                vty_out(vty, " %s", zebra_route_string(i));
        }
 }
 
+void rip_zebra_vrf_register(struct vrf *vrf)
+{
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return;
+
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: register VRF %s(%u) to zebra", __func__,
+                          vrf->name, vrf->vrf_id);
+
+       zclient_send_reg_requests(zclient, vrf->vrf_id);
+}
+
+void rip_zebra_vrf_deregister(struct vrf *vrf)
+{
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return;
+
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: deregister VRF %s(%u) from zebra.", __func__,
+                          vrf->name, vrf->vrf_id);
+
+       zclient_send_dereg_requests(zclient, vrf->vrf_id);
+}
+
 static void rip_zebra_connected(struct zclient *zclient)
 {
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
@@ -215,6 +241,7 @@ void rip_zclient_init(struct thread_master *master)
        zclient->interface_address_delete = rip_interface_address_delete;
        zclient->interface_up = rip_interface_up;
        zclient->interface_down = rip_interface_down;
+       zclient->interface_vrf_update = rip_interface_vrf_update;
        zclient->redistribute_route_add = rip_zebra_read_route;
        zclient->redistribute_route_del = rip_zebra_read_route;
 }
index c6abfb557d708de98048e10c6ff7cb6cbf8e8a46..a6a2a29debd426116533092a257e33417fee70f0 100644 (file)
@@ -46,6 +46,7 @@
 #include "ripd/ripd.h"
 #include "ripd/rip_debug.h"
 #include "ripd/rip_errors.h"
+#include "ripd/rip_interface.h"
 
 /* UDP receive buffer size */
 #define RIP_UDP_RCV_BUF 41600
@@ -57,6 +58,8 @@ static int rip_triggered_update(struct thread *);
 static int rip_update_jitter(unsigned long);
 static void rip_distance_table_node_cleanup(struct route_table *table,
                                            struct route_node *node);
+static void rip_instance_enable(struct rip *rip, struct vrf *vrf, int sock);
+static void rip_instance_disable(struct rip *rip);
 
 static void rip_distribute_update(struct distribute_ctx *ctx,
                                  struct distribute *dist);
@@ -73,6 +76,15 @@ static const struct message rip_msg[] = {{RIP_REQUEST, "REQUEST"},
                                         {RIP_POLL_ENTRY, "POLL ENTRY"},
                                         {0}};
 
+/* Generate rb-tree of RIP instances. */
+static inline int rip_instance_compare(const struct rip *a, const struct rip *b)
+{
+       return strcmp(a->vrf_name, b->vrf_name);
+}
+RB_GENERATE(rip_instance_head, rip, entry, rip_instance_compare)
+
+struct rip_instance_head rip_instances = RB_INITIALIZER(&rip_instances);
+
 /* Utility function to set boradcast option to the socket. */
 static int sockopt_broadcast(int sock)
 {
@@ -372,7 +384,6 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p,
 /* Check nexthop address validity. */
 static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct interface *ifp;
        struct listnode *cnode;
        struct connected *ifc;
@@ -381,7 +392,7 @@ static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
        /* If nexthop address matches local configured address then it is
           invalid nexthop. */
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, ifc)) {
                        p = ifc->address;
 
@@ -1114,7 +1125,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
           whether the datagram is from a valid neighbor; the source of the
           datagram must be on a directly connected network (RFC2453 - Sec.
           3.9.2) */
-       if (if_lookup_address((void *)&from->sin_addr, AF_INET, rip->vrf_id)
+       if (if_lookup_address((void *)&from->sin_addr, AF_INET,
+                             rip->vrf->vrf_id)
            == NULL) {
                zlog_info(
                        "This datagram doesn't came from a valid neighbor: %s",
@@ -1197,7 +1209,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                        }
 
                        if (!if_lookup_address((void *)&rte->nexthop, AF_INET,
-                                              rip->vrf_id)) {
+                                              rip->vrf->vrf_id)) {
                                struct route_node *rn;
                                struct rip_info *rinfo;
 
@@ -1327,11 +1339,12 @@ static void rip_response_process(struct rip_packet *packet, int size,
 }
 
 /* Make socket for RIP protocol. */
-int rip_create_socket(void)
+int rip_create_socket(struct vrf *vrf)
 {
        int ret;
        int sock;
        struct sockaddr_in addr;
+       const char *vrf_dev = NULL;
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family = AF_INET;
@@ -1343,11 +1356,17 @@ int rip_create_socket(void)
        addr.sin_port = htons(RIP_PORT_DEFAULT);
 
        /* Make datagram socket. */
-       sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-       if (sock < 0) {
-               flog_err_sys(EC_LIB_SOCKET, "Cannot create UDP socket: %s",
-                            safe_strerror(errno));
-               return -1;
+       if (vrf->vrf_id != VRF_DEFAULT)
+               vrf_dev = vrf->name;
+       frr_elevate_privs(&ripd_privs) {
+               sock = vrf_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, vrf->vrf_id,
+                                 vrf_dev);
+               if (sock < 0) {
+                       flog_err_sys(EC_LIB_SOCKET,
+                                    "Cannot create UDP socket: %s",
+                                    safe_strerror(errno));
+                       return -1;
+               }
        }
 
        sockopt_broadcast(sock);
@@ -1586,8 +1605,9 @@ void rip_redistribute_delete(struct rip *rip, int type, int sub_type,
                                                "infinity metric [delete]",
                                                inet_ntoa(p->prefix),
                                                p->prefixlen,
-                                               ifindex2ifname(ifindex,
-                                                              rip->vrf_id));
+                                               ifindex2ifname(
+                                                       ifindex,
+                                                       rip->vrf->vrf_id));
 
                                rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
                        }
@@ -1708,33 +1728,37 @@ static int rip_read(struct thread *t)
        len = recvfrom(sock, (char *)&rip_buf.buf, sizeof(rip_buf.buf), 0,
                       (struct sockaddr *)&from, &fromlen);
        if (len < 0) {
-               zlog_info("recvfrom failed: %s", safe_strerror(errno));
+               zlog_info("recvfrom failed (VRF %s): %s", rip->vrf_name,
+                         safe_strerror(errno));
                return len;
        }
 
        /* Check is this packet comming from myself? */
        if (if_check_address(rip, from.sin_addr)) {
                if (IS_RIP_DEBUG_PACKET)
-                       zlog_debug("ignore packet comes from myself");
+                       zlog_debug("ignore packet comes from myself (VRF %s)",
+                                  rip->vrf_name);
                return -1;
        }
 
        /* Which interface is this packet comes from. */
-       ifc = if_lookup_address((void *)&from.sin_addr, AF_INET, rip->vrf_id);
+       ifc = if_lookup_address((void *)&from.sin_addr, AF_INET,
+                               rip->vrf->vrf_id);
        if (ifc)
                ifp = ifc->ifp;
 
        /* RIP packet received */
        if (IS_RIP_DEBUG_EVENT)
-               zlog_debug("RECV packet from %s port %d on %s",
+               zlog_debug("RECV packet from %s port %d on %s (VRF %s)",
                           inet_ntoa(from.sin_addr), ntohs(from.sin_port),
-                          ifp ? ifp->name : "unknown");
+                          ifp ? ifp->name : "unknown", rip->vrf_name);
 
        /* If this packet come from unknown interface, ignore it. */
        if (ifp == NULL) {
                zlog_info(
-                       "rip_read: cannot find interface for packet from %s port %d",
-                       inet_ntoa(from.sin_addr), ntohs(from.sin_port));
+                       "rip_read: cannot find interface for packet from %s port %d (VRF %s)",
+                       inet_ntoa(from.sin_addr), ntohs(from.sin_port),
+                       rip->vrf_name);
                return -1;
        }
 
@@ -1747,9 +1771,9 @@ static int rip_read(struct thread *t)
        if (ifc == NULL) {
                zlog_info(
                        "rip_read: cannot find connected address for packet from %s "
-                       "port %d on interface %s",
+                       "port %d on interface %s (VRF %s)",
                        inet_ntoa(from.sin_addr), ntohs(from.sin_port),
-                       ifp->name);
+                       ifp->name, rip->vrf_name);
                return -1;
        }
 
@@ -2415,7 +2439,6 @@ static void rip_update_interface(struct connected *ifc, uint8_t version,
 /* Update send to all interface and neighbor. */
 static void rip_update_process(struct rip *rip, int route_type)
 {
-       struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
        struct listnode *ifnode, *ifnnode;
        struct connected *connected;
        struct interface *ifp;
@@ -2425,7 +2448,7 @@ static void rip_update_process(struct rip *rip, int route_type)
        struct prefix *p;
 
        /* Send RIP update to each interface. */
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                if (if_is_loopback(ifp))
                        continue;
 
@@ -2478,7 +2501,7 @@ static void rip_update_process(struct rip *rip, int route_type)
                        p = &rp->p;
 
                        connected = if_lookup_address(&p->u.prefix4, AF_INET,
-                                                     rip->vrf_id);
+                                                     rip->vrf->vrf_id);
                        if (!connected) {
                                zlog_warn(
                                        "Neighbor %s doesn't have connected interface!",
@@ -2622,7 +2645,7 @@ void rip_redistribute_withdraw(struct rip *rip, int type)
                                                p->prefixlen,
                                                ifindex2ifname(
                                                        rinfo->nh.ifindex,
-                                                       rip->vrf_id));
+                                                       rip->vrf->vrf_id));
                                }
 
                                rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
@@ -2641,13 +2664,22 @@ struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id)
        return vrf->info;
 }
 
+struct rip *rip_lookup_by_vrf_name(const char *vrf_name)
+{
+       struct rip rip;
+
+       rip.vrf_name = (char *)vrf_name;
+
+       return RB_FIND(rip_instance_head, &rip_instances, &rip);
+}
+
 /* Create new RIP instance and set it to global variable. */
-struct rip *rip_create(struct vrf *vrf, int socket)
+struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
 {
        struct rip *rip;
-       struct interface *ifp;
 
        rip = XCALLOC(MTYPE_RIP, sizeof(struct rip));
+       rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf_name);
 
        /* Set initial value. */
        rip->ecmp = yang_get_default_bool("%s/allow-ecmp", RIP_INSTANCE);
@@ -2685,31 +2717,23 @@ struct rip *rip_create(struct vrf *vrf, int socket)
        rip->offset_list_master->del = (void (*)(void *))offset_list_del;
 
        /* Distribute list install. */
-       rip->distribute_ctx =
-               distribute_list_ctx_create(vrf_lookup_by_id(VRF_DEFAULT));
+       rip->distribute_ctx = distribute_list_ctx_create(vrf);
        distribute_list_add_hook(rip->distribute_ctx, rip_distribute_update);
        distribute_list_delete_hook(rip->distribute_ctx, rip_distribute_update);
 
        /* Make output stream. */
        rip->obuf = stream_new(1500);
 
-       /* Set socket. */
-       rip->sock = socket;
-
-       /* Create read and timer thread. */
-       rip_event(rip, RIP_READ, rip->sock);
-       rip_event(rip, RIP_UPDATE_EVENT, 1);
-
-       /* Link RIP instance to VRF. */
-       rip->vrf_id = vrf->vrf_id;
-       vrf->info = rip;
-       FOR_ALL_INTERFACES (vrf, ifp) {
-               struct rip_interface *ri;
-
-               ri = ifp->info;
-               ri->rip = rip;
+       /* Enable the routing instance if possible. */
+       if (vrf && vrf_is_enabled(vrf))
+               rip_instance_enable(rip, vrf, socket);
+       else {
+               rip->vrf = NULL;
+               rip->sock = -1;
        }
 
+       RB_INSERT(rip_instance_head, &rip_instances, rip);
+
        return rip;
 }
 
@@ -2988,20 +3012,34 @@ static const char *rip_route_type_print(int sub_type)
 
 DEFUN (show_ip_rip,
        show_ip_rip_cmd,
-       "show ip rip",
+       "show ip rip [vrf NAME]",
        SHOW_STR
        IP_STR
-       "Show RIP routes\n")
+       "Show RIP routes\n"
+       VRF_CMD_HELP_STR)
 {
        struct rip *rip;
        struct route_node *np;
        struct rip_info *rinfo = NULL;
        struct list *list = NULL;
        struct listnode *listnode = NULL;
+       const char *vrf_name;
+       int idx = 0;
 
-       rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
-       if (!rip)
+       if (argv_find(argv, argc, "vrf", &idx))
+               vrf_name = argv[idx + 1]->arg;
+       else
+               vrf_name = VRF_DEFAULT_NAME;
+
+       rip = rip_lookup_by_vrf_name(vrf_name);
+       if (!rip) {
+               vty_out(vty, "%% RIP instance not found\n");
+               return CMD_SUCCESS;
+       }
+       if (!rip->enabled) {
+               vty_out(vty, "%% RIP instance is disabled\n");
                return CMD_SUCCESS;
+       }
 
        vty_out(vty,
                "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n"
@@ -3093,23 +3131,36 @@ DEFUN (show_ip_rip,
 /* Vincent: formerly, it was show_ip_protocols_rip: "show ip protocols" */
 DEFUN (show_ip_rip_status,
        show_ip_rip_status_cmd,
-       "show ip rip status",
+       "show ip rip [vrf NAME] status",
        SHOW_STR
        IP_STR
        "Show RIP routes\n"
+       VRF_CMD_HELP_STR
        "IP routing protocol process parameters and statistics\n")
 {
        struct rip *rip;
-       struct vrf *vrf;
        struct interface *ifp;
        struct rip_interface *ri;
        extern const struct message ri_version_msg[];
        const char *send_version;
        const char *receive_version;
+       const char *vrf_name;
+       int idx = 0;
 
-       rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
-       if (!rip)
+       if (argv_find(argv, argc, "vrf", &idx))
+               vrf_name = argv[idx + 1]->arg;
+       else
+               vrf_name = VRF_DEFAULT_NAME;
+
+       rip = rip_lookup_by_vrf_name(vrf_name);
+       if (!rip) {
+               vty_out(vty, "%% RIP instance not found\n");
                return CMD_SUCCESS;
+       }
+       if (!rip->enabled) {
+               vty_out(vty, "%% RIP instance is disabled\n");
+               return CMD_SUCCESS;
+       }
 
        vty_out(vty, "Routing Protocol is \"rip\"\n");
        vty_out(vty, "  Sending updates every %u seconds with +/-50%%,",
@@ -3141,8 +3192,7 @@ DEFUN (show_ip_rip_status,
 
        vty_out(vty, "    Interface        Send  Recv   Key-chain\n");
 
-       vrf = vrf_lookup_by_id(rip->vrf_id);
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                ri = ifp->info;
 
                if (!ri->running)
@@ -3176,7 +3226,7 @@ DEFUN (show_ip_rip_status,
 
        {
                int found_passive = 0;
-               FOR_ALL_INTERFACES (vrf, ifp) {
+               FOR_ALL_INTERFACES (rip->vrf, ifp) {
                        ri = ifp->info;
 
                        if ((ri->enable_network || ri->enable_interface)
@@ -3204,28 +3254,31 @@ DEFUN (show_ip_rip_status,
 /* RIP configuration write function. */
 static int config_write_rip(struct vty *vty)
 {
+       struct rip *rip;
        int write = 0;
-       struct lyd_node *dnode;
 
-       dnode = yang_dnode_get(running_config->dnode,
-                              "/frr-ripd:ripd/instance");
-       if (dnode) {
-               struct rip *rip;
+       RB_FOREACH(rip, rip_instance_head, &rip_instances) {
+               char xpath[XPATH_MAXLEN];
+               struct lyd_node *dnode;
 
-               write++;
+               snprintf(xpath, sizeof(xpath),
+                        "/frr-ripd:ripd/instance[vrf='%s']", rip->vrf_name);
+
+               dnode = yang_dnode_get(running_config->dnode, xpath);
+               assert(dnode);
 
                nb_cli_show_dnode_cmds(vty, dnode, false);
 
-               rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
-               if (rip) {
-                       /* Distribute configuration. */
-                       write += config_write_distribute(vty,
-                                                        rip->distribute_ctx);
+               /* Distribute configuration. */
+               config_write_distribute(vty, rip->distribute_ctx);
 
-                       /* Interface routemap configuration */
-                       write += config_write_if_rmap(vty);
-               }
+               /* Interface routemap configuration */
+               if (strmatch(rip->vrf_name, VRF_DEFAULT_NAME))
+                       config_write_if_rmap(vty);
+
+               write = 1;
        }
+
        return write;
 }
 
@@ -3241,10 +3294,10 @@ static void rip_distribute_update(struct distribute_ctx *ctx,
        struct access_list *alist;
        struct prefix_list *plist;
 
-       if (!dist->ifname)
+       if (!ctx->vrf || !dist->ifname)
                return;
 
-       ifp = if_lookup_by_name(dist->ifname, VRF_DEFAULT);
+       ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id);
        if (ifp == NULL)
                return;
 
@@ -3323,46 +3376,8 @@ static void rip_distribute_update_all_wrapper(struct access_list *notused)
 /* Delete all added rip route. */
 void rip_clean(struct rip *rip)
 {
-       struct vrf *vrf;
-       struct interface *ifp;
-       struct route_node *rp;
-
-       /* Clear RIP routes */
-       for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
-               struct rip_info *rinfo;
-               struct list *list;
-               struct listnode *listnode;
-
-               if ((list = rp->info) == NULL)
-                       continue;
-
-               rinfo = listgetdata(listhead(list));
-               if (rip_route_rte(rinfo))
-                       rip_zebra_ipv4_delete(rip, rp);
-
-               for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
-                       RIP_TIMER_OFF(rinfo->t_timeout);
-                       RIP_TIMER_OFF(rinfo->t_garbage_collect);
-                       rip_info_free(rinfo);
-               }
-               list_delete(&list);
-               rp->info = NULL;
-               route_unlock_node(rp);
-       }
-
-       /* Cancel RIP related timers. */
-       RIP_TIMER_OFF(rip->t_update);
-       RIP_TIMER_OFF(rip->t_triggered_update);
-       RIP_TIMER_OFF(rip->t_triggered_interval);
-
-       /* Cancel read thread. */
-       THREAD_READ_OFF(rip->t_read);
-
-       /* Close RIP socket. */
-       if (rip->sock >= 0) {
-               close(rip->sock);
-               rip->sock = -1;
-       }
+       if (rip->enabled)
+               rip_instance_disable(rip);
 
        stream_free(rip->obuf);
 
@@ -3385,16 +3400,8 @@ void rip_clean(struct rip *rip)
        route_table_finish(rip->distance_table);
        rip_redistribute_clean(rip);
 
-       vrf = vrf_lookup_by_id(rip->vrf_id);
-       vrf->info = NULL;
-
-       FOR_ALL_INTERFACES (vrf, ifp) {
-               struct rip_interface *ri;
-
-               ri = ifp->info;
-               ri->rip = NULL;
-       }
-
+       RB_REMOVE(rip_instance_head, &rip_instances, rip);
+       XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
        XFREE(MTYPE_RIP, rip);
 }
 
@@ -3461,6 +3468,168 @@ static void rip_routemap_update(const char *notused)
                rip_routemap_update_redistribute(rip);
 }
 
+/* Link RIP instance to VRF. */
+static void rip_vrf_link(struct rip *rip, struct vrf *vrf)
+{
+       struct interface *ifp;
+
+       rip->vrf = vrf;
+       rip->distribute_ctx->vrf = vrf;
+       vrf->info = rip;
+
+       FOR_ALL_INTERFACES (vrf, ifp)
+               rip_interface_sync(ifp);
+}
+
+/* Unlink RIP instance from VRF. */
+static void rip_vrf_unlink(struct rip *rip, struct vrf *vrf)
+{
+       struct interface *ifp;
+
+       rip->vrf = NULL;
+       rip->distribute_ctx->vrf = NULL;
+       vrf->info = NULL;
+
+       FOR_ALL_INTERFACES (vrf, ifp)
+               rip_interface_sync(ifp);
+}
+
+static void rip_instance_enable(struct rip *rip, struct vrf *vrf, int sock)
+{
+       rip->sock = sock;
+
+       rip_vrf_link(rip, vrf);
+       rip->enabled = true;
+
+       /* Create read and timer thread. */
+       rip_event(rip, RIP_READ, rip->sock);
+       rip_event(rip, RIP_UPDATE_EVENT, 1);
+
+       rip_zebra_vrf_register(vrf);
+}
+
+static void rip_instance_disable(struct rip *rip)
+{
+       struct vrf *vrf = rip->vrf;
+       struct route_node *rp;
+
+       /* Clear RIP routes */
+       for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+               struct rip_info *rinfo;
+               struct list *list;
+               struct listnode *listnode;
+
+               if ((list = rp->info) == NULL)
+                       continue;
+
+               rinfo = listgetdata(listhead(list));
+               if (rip_route_rte(rinfo))
+                       rip_zebra_ipv4_delete(rip, rp);
+
+               for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+                       RIP_TIMER_OFF(rinfo->t_timeout);
+                       RIP_TIMER_OFF(rinfo->t_garbage_collect);
+                       rip_info_free(rinfo);
+               }
+               list_delete(&list);
+               rp->info = NULL;
+               route_unlock_node(rp);
+       }
+
+       /* Cancel RIP related timers. */
+       RIP_TIMER_OFF(rip->t_update);
+       RIP_TIMER_OFF(rip->t_triggered_update);
+       RIP_TIMER_OFF(rip->t_triggered_interval);
+
+       /* Cancel read thread. */
+       THREAD_READ_OFF(rip->t_read);
+
+       /* Close RIP socket. */
+       close(rip->sock);
+       rip->sock = -1;
+
+       /* Clear existing peers. */
+       list_delete_all_node(rip->peer_list);
+
+       rip_zebra_vrf_deregister(vrf);
+
+       rip_vrf_unlink(rip, vrf);
+       rip->enabled = false;
+}
+
+static int rip_vrf_new(struct vrf *vrf)
+{
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       return 0;
+}
+
+static int rip_vrf_delete(struct vrf *vrf)
+{
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       return 0;
+}
+
+static int rip_vrf_enable(struct vrf *vrf)
+{
+       struct rip *rip;
+       int socket;
+
+       rip = rip_lookup_by_vrf_name(vrf->name);
+       if (!rip || rip->enabled)
+               return 0;
+
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       /* Activate the VRF RIP instance. */
+       if (!rip->enabled) {
+               socket = rip_create_socket(vrf);
+               if (socket < 0)
+                       return -1;
+
+               rip_instance_enable(rip, vrf, socket);
+       }
+
+       return 0;
+}
+
+static int rip_vrf_disable(struct vrf *vrf)
+{
+       struct rip *rip;
+
+       rip = rip_lookup_by_vrf_name(vrf->name);
+       if (!rip || !rip->enabled)
+               return 0;
+
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       /* Deactivate the VRF RIP instance. */
+       if (rip->enabled)
+               rip_instance_disable(rip);
+
+       return 0;
+}
+
+void rip_vrf_init(void)
+{
+       vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete,
+                NULL);
+}
+
+void rip_vrf_terminate(void)
+{
+       vrf_terminate();
+}
+
 /* Allocate new rip structure and set default value. */
 void rip_init(void)
 {
index a18a741579578d8c577bdb6b318b5e2cde032524..268ba74b964401a1c2d2c1652de79329d1f3b9af 100644 (file)
 
 /* RIP structure. */
 struct rip {
-       /* VRF ID. */
-       vrf_id_t vrf_id;
+       RB_ENTRY(rip) entry;
+
+       /* VRF this routing instance is associated with. */
+       char *vrf_name;
+
+       /* VRF backpointer (might be NULL if the VRF doesn't exist). */
+       struct vrf *vrf;
+
+       /* Status of the routing instance. */
+       bool enabled;
 
        /* RIP socket. */
        int sock;
@@ -182,6 +190,8 @@ struct rip {
                long queries;
        } counters;
 };
+RB_HEAD(rip_instance_head, rip);
+RB_PROTOTYPE(rip_instance_head, rip, entry, rip_instance_compare)
 
 /* RIP routing table entry which belong to rip_packet. */
 struct rte {
@@ -416,11 +426,15 @@ extern int rip_passive_nondefault_unset(struct rip *rip, const char *ifname);
 extern void rip_passive_nondefault_clean(struct rip *rip);
 extern void rip_if_init(void);
 extern void rip_route_map_init(void);
+extern void rip_zebra_vrf_register(struct vrf *vrf);
+extern void rip_zebra_vrf_deregister(struct vrf *vrf);
 extern void rip_zclient_init(struct thread_master *);
 extern void rip_zclient_stop(void);
 extern int if_check_address(struct rip *rip, struct in_addr addr);
 extern struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id);
-extern struct rip *rip_create(struct vrf *vrf, int socket);
+extern struct rip *rip_lookup_by_vrf_name(const char *vrf_name);
+extern struct rip *rip_create(const char *vrf_name, struct vrf *vrf,
+                             int socket);
 
 extern int rip_request_send(struct sockaddr_in *, struct interface *, uint8_t,
                            struct connected *);
@@ -436,7 +450,7 @@ extern int rip_enable_if_delete(struct rip *rip, const char *ifname);
 extern void rip_event(struct rip *rip, enum rip_event event, int sock);
 extern void rip_ecmp_disable(struct rip *rip);
 
-extern int rip_create_socket(void);
+extern int rip_create_socket(struct vrf *vrf);
 
 extern int rip_redistribute_check(struct rip *rip, int type);
 extern void rip_redistribute_conf_update(struct rip *rip, int type);
@@ -495,6 +509,9 @@ extern int rip_offset_list_apply_out(struct prefix_ipv4 *, struct interface *,
 extern int offset_list_cmp(struct rip_offset_list *o1,
                           struct rip_offset_list *o2);
 
+extern void rip_vrf_init(void);
+extern void rip_vrf_terminate(void);
+
 /* YANG notifications */
 extern void ripd_notif_send_auth_type_failure(const char *ifname);
 extern void ripd_notif_send_auth_failure(const char *ifname);
index 6cf45789dd97459ea5aa216c39e0139fd86c1059..11be03363ca29ab6a778eb51b714eca62d41bfa0 100644 (file)
@@ -1519,8 +1519,8 @@ DEFUNSH(VTYSH_KEYS, key, key_cmd, "key (0-2147483647)",
        return CMD_SUCCESS;
 }
 
-DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip",
-       ROUTER_STR "RIP\n")
+DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]",
+       ROUTER_STR "RIP\n" VRF_CMD_HELP_STR)
 {
        vty->node = RIP_NODE;
        return CMD_SUCCESS;
index 888c52b93097dcaaf22e59d15fcaab5837cd5427..00040622e5d7e7c1e6bf9702c9dc3ecf354758e0 100644 (file)
         ]
     },
     "frr-ripd:ripd": {
-        "instance": {
-            "allow-ecmp": "true",
-            "distance": {
-                "source": [
+        "instance": [
+            {
+                "vrf": "default",
+                "allow-ecmp": "true",
+                "distance": {
+                    "source": [
+                        {
+                            "distance": "25",
+                            "prefix": "172.16.1.0/24"
+                        }
+                    ]
+                },
+                "redistribute": [
                     {
-                        "prefix": "172.16.1.0/24",
-                        "distance": "25"
+                        "metric": "3",
+                        "protocol": "ospf"
                     }
+                ],
+                "static-route": [
+                    "10.0.1.0/24"
                 ]
-            },
-            "redistribute": [
-                {
-                    "protocol": "ospf",
-                    "metric": "3"
-                }
-            ],
-            "static-route": [
-                "10.0.1.0/24"
-            ]
-        }
+            }
+        ]
     }
 }
index 756e382bd6ec8e38543d96f6f2a40e7c0f7fe629..2feddde2d86b8fc263d8fd751a4fe3bc7f3d1cad 100644 (file)
@@ -18,6 +18,7 @@
 </lib>
 <ripd xmlns="http://frrouting.org/yang/ripd">
        <instance>
+               <vrf>default</vrf>
                <allow-ecmp>true</allow-ecmp>
                <static-route>10.0.1.0/24</static-route>
                <distance>
index 8073fba77e0752a7365af865bf8f3a3084ae9170..ca2b766159a4267cd52a5eee0efeba061d6b2671 100644 (file)
@@ -34,13 +34,18 @@ module frr-ripd {
 
   container ripd {
     /*
-     * Global configuration data
+     * Routing instance configuration.
      */
-    container instance {
-      presence "Present if the RIP protocol is enabled.";
+    list instance {
+      key "vrf";
       description
         "RIP routing instance.";
 
+      leaf vrf {
+        type string;
+        description
+          "VRF name.";
+      }
       leaf allow-ecmp {
         type boolean;
         default "false";