]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge remote-tracking branch 'frr/master' into rip-vrf
authorRenato Westphal <renato@opensourcerouting.org>
Sat, 2 Mar 2019 18:00:46 +0000 (15:00 -0300)
committerRenato Westphal <renatowestphal@gmail.com>
Fri, 29 Mar 2019 14:32:21 +0000 (11:32 -0300)
Merge commit to solve a bunch of conflicts with other PRs that were
merged in the previous weeks.

Signed-off-by: Renato Westphal <renato@opensourcerouting.org>
38 files changed:
lib/northbound_cli.c
lib/vrf.c
lib/vrf.h
lib/yang.c
lib/yang.h
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_offset.c
ripd/rip_peer.c
ripd/rip_snmp.c
ripd/rip_zebra.c
ripd/ripd.c
ripd/ripd.h
ripngd/ripng_cli.c
ripngd/ripng_interface.c
ripngd/ripng_main.c
ripngd/ripng_memory.c
ripngd/ripng_memory.h
ripngd/ripng_nexthop.c
ripngd/ripng_northbound.c
ripngd/ripng_offset.c
ripngd/ripng_peer.c
ripngd/ripng_route.c
ripngd/ripng_route.h
ripngd/ripng_zebra.c
ripngd/ripngd.c
ripngd/ripngd.h
vtysh/vtysh.c
yang/example/ripd.json
yang/example/ripd.xml
yang/frr-ripd.yang
yang/frr-ripngd.yang
yang/ietf/frr-ietf-translator.json

index 33035de31bea826f28bae2c7c1e967c70630a0ed..917b04810502f030ba8cab81d3e8ccc7ee3c6038 100644 (file)
@@ -1297,7 +1297,7 @@ DEFPY (show_yang_operational_data,
                yang_dnode_free(dnode);
                return CMD_WARNING;
        }
-       lyd_validate(&dnode, LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB, ly_ctx);
+       lyd_validate(&dnode, LYD_OPT_GET, ly_ctx);
 
        /* Display the data. */
        if (lyd_print_mem(&strp, dnode, format,
index df93bc33b948e0c6c04e2d96967852f7b0ebda38..a3195de08ff79011cd2dad3ee783138bb3a6385f 100644 (file)
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -572,7 +572,7 @@ static int vrf_default_accepts_vrf(int type)
 
 /* Create a socket for the VRF. */
 int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
-              char *interfacename)
+              const char *interfacename)
 {
        int ret, save_errno, ret2;
 
@@ -940,7 +940,7 @@ vrf_id_t vrf_get_default_id(void)
                return VRF_DEFAULT_INTERNAL;
 }
 
-int vrf_bind(vrf_id_t vrf_id, int fd, char *name)
+int vrf_bind(vrf_id_t vrf_id, int fd, const char *name)
 {
        int ret = 0;
 
@@ -999,7 +999,7 @@ int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *params)
 }
 
 int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
-                        char *interfacename)
+                        const char *interfacename)
 {
        int ret, save_errno, ret2;
 
index b947ab1d52ca1640146baeff242c6f05c93fb28a..b41ad12f01da94bfc4b1b6f345322385c005f5dd 100644 (file)
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -219,12 +219,12 @@ extern void vrf_terminate(void);
 
 /* Create a socket serving for the given VRF */
 extern int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id,
-                     char *name);
+                     const char *name);
 
 extern int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
-                               char *name);
+                               const char *name);
 
-extern int vrf_bind(vrf_id_t vrf_id, int fd, char *name);
+extern int vrf_bind(vrf_id_t vrf_id, int fd, const char *name);
 
 /* VRF ioctl operations */
 extern int vrf_getaddrinfo(const char *node, const char *service,
index 1d8e82eb28d8b94891c62aca44509d58b52f618d..7982d14fdddb9c56ada01af1ae0842d6e289b85f 100644 (file)
@@ -610,6 +610,25 @@ struct list *yang_data_list_new(void)
        return list;
 }
 
+struct yang_data *yang_data_list_find(const struct list *list,
+                                     const char *xpath_fmt, ...)
+{
+       char xpath[XPATH_MAXLEN];
+       struct yang_data *data;
+       struct listnode *node;
+       va_list ap;
+
+       va_start(ap, xpath_fmt);
+       vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap);
+       va_end(ap);
+
+       for (ALL_LIST_ELEMENTS_RO(list, node, data))
+               if (strmatch(data->xpath, xpath))
+                       return data;
+
+       return NULL;
+}
+
 static void *ly_dup_cb(const void *priv)
 {
        /* Make a shallow copy of the priv pointer. */
index 885218272a5fb0ef1853d074a29e655f3287222c..15f0ec7ae6af0854809adf7de806880f46a6d495 100644 (file)
@@ -513,6 +513,21 @@ extern void yang_data_free(struct yang_data *data);
  */
 extern struct list *yang_data_list_new(void);
 
+/*
+ * Find the yang_data structure corresponding to an XPath in a list.
+ *
+ * list
+ *    list of yang_data structures to operate on.
+ *
+ * xpath_fmt
+ *    XPath to search for (format string).
+ *
+ * Returns:
+ *    Pointer to yang_data if found, NULL otherwise.
+ */
+extern struct yang_data *yang_data_list_find(const struct list *list,
+                                            const char *xpath_fmt, ...);
+
 /*
  * Create and set up a libyang context (for use by the translator)
  */
index 6fbcdc059be0f87e900f9b344585d6834c4027f4..6b94258ea55d189aad929061ae7522604c8ca45a 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_DESTROY,
-                             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_DESTROY, 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");
 }
 
 /*
@@ -893,7 +915,7 @@ DEFPY (no_ip_rip_authentication_string,
        "Authentication string\n"
        "Authentication string\n")
 {
-       nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_MODIFY,
+       nb_cli_enqueue_change(vty, "./authentication-password", NB_OP_DESTROY,
                              NULL);
 
        return nb_cli_apply_changes(vty, "./frr-ripd:rip");
@@ -961,12 +983,24 @@ void cli_show_ip_rip_authentication_key_chain(struct vty *vty,
  */
 DEFPY (clear_ip_rip,
        clear_ip_rip_cmd,
-       "clear ip rip",
+       "clear ip rip [vrf WORD]",
        CLEAR_STR
        IP_STR
-       "Clear IP RIP database\n")
+       "Clear IP RIP database\n"
+       VRF_CMD_HELP_STR)
 {
-       return nb_cli_rpc("/frr-ripd:clear-rip-route", NULL, NULL);
+       struct list *input;
+
+       input = list_new();
+       if (vrf) {
+               struct yang_data *yang_vrf;
+
+               yang_vrf = yang_data_new("/frr-ripd:clear-rip-route/input/vrf",
+                                        vrf);
+               listnode_add(input, yang_vrf);
+       }
+
+       return nb_cli_rpc("/frr-ripd:clear-rip-route", input, NULL);
 }
 
 void rip_cli_init(void)
index 9575f6b8a8d466c80176177e4f35354909618f84..86fb2952dd810b26cae65df806f0b6354ec887f5 100644 (file)
@@ -50,9 +50,9 @@ DEFINE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
 static void rip_enable_apply(struct interface *);
 static void rip_passive_interface_apply(struct interface *);
 static int rip_if_down(struct interface *ifp);
-static int rip_enable_if_lookup(const char *ifname);
+static int rip_enable_if_lookup(struct rip *rip, const char *ifname);
 static int rip_enable_network_lookup2(struct connected *connected);
-static void rip_enable_apply_all(void);
+static void rip_enable_apply_all(struct rip *rip);
 
 const struct message ri_version_msg[] = {{RI_RIP_VERSION_1, "1"},
                                         {RI_RIP_VERSION_2, "2"},
@@ -60,15 +60,6 @@ const struct message ri_version_msg[] = {{RI_RIP_VERSION_1, "1"},
                                         {RI_RIP_VERSION_NONE, "none"},
                                         {0}};
 
-/* RIP enabled network vector. */
-vector rip_enable_interface;
-
-/* RIP enabled interface table. */
-struct route_table *rip_enable_network;
-
-/* Vector to store passive-interface name. */
-vector Vrip_passive_nondefault;
-
 /* Join to the RIP version 2 multicast group. */
 static int ipv4_multicast_join(int sock, struct in_addr group,
                               struct in_addr ifa, ifindex_t ifindex)
@@ -208,7 +199,7 @@ static void rip_request_interface(struct interface *ifp)
 
        /* If there is no version configuration in the interface,
           use rip's version setting. */
-       vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? rip->version_send
+       vsend = ((ri->ri_send == RI_RIP_UNSPEC) ? ri->rip->version_send
                                                : ri->ri_send);
        if (vsend & RIPv1)
                rip_request_interface_send(ifp, RIPv1);
@@ -329,12 +320,11 @@ static int rip_if_ipv4_address_check(struct interface *ifp)
 
 
 /* Does this address belongs to me ? */
-int if_check_address(struct in_addr addr)
+int if_check_address(struct rip *rip, struct in_addr addr)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                struct listnode *cnode;
                struct connected *connected;
 
@@ -369,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;
 }
@@ -395,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);
@@ -418,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);
@@ -456,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); */
@@ -471,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;
@@ -483,12 +501,11 @@ static void rip_interface_clean(struct rip_interface *ri)
        }
 }
 
-void rip_interfaces_clean(void)
+void rip_interfaces_clean(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_interface_clean(ifp->info);
 }
 
@@ -533,20 +550,22 @@ static void rip_interface_reset(struct rip_interface *ri)
 
 int rip_if_down(struct interface *ifp)
 {
+       struct rip *rip;
        struct route_node *rp;
        struct rip_info *rinfo;
        struct rip_interface *ri = NULL;
        struct list *list = NULL;
        struct listnode *listnode = NULL, *nextnode = NULL;
+
+       ri = ifp->info;
+       rip = ri->rip;
        if (rip) {
                for (rp = route_top(rip->table); rp; rp = route_next(rp))
                        if ((list = rp->info) != NULL)
                                for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
                                                       rinfo))
                                        if (rinfo->nh.ifindex == ifp->ifindex)
-                                               rip_ecmp_delete(rinfo);
-
-               ri = ifp->info;
+                                               rip_ecmp_delete(rip, rinfo);
 
                if (ri->running) {
                        if (IS_RIP_DEBUG_EVENT)
@@ -562,18 +581,10 @@ int rip_if_down(struct interface *ifp)
        return 0;
 }
 
-/* Needed for stop RIP process. */
-void rip_if_down_all(void)
-{
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
-       struct interface *ifp;
-
-       FOR_ALL_INTERFACES (vrf, ifp)
-               rip_if_down(ifp);
-}
-
 static void rip_apply_address_add(struct connected *ifc)
 {
+       struct rip_interface *ri = ifc->ifp->info;
+       struct rip *rip = ri->rip;
        struct prefix_ipv4 address;
        struct nexthop nh;
        struct prefix *p;
@@ -599,10 +610,11 @@ static void rip_apply_address_add(struct connected *ifc)
 
        /* Check if this interface is RIP enabled or not
           or  Check if this address's prefix is RIP enabled */
-       if ((rip_enable_if_lookup(ifc->ifp->name) >= 0)
+       if ((rip_enable_if_lookup(rip, ifc->ifp->name) >= 0)
            || (rip_enable_network_lookup2(ifc) >= 0))
-               rip_redistribute_add(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
-                                    &address, &nh, 0, 0, 0);
+               rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
+                                    RIP_ROUTE_INTERFACE, &address, &nh, 0, 0,
+                                    0);
 }
 
 int rip_interface_address_add(int command, struct zclient *zclient,
@@ -636,6 +648,8 @@ int rip_interface_address_add(int command, struct zclient *zclient,
 
 static void rip_apply_address_del(struct connected *ifc)
 {
+       struct rip_interface *ri = ifc->ifp->info;
+       struct rip *rip = ri->rip;
        struct prefix_ipv4 address;
        struct prefix *p;
 
@@ -653,7 +667,7 @@ static void rip_apply_address_del(struct connected *ifc)
        address.prefixlen = p->prefixlen;
        apply_mask_ipv4(&address);
 
-       rip_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
+       rip_redistribute_delete(rip, ZEBRA_ROUTE_CONNECT, RIP_ROUTE_INTERFACE,
                                &address, ifc->ifp->ifindex);
 }
 
@@ -691,10 +705,15 @@ int rip_interface_address_delete(int command, struct zclient *zclient,
  * is within the ripng_enable_network table. */
 static int rip_enable_network_lookup_if(struct interface *ifp)
 {
+       struct rip_interface *ri = ifp->info;
+       struct rip *rip = ri->rip;
        struct listnode *node, *nnode;
        struct connected *connected;
        struct prefix_ipv4 address;
 
+       if (!rip)
+               return -1;
+
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, connected)) {
                struct prefix *p;
                struct route_node *n;
@@ -706,7 +725,7 @@ static int rip_enable_network_lookup_if(struct interface *ifp)
                        address.prefix = p->u.prefix4;
                        address.prefixlen = IPV4_MAX_BITLEN;
 
-                       n = route_node_match(rip_enable_network,
+                       n = route_node_match(rip->enable_network,
                                             (struct prefix *)&address);
                        if (n) {
                                route_unlock_node(n);
@@ -718,8 +737,10 @@ static int rip_enable_network_lookup_if(struct interface *ifp)
 }
 
 /* Check wether connected is within the ripng_enable_network table. */
-int rip_enable_network_lookup2(struct connected *connected)
+static int rip_enable_network_lookup2(struct connected *connected)
 {
+       struct rip_interface *ri = connected->ifp->info;
+       struct rip *rip = ri->rip;
        struct prefix_ipv4 address;
        struct prefix *p;
 
@@ -733,8 +754,8 @@ int rip_enable_network_lookup2(struct connected *connected)
                address.prefixlen = IPV4_MAX_BITLEN;
 
                /* LPM on p->family, p->u.prefix4/IPV4_MAX_BITLEN within
-                * rip_enable_network */
-               node = route_node_match(rip_enable_network,
+                * rip->enable_network */
+               node = route_node_match(rip->enable_network,
                                        (struct prefix *)&address);
 
                if (node) {
@@ -746,11 +767,11 @@ int rip_enable_network_lookup2(struct connected *connected)
        return -1;
 }
 /* Add RIP enable network. */
-int rip_enable_network_add(struct prefix *p)
+int rip_enable_network_add(struct rip *rip, struct prefix *p)
 {
        struct route_node *node;
 
-       node = route_node_get(rip_enable_network, p);
+       node = route_node_get(rip->enable_network, p);
 
        if (node->info) {
                route_unlock_node(node);
@@ -759,17 +780,17 @@ int rip_enable_network_add(struct prefix *p)
                node->info = (void *)1;
 
        /* XXX: One should find a better solution than a generic one */
-       rip_enable_apply_all();
+       rip_enable_apply_all(rip);
 
        return NB_OK;
 }
 
 /* Delete RIP enable network. */
-int rip_enable_network_delete(struct prefix *p)
+int rip_enable_network_delete(struct rip *rip, struct prefix *p)
 {
        struct route_node *node;
 
-       node = route_node_lookup(rip_enable_network, p);
+       node = route_node_lookup(rip->enable_network, p);
        if (node) {
                node->info = NULL;
 
@@ -780,7 +801,7 @@ int rip_enable_network_delete(struct prefix *p)
                route_unlock_node(node);
 
                /* XXX: One should find a better solution than a generic one */
-               rip_enable_apply_all();
+               rip_enable_apply_all(rip);
 
                return NB_OK;
        }
@@ -789,50 +810,53 @@ int rip_enable_network_delete(struct prefix *p)
 }
 
 /* Check interface is enabled by ifname statement. */
-static int rip_enable_if_lookup(const char *ifname)
+static int rip_enable_if_lookup(struct rip *rip, const char *ifname)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(rip_enable_interface); i++)
-               if ((str = vector_slot(rip_enable_interface, i)) != NULL)
+       if (!rip)
+               return -1;
+
+       for (i = 0; i < vector_active(rip->enable_interface); i++)
+               if ((str = vector_slot(rip->enable_interface, i)) != NULL)
                        if (strcmp(str, ifname) == 0)
                                return i;
        return -1;
 }
 
 /* Add interface to rip_enable_if. */
-int rip_enable_if_add(const char *ifname)
+int rip_enable_if_add(struct rip *rip, const char *ifname)
 {
        int ret;
 
-       ret = rip_enable_if_lookup(ifname);
+       ret = rip_enable_if_lookup(rip, ifname);
        if (ret >= 0)
                return NB_ERR_INCONSISTENCY;
 
-       vector_set(rip_enable_interface,
+       vector_set(rip->enable_interface,
                   XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname));
 
-       rip_enable_apply_all(); /* TODOVJ */
+       rip_enable_apply_all(rip); /* TODOVJ */
 
        return NB_OK;
 }
 
 /* Delete interface from rip_enable_if. */
-int rip_enable_if_delete(const char *ifname)
+int rip_enable_if_delete(struct rip *rip, const char *ifname)
 {
        int index;
        char *str;
 
-       index = rip_enable_if_lookup(ifname);
+       index = rip_enable_if_lookup(rip, ifname);
        if (index < 0)
                return NB_ERR_INCONSISTENCY;
 
-       str = vector_slot(rip_enable_interface, index);
+       str = vector_slot(rip->enable_interface, index);
        XFREE(MTYPE_RIP_INTERFACE_STRING, str);
-       vector_unset(rip_enable_interface, index);
+       vector_unset(rip->enable_interface, index);
 
-       rip_enable_apply_all(); /* TODOVJ */
+       rip_enable_apply_all(rip); /* TODOVJ */
 
        return NB_OK;
 }
@@ -850,7 +874,7 @@ static int rip_interface_wakeup(struct thread *t)
        ri->t_wakeup = NULL;
 
        /* Join to multicast group. */
-       if (rip_multicast_join(ifp, rip->sock) < 0) {
+       if (rip_multicast_join(ifp, ri->rip->sock) < 0) {
                flog_err_sys(EC_LIB_SOCKET,
                             "multicast join failed, interface %s not running",
                             ifp->name);
@@ -868,6 +892,8 @@ static int rip_interface_wakeup(struct thread *t)
 
 static void rip_connect_set(struct interface *ifp, int set)
 {
+       struct rip_interface *ri = ifp->info;
+       struct rip *rip = ri->rip;
        struct listnode *node, *nnode;
        struct connected *connected;
        struct prefix_ipv4 address;
@@ -892,17 +918,18 @@ static void rip_connect_set(struct interface *ifp, int set)
                if (set) {
                        /* Check once more wether this prefix is within a
                         * "network IF_OR_PREF" one */
-                       if ((rip_enable_if_lookup(connected->ifp->name) >= 0)
+                       if ((rip_enable_if_lookup(rip, connected->ifp->name)
+                            >= 0)
                            || (rip_enable_network_lookup2(connected) >= 0))
-                               rip_redistribute_add(ZEBRA_ROUTE_CONNECT,
+                               rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
                                                     RIP_ROUTE_INTERFACE,
                                                     &address, &nh, 0, 0, 0);
                } else {
-                       rip_redistribute_delete(ZEBRA_ROUTE_CONNECT,
+                       rip_redistribute_delete(rip, ZEBRA_ROUTE_CONNECT,
                                                RIP_ROUTE_INTERFACE, &address,
                                                connected->ifp->ifindex);
-                       if (rip_redistribute_check(ZEBRA_ROUTE_CONNECT))
-                               rip_redistribute_add(ZEBRA_ROUTE_CONNECT,
+                       if (rip_redistribute_check(rip, ZEBRA_ROUTE_CONNECT))
+                               rip_redistribute_add(rip, ZEBRA_ROUTE_CONNECT,
                                                     RIP_ROUTE_REDISTRIBUTE,
                                                     &address, &nh, 0, 0, 0);
                }
@@ -931,7 +958,7 @@ void rip_enable_apply(struct interface *ifp)
                ri->enable_network = 0;
 
        /* Check interface name configuration. */
-       ret = rip_enable_if_lookup(ifp->name);
+       ret = rip_enable_if_lookup(ri->rip, ifp->name);
        if (ret >= 0)
                ri->enable_interface = 1;
        else
@@ -964,17 +991,16 @@ void rip_enable_apply(struct interface *ifp)
 }
 
 /* Apply network configuration to all interface. */
-void rip_enable_apply_all(void)
+static void rip_enable_apply_all(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
        /* Check each interface. */
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_enable_apply(ifp);
 }
 
-int rip_neighbor_lookup(struct sockaddr_in *from)
+int rip_neighbor_lookup(struct rip *rip, struct sockaddr_in *from)
 {
        struct prefix_ipv4 p;
        struct route_node *node;
@@ -993,7 +1019,7 @@ int rip_neighbor_lookup(struct sockaddr_in *from)
 }
 
 /* Add new RIP neighbor to the neighbor tree. */
-int rip_neighbor_add(struct prefix_ipv4 *p)
+int rip_neighbor_add(struct rip *rip, struct prefix_ipv4 *p)
 {
        struct route_node *node;
 
@@ -1008,7 +1034,7 @@ int rip_neighbor_add(struct prefix_ipv4 *p)
 }
 
 /* Delete RIP neighbor from the neighbor tree. */
-int rip_neighbor_delete(struct prefix_ipv4 *p)
+int rip_neighbor_delete(struct rip *rip, struct prefix_ipv4 *p)
 {
        struct route_node *node;
 
@@ -1029,50 +1055,51 @@ int rip_neighbor_delete(struct prefix_ipv4 *p)
 }
 
 /* Clear all network and neighbor configuration. */
-void rip_clean_network(void)
+void rip_clean_network(struct rip *rip)
 {
        unsigned int i;
        char *str;
        struct route_node *rn;
 
-       /* rip_enable_network. */
-       for (rn = route_top(rip_enable_network); rn; rn = route_next(rn))
+       /* rip->enable_network. */
+       for (rn = route_top(rip->enable_network); rn; rn = route_next(rn))
                if (rn->info) {
                        rn->info = NULL;
                        route_unlock_node(rn);
                }
 
-       /* rip_enable_interface. */
-       for (i = 0; i < vector_active(rip_enable_interface); i++)
-               if ((str = vector_slot(rip_enable_interface, i)) != NULL) {
+       /* rip->enable_interface. */
+       for (i = 0; i < vector_active(rip->enable_interface); i++)
+               if ((str = vector_slot(rip->enable_interface, i)) != NULL) {
                        XFREE(MTYPE_RIP_INTERFACE_STRING, str);
-                       vector_slot(rip_enable_interface, i) = NULL;
+                       vector_slot(rip->enable_interface, i) = NULL;
                }
 }
 
 /* Utility function for looking up passive interface settings. */
-static int rip_passive_nondefault_lookup(const char *ifname)
+static int rip_passive_nondefault_lookup(struct rip *rip, const char *ifname)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(Vrip_passive_nondefault); i++)
-               if ((str = vector_slot(Vrip_passive_nondefault, i)) != NULL)
+       for (i = 0; i < vector_active(rip->passive_nondefault); i++)
+               if ((str = vector_slot(rip->passive_nondefault, i)) != NULL)
                        if (strcmp(str, ifname) == 0)
                                return i;
        return -1;
 }
 
-void rip_passive_interface_apply(struct interface *ifp)
+static void rip_passive_interface_apply(struct interface *ifp)
 {
+       struct rip *rip;
        struct rip_interface *ri;
 
+       ri = ifp->info;
+       rip = ri->rip;
        if (rip == NULL)
                return;
 
-       ri = ifp->info;
-
-       ri->passive = ((rip_passive_nondefault_lookup(ifp->name) < 0)
+       ri->passive = ((rip_passive_nondefault_lookup(rip, ifp->name) < 0)
                               ? rip->passive_default
                               : !rip->passive_default);
 
@@ -1081,39 +1108,38 @@ void rip_passive_interface_apply(struct interface *ifp)
                           ri->passive);
 }
 
-static void rip_passive_interface_apply_all(void)
+static void rip_passive_interface_apply_all(struct rip *rip)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (rip->vrf, ifp)
                rip_passive_interface_apply(ifp);
 }
 
 /* Passive interface. */
-int rip_passive_nondefault_set(const char *ifname)
+int rip_passive_nondefault_set(struct rip *rip, const char *ifname)
 {
-       if (rip_passive_nondefault_lookup(ifname) >= 0)
+       if (rip_passive_nondefault_lookup(rip, ifname) >= 0)
                /*
                 * Don't return an error, this can happen after changing
                 * 'passive-default'.
                 */
                return NB_OK;
 
-       vector_set(Vrip_passive_nondefault,
+       vector_set(rip->passive_nondefault,
                   XSTRDUP(MTYPE_RIP_INTERFACE_STRING, ifname));
 
-       rip_passive_interface_apply_all();
+       rip_passive_interface_apply_all(rip);
 
        return NB_OK;
 }
 
-int rip_passive_nondefault_unset(const char *ifname)
+int rip_passive_nondefault_unset(struct rip *rip, const char *ifname)
 {
        int i;
        char *str;
 
-       i = rip_passive_nondefault_lookup(ifname);
+       i = rip_passive_nondefault_lookup(rip, ifname);
        if (i < 0)
                /*
                 * Don't return an error, this can happen after changing
@@ -1121,61 +1147,64 @@ int rip_passive_nondefault_unset(const char *ifname)
                 */
                return NB_OK;
 
-       str = vector_slot(Vrip_passive_nondefault, i);
+       str = vector_slot(rip->passive_nondefault, i);
        XFREE(MTYPE_RIP_INTERFACE_STRING, str);
-       vector_unset(Vrip_passive_nondefault, i);
+       vector_unset(rip->passive_nondefault, i);
 
-       rip_passive_interface_apply_all();
+       rip_passive_interface_apply_all(rip);
 
        return NB_OK;
 }
 
 /* Free all configured RIP passive-interface settings. */
-void rip_passive_nondefault_clean(void)
+void rip_passive_nondefault_clean(struct rip *rip)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(Vrip_passive_nondefault); i++)
-               if ((str = vector_slot(Vrip_passive_nondefault, i)) != NULL) {
+       for (i = 0; i < vector_active(rip->passive_nondefault); i++)
+               if ((str = vector_slot(rip->passive_nondefault, i)) != NULL) {
                        XFREE(MTYPE_RIP_INTERFACE_STRING, str);
-                       vector_slot(Vrip_passive_nondefault, i) = NULL;
+                       vector_slot(rip->passive_nondefault, i) = NULL;
                }
-       rip_passive_interface_apply_all();
+       rip_passive_interface_apply_all(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;
 }
 
-int rip_show_network_config(struct vty *vty)
+int rip_show_network_config(struct vty *vty, struct rip *rip)
 {
        unsigned int i;
        char *ifname;
        struct route_node *node;
 
        /* Network type RIP enable interface statement. */
-       for (node = route_top(rip_enable_network); node;
+       for (node = route_top(rip->enable_network); node;
             node = route_next(node))
                if (node->info)
                        vty_out(vty, "    %s/%u\n",
@@ -1183,8 +1212,8 @@ int rip_show_network_config(struct vty *vty)
                                node->p.prefixlen);
 
        /* Interface name RIP enable statement. */
-       for (i = 0; i < vector_active(rip_enable_interface); i++)
-               if ((ifname = vector_slot(rip_enable_interface, i)) != NULL)
+       for (i = 0; i < vector_active(rip->enable_interface); i++)
+               if ((ifname = vector_slot(rip->enable_interface, i)) != NULL)
                        vty_out(vty, "    %s\n", ifname);
 
        /* RIP neighbors listing. */
@@ -1199,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();
+       rip_interface_sync(ifp);
+
        return 0;
 }
 
@@ -1222,13 +1267,6 @@ void rip_if_init(void)
        hook_register_prio(if_add, 0, rip_interface_new_hook);
        hook_register_prio(if_del, 0, rip_interface_delete_hook);
 
-       /* RIP network init. */
-       rip_enable_interface = vector_init(1);
-       rip_enable_network = route_table_init();
-
-       /* RIP passive interface. */
-       Vrip_passive_nondefault = vector_init(1);
-
        /* Install interface node. */
        install_node(&interface_node, rip_interface_config_write);
        if_cmd_init();
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 5db9c4b7e9e0250d9240a9404d5163de9db210e6..65da51f83abd066e52ea130fa6726a1bae828f80 100644 (file)
@@ -34,6 +34,7 @@
 #include "sigevent.h"
 #include "zclient.h"
 #include "vrf.h"
+#include "if_rmap.h"
 #include "libfrr.h"
 
 #include "ripd/ripd.h"
@@ -46,7 +47,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 +60,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. */
@@ -81,8 +82,8 @@ static void sigint(void)
 {
        zlog_notice("Terminating on signal");
 
-       rip_clean();
-
+       rip_vrf_terminate();
+       if_rmap_terminate();
        rip_zclient_stop();
        frr_fini();
 
@@ -171,14 +172,13 @@ 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();
        rip_if_init();
        rip_cli_init();
        rip_zclient_init(master);
-       rip_peer_init();
 
        frr_config_fork();
        frr_run(master);
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 1e5f86eff80950eb22609b675fe25bea2d6a0bf9..2c53824ea12039db9b9ef5c922a0cb2ff3a152e3 100644 (file)
@@ -31,6 +31,7 @@
 #include "libfrr.h"
 
 #include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
 #include "ripd/rip_cli.h"
 
 /*
@@ -40,24 +41,45 @@ static int ripd_instance_create(enum nb_event event,
                                const struct lyd_node *dnode,
                                union nb_resource *resource)
 {
+       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:
-               socket = resource->fd;
-               rip_create(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;
        }
 
@@ -67,14 +89,49 @@ static int ripd_instance_create(enum nb_event event,
 static int ripd_instance_delete(enum nb_event event,
                                const struct lyd_node *dnode)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       rip_clean();
+       rip = yang_dnode_get_entry(dnode, true);
+       rip_clean(rip);
+
+       return NB_OK;
+}
+
+static const void *ripd_instance_get_next(const void *parent_list_entry,
+                                         const void *list_entry)
+{
+       const struct rip *rip = list_entry;
+
+       if (list_entry == NULL)
+               rip = RB_MIN(rip_instance_head, &rip_instances);
+       else
+               rip = RB_NEXT(rip_instance_head, (struct rip *)rip);
+
+       return rip;
+}
+
+static int ripd_instance_get_keys(const void *list_entry,
+                                 struct yang_list_keys *keys)
+{
+       const struct rip *rip = list_entry;
+
+       keys->num = 1;
+       strlcpy(keys->key[0], rip->vrf_name, sizeof(keys->key[0]));
 
        return NB_OK;
 }
 
+static const void *ripd_instance_lookup_entry(const void *parent_list_entry,
+                                             const struct yang_list_keys *keys)
+{
+       const char *vrf_name = keys->key[0];
+
+       return rip_lookup_by_vrf_name(vrf_name);
+}
+
 /*
  * XPath: /frr-ripd:ripd/instance/allow-ecmp
  */
@@ -82,12 +139,15 @@ static int ripd_instance_allow_ecmp_modify(enum nb_event event,
                                           const struct lyd_node *dnode,
                                           union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->ecmp = yang_dnode_get_bool(dnode, NULL);
        if (!rip->ecmp)
-               rip_ecmp_disable();
+               rip_ecmp_disable(rip);
 
        return NB_OK;
 }
@@ -100,12 +160,14 @@ ripd_instance_default_information_originate_modify(enum nb_event event,
                                                   const struct lyd_node *dnode,
                                                   union nb_resource *resource)
 {
+       struct rip *rip;
        bool default_information;
        struct prefix_ipv4 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        default_information = yang_dnode_get_bool(dnode, NULL);
 
        memset(&p, 0, sizeof(struct prefix_ipv4));
@@ -115,11 +177,11 @@ ripd_instance_default_information_originate_modify(enum nb_event event,
 
                memset(&nh, 0, sizeof(nh));
                nh.type = NEXTHOP_TYPE_IPV4;
-               rip_redistribute_add(ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p,
-                                    &nh, 0, 0, 0);
+               rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
+                                    &p, &nh, 0, 0, 0);
        } else {
-               rip_redistribute_delete(ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT, &p,
-                                       0);
+               rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_DEFAULT,
+                                       &p, 0);
        }
 
        return NB_OK;
@@ -132,9 +194,12 @@ static int ripd_instance_default_metric_modify(enum nb_event event,
                                               const struct lyd_node *dnode,
                                               union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->default_metric = yang_dnode_get_uint8(dnode, NULL);
        /* rip_update_default_metric (); */
 
@@ -148,9 +213,12 @@ static int ripd_instance_distance_default_modify(enum nb_event event,
                                                 const struct lyd_node *dnode,
                                                 union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->distance = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -163,6 +231,7 @@ static int ripd_instance_distance_source_create(enum nb_event event,
                                                const struct lyd_node *dnode,
                                                union nb_resource *resource)
 {
+       struct rip *rip;
        struct prefix_ipv4 prefix;
        struct route_node *rn;
 
@@ -173,7 +242,8 @@ static int ripd_instance_distance_source_create(enum nb_event event,
        apply_mask_ipv4(&prefix);
 
        /* Get RIP distance node. */
-       rn = route_node_get(rip_distance_table, (struct prefix *)&prefix);
+       rip = yang_dnode_get_entry(dnode, true);
+       rn = route_node_get(rip->distance_table, (struct prefix *)&prefix);
        rn->info = rip_distance_new();
        yang_dnode_set_entry(dnode, rn);
 
@@ -191,10 +261,7 @@ static int ripd_instance_distance_source_delete(enum nb_event event,
 
        rn = yang_dnode_get_entry(dnode, true);
        rdistance = rn->info;
-       if (rdistance->access_list)
-               free(rdistance->access_list);
        rip_distance_free(rdistance);
-
        rn->info = NULL;
        route_unlock_node(rn);
 
@@ -278,31 +345,35 @@ static int ripd_instance_explicit_neighbor_create(enum nb_event event,
                                                  const struct lyd_node *dnode,
                                                  union nb_resource *resource)
 {
+       struct rip *rip;
        struct prefix_ipv4 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        p.family = AF_INET;
        p.prefixlen = IPV4_MAX_BITLEN;
        yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
 
-       return rip_neighbor_add(&p);
+       return rip_neighbor_add(rip, &p);
 }
 
 static int ripd_instance_explicit_neighbor_delete(enum nb_event event,
                                                  const struct lyd_node *dnode)
 {
+       struct rip *rip;
        struct prefix_ipv4 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        p.family = AF_INET;
        p.prefixlen = IPV4_MAX_BITLEN;
        yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
 
-       return rip_neighbor_delete(&p);
+       return rip_neighbor_delete(rip, &p);
 }
 
 /*
@@ -312,29 +383,33 @@ static int ripd_instance_network_create(enum nb_event event,
                                        const struct lyd_node *dnode,
                                        union nb_resource *resource)
 {
+       struct rip *rip;
        struct prefix p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4((struct prefix_ipv4 *)&p);
 
-       return rip_enable_network_add(&p);
+       return rip_enable_network_add(rip, &p);
 }
 
 static int ripd_instance_network_delete(enum nb_event event,
                                        const struct lyd_node *dnode)
 {
+       struct rip *rip;
        struct prefix p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4((struct prefix_ipv4 *)&p);
 
-       return rip_enable_network_delete(&p);
+       return rip_enable_network_delete(rip, &p);
 }
 
 /*
@@ -344,27 +419,31 @@ static int ripd_instance_interface_create(enum nb_event event,
                                          const struct lyd_node *dnode,
                                          union nb_resource *resource)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_enable_if_add(ifname);
+       return rip_enable_if_add(rip, ifname);
 }
 
 static int ripd_instance_interface_delete(enum nb_event event,
                                          const struct lyd_node *dnode)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_enable_if_delete(ifname);
+       return rip_enable_if_delete(rip, ifname);
 }
 
 /*
@@ -374,15 +453,17 @@ static int ripd_instance_offset_list_create(enum nb_event event,
                                            const struct lyd_node *dnode,
                                            union nb_resource *resource)
 {
+       struct rip *rip;
        const char *ifname;
        struct rip_offset_list *offset;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, "./interface");
 
-       offset = rip_offset_list_new(ifname);
+       offset = rip_offset_list_new(rip, ifname);
        yang_dnode_set_entry(dnode, offset);
 
        return NB_OK;
@@ -467,11 +548,14 @@ static int ripd_instance_passive_default_modify(enum nb_event event,
                                                const struct lyd_node *dnode,
                                                union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->passive_default = yang_dnode_get_bool(dnode, NULL);
-       rip_passive_nondefault_clean();
+       rip_passive_nondefault_clean(rip);
 
        return NB_OK;
 }
@@ -483,27 +567,31 @@ static int ripd_instance_passive_interface_create(enum nb_event event,
                                                  const struct lyd_node *dnode,
                                                  union nb_resource *resource)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_passive_nondefault_set(ifname);
+       return rip_passive_nondefault_set(rip, ifname);
 }
 
 static int ripd_instance_passive_interface_delete(enum nb_event event,
                                                  const struct lyd_node *dnode)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_passive_nondefault_unset(ifname);
+       return rip_passive_nondefault_unset(rip, ifname);
 }
 
 /*
@@ -514,28 +602,32 @@ ripd_instance_non_passive_interface_create(enum nb_event event,
                                           const struct lyd_node *dnode,
                                           union nb_resource *resource)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_passive_nondefault_unset(ifname);
+       return rip_passive_nondefault_unset(rip, ifname);
 }
 
 static int
 ripd_instance_non_passive_interface_delete(enum nb_event event,
                                           const struct lyd_node *dnode)
 {
+       struct rip *rip;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return rip_passive_nondefault_set(ifname);
+       return rip_passive_nondefault_set(rip, ifname);
 }
 
 /*
@@ -545,20 +637,43 @@ static int ripd_instance_redistribute_create(enum nb_event event,
                                             const struct lyd_node *dnode,
                                             union nb_resource *resource)
 {
+       struct rip *rip;
+       int type;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       rip = yang_dnode_get_entry(dnode, true);
+       type = yang_dnode_get_enum(dnode, "./protocol");
+
+       rip->redist[type].enabled = true;
+
        return NB_OK;
 }
 
 static int ripd_instance_redistribute_delete(enum nb_event event,
                                             const struct lyd_node *dnode)
 {
+       struct rip *rip;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
-       rip_redistribute_conf_delete(type);
+       rip->redist[type].enabled = false;
+       if (rip->redist[type].route_map.name) {
+               free(rip->redist[type].route_map.name);
+               rip->redist[type].route_map.name = NULL;
+               rip->redist[type].route_map.map = NULL;
+       }
+       rip->redist[type].metric_config = false;
+       rip->redist[type].metric = 0;
+
+       if (rip->enabled)
+               rip_redistribute_conf_delete(rip, type);
 
        return NB_OK;
 }
@@ -566,10 +681,14 @@ static int ripd_instance_redistribute_delete(enum nb_event event,
 static void
 ripd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
 {
+       struct rip *rip;
        int type;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
-       rip_redistribute_conf_update(type);
+
+       if (rip->enabled)
+               rip_redistribute_conf_update(rip, type);
 }
 
 /*
@@ -580,19 +699,21 @@ ripd_instance_redistribute_route_map_modify(enum nb_event event,
                                            const struct lyd_node *dnode,
                                            union nb_resource *resource)
 {
+       struct rip *rip;
        int type;
        const char *rmap_name;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        rmap_name = yang_dnode_get_string(dnode, NULL);
 
-       if (rip->route_map[type].name)
-               free(rip->route_map[type].name);
-       rip->route_map[type].name = strdup(rmap_name);
-       rip->route_map[type].map = route_map_lookup_by_name(rmap_name);
+       if (rip->redist[type].route_map.name)
+               free(rip->redist[type].route_map.name);
+       rip->redist[type].route_map.name = strdup(rmap_name);
+       rip->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
 
        return NB_OK;
 }
@@ -601,16 +722,18 @@ static int
 ripd_instance_redistribute_route_map_delete(enum nb_event event,
                                            const struct lyd_node *dnode)
 {
+       struct rip *rip;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
-       free(rip->route_map[type].name);
-       rip->route_map[type].name = NULL;
-       rip->route_map[type].map = NULL;
+       free(rip->redist[type].route_map.name);
+       rip->redist[type].route_map.name = NULL;
+       rip->redist[type].route_map.map = NULL;
 
        return NB_OK;
 }
@@ -623,17 +746,19 @@ ripd_instance_redistribute_metric_modify(enum nb_event event,
                                         const struct lyd_node *dnode,
                                         union nb_resource *resource)
 {
+       struct rip *rip;
        int type;
        uint8_t metric;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
-       rip->route_map[type].metric_config = true;
-       rip->route_map[type].metric = metric;
+       rip->redist[type].metric_config = true;
+       rip->redist[type].metric = metric;
 
        return NB_OK;
 }
@@ -642,15 +767,17 @@ static int
 ripd_instance_redistribute_metric_delete(enum nb_event event,
                                         const struct lyd_node *dnode)
 {
+       struct rip *rip;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
-       rip->route_map[type].metric_config = false;
-       rip->route_map[type].metric = 0;
+       rip->redist[type].metric_config = false;
+       rip->redist[type].metric = 0;
 
        return NB_OK;
 }
@@ -662,19 +789,21 @@ static int ripd_instance_static_route_create(enum nb_event event,
                                             const struct lyd_node *dnode,
                                             union nb_resource *resource)
 {
+       struct rip *rip;
        struct nexthop nh;
        struct prefix_ipv4 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4(&p);
 
        memset(&nh, 0, sizeof(nh));
        nh.type = NEXTHOP_TYPE_IPV4;
-       rip_redistribute_add(ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, &nh, 0, 0,
-                            0);
+       rip_redistribute_add(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, &nh, 0,
+                            0, 0);
 
        return NB_OK;
 }
@@ -682,15 +811,17 @@ static int ripd_instance_static_route_create(enum nb_event event,
 static int ripd_instance_static_route_delete(enum nb_event event,
                                             const struct lyd_node *dnode)
 {
+       struct rip *rip;
        struct prefix_ipv4 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv4p(&p, dnode, NULL);
        apply_mask_ipv4(&p);
 
-       rip_redistribute_delete(ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
+       rip_redistribute_delete(rip, ZEBRA_ROUTE_RIP, RIP_ROUTE_STATIC, &p, 0);
 
        return NB_OK;
 }
@@ -700,8 +831,12 @@ static int ripd_instance_static_route_delete(enum nb_event event,
  */
 static void ripd_instance_timers_apply_finish(const struct lyd_node *dnode)
 {
+       struct rip *rip;
+
+       rip = yang_dnode_get_entry(dnode, true);
+
        /* Reset update timer thread. */
-       rip_event(RIP_UPDATE_EVENT, 0);
+       rip_event(rip, RIP_UPDATE_EVENT, 0);
 }
 
 /*
@@ -712,9 +847,12 @@ ripd_instance_timers_flush_interval_modify(enum nb_event event,
                                           const struct lyd_node *dnode,
                                           union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->garbage_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -728,9 +866,12 @@ ripd_instance_timers_holddown_interval_modify(enum nb_event event,
                                              const struct lyd_node *dnode,
                                              union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->timeout_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -744,9 +885,12 @@ ripd_instance_timers_update_interval_modify(enum nb_event event,
                                            const struct lyd_node *dnode,
                                            union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->update_time = yang_dnode_get_uint32(dnode, NULL);
 
        return NB_OK;
@@ -759,9 +903,12 @@ static int ripd_instance_version_receive_modify(enum nb_event event,
                                                const struct lyd_node *dnode,
                                                union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->version_recv = yang_dnode_get_enum(dnode, NULL);
 
        return NB_OK;
@@ -774,9 +921,12 @@ static int ripd_instance_version_send_modify(enum nb_event event,
                                             const struct lyd_node *dnode,
                                             union nb_resource *resource)
 {
+       struct rip *rip;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       rip = yang_dnode_get_entry(dnode, true);
        rip->version_send = yang_dnode_get_enum(dnode, NULL);
 
        return NB_OK;
@@ -1004,24 +1154,26 @@ lib_interface_rip_authentication_key_chain_delete(enum nb_event event,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/neighbors/neighbor
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor
  */
 static const void *
-ripd_state_neighbors_neighbor_get_next(const void *parent_list_entry,
-                                      const void *list_entry)
+ripd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+                                               const void *list_entry)
 {
+       const struct rip *rip = parent_list_entry;
        struct listnode *node;
 
        if (list_entry == NULL)
-               node = listhead(peer_list);
+               node = listhead(rip->peer_list);
        else
                node = listnextnode((struct listnode *)list_entry);
 
        return node;
 }
 
-static int ripd_state_neighbors_neighbor_get_keys(const void *list_entry,
-                                                 struct yang_list_keys *keys)
+static int
+ripd_instance_state_neighbors_neighbor_get_keys(const void *list_entry,
+                                               struct yang_list_keys *keys)
 {
        const struct listnode *node = list_entry;
        const struct rip_peer *peer = listgetdata(node);
@@ -1033,17 +1185,17 @@ static int ripd_state_neighbors_neighbor_get_keys(const void *list_entry,
        return NB_OK;
 }
 
-static const void *
-ripd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry,
-                                          const struct yang_list_keys *keys)
+static const void *ripd_instance_state_neighbors_neighbor_lookup_entry(
+       const void *parent_list_entry, const struct yang_list_keys *keys)
 {
+       const struct rip *rip = parent_list_entry;
        struct in_addr address;
        struct rip_peer *peer;
        struct listnode *node;
 
        yang_str2ipv4(keys->key[0], &address);
 
-       for (ALL_LIST_ELEMENTS_RO(peer_list, node, peer)) {
+       for (ALL_LIST_ELEMENTS_RO(rip->peer_list, node, peer)) {
                if (IPV4_ADDR_SAME(&peer->addr, &address))
                        return node;
        }
@@ -1052,11 +1204,11 @@ ripd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/neighbors/neighbor/address
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/address
  */
 static struct yang_data *
-ripd_state_neighbors_neighbor_address_get_elem(const char *xpath,
-                                              const void *list_entry)
+ripd_instance_state_neighbors_neighbor_address_get_elem(const char *xpath,
+                                                       const void *list_entry)
 {
        const struct listnode *node = list_entry;
        const struct rip_peer *peer = listgetdata(node);
@@ -1065,22 +1217,22 @@ ripd_state_neighbors_neighbor_address_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/neighbors/neighbor/last-update
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/last-update
  */
 static struct yang_data *
-ripd_state_neighbors_neighbor_last_update_get_elem(const char *xpath,
-                                                  const void *list_entry)
+ripd_instance_state_neighbors_neighbor_last_update_get_elem(
+       const char *xpath, const void *list_entry)
 {
        /* TODO: yang:date-and-time is tricky */
        return NULL;
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd
  */
 static struct yang_data *
-ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(const char *xpath,
-                                                       const void *list_entry)
+ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+       const char *xpath, const void *list_entry)
 {
        const struct listnode *node = list_entry;
        const struct rip_peer *peer = listgetdata(node);
@@ -1089,11 +1241,11 @@ ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd
+ * XPath: /frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd
  */
 static struct yang_data *
-ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath,
-                                                      const void *list_entry)
+ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+       const char *xpath, const void *list_entry)
 {
        const struct listnode *node = list_entry;
        const struct rip_peer *peer = listgetdata(node);
@@ -1102,17 +1254,15 @@ ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/routes/route
+ * XPath: /frr-ripd:ripd/instance/state/routes/route
  */
 static const void *
-ripd_state_routes_route_get_next(const void *parent_list_entry,
-                                const void *list_entry)
+ripd_instance_state_routes_route_get_next(const void *parent_list_entry,
+                                         const void *list_entry)
 {
+       const struct rip *rip = parent_list_entry;
        struct route_node *rn;
 
-       if (rip == NULL)
-               return NULL;
-
        if (list_entry == NULL)
                rn = route_top(rip->table);
        else
@@ -1123,8 +1273,9 @@ ripd_state_routes_route_get_next(const void *parent_list_entry,
        return rn;
 }
 
-static int ripd_state_routes_route_get_keys(const void *list_entry,
-                                           struct yang_list_keys *keys)
+static int
+ripd_instance_state_routes_route_get_keys(const void *list_entry,
+                                         struct yang_list_keys *keys)
 {
        const struct route_node *rn = list_entry;
 
@@ -1135,9 +1286,10 @@ static int ripd_state_routes_route_get_keys(const void *list_entry,
 }
 
 static const void *
-ripd_state_routes_route_lookup_entry(const void *parent_list_entry,
-                                    const struct yang_list_keys *keys)
+ripd_instance_state_routes_route_lookup_entry(const void *parent_list_entry,
+                                             const struct yang_list_keys *keys)
 {
+       const struct rip *rip = parent_list_entry;
        struct prefix prefix;
        struct route_node *rn;
 
@@ -1153,11 +1305,11 @@ ripd_state_routes_route_lookup_entry(const void *parent_list_entry,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/routes/route/prefix
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/prefix
  */
 static struct yang_data *
-ripd_state_routes_route_prefix_get_elem(const char *xpath,
-                                       const void *list_entry)
+ripd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+                                                const void *list_entry)
 {
        const struct route_node *rn = list_entry;
        const struct rip_info *rinfo = listnode_head(rn->info);
@@ -1166,11 +1318,11 @@ ripd_state_routes_route_prefix_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/routes/route/next-hop
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/next-hop
  */
 static struct yang_data *
-ripd_state_routes_route_next_hop_get_elem(const char *xpath,
-                                         const void *list_entry)
+ripd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+                                                  const void *list_entry)
 {
        const struct route_node *rn = list_entry;
        const struct rip_info *rinfo = listnode_head(rn->info);
@@ -1185,31 +1337,33 @@ ripd_state_routes_route_next_hop_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/routes/route/interface
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/interface
  */
 static struct yang_data *
-ripd_state_routes_route_interface_get_elem(const char *xpath,
-                                          const void *list_entry)
+ripd_instance_state_routes_route_interface_get_elem(const char *xpath,
+                                                   const void *list_entry)
 {
        const struct route_node *rn = list_entry;
        const struct rip_info *rinfo = listnode_head(rn->info);
+       const struct rip *rip = rip_info_get_instance(rinfo);
 
        switch (rinfo->nh.type) {
        case NEXTHOP_TYPE_IFINDEX:
        case NEXTHOP_TYPE_IPV4_IFINDEX:
                return yang_data_new_string(
-                       xpath, ifindex2ifname(rinfo->nh.ifindex, VRF_DEFAULT));
+                       xpath,
+                       ifindex2ifname(rinfo->nh.ifindex, rip->vrf->vrf_id));
        default:
                return NULL;
        }
 }
 
 /*
- * XPath: /frr-ripd:ripd/state/routes/route/metric
+ * XPath: /frr-ripd:ripd/instance/state/routes/route/metric
  */
 static struct yang_data *
-ripd_state_routes_route_metric_get_elem(const char *xpath,
-                                       const void *list_entry)
+ripd_instance_state_routes_route_metric_get_elem(const char *xpath,
+                                                const void *list_entry)
 {
        const struct route_node *rn = list_entry;
        const struct rip_info *rinfo = listnode_head(rn->info);
@@ -1220,16 +1374,19 @@ ripd_state_routes_route_metric_get_elem(const char *xpath,
 /*
  * XPath: /frr-ripd:clear-rip-route
  */
-static int clear_rip_route_rpc(const char *xpath, const struct list *input,
-                              struct list *output)
+static void clear_rip_route(struct rip *rip)
 {
        struct route_node *rp;
-       struct rip_info *rinfo;
-       struct list *list;
-       struct listnode *listnode;
+
+       if (IS_RIP_DEBUG_EVENT)
+               zlog_debug("Clearing all RIP routes (VRF %s)", rip->vrf_name);
 
        /* Clear received RIP routes */
        for (rp = route_top(rip->table); rp; rp = route_next(rp)) {
+               struct list *list;
+               struct listnode *listnode;
+               struct rip_info *rinfo;
+
                list = rp->info;
                if (!list)
                        continue;
@@ -1239,7 +1396,7 @@ static int clear_rip_route_rpc(const char *xpath, const struct list *input,
                                continue;
 
                        if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
-                               rip_zebra_ipv4_delete(rp);
+                               rip_zebra_ipv4_delete(rip, rp);
                        break;
                }
 
@@ -1256,6 +1413,30 @@ static int clear_rip_route_rpc(const char *xpath, const struct list *input,
                        route_unlock_node(rp);
                }
        }
+}
+
+static int clear_rip_route_rpc(const char *xpath, const struct list *input,
+                              struct list *output)
+{
+       struct rip *rip;
+       struct yang_data *yang_vrf;
+
+       yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
+       if (yang_vrf) {
+               rip = rip_lookup_by_vrf_name(yang_vrf->value);
+               if (rip)
+                       clear_rip_route(rip);
+       } else {
+               struct vrf *vrf;
+
+               RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+                       rip = vrf->info;
+                       if (!rip)
+                               continue;
+
+                       clear_rip_route(rip);
+               }
+       }
 
        return NB_OK;
 }
@@ -1306,6 +1487,9 @@ const struct frr_yang_module_info frr_ripd_info = {
                        .xpath = "/frr-ripd:ripd/instance",
                        .cbs.create = ripd_instance_create,
                        .cbs.destroy = ripd_instance_delete,
+                       .cbs.get_next = ripd_instance_get_next,
+                       .cbs.get_keys = ripd_instance_get_keys,
+                       .cbs.lookup_entry = ripd_instance_lookup_entry,
                        .cbs.cli_show = cli_show_router_rip,
                },
                {
@@ -1490,48 +1674,48 @@ const struct frr_yang_module_info frr_ripd_info = {
                        .cbs.cli_show = cli_show_ip_rip_authentication_key_chain,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/neighbors/neighbor",
-                       .cbs.get_next = ripd_state_neighbors_neighbor_get_next,
-                       .cbs.get_keys = ripd_state_neighbors_neighbor_get_keys,
-                       .cbs.lookup_entry = ripd_state_neighbors_neighbor_lookup_entry,
+                       .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor",
+                       .cbs.get_next = ripd_instance_state_neighbors_neighbor_get_next,
+                       .cbs.get_keys = ripd_instance_state_neighbors_neighbor_get_keys,
+                       .cbs.lookup_entry = ripd_instance_state_neighbors_neighbor_lookup_entry,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/address",
-                       .cbs.get_elem = ripd_state_neighbors_neighbor_address_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/address",
+                       .cbs.get_elem = ripd_instance_state_neighbors_neighbor_address_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/last-update",
-                       .cbs.get_elem = ripd_state_neighbors_neighbor_last_update_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/last-update",
+                       .cbs.get_elem = ripd_instance_state_neighbors_neighbor_last_update_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-packets-rcvd",
-                       .cbs.get_elem = ripd_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-packets-rcvd",
+                       .cbs.get_elem = ripd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/neighbors/neighbor/bad-routes-rcvd",
-                       .cbs.get_elem = ripd_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/neighbors/neighbor/bad-routes-rcvd",
+                       .cbs.get_elem = ripd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/routes/route",
-                       .cbs.get_next = ripd_state_routes_route_get_next,
-                       .cbs.get_keys = ripd_state_routes_route_get_keys,
-                       .cbs.lookup_entry = ripd_state_routes_route_lookup_entry,
+                       .xpath = "/frr-ripd:ripd/instance/state/routes/route",
+                       .cbs.get_next = ripd_instance_state_routes_route_get_next,
+                       .cbs.get_keys = ripd_instance_state_routes_route_get_keys,
+                       .cbs.lookup_entry = ripd_instance_state_routes_route_lookup_entry,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/routes/route/prefix",
-                       .cbs.get_elem = ripd_state_routes_route_prefix_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/routes/route/prefix",
+                       .cbs.get_elem = ripd_instance_state_routes_route_prefix_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/routes/route/next-hop",
-                       .cbs.get_elem = ripd_state_routes_route_next_hop_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/routes/route/next-hop",
+                       .cbs.get_elem = ripd_instance_state_routes_route_next_hop_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/routes/route/interface",
-                       .cbs.get_elem = ripd_state_routes_route_interface_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/routes/route/interface",
+                       .cbs.get_elem = ripd_instance_state_routes_route_interface_get_elem,
                },
                {
-                       .xpath = "/frr-ripd:ripd/state/routes/route/metric",
-                       .cbs.get_elem = ripd_state_routes_route_metric_get_elem,
+                       .xpath = "/frr-ripd:ripd/instance/state/routes/route/metric",
+                       .cbs.get_elem = ripd_instance_state_routes_route_metric_get_elem,
                },
                {
                        .xpath = "/frr-ripd:clear-rip-route",
index ca273c53b2fc41432a355ad4e7508aa7437c3282..b3f84fe50f6a702b1ae8b54415e795c5ff9d0f16 100644 (file)
 
 #include "ripd/ripd.h"
 
-static struct list *rip_offset_list_master;
-
 #define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_IN].alist_name)
 #define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_IN].metric)
 
 #define OFFSET_LIST_OUT_NAME(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].alist_name)
 #define OFFSET_LIST_OUT_METRIC(O)  ((O)->direct[RIP_OFFSET_LIST_OUT].metric)
 
-struct rip_offset_list *rip_offset_list_new(const char *ifname)
+struct rip_offset_list *rip_offset_list_new(struct rip *rip, const char *ifname)
 {
        struct rip_offset_list *offset;
 
        offset = XCALLOC(MTYPE_RIP_OFFSET_LIST, sizeof(struct rip_offset_list));
+       offset->rip = rip;
        offset->ifname = strdup(ifname);
-       listnode_add_sort(rip_offset_list_master, offset);
+       listnode_add_sort(rip->offset_list_master, offset);
 
        return offset;
 }
 
 void offset_list_del(struct rip_offset_list *offset)
 {
-       listnode_delete(rip_offset_list_master, offset);
+       listnode_delete(offset->rip->offset_list_master, offset);
        if (OFFSET_LIST_IN_NAME(offset))
                free(OFFSET_LIST_IN_NAME(offset));
        if (OFFSET_LIST_OUT_NAME(offset))
@@ -59,12 +58,13 @@ void offset_list_del(struct rip_offset_list *offset)
        XFREE(MTYPE_RIP_OFFSET_LIST, offset);
 }
 
-struct rip_offset_list *rip_offset_list_lookup(const char *ifname)
+struct rip_offset_list *rip_offset_list_lookup(struct rip *rip,
+                                              const char *ifname)
 {
        struct rip_offset_list *offset;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(rip_offset_list_master, node, nnode, offset)) {
+       for (ALL_LIST_ELEMENTS(rip->offset_list_master, node, nnode, offset)) {
                if (strcmp(offset->ifname, ifname) == 0)
                        return offset;
        }
@@ -75,11 +75,12 @@ struct rip_offset_list *rip_offset_list_lookup(const char *ifname)
 int rip_offset_list_apply_in(struct prefix_ipv4 *p, struct interface *ifp,
                             uint32_t *metric)
 {
+       struct rip_interface *ri = ifp->info;
        struct rip_offset_list *offset;
        struct access_list *alist;
 
        /* Look up offset-list with interface name. */
-       offset = rip_offset_list_lookup(ifp->name);
+       offset = rip_offset_list_lookup(ri->rip, ifp->name);
        if (offset && OFFSET_LIST_IN_NAME(offset)) {
                alist = access_list_lookup(AFI_IP, OFFSET_LIST_IN_NAME(offset));
 
@@ -92,7 +93,7 @@ int rip_offset_list_apply_in(struct prefix_ipv4 *p, struct interface *ifp,
                return 0;
        }
        /* Look up offset-list without interface name. */
-       offset = rip_offset_list_lookup("*");
+       offset = rip_offset_list_lookup(ri->rip, "*");
        if (offset && OFFSET_LIST_IN_NAME(offset)) {
                alist = access_list_lookup(AFI_IP, OFFSET_LIST_IN_NAME(offset));
 
@@ -111,11 +112,12 @@ int rip_offset_list_apply_in(struct prefix_ipv4 *p, struct interface *ifp,
 int rip_offset_list_apply_out(struct prefix_ipv4 *p, struct interface *ifp,
                              uint32_t *metric)
 {
+       struct rip_interface *ri = ifp->info;
        struct rip_offset_list *offset;
        struct access_list *alist;
 
        /* Look up offset-list with interface name. */
-       offset = rip_offset_list_lookup(ifp->name);
+       offset = rip_offset_list_lookup(ri->rip, ifp->name);
        if (offset && OFFSET_LIST_OUT_NAME(offset)) {
                alist = access_list_lookup(AFI_IP,
                                           OFFSET_LIST_OUT_NAME(offset));
@@ -130,7 +132,7 @@ int rip_offset_list_apply_out(struct prefix_ipv4 *p, struct interface *ifp,
        }
 
        /* Look up offset-list without interface name. */
-       offset = rip_offset_list_lookup("*");
+       offset = rip_offset_list_lookup(ri->rip, "*");
        if (offset && OFFSET_LIST_OUT_NAME(offset)) {
                alist = access_list_lookup(AFI_IP,
                                           OFFSET_LIST_OUT_NAME(offset));
@@ -146,24 +148,7 @@ int rip_offset_list_apply_out(struct prefix_ipv4 *p, struct interface *ifp,
        return 0;
 }
 
-static int offset_list_cmp(struct rip_offset_list *o1,
-                          struct rip_offset_list *o2)
+int offset_list_cmp(struct rip_offset_list *o1, struct rip_offset_list *o2)
 {
        return strcmp(o1->ifname, o2->ifname);
 }
-
-void rip_offset_init(void)
-{
-       rip_offset_list_master = list_new();
-       rip_offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp;
-       rip_offset_list_master->del = (void (*)(void *))offset_list_del;
-}
-
-void rip_offset_clean(void)
-{
-       list_delete(&rip_offset_list_master);
-
-       rip_offset_list_master = list_new();
-       rip_offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp;
-       rip_offset_list_master->del = (void (*)(void *))offset_list_del;
-}
index 21317915d42613853a489112a18684b018c12f62..08aa61257d2853e8cade46a696f3e4e238a1b117 100644 (file)
@@ -29,9 +29,6 @@
 
 #include "ripd/ripd.h"
 
-/* Linked list of RIP peer. */
-struct list *peer_list;
-
 static struct rip_peer *rip_peer_new(void)
 {
        return XCALLOC(MTYPE_RIP_PEER, sizeof(struct rip_peer));
@@ -39,27 +36,28 @@ static struct rip_peer *rip_peer_new(void)
 
 static void rip_peer_free(struct rip_peer *peer)
 {
+       RIP_TIMER_OFF(peer->t_timeout);
        XFREE(MTYPE_RIP_PEER, peer);
 }
 
-struct rip_peer *rip_peer_lookup(struct in_addr *addr)
+struct rip_peer *rip_peer_lookup(struct rip *rip, struct in_addr *addr)
 {
        struct rip_peer *peer;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
                if (IPV4_ADDR_SAME(&peer->addr, addr))
                        return peer;
        }
        return NULL;
 }
 
-struct rip_peer *rip_peer_lookup_next(struct in_addr *addr)
+struct rip_peer *rip_peer_lookup_next(struct rip *rip, struct in_addr *addr)
 {
        struct rip_peer *peer;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
                if (htonl(peer->addr.s_addr) > htonl(addr->s_addr))
                        return peer;
        }
@@ -72,26 +70,27 @@ static int rip_peer_timeout(struct thread *t)
        struct rip_peer *peer;
 
        peer = THREAD_ARG(t);
-       listnode_delete(peer_list, peer);
+       listnode_delete(peer->rip->peer_list, peer);
        rip_peer_free(peer);
 
        return 0;
 }
 
 /* Get RIP peer.  At the same time update timeout thread. */
-static struct rip_peer *rip_peer_get(struct in_addr *addr)
+static struct rip_peer *rip_peer_get(struct rip *rip, struct in_addr *addr)
 {
        struct rip_peer *peer;
 
-       peer = rip_peer_lookup(addr);
+       peer = rip_peer_lookup(rip, addr);
 
        if (peer) {
                if (peer->t_timeout)
                        thread_cancel(peer->t_timeout);
        } else {
                peer = rip_peer_new();
+               peer->rip = rip;
                peer->addr = *addr;
-               listnode_add_sort(peer_list, peer);
+               listnode_add_sort(rip->peer_list, peer);
        }
 
        /* Update timeout thread. */
@@ -105,24 +104,24 @@ static struct rip_peer *rip_peer_get(struct in_addr *addr)
        return peer;
 }
 
-void rip_peer_update(struct sockaddr_in *from, uint8_t version)
+void rip_peer_update(struct rip *rip, struct sockaddr_in *from, uint8_t version)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(&from->sin_addr);
+       peer = rip_peer_get(rip, &from->sin_addr);
        peer->version = version;
 }
 
-void rip_peer_bad_route(struct sockaddr_in *from)
+void rip_peer_bad_route(struct rip *rip, struct sockaddr_in *from)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(&from->sin_addr);
+       peer = rip_peer_get(rip, &from->sin_addr);
        peer->recv_badroutes++;
 }
 
-void rip_peer_bad_packet(struct sockaddr_in *from)
+void rip_peer_bad_packet(struct rip *rip, struct sockaddr_in *from)
 {
        struct rip_peer *peer;
-       peer = rip_peer_get(&from->sin_addr);
+       peer = rip_peer_get(rip, &from->sin_addr);
        peer->recv_badpackets++;
 }
 
@@ -155,14 +154,14 @@ static char *rip_peer_uptime(struct rip_peer *peer, char *buf, size_t len)
        return buf;
 }
 
-void rip_peer_display(struct vty *vty)
+void rip_peer_display(struct vty *vty, struct rip *rip)
 {
        struct rip_peer *peer;
        struct listnode *node, *nnode;
 #define RIP_UPTIME_LEN 25
        char timebuf[RIP_UPTIME_LEN];
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(rip->peer_list, node, nnode, peer)) {
                vty_out(vty, "    %-16s %9d %9d %9d   %s\n",
                        inet_ntoa(peer->addr), peer->recv_badpackets,
                        peer->recv_badroutes, ZEBRA_RIP_DISTANCE_DEFAULT,
@@ -170,7 +169,7 @@ void rip_peer_display(struct vty *vty)
        }
 }
 
-static int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2)
+int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2)
 {
        if (p2->addr.s_addr == p1->addr.s_addr)
                return 0;
@@ -178,8 +177,7 @@ static int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2)
        return (htonl(p1->addr.s_addr) < htonl(p2->addr.s_addr)) ? -1 : 1;
 }
 
-void rip_peer_init(void)
+void rip_peer_list_del(void *arg)
 {
-       peer_list = list_new();
-       peer_list->cmp = (int (*)(void *, void *))rip_peer_list_cmp;
+       rip_peer_free(arg);
 }
index 19367638cc36e9cb9e70b1304b4ec8028b93f90b..5a6b71fbaaacaa1953b002047b341a9531857d7f 100644 (file)
@@ -156,17 +156,23 @@ static uint8_t *rip2Globals(struct variable *v, oid name[], size_t *length,
                            int exact, size_t *var_len,
                            WriteMethod **write_method)
 {
+       struct rip *rip;
+
        if (smux_header_generic(v, name, length, exact, var_len, write_method)
            == MATCH_FAILED)
                return NULL;
 
+       rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
+       if (!rip)
+               return NULL;
+
        /* Retrun global counter. */
        switch (v->magic) {
        case RIP2GLOBALROUTECHANGES:
-               return SNMP_INTEGER(rip_global_route_changes);
+               return SNMP_INTEGER(rip->counters.route_changes);
                break;
        case RIP2GLOBALQUERIES:
-               return SNMP_INTEGER(rip_global_queries);
+               return SNMP_INTEGER(rip->counters.queries);
                break;
        default:
                return NULL;
@@ -281,9 +287,14 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
                                       size_t *length, struct in_addr *addr,
                                       int exact)
 {
+       struct rip *rip;
        int len;
        struct rip_peer *peer;
 
+       rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
+       if (!rip)
+               return NULL;
+
        if (exact) {
                /* Check the length. */
                if (*length - v->namelen != sizeof(struct in_addr) + 1)
@@ -291,7 +302,7 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
 
                oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr);
 
-               peer = rip_peer_lookup(addr);
+               peer = rip_peer_lookup(rip, addr);
 
                if (peer->domain
                    == (int)name[v->namelen + sizeof(struct in_addr)])
@@ -306,7 +317,7 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
                oid2in_addr(name + v->namelen, len, addr);
 
                len = *length - v->namelen;
-               peer = rip_peer_lookup(addr);
+               peer = rip_peer_lookup(rip, addr);
                if (peer) {
                        if ((len < (int)sizeof(struct in_addr) + 1)
                            || (peer->domain
@@ -321,7 +332,7 @@ static struct rip_peer *rip2PeerLookup(struct variable *v, oid name[],
                                return peer;
                        }
                }
-               peer = rip_peer_lookup_next(addr);
+               peer = rip_peer_lookup_next(rip, addr);
 
                if (!peer)
                        return NULL;
@@ -402,10 +413,10 @@ static long rip2IfConfSend(struct rip_interface *ri)
                return ripVersion2;
        else if (ri->ri_send & RIPv1)
                return ripVersion1;
-       else if (rip) {
-               if (rip->version_send == RIPv2)
+       else if (ri->rip) {
+               if (ri->rip->version_send == RIPv2)
                        return ripVersion2;
-               else if (rip->version_send == RIPv1)
+               else if (ri->rip->version_send == RIPv1)
                        return ripVersion1;
        }
        return doNotSend;
@@ -423,7 +434,7 @@ static long rip2IfConfReceive(struct rip_interface *ri)
        if (!ri->running)
                return doNotReceive;
 
-       recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? rip->version_recv
+       recvv = (ri->ri_receive == RI_RIP_UNSPEC) ? ri->rip->version_recv
                                                  : ri->ri_receive;
        if (recvv == RI_RIP_VERSION_1_AND_2)
                return rip1OrRip2;
index fff8681775a8c997f94b37272956d7b063cb6fae..4f0df122329cc0aaa1dceb410c0448b1f854cf62 100644 (file)
@@ -36,7 +36,8 @@
 struct zclient *zclient = NULL;
 
 /* Send ECMP routes to zebra. */
-static void rip_zebra_ipv4_send(struct route_node *rp, uint8_t cmd)
+static void rip_zebra_ipv4_send(struct rip *rip, struct route_node *rp,
+                               uint8_t cmd)
 {
        struct list *list = (struct list *)rp->info;
        struct zapi_route api;
@@ -46,7 +47,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, uint8_t cmd)
        int count = 0;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = rip->vrf->vrf_id;
        api.type = ZEBRA_ROUTE_RIP;
        api.safi = SAFI_UNICAST;
 
@@ -55,7 +56,7 @@ static void rip_zebra_ipv4_send(struct route_node *rp, uint8_t cmd)
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
-               api_nh->vrf_id = VRF_DEFAULT;
+               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)
@@ -101,28 +102,30 @@ static void rip_zebra_ipv4_send(struct route_node *rp, uint8_t cmd)
                                   inet_ntoa(rp->p.u.prefix4), rp->p.prefixlen);
        }
 
-       rip_global_route_changes++;
+       rip->counters.route_changes++;
 }
 
 /* Add/update ECMP routes to zebra. */
-void rip_zebra_ipv4_add(struct route_node *rp)
+void rip_zebra_ipv4_add(struct rip *rip, struct route_node *rp)
 {
-       rip_zebra_ipv4_send(rp, ZEBRA_ROUTE_ADD);
+       rip_zebra_ipv4_send(rip, rp, ZEBRA_ROUTE_ADD);
 }
 
 /* Delete ECMP routes from zebra. */
-void rip_zebra_ipv4_delete(struct route_node *rp)
+void rip_zebra_ipv4_delete(struct rip *rip, struct route_node *rp)
 {
-       rip_zebra_ipv4_send(rp, ZEBRA_ROUTE_DELETE);
+       rip_zebra_ipv4_send(rip, rp, ZEBRA_ROUTE_DELETE);
 }
 
 /* Zebra route add and delete treatment. */
 static int rip_zebra_read_route(int command, struct zclient *zclient,
                                zebra_size_t length, vrf_id_t vrf_id)
 {
+       struct rip *rip;
        struct zapi_route api;
        struct nexthop nh;
 
+       rip = rip_lookup_by_vrf_id(vrf_id);
        if (!rip)
                return 0;
 
@@ -136,68 +139,95 @@ static int rip_zebra_read_route(int command, struct zclient *zclient,
 
        /* Then fetch IPv4 prefixes. */
        if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
-               rip_redistribute_add(api.type, RIP_ROUTE_REDISTRIBUTE,
+               rip_redistribute_add(rip, api.type, RIP_ROUTE_REDISTRIBUTE,
                                     (struct prefix_ipv4 *)&api.prefix, &nh,
                                     api.metric, api.distance, api.tag);
        else if (command == ZEBRA_REDISTRIBUTE_ROUTE_DEL)
-               rip_redistribute_delete(api.type, RIP_ROUTE_REDISTRIBUTE,
+               rip_redistribute_delete(rip, api.type, RIP_ROUTE_REDISTRIBUTE,
                                        (struct prefix_ipv4 *)&api.prefix,
                                        nh.ifindex);
 
        return 0;
 }
 
-void rip_redistribute_conf_update(int type)
+void rip_redistribute_conf_update(struct rip *rip, int type)
 {
        zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
-                            0, VRF_DEFAULT);
+                            0, rip->vrf->vrf_id);
 }
 
-void rip_redistribute_conf_delete(int type)
+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, VRF_DEFAULT);
+                                       AFI_IP, type, 0, rip->vrf->vrf_id);
 
        /* Remove the routes from RIP table. */
-       rip_redistribute_withdraw(type);
+       rip_redistribute_withdraw(rip, type);
 }
 
-int rip_redistribute_check(int type)
+int rip_redistribute_check(struct rip *rip, int type)
 {
-       return vrf_bitmap_check(zclient->redist[AFI_IP][type], VRF_DEFAULT);
+       return rip->redist[type].enabled;
 }
 
-void rip_redistribute_clean(void)
+void rip_redistribute_enable(struct rip *rip)
 {
        for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-               if (!vrf_bitmap_check(zclient->redist[AFI_IP][i], VRF_DEFAULT))
+               if (!rip_redistribute_check(rip, i))
                        continue;
 
-               if (zclient->sock > 0)
-                       zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE,
-                                               zclient, AFI_IP, i, 0,
-                                               VRF_DEFAULT);
+               zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP,
+                                       i, 0, rip->vrf->vrf_id);
+       }
+}
 
-               vrf_bitmap_unset(zclient->redist[AFI_IP][i], VRF_DEFAULT);
+void rip_redistribute_disable(struct rip *rip)
+{
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+               if (!rip_redistribute_check(rip, i))
+                       continue;
 
-               /* Remove the routes from RIP table. */
-               rip_redistribute_withdraw(i);
+               zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
+                                       AFI_IP, i, 0, rip->vrf->vrf_id);
        }
 }
 
-void rip_show_redistribute_config(struct vty *vty)
+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],
-                                        VRF_DEFAULT))
+                   || !rip_redistribute_check(rip, i))
                        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 +245,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 d2fc9eb303271aede6cd3d9d236f6fc2b176c51c..9683e26b56c2ad3c26e6ebcaf5c5c63ec235310a 100644 (file)
 #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
 
-/* RIP Structure. */
-struct rip *rip = NULL;
-
-/* RIP neighbor address table. */
-struct route_table *rip_neighbor_table;
-
-/* RIP route changes. */
-long rip_global_route_changes = 0;
-
-/* RIP queries. */
-long rip_global_queries = 0;
-
 /* Prototypes. */
 static void rip_output_process(struct connected *, struct sockaddr_in *, int,
                               uint8_t);
 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);
@@ -86,6 +79,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)
 {
@@ -117,6 +119,11 @@ void rip_info_free(struct rip_info *rinfo)
        XFREE(MTYPE_RIP_INFO, rinfo);
 }
 
+struct rip *rip_info_get_instance(const struct rip_info *rinfo)
+{
+       return route_table_get_info(rinfo->rp->table);
+}
+
 /* RIP route garbage collect timer. */
 static int rip_garbage_collect(struct thread *t)
 {
@@ -145,13 +152,13 @@ static int rip_garbage_collect(struct thread *t)
        return 0;
 }
 
-static void rip_timeout_update(struct rip_info *rinfo);
+static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo);
 
 /* Add new route to the ECMP list.
  * RETURN: the new entry added in the list, or NULL if it is not the first
  *         entry and ECMP is not allowed.
  */
-struct rip_info *rip_ecmp_add(struct rip_info *rinfo_new)
+struct rip_info *rip_ecmp_add(struct rip *rip, struct rip_info *rinfo_new)
 {
        struct route_node *rp = rinfo_new->rp;
        struct rip_info *rinfo = NULL;
@@ -171,8 +178,8 @@ struct rip_info *rip_ecmp_add(struct rip_info *rinfo_new)
        listnode_add(list, rinfo);
 
        if (rip_route_rte(rinfo)) {
-               rip_timeout_update(rinfo);
-               rip_zebra_ipv4_add(rp);
+               rip_timeout_update(rip, rinfo);
+               rip_zebra_ipv4_add(rip, rp);
        }
 
        /* Set the route change flag on the first entry. */
@@ -180,7 +187,7 @@ struct rip_info *rip_ecmp_add(struct rip_info *rinfo_new)
        SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
 
        /* Signal the output process to trigger an update (see section 2.5). */
-       rip_event(RIP_TRIGGERED_UPDATE, 0);
+       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -188,7 +195,7 @@ struct rip_info *rip_ecmp_add(struct rip_info *rinfo_new)
 /* Replace the ECMP list with the new route.
  * RETURN: the new entry added in the list
  */
-struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new)
+struct rip_info *rip_ecmp_replace(struct rip *rip, struct rip_info *rinfo_new)
 {
        struct route_node *rp = rinfo_new->rp;
        struct list *list = (struct list *)rp->info;
@@ -196,7 +203,7 @@ struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new)
        struct listnode *node = NULL, *nextnode = NULL;
 
        if (list == NULL || listcount(list) == 0)
-               return rip_ecmp_add(rinfo_new);
+               return rip_ecmp_add(rip, rinfo_new);
 
        /* Get the first entry */
        rinfo = listgetdata(listhead(list));
@@ -204,7 +211,7 @@ struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new)
        /* Learnt route replaced by a local one. Delete it from zebra. */
        if (rip_route_rte(rinfo) && !rip_route_rte(rinfo_new))
                if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
-                       rip_zebra_ipv4_delete(rp);
+                       rip_zebra_ipv4_delete(rip, rp);
 
        /* Re-use the first entry, and delete the others. */
        for (ALL_LIST_ELEMENTS(list, node, nextnode, tmp_rinfo))
@@ -220,16 +227,16 @@ struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new)
        memcpy(rinfo, rinfo_new, sizeof(struct rip_info));
 
        if (rip_route_rte(rinfo)) {
-               rip_timeout_update(rinfo);
+               rip_timeout_update(rip, rinfo);
                /* The ADD message implies an update. */
-               rip_zebra_ipv4_add(rp);
+               rip_zebra_ipv4_add(rip, rp);
        }
 
        /* Set the route change flag. */
        SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
 
        /* Signal the output process to trigger an update (see section 2.5). */
-       rip_event(RIP_TRIGGERED_UPDATE, 0);
+       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -240,7 +247,7 @@ struct rip_info *rip_ecmp_replace(struct rip_info *rinfo_new)
  *  the entry - the entry is the last one in the list; its metric is set
  *              to INFINITY, and the garbage collector is started for it
  */
-struct rip_info *rip_ecmp_delete(struct rip_info *rinfo)
+struct rip_info *rip_ecmp_delete(struct rip *rip, struct rip_info *rinfo)
 {
        struct route_node *rp = rinfo->rp;
        struct list *list = (struct list *)rp->info;
@@ -255,7 +262,7 @@ struct rip_info *rip_ecmp_delete(struct rip_info *rinfo)
                if (rip_route_rte(rinfo)
                    && CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
                        /* The ADD message implies the update. */
-                       rip_zebra_ipv4_add(rp);
+                       rip_zebra_ipv4_add(rip, rp);
                rip_info_free(rinfo);
                rinfo = NULL;
        } else {
@@ -271,7 +278,7 @@ struct rip_info *rip_ecmp_delete(struct rip_info *rinfo)
 
                if (rip_route_rte(rinfo)
                    && CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
-                       rip_zebra_ipv4_delete(rp);
+                       rip_zebra_ipv4_delete(rip, rp);
        }
 
        /* Set the route change flag on the first entry. */
@@ -279,7 +286,7 @@ struct rip_info *rip_ecmp_delete(struct rip_info *rinfo)
        SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
 
        /* Signal the output process to trigger an update (see section 2.5). */
-       rip_event(RIP_TRIGGERED_UPDATE, 0);
+       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -287,15 +294,20 @@ struct rip_info *rip_ecmp_delete(struct rip_info *rinfo)
 /* Timeout RIP routes. */
 static int rip_timeout(struct thread *t)
 {
-       rip_ecmp_delete((struct rip_info *)THREAD_ARG(t));
+       struct rip_info *rinfo = THREAD_ARG(t);
+       struct rip *rip = rip_info_get_instance(rinfo);
+
+       rip_ecmp_delete(rip, rinfo);
+
        return 0;
 }
 
-static void rip_timeout_update(struct rip_info *rinfo)
+static void rip_timeout_update(struct rip *rip, struct rip_info *rinfo)
 {
        if (rinfo->metric != RIP_METRIC_INFINITY) {
                RIP_TIMER_OFF(rinfo->t_timeout);
-               RIP_TIMER_ON(rinfo->t_timeout, rip_timeout, rip->timeout_time);
+               thread_add_timer(master, rip_timeout, rinfo, rip->timeout_time,
+                                &rinfo->t_timeout);
        }
 }
 
@@ -334,7 +346,7 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p,
        }
 
        /* All interface filter check. */
-       dist = distribute_lookup(rip->distribute_ctx, NULL);
+       dist = distribute_lookup(ri->rip->distribute_ctx, NULL);
        if (dist) {
                if (dist->list[distribute]) {
                        alist = access_list_lookup(AFI_IP,
@@ -373,9 +385,8 @@ static int rip_filter(int rip_distribute, struct prefix_ipv4 *p,
 }
 
 /* Check nexthop address validity. */
-static int rip_nexthop_check(struct in_addr *addr)
+static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
        struct listnode *cnode;
        struct connected *ifc;
@@ -384,7 +395,7 @@ static int rip_nexthop_check(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;
 
@@ -400,6 +411,7 @@ static int rip_nexthop_check(struct in_addr *addr)
 static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                            struct interface *ifp)
 {
+       struct rip *rip;
        int ret;
        struct prefix_ipv4 p;
        struct route_node *rp;
@@ -420,9 +432,10 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
        /* Make sure mask is applied. */
        apply_mask_ipv4(&p);
 
-       /* Apply input filters. */
        ri = ifp->info;
+       rip = ri->rip;
 
+       /* Apply input filters. */
        ret = rip_filter(RIP_FILTER_IN, &p, ri);
        if (ret < 0)
                return;
@@ -481,7 +494,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                nexthop = &rte->nexthop;
 
        /* Check if nexthop address is myself, then do nothing. */
-       if (rip_nexthop_check(nexthop) < 0) {
+       if (rip_nexthop_check(rip, nexthop) < 0) {
                if (IS_RIP_DEBUG_PACKET)
                        zlog_debug("Nexthop address %s is myself",
                                   inet_ntoa(*nexthop));
@@ -496,7 +509,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
        newinfo.nh.type = NEXTHOP_TYPE_IPV4;
        newinfo.metric = rte->metric;
        newinfo.tag = ntohs(rte->tag);
-       newinfo.distance = rip_distance_apply(&newinfo);
+       newinfo.distance = rip_distance_apply(rip, &newinfo);
 
        new_dist = newinfo.distance ? newinfo.distance
                                    : ZEBRA_RIP_DISTANCE_DEFAULT;
@@ -580,7 +593,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                           mark it as a ghost */
                        if (new_dist <= old_dist
                            && rte->metric != RIP_METRIC_INFINITY)
-                               rip_ecmp_replace(&newinfo);
+                               rip_ecmp_replace(rip, &newinfo);
 
                        route_unlock_node(rp);
                        return;
@@ -597,7 +610,7 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                   infinity (there is no point in adding a route which
                   unusable). */
                if (rte->metric != RIP_METRIC_INFINITY)
-                       rip_ecmp_add(&newinfo);
+                       rip_ecmp_add(rip, &newinfo);
        } else {
                /* Route is there but we are not sure the route is RIP or not.
                 */
@@ -626,18 +639,18 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                    || ((old_dist != new_dist) && same)) {
                        if (listcount(list) == 1) {
                                if (newinfo.metric != RIP_METRIC_INFINITY)
-                                       rip_ecmp_replace(&newinfo);
+                                       rip_ecmp_replace(rip, &newinfo);
                                else
-                                       rip_ecmp_delete(rinfo);
+                                       rip_ecmp_delete(rip, rinfo);
                        } else {
                                if (newinfo.metric < rinfo->metric)
-                                       rip_ecmp_replace(&newinfo);
+                                       rip_ecmp_replace(rip, &newinfo);
                                else if (newinfo.metric > rinfo->metric)
-                                       rip_ecmp_delete(rinfo);
+                                       rip_ecmp_delete(rip, rinfo);
                                else if (new_dist < old_dist)
-                                       rip_ecmp_replace(&newinfo);
+                                       rip_ecmp_replace(rip, &newinfo);
                                else if (new_dist > old_dist)
-                                       rip_ecmp_delete(rinfo);
+                                       rip_ecmp_delete(rip, rinfo);
                                else {
                                        int update = CHECK_FLAG(rinfo->flags,
                                                                RIP_RTF_FIB)
@@ -651,20 +664,20 @@ static void rip_rte_process(struct rte *rte, struct sockaddr_in *from,
                                        RIP_TIMER_OFF(rinfo->t_garbage_collect);
                                        memcpy(rinfo, &newinfo,
                                               sizeof(struct rip_info));
-                                       rip_timeout_update(rinfo);
+                                       rip_timeout_update(rip, rinfo);
 
                                        if (update)
-                                               rip_zebra_ipv4_add(rp);
+                                               rip_zebra_ipv4_add(rip, rp);
 
                                        /* - Set the route change flag on the
                                         * first entry. */
                                        rinfo = listgetdata(listhead(list));
                                        SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
-                                       rip_event(RIP_TRIGGERED_UPDATE, 0);
+                                       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
                                }
                        }
                } else /* same & no change */
-                       rip_timeout_update(rinfo);
+                       rip_timeout_update(rip, rinfo);
 
                /* Unlock tempolary lock of the route. */
                route_unlock_node(rp);
@@ -1088,6 +1101,8 @@ static void rip_response_process(struct rip_packet *packet, int size,
                                 struct sockaddr_in *from,
                                 struct connected *ifc)
 {
+       struct rip_interface *ri = ifc->ifp->info;
+       struct rip *rip = ri->rip;
        caddr_t lim;
        struct rte *rte;
        struct prefix_ipv4 ifaddr;
@@ -1103,7 +1118,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
        if (from->sin_port != htons(RIP_PORT_DEFAULT)) {
                zlog_info("response doesn't come from RIP port: %d",
                          from->sin_port);
-               rip_peer_bad_packet(from);
+               rip_peer_bad_packet(rip, from);
                return;
        }
 
@@ -1111,12 +1126,13 @@ 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, VRF_DEFAULT)
+       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",
                        inet_ntoa(from->sin_addr));
-               rip_peer_bad_packet(from);
+               rip_peer_bad_packet(rip, from);
                return;
        }
 
@@ -1126,7 +1142,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
        ; /* Alredy done in rip_read () */
 
        /* Update RIP peer. */
-       rip_peer_update(from, packet->version);
+       rip_peer_update(rip, from, packet->version);
 
        /* Set RTE pointer. */
        rte = packet->rte;
@@ -1155,7 +1171,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                if (!rip_destination_check(rte->prefix)) {
                        zlog_info(
                                "Network is net 0 or net 127 or it is not unicast network");
-                       rip_peer_bad_route(from);
+                       rip_peer_bad_route(rip, from);
                        continue;
                }
 
@@ -1165,7 +1181,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                /* - is the metric valid (i.e., between 1 and 16, inclusive) */
                if (!(rte->metric >= 1 && rte->metric <= 16)) {
                        zlog_info("Route's metric is not in the 1-16 range.");
-                       rip_peer_bad_route(from);
+                       rip_peer_bad_route(rip, from);
                        continue;
                }
 
@@ -1173,7 +1189,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                if (packet->version == RIPv1 && rte->nexthop.s_addr != 0) {
                        zlog_info("RIPv1 packet with nexthop value %s",
                                  inet_ntoa(rte->nexthop));
-                       rip_peer_bad_route(from);
+                       rip_peer_bad_route(rip, from);
                        continue;
                }
 
@@ -1194,7 +1210,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                        }
 
                        if (!if_lookup_address((void *)&rte->nexthop, AF_INET,
-                                              VRF_DEFAULT)) {
+                                              rip->vrf->vrf_id)) {
                                struct route_node *rn;
                                struct rip_info *rinfo;
 
@@ -1305,7 +1321,7 @@ static void rip_response_process(struct rip_packet *packet, int size,
                        zlog_warn(
                                "RIPv2 address %s is not mask /%d applied one",
                                inet_ntoa(rte->prefix), ip_masklen(rte->mask));
-                       rip_peer_bad_route(from);
+                       rip_peer_bad_route(rip, from);
                        continue;
                }
 
@@ -1324,11 +1340,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;
@@ -1340,20 +1357,23 @@ 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));
-               exit(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);
        sockopt_reuseaddr(sock);
        sockopt_reuseport(sock);
        setsockopt_ipv4_multicast_loop(sock, 0);
-#ifdef RIP_RECVMSG
-       setsockopt_pktinfo(sock);
-#endif /* RIP_RECVMSG */
 #ifdef IPTOS_PREC_INTERNETCONTROL
        setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL);
 #endif
@@ -1382,10 +1402,21 @@ int rip_create_socket(void)
 static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to,
                           struct connected *ifc)
 {
+       struct rip_interface *ri;
+       struct rip *rip;
        int ret;
        struct sockaddr_in sin;
+       struct msghdr msg;
+       struct iovec iov;
+#ifdef GNU_LINUX
+       struct cmsghdr *cmsgptr;
+       char adata[256] = {};
+       struct in_pktinfo *pkt;
+#endif /* GNU_LINUX */
 
        assert(ifc != NULL);
+       ri = ifc->ifp->info;
+       rip = ri->rip;
 
        if (IS_RIP_DEBUG_PACKET) {
 #define ADDRESS_SIZE 20
@@ -1443,8 +1474,27 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to,
                rip_interface_multicast_set(rip->sock, ifc);
        }
 
-       ret = sendto(rip->sock, buf, size, 0, (struct sockaddr *)&sin,
-                    sizeof(struct sockaddr_in));
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_name = (void *)&sin;
+       msg.msg_namelen = sizeof(struct sockaddr_in);
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       iov.iov_base = buf;
+       iov.iov_len = size;
+
+#ifdef GNU_LINUX
+       msg.msg_control = (void *)adata;
+       msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+
+       cmsgptr = (struct cmsghdr *)adata;
+       cmsgptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+       cmsgptr->cmsg_level = IPPROTO_IP;
+       cmsgptr->cmsg_type = IP_PKTINFO;
+       pkt = (struct in_pktinfo *)CMSG_DATA(cmsgptr);
+       pkt->ipi_ifindex = ifc->ifp->ifindex;
+#endif /* GNU_LINUX */
+
+       ret = sendmsg(rip->sock, &msg, 0);
 
        if (IS_RIP_DEBUG_EVENT)
                zlog_debug("SEND to  %s.%d", inet_ntoa(sin.sin_addr),
@@ -1457,9 +1507,10 @@ static int rip_send_packet(uint8_t *buf, int size, struct sockaddr_in *to,
 }
 
 /* Add redistributed route to RIP table. */
-void rip_redistribute_add(int type, int sub_type, struct prefix_ipv4 *p,
-                         struct nexthop *nh, unsigned int metric,
-                         unsigned char distance, route_tag_t tag)
+void rip_redistribute_add(struct rip *rip, int type, int sub_type,
+                         struct prefix_ipv4 *p, struct nexthop *nh,
+                         unsigned int metric, unsigned char distance,
+                         route_tag_t tag)
 {
        int ret;
        struct route_node *rp = NULL;
@@ -1506,22 +1557,22 @@ void rip_redistribute_add(int type, int sub_type, struct prefix_ipv4 *p,
                        }
                }
 
-               (void)rip_ecmp_replace(&newinfo);
+               (void)rip_ecmp_replace(rip, &newinfo);
                route_unlock_node(rp);
        } else
-               (void)rip_ecmp_add(&newinfo);
+               (void)rip_ecmp_add(rip, &newinfo);
 
        if (IS_RIP_DEBUG_EVENT) {
                zlog_debug("Redistribute new prefix %s/%d",
                           inet_ntoa(p->prefix), p->prefixlen);
        }
 
-       rip_event(RIP_TRIGGERED_UPDATE, 0);
+       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
 }
 
 /* Delete redistributed route from RIP table. */
-void rip_redistribute_delete(int type, int sub_type, struct prefix_ipv4 *p,
-                            ifindex_t ifindex)
+void rip_redistribute_delete(struct rip *rip, int type, int sub_type,
+                            struct prefix_ipv4 *p, ifindex_t ifindex)
 {
        int ret;
        struct route_node *rp;
@@ -1554,10 +1605,11 @@ void rip_redistribute_delete(int type, int sub_type, struct prefix_ipv4 *p,
                                                "infinity metric [delete]",
                                                inet_ntoa(p->prefix),
                                                p->prefixlen,
-                                               ifindex2ifname(ifindex,
-                                                              VRF_DEFAULT));
+                                               ifindex2ifname(
+                                                       ifindex,
+                                                       rip->vrf->vrf_id));
 
-                               rip_event(RIP_TRIGGERED_UPDATE, 0);
+                               rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
                        }
                }
                route_unlock_node(rp);
@@ -1568,6 +1620,7 @@ void rip_redistribute_delete(int type, int sub_type, struct prefix_ipv4 *p,
 static void rip_request_process(struct rip_packet *packet, int size,
                                struct sockaddr_in *from, struct connected *ifc)
 {
+       struct rip *rip;
        caddr_t lim;
        struct rte *rte;
        struct prefix_ipv4 p;
@@ -1583,13 +1636,14 @@ static void rip_request_process(struct rip_packet *packet, int size,
        ri = ifc->ifp->info;
        if (!ri->running)
                return;
+       rip = ri->rip;
 
        /* When passive interface is specified, suppress responses */
        if (ri->passive)
                return;
 
        /* RIP peer update. */
-       rip_peer_update(from, packet->version);
+       rip_peer_update(rip, from, packet->version);
 
        lim = ((caddr_t)packet) + size;
        rte = packet->rte;
@@ -1639,87 +1693,13 @@ static void rip_request_process(struct rip_packet *packet, int size,
 
                (void)rip_send_packet((uint8_t *)packet, size, from, ifc);
        }
-       rip_global_queries++;
-}
-
-#if RIP_RECVMSG
-/* Set IPv6 packet info to the socket. */
-static int setsockopt_pktinfo(int sock)
-{
-       int ret;
-       int val = 1;
-
-       ret = setsockopt(sock, IPPROTO_IP, IP_PKTINFO, &val, sizeof(val));
-       if (ret < 0)
-               zlog_warn("Can't setsockopt IP_PKTINFO : %s",
-                         safe_strerror(errno));
-       return ret;
-}
-
-/* Read RIP packet by recvmsg function. */
-int rip_recvmsg(int sock, uint8_t *buf, int size, struct sockaddr_in *from,
-               ifindex_t *ifindex)
-{
-       int ret;
-       struct msghdr msg;
-       struct iovec iov;
-       struct cmsghdr *ptr;
-       char adata[1024];
-
-       memset(&msg, 0, sizeof(msg));
-       msg.msg_name = (void *)from;
-       msg.msg_namelen = sizeof(struct sockaddr_in);
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       msg.msg_control = (void *)adata;
-       msg.msg_controllen = sizeof adata;
-       iov.iov_base = buf;
-       iov.iov_len = size;
-
-       ret = recvmsg(sock, &msg, 0);
-       if (ret < 0)
-               return ret;
-
-       for (ptr = ZCMSG_FIRSTHDR(&msg); ptr != NULL;
-            ptr = CMSG_NXTHDR(&msg, ptr))
-               if (ptr->cmsg_level == IPPROTO_IP
-                   && ptr->cmsg_type == IP_PKTINFO) {
-                       struct in_pktinfo *pktinfo;
-                       int i;
-
-                       pktinfo = (struct in_pktinfo *)CMSG_DATA(ptr);
-                       i = pktinfo->ipi_ifindex;
-               }
-       return ret;
-}
-
-/* RIP packet read function. */
-int rip_read_new(struct thread *t)
-{
-       int ret;
-       int sock;
-       char buf[RIP_PACKET_MAXSIZ];
-       struct sockaddr_in from;
-       ifindex_t ifindex;
-
-       /* Fetch socket then register myself. */
-       sock = THREAD_FD(t);
-       rip_event(RIP_READ, sock);
-
-       /* Read RIP packet. */
-       ret = rip_recvmsg(sock, buf, RIP_PACKET_MAXSIZ, &from, (int *)&ifindex);
-       if (ret < 0) {
-               zlog_warn("Can't read RIP packet: %s", safe_strerror(errno));
-               return ret;
-       }
-
-       return ret;
+       rip->counters.queries++;
 }
-#endif /* RIP_RECVMSG */
 
 /* First entry point of RIP packet. */
 static int rip_read(struct thread *t)
 {
+       struct rip *rip = THREAD_ARG(t);
        int sock;
        int ret;
        int rtenum;
@@ -1739,7 +1719,7 @@ static int rip_read(struct thread *t)
        rip->t_read = NULL;
 
        /* Add myself to tne next event */
-       rip_event(RIP_READ, sock);
+       rip_event(rip, RIP_READ, sock);
 
        /* RIPd manages only IPv4. */
        memset(&from, 0, sizeof(struct sockaddr_in));
@@ -1748,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(from.sin_addr)) {
+       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, VRF_DEFAULT);
+       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;
        }
 
@@ -1787,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;
        }
 
@@ -1797,13 +1781,13 @@ static int rip_read(struct thread *t)
        if (len < RIP_PACKET_MINSIZ) {
                zlog_warn("packet size %d is smaller than minimum size %d", len,
                          RIP_PACKET_MINSIZ);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return len;
        }
        if (len > RIP_PACKET_MAXSIZ) {
                zlog_warn("packet size %d is larger than max size %d", len,
                          RIP_PACKET_MAXSIZ);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return len;
        }
 
@@ -1811,7 +1795,7 @@ static int rip_read(struct thread *t)
        if ((len - RIP_PACKET_MINSIZ) % 20) {
                zlog_warn("packet size %d is wrong for RIP packet alignment",
                          len);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return len;
        }
 
@@ -1825,7 +1809,7 @@ static int rip_read(struct thread *t)
        if (packet->version == 0) {
                zlog_info("version 0 with command %d received.",
                          packet->command);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return -1;
        }
 
@@ -1842,11 +1826,11 @@ static int rip_read(struct thread *t)
 
        /* Is RIP running or is this RIP neighbor ?*/
        ri = ifp->info;
-       if (!ri->running && !rip_neighbor_lookup(&from)) {
+       if (!ri->running && !rip_neighbor_lookup(rip, &from)) {
                if (IS_RIP_DEBUG_EVENT)
                        zlog_debug("RIP is not enabled on interface %s.",
                                   ifp->name);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return -1;
        }
 
@@ -1860,7 +1844,7 @@ static int rip_read(struct thread *t)
                        zlog_debug(
                                "  packet's v%d doesn't fit to if version spec",
                                packet->version);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return -1;
        }
 
@@ -1875,7 +1859,7 @@ static int rip_read(struct thread *t)
                                "packet RIPv%d is dropped because authentication disabled",
                                packet->version);
                ripd_notif_send_auth_type_failure(ifp->name);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                return -1;
        }
 
@@ -1912,7 +1896,7 @@ static int rip_read(struct thread *t)
                                        "RIPv1"
                                        " dropped because authentication enabled");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(&from);
+                       rip_peer_bad_packet(rip, &from);
                        return -1;
                }
        } else if (ri->auth_type != RIP_NO_AUTH) {
@@ -1925,7 +1909,7 @@ static int rip_read(struct thread *t)
                                zlog_debug(
                                        "RIPv2 authentication failed: no auth RTE in packet");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(&from);
+                       rip_peer_bad_packet(rip, &from);
                        return -1;
                }
 
@@ -1936,7 +1920,7 @@ static int rip_read(struct thread *t)
                                        "RIPv2"
                                        " dropped because authentication enabled");
                        ripd_notif_send_auth_type_failure(ifp->name);
-                       rip_peer_bad_packet(&from);
+                       rip_peer_bad_packet(rip, &from);
                        return -1;
                }
 
@@ -1972,7 +1956,7 @@ static int rip_read(struct thread *t)
                                zlog_debug("RIPv2 %s authentication failure",
                                           auth_desc);
                        ripd_notif_send_auth_failure(ifp->name);
-                       rip_peer_bad_packet(&from);
+                       rip_peer_bad_packet(rip, &from);
                        return -1;
                }
        }
@@ -1991,16 +1975,16 @@ static int rip_read(struct thread *t)
                zlog_info(
                        "Obsolete command %s received, please sent it to routed",
                        lookup_msg(rip_msg, packet->command, NULL));
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                break;
        case RIP_POLL_ENTRY:
                zlog_info("Obsolete command %s received",
                          lookup_msg(rip_msg, packet->command, NULL));
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                break;
        default:
                zlog_info("Unknown RIP command %d received", packet->command);
-               rip_peer_bad_packet(&from);
+               rip_peer_bad_packet(rip, &from);
                break;
        }
 
@@ -2040,6 +2024,7 @@ static int rip_write_rte(int num, struct stream *s, struct prefix_ipv4 *p,
 void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                        int route_type, uint8_t version)
 {
+       struct rip *rip;
        int ret;
        struct stream *s;
        struct route_node *rp;
@@ -2069,6 +2054,10 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                                   ifc->ifp->name, ifc->ifp->ifindex);
        }
 
+       /* Get RIP interface. */
+       ri = ifc->ifp->info;
+       rip = ri->rip;
+
        /* Set output stream. */
        s = rip->obuf;
 
@@ -2076,9 +2065,6 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
        stream_reset(s);
        rtemax = RIP_MAX_RTE;
 
-       /* Get RIP interface. */
-       ri = ifc->ifp->info;
-
        /* If output interface is in simple password authentication mode, we
           need space for authentication data.  */
        if (ri->auth_type == RIP_AUTH_SIMPLE_PASSWORD)
@@ -2252,10 +2238,10 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                        }
 
                        /* Apply redistribute route map - continue, if deny */
-                       if (rip->route_map[rinfo->type].name
+                       if (rip->redist[rinfo->type].route_map.name
                            && rinfo->sub_type != RIP_ROUTE_INTERFACE) {
                                ret = route_map_apply(
-                                       rip->route_map[rinfo->type].map,
+                                       rip->redist[rinfo->type].route_map.map,
                                        (struct prefix *)p, RMAP_RIP, rinfo);
 
                                if (ret == RMAP_DENYMATCH) {
@@ -2271,11 +2257,10 @@ void rip_output_process(struct connected *ifc, struct sockaddr_in *to,
                        /* When route-map does not set metric. */
                        if (!rinfo->metric_set) {
                                /* If redistribute metric is set. */
-                               if (rip->route_map[rinfo->type].metric_config
+                               if (rip->redist[rinfo->type].metric_config
                                    && rinfo->metric != RIP_METRIC_INFINITY) {
                                        rinfo->metric_out =
-                                               rip->route_map[rinfo->type]
-                                                       .metric;
+                                               rip->redist[rinfo->type].metric;
                                } else {
                                        /* If the route is not connected or
                                           localy generated
@@ -2450,9 +2435,8 @@ static void rip_update_interface(struct connected *ifc, uint8_t version,
 }
 
 /* Update send to all interface and neighbor. */
-static void rip_update_process(int route_type)
+static void rip_update_process(struct rip *rip, int route_type)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct listnode *ifnode, *ifnnode;
        struct connected *connected;
        struct interface *ifp;
@@ -2462,7 +2446,7 @@ static void rip_update_process(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;
 
@@ -2515,7 +2499,7 @@ static void rip_update_process(int route_type)
                        p = &rp->p;
 
                        connected = if_lookup_address(&p->u.prefix4, AF_INET,
-                                                     VRF_DEFAULT);
+                                                     rip->vrf->vrf_id);
                        if (!connected) {
                                zlog_warn(
                                        "Neighbor %s doesn't have connected interface!",
@@ -2537,6 +2521,8 @@ static void rip_update_process(int route_type)
 /* RIP's periodical timer. */
 static int rip_update(struct thread *t)
 {
+       struct rip *rip = THREAD_ARG(t);
+
        /* Clear timer pointer. */
        rip->t_update = NULL;
 
@@ -2544,7 +2530,7 @@ static int rip_update(struct thread *t)
                zlog_debug("update timer fire!");
 
        /* Process update output. */
-       rip_update_process(rip_all_route);
+       rip_update_process(rip, rip_all_route);
 
        /* Triggered updates may be suppressed if a regular update is due by
           the time the triggered update would be sent. */
@@ -2552,13 +2538,13 @@ static int rip_update(struct thread *t)
        rip->trigger = 0;
 
        /* Register myself. */
-       rip_event(RIP_UPDATE_EVENT, 0);
+       rip_event(rip, RIP_UPDATE_EVENT, 0);
 
        return 0;
 }
 
 /* Walk down the RIP routing table then clear changed flag. */
-static void rip_clear_changed_flag(void)
+static void rip_clear_changed_flag(struct rip *rip)
 {
        struct route_node *rp;
        struct rip_info *rinfo = NULL;
@@ -2578,7 +2564,7 @@ static void rip_clear_changed_flag(void)
 /* Triggered update interval timer. */
 static int rip_triggered_interval(struct thread *t)
 {
-       int rip_triggered_update(struct thread *);
+       struct rip *rip = THREAD_ARG(t);
 
        rip->t_triggered_interval = NULL;
 
@@ -2592,6 +2578,7 @@ static int rip_triggered_interval(struct thread *t)
 /* Execute triggered update. */
 static int rip_triggered_update(struct thread *t)
 {
+       struct rip *rip = THREAD_ARG(t);
        int interval;
 
        /* Clear thred pointer. */
@@ -2607,11 +2594,11 @@ static int rip_triggered_update(struct thread *t)
 
        /* Split Horizon processing is done when generating triggered
           updates as well as normal updates (see section 2.6). */
-       rip_update_process(rip_changed_route);
+       rip_update_process(rip, rip_changed_route);
 
        /* Once all of the triggered updates have been generated, the route
           change flags should be cleared. */
-       rip_clear_changed_flag();
+       rip_clear_changed_flag(rip);
 
        /* After a triggered update is sent, a timer should be set for a
         random interval between 1 and 5 seconds.  If other changes that
@@ -2620,22 +2607,19 @@ static int rip_triggered_update(struct thread *t)
        interval = (random() % 5) + 1;
 
        rip->t_triggered_interval = NULL;
-       thread_add_timer(master, rip_triggered_interval, NULL, interval,
+       thread_add_timer(master, rip_triggered_interval, rip, interval,
                         &rip->t_triggered_interval);
 
        return 0;
 }
 
 /* Withdraw redistributed route. */
-void rip_redistribute_withdraw(int type)
+void rip_redistribute_withdraw(struct rip *rip, int type)
 {
        struct route_node *rp;
        struct rip_info *rinfo = NULL;
        struct list *list = NULL;
 
-       if (!rip)
-               return;
-
        for (rp = route_top(rip->table); rp; rp = route_next(rp))
                if ((list = rp->info) != NULL) {
                        rinfo = listgetdata(listhead(list));
@@ -2659,18 +2643,41 @@ void rip_redistribute_withdraw(int type)
                                                p->prefixlen,
                                                ifindex2ifname(
                                                        rinfo->nh.ifindex,
-                                                       VRF_DEFAULT));
+                                                       rip->vrf->vrf_id));
                                }
 
-                               rip_event(RIP_TRIGGERED_UPDATE, 0);
+                               rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
                        }
                }
 }
 
+struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
+       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. */
-int rip_create(int socket)
+struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
 {
+       struct rip *rip;
+
        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);
@@ -2691,33 +2698,46 @@ int rip_create(int socket)
        rip->version_recv =
                yang_get_default_enum("%s/version/receive", RIP_INSTANCE);
 
-       /* Initialize RIP routig table. */
+       /* Initialize RIP data structures. */
        rip->table = route_table_init();
+       route_table_set_info(rip->table, rip);
        rip->neighbor = route_table_init();
+       rip->peer_list = list_new();
+       rip->peer_list->cmp = (int (*)(void *, void *))rip_peer_list_cmp;
+       rip->peer_list->del = rip_peer_list_del;
+       rip->distance_table = route_table_init();
+       rip->distance_table->cleanup = rip_distance_table_node_cleanup;
+       rip->enable_interface = vector_init(1);
+       rip->enable_network = route_table_init();
+       rip->passive_nondefault = vector_init(1);
+       rip->offset_list_master = list_new();
+       rip->offset_list_master->cmp = (int (*)(void *, void *))offset_list_cmp;
+       rip->offset_list_master->del = (void (*)(void *))offset_list_del;
 
-       /* Make output stream. */
-       rip->obuf = stream_new(1500);
-
-       /* Set socket. */
-       rip->sock = socket;
-
-       /* Create read and timer thread. */
-       rip_event(RIP_READ, rip->sock);
-       rip_event(RIP_UPDATE_EVENT, 1);
        /* Distribute list install. */
-       rip->distribute_ctx = distribute_list_ctx_create(
-                                        vrf_lookup_by_id(VRF_DEFAULT));
-       distribute_list_add_hook(rip->distribute_ctx,
-                                rip_distribute_update);
-       distribute_list_delete_hook(rip->distribute_ctx,
-                                   rip_distribute_update);
+       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);
 
        /* if rmap install. */
-       rip->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME);
+       rip->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
        if_rmap_hook_add(rip->if_rmap_ctx, rip_if_rmap_update);
        if_rmap_hook_delete(rip->if_rmap_ctx, rip_if_rmap_update);
 
-       return 0;
+       /* Make output stream. */
+       rip->obuf = stream_new(1500);
+
+       /* 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;
 }
 
 /* Sned RIP request to the destination. */
@@ -2786,19 +2806,19 @@ static int rip_update_jitter(unsigned long time)
        return jitter / JITTER_BOUND;
 }
 
-void rip_event(enum rip_event event, int sock)
+void rip_event(struct rip *rip, enum rip_event event, int sock)
 {
        int jitter = 0;
 
        switch (event) {
        case RIP_READ:
                rip->t_read = NULL;
-               thread_add_read(master, rip_read, NULL, sock, &rip->t_read);
+               thread_add_read(master, rip_read, rip, sock, &rip->t_read);
                break;
        case RIP_UPDATE_EVENT:
                RIP_TIMER_OFF(rip->t_update);
                jitter = rip_update_jitter(rip->update_time);
-               thread_add_timer(master, rip_update, NULL,
+               thread_add_timer(master, rip_update, rip,
                                 sock ? 2 : rip->update_time + jitter,
                                 &rip->t_update);
                break;
@@ -2806,7 +2826,7 @@ void rip_event(enum rip_event event, int sock)
                if (rip->t_triggered_interval)
                        rip->trigger = 1;
                else
-                       thread_add_event(master, rip_triggered_update, NULL, 0,
+                       thread_add_event(master, rip_triggered_update, rip, 0,
                                         &rip->t_triggered_update);
                break;
        default:
@@ -2831,9 +2851,6 @@ rip_update_default_metric (void)
 }
 #endif
 
-
-struct route_table *rip_distance_table;
-
 struct rip_distance *rip_distance_new(void)
 {
        return XCALLOC(MTYPE_RIP_DISTANCE, sizeof(struct rip_distance));
@@ -2841,42 +2858,36 @@ struct rip_distance *rip_distance_new(void)
 
 void rip_distance_free(struct rip_distance *rdistance)
 {
+       if (rdistance->access_list)
+               free(rdistance->access_list);
        XFREE(MTYPE_RIP_DISTANCE, rdistance);
 }
 
-static void rip_distance_reset(void)
+static void rip_distance_table_node_cleanup(struct route_table *table,
+                                           struct route_node *node)
 {
-       struct route_node *rn;
        struct rip_distance *rdistance;
 
-       for (rn = route_top(rip_distance_table); rn; rn = route_next(rn))
-               if ((rdistance = rn->info) != NULL) {
-                       if (rdistance->access_list)
-                               free(rdistance->access_list);
-                       rip_distance_free(rdistance);
-                       rn->info = NULL;
-                       route_unlock_node(rn);
-               }
+       rdistance = node->info;
+       if (rdistance)
+               rip_distance_free(rdistance);
 }
 
 /* Apply RIP information to distance method. */
-uint8_t rip_distance_apply(struct rip_info *rinfo)
+uint8_t rip_distance_apply(struct rip *rip, struct rip_info *rinfo)
 {
        struct route_node *rn;
        struct prefix_ipv4 p;
        struct rip_distance *rdistance;
        struct access_list *alist;
 
-       if (!rip)
-               return 0;
-
        memset(&p, 0, sizeof(struct prefix_ipv4));
        p.family = AF_INET;
        p.prefix = rinfo->from;
        p.prefixlen = IPV4_MAX_BITLEN;
 
        /* Check source address. */
-       rn = route_node_match(rip_distance_table, (struct prefix *)&p);
+       rn = route_node_match(rip->distance_table, (struct prefix *)&p);
        if (rn) {
                rdistance = rn->info;
                route_unlock_node(rn);
@@ -2901,7 +2912,7 @@ uint8_t rip_distance_apply(struct rip_info *rinfo)
        return 0;
 }
 
-static void rip_distance_show(struct vty *vty)
+static void rip_distance_show(struct vty *vty, struct rip *rip)
 {
        struct route_node *rn;
        struct rip_distance *rdistance;
@@ -2911,7 +2922,7 @@ static void rip_distance_show(struct vty *vty)
        vty_out(vty, "  Distance: (default is %u)\n",
                rip->distance ? rip->distance : ZEBRA_RIP_DISTANCE_DEFAULT);
 
-       for (rn = route_top(rip_distance_table); rn; rn = route_next(rn))
+       for (rn = route_top(rip->distance_table); rn; rn = route_next(rn))
                if ((rdistance = rn->info) != NULL) {
                        if (header) {
                                vty_out(vty,
@@ -2928,16 +2939,13 @@ static void rip_distance_show(struct vty *vty)
 }
 
 /* Update ECMP routes to zebra when ECMP is disabled. */
-void rip_ecmp_disable(void)
+void rip_ecmp_disable(struct rip *rip)
 {
        struct route_node *rp;
        struct rip_info *rinfo, *tmp_rinfo;
        struct list *list;
        struct listnode *node, *nextnode;
 
-       if (!rip)
-               return;
-
        for (rp = route_top(rip->table); rp; rp = route_next(rp))
                if ((list = rp->info) != NULL && listcount(list) > 1) {
                        rinfo = listgetdata(listhead(list));
@@ -2955,13 +2963,13 @@ void rip_ecmp_disable(void)
                                }
 
                        /* Update zebra. */
-                       rip_zebra_ipv4_add(rp);
+                       rip_zebra_ipv4_add(rip, rp);
 
                        /* Set the route change flag. */
                        SET_FLAG(rinfo->flags, RIP_RTF_CHANGED);
 
                        /* Signal the output process to trigger an update. */
-                       rip_event(RIP_TRIGGERED_UPDATE, 0);
+                       rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
                }
 }
 
@@ -3007,18 +3015,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;
 
-       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"
@@ -3110,21 +3134,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 vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct rip *rip;
        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;
 
-       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%%,",
@@ -3143,7 +3182,7 @@ DEFUN (show_ip_rip_status,
 
        /* Redistribute information. */
        vty_out(vty, "  Redistributing:");
-       rip_show_redistribute_config(vty);
+       rip_show_redistribute_config(vty, rip);
        vty_out(vty, "\n");
 
        vty_out(vty, "  Default version control: send version %s,",
@@ -3156,7 +3195,7 @@ DEFUN (show_ip_rip_status,
 
        vty_out(vty, "    Interface        Send  Recv   Key-chain\n");
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (rip->vrf, ifp) {
                ri = ifp->info;
 
                if (!ri->running)
@@ -3186,11 +3225,11 @@ DEFUN (show_ip_rip_status,
        }
 
        vty_out(vty, "  Routing for Networks:\n");
-       rip_show_network_config(vty);
+       rip_show_network_config(vty, rip);
 
        {
                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)
@@ -3208,9 +3247,9 @@ DEFUN (show_ip_rip_status,
        vty_out(vty, "  Routing Information Sources:\n");
        vty_out(vty,
                "    Gateway          BadPackets BadRoutes  Distance Last Update\n");
-       rip_peer_display(vty);
+       rip_peer_display(vty, rip);
 
-       rip_distance_show(vty);
+       rip_distance_show(vty, rip);
 
        return CMD_SUCCESS;
 }
@@ -3218,23 +3257,30 @@ 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) {
-               write++;
+       RB_FOREACH(rip, rip_instance_head, &rip_instances) {
+               char xpath[XPATH_MAXLEN];
+               struct lyd_node *dnode;
+
+               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);
 
                /* Distribute configuration. */
-               write += config_write_distribute(vty,
-                                                rip->distribute_ctx);
+               config_write_distribute(vty, rip->distribute_ctx);
 
                /* Interface routemap configuration */
-               write += config_write_if_rmap(vty, rip->if_rmap_ctx);
+               config_write_if_rmap(vty, rip->if_rmap_ctx);
+
+               write = 1;
        }
+
        return write;
 }
 
@@ -3250,10 +3296,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;
 
@@ -3302,6 +3348,8 @@ static void rip_distribute_update(struct distribute_ctx *ctx,
 
 void rip_distribute_update_interface(struct interface *ifp)
 {
+       struct rip_interface *ri = ifp->info;
+       struct rip *rip = ri->rip;
        struct distribute *dist;
 
        if (!rip)
@@ -3328,77 +3376,35 @@ static void rip_distribute_update_all_wrapper(struct access_list *notused)
 }
 
 /* Delete all added rip route. */
-void rip_clean(void)
+void rip_clean(struct rip *rip)
 {
-       int i;
-       struct route_node *rp;
-       struct rip_info *rinfo = NULL;
-       struct list *list = NULL;
-       struct listnode *listnode = NULL;
-
-       if (rip) {
-               /* Clear RIP routes */
-               for (rp = route_top(rip->table); rp; rp = route_next(rp))
-                       if ((list = rp->info) != NULL) {
-                               rinfo = listgetdata(listhead(list));
-                               if (rip_route_rte(rinfo))
-                                       rip_zebra_ipv4_delete(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;
-               }
-
-               stream_free(rip->obuf);
-
-               /* RIP neighbor configuration. */
-               for (rp = route_top(rip->neighbor); rp; rp = route_next(rp))
-                       if (rp->info) {
-                               rp->info = NULL;
-                               route_unlock_node(rp);
-                       }
+       if (rip->enabled)
+               rip_instance_disable(rip);
 
-               for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                       if (rip->route_map[i].name)
-                               free(rip->route_map[i].name);
+       stream_free(rip->obuf);
 
-               route_table_finish(rip->table);
-               route_table_finish(rip->neighbor);
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
+               if (rip->redist[i].route_map.name)
+                       free(rip->redist[i].route_map.name);
 
-               distribute_list_delete(&rip->distribute_ctx);
+       route_table_finish(rip->table);
+       route_table_finish(rip->neighbor);
+       list_delete(&rip->peer_list);
+       distribute_list_delete(&rip->distribute_ctx);
+       if_rmap_ctx_delete(rip->if_rmap_ctx);
 
-               if_rmap_ctx_delete(rip->if_rmap_ctx);
+       rip_clean_network(rip);
+       rip_passive_nondefault_clean(rip);
+       vector_free(rip->enable_interface);
+       route_table_finish(rip->enable_network);
+       vector_free(rip->passive_nondefault);
+       list_delete(&rip->offset_list_master);
+       rip_interfaces_clean(rip);
+       route_table_finish(rip->distance_table);
 
-               XFREE(MTYPE_RIP, rip);
-               rip = NULL;
-       }
-       rip_clean_network();
-       rip_passive_nondefault_clean();
-       rip_offset_clean();
-       rip_interfaces_clean();
-       rip_distance_reset();
-       rip_redistribute_clean();
-       if_rmap_terminate();
+       RB_REMOVE(rip_instance_head, &rip_instances, rip);
+       XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
+       XFREE(MTYPE_RIP, rip);
 }
 
 static void rip_if_rmap_update(struct if_rmap_ctx *ctx,
@@ -3438,13 +3444,13 @@ static void rip_if_rmap_update(struct if_rmap_ctx *ctx,
 
 void rip_if_rmap_update_interface(struct interface *ifp)
 {
+       struct rip_interface *ri = ifp->info;
+       struct rip *rip = ri->rip;
        struct if_rmap *if_rmap;
        struct if_rmap_ctx *ctx;
 
        if (!rip)
                return;
-       if (ifp->vrf_id != VRF_DEFAULT)
-               return;
        ctx = rip->if_rmap_ctx;
        if (!ctx)
                return;
@@ -3453,19 +3459,14 @@ void rip_if_rmap_update_interface(struct interface *ifp)
                rip_if_rmap_update(ctx, if_rmap);
 }
 
-static void rip_routemap_update_redistribute(void)
+static void rip_routemap_update_redistribute(struct rip *rip)
 {
-       int i;
-
-       if (rip) {
-               for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-                       if (rip->route_map[i].name) {
-                               rip->route_map[i].map =
-                                       route_map_lookup_by_name(
-                                               rip->route_map[i].name);
-                               route_map_counter_increment(
-                                       rip->route_map[i].map);
-                       }
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+               if (rip->redist[i].route_map.name) {
+                       rip->redist[i].route_map.map = route_map_lookup_by_name(
+                               rip->redist[i].route_map.name);
+                       route_map_counter_increment(
+                               rip->redist[i].route_map.map);
                }
        }
 }
@@ -3474,12 +3475,183 @@ static void rip_routemap_update_redistribute(void)
 static void rip_routemap_update(const char *notused)
 {
        struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct rip *rip;
        struct interface *ifp;
 
        FOR_ALL_INTERFACES (vrf, ifp)
                rip_if_rmap_update_interface(ifp);
 
-       rip_routemap_update_redistribute();
+       rip = vrf->info;
+       if (rip)
+               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;
+
+       /* Resend all redistribute requests. */
+       rip_redistribute_enable(rip);
+
+       /* 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);
+       }
+
+       /* Flush all redistribute requests. */
+       rip_redistribute_disable(rip);
+
+       /* 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. */
@@ -3512,13 +3684,9 @@ void rip_init(void)
 
        /* Route-map */
        rip_route_map_init();
-       rip_offset_init();
 
        route_map_add_hook(rip_routemap_update);
        route_map_delete_hook(rip_routemap_update);
 
        if_rmap_init(RIP_NODE);
-
-       /* Distance control. */
-       rip_distance_table = route_table_init();
 }
index 383df3707ba9b6ecc4f911ff50ad6bb641c6d774..7b196a16be40e13a489b05918965b6e6efd35634 100644 (file)
 
 /* RIP structure. */
 struct rip {
+       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;
 
@@ -112,9 +123,12 @@ struct rip {
        /* RIP routing information base. */
        struct route_table *table;
 
-       /* RIP neighbor. */
+       /* RIP static neighbors. */
        struct route_table *neighbor;
 
+       /* Linked list of RIP peers. */
+       struct list *peer_list;
+
        /* RIP threads. */
        struct thread *t_read;
 
@@ -144,20 +158,46 @@ struct rip {
        /* Are we in passive-interface default mode? */
        bool passive_default;
 
-       /* For redistribute route map. */
+       /* RIP enabled interfaces. */
+       vector enable_interface;
+
+       /* RIP enabled networks. */
+       struct route_table *enable_network;
+
+       /* Vector to store passive-interface name. */
+       vector passive_nondefault;
+
+       /* RIP offset-lists. */
+       struct list *offset_list_master;
+
+       /* RIP redistribute configuration. */
        struct {
-               char *name;
-               struct route_map *map;
+               bool enabled;
+               struct {
+                       char *name;
+                       struct route_map *map;
+               } route_map;
                bool metric_config;
                uint8_t metric;
-       } route_map[ZEBRA_ROUTE_MAX];
+       } redist[ZEBRA_ROUTE_MAX];
 
        /* For distribute-list container */
        struct distribute_ctx *distribute_ctx;
 
        /* For if_rmap container */
        struct if_rmap_ctx *if_rmap_ctx;
+
+       /* Counters for SNMP. */
+       struct {
+               /* RIP route changes. */
+               long route_changes;
+
+               /* RIP queries. */
+               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 {
@@ -225,11 +265,6 @@ struct rip_info {
        struct route_node *rp;
 
        uint8_t distance;
-
-#ifdef NEW_RIP_TABLE
-       struct rip_info *next;
-       struct rip_info *prev;
-#endif /* NEW_RIP_TABLE */
 };
 
 typedef enum {
@@ -240,6 +275,9 @@ typedef enum {
 
 /* RIP specific interface configuration. */
 struct rip_interface {
+       /* Parent routing instance. */
+       struct rip *rip;
+
        /* RIP is enabled on this interface. */
        int enable_network;
        int enable_interface;
@@ -297,6 +335,9 @@ struct rip_interface {
 
 /* RIP peer information. */
 struct rip_peer {
+       /* Parent routing instance. */
+       struct rip *rip;
+
        /* Peer address. */
        struct in_addr addr;
 
@@ -369,6 +410,9 @@ enum rip_event {
 #define RIP_OFFSET_LIST_MAX 2
 
 struct rip_offset_list {
+       /* Parent routing instance. */
+       struct rip *rip;
+
        char *ifname;
 
        struct {
@@ -380,104 +424,114 @@ struct rip_offset_list {
 
 /* Prototypes. */
 extern void rip_init(void);
-extern void rip_clean(void);
-extern void rip_clean_network(void);
-extern void rip_interfaces_clean(void);
-extern int rip_passive_nondefault_set(const char *ifname);
-extern int rip_passive_nondefault_unset(const char *ifname);
-extern void rip_passive_nondefault_clean(void);
+extern void rip_clean(struct rip *rip);
+extern void rip_clean_network(struct rip *rip);
+extern void rip_interfaces_clean(struct rip *rip);
+extern int rip_passive_nondefault_set(struct rip *rip, const char *ifname);
+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_if_down_all(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 in_addr addr);
-extern int rip_create(int socket);
+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_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 *);
-extern int rip_neighbor_lookup(struct sockaddr_in *);
-extern int rip_neighbor_add(struct prefix_ipv4 *p);
-extern int rip_neighbor_delete(struct prefix_ipv4 *p);
-
-extern int rip_enable_network_add(struct prefix *p);
-extern int rip_enable_network_delete(struct prefix *p);
-extern int rip_enable_if_add(const char *ifname);
-extern int rip_enable_if_delete(const char *ifname);
-
-extern void rip_event(enum rip_event, int);
-extern void rip_ecmp_disable(void);
-
-extern int rip_create_socket(void);
-
-extern int rip_redistribute_check(int);
-extern void rip_redistribute_conf_update(int type);
-extern void rip_redistribute_conf_delete(int type);
-extern void rip_redistribute_add(int type, int sub_type, struct prefix_ipv4 *p,
-                                struct nexthop *nh, unsigned int metric,
-                                unsigned char distance, route_tag_t tag);
-extern void rip_redistribute_delete(int, int, struct prefix_ipv4 *, ifindex_t);
-extern void rip_redistribute_withdraw(int);
-extern void rip_zebra_ipv4_add(struct route_node *);
-extern void rip_zebra_ipv4_delete(struct route_node *);
+extern int rip_neighbor_lookup(struct rip *rip, struct sockaddr_in *from);
+extern int rip_neighbor_add(struct rip *rip, struct prefix_ipv4 *p);
+extern int rip_neighbor_delete(struct rip *rip, struct prefix_ipv4 *p);
+
+extern int rip_enable_network_add(struct rip *rip, struct prefix *p);
+extern int rip_enable_network_delete(struct rip *rip, struct prefix *p);
+extern int rip_enable_if_add(struct rip *rip, const char *ifname);
+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(struct vrf *vrf);
+
+extern int rip_redistribute_check(struct rip *rip, int type);
+extern void rip_redistribute_conf_update(struct rip *rip, int type);
+extern void rip_redistribute_conf_delete(struct rip *rip, int type);
+extern void rip_redistribute_add(struct rip *rip, int type, int sub_type,
+                                struct prefix_ipv4 *p, struct nexthop *nh,
+                                unsigned int metric, unsigned char distance,
+                                route_tag_t tag);
+extern void rip_redistribute_delete(struct rip *rip, int type, int sub_type,
+                                   struct prefix_ipv4 *p, ifindex_t ifindex);
+extern void rip_redistribute_withdraw(struct rip *rip, int type);
+extern void rip_zebra_ipv4_add(struct rip *rip, struct route_node *rp);
+extern void rip_zebra_ipv4_delete(struct rip *rip, struct route_node *rp);
 extern void rip_interface_multicast_set(int, struct connected *);
 extern void rip_distribute_update_interface(struct interface *);
 extern void rip_if_rmap_update_interface(struct interface *ifp);
-extern int rip_show_network_config(struct vty *);
-extern void rip_show_redistribute_config(struct vty *);
 
-extern void rip_peer_init(void);
-extern void rip_peer_update(struct sockaddr_in *, uint8_t);
-extern void rip_peer_bad_route(struct sockaddr_in *);
-extern void rip_peer_bad_packet(struct sockaddr_in *);
-extern void rip_peer_display(struct vty *);
-extern struct rip_peer *rip_peer_lookup(struct in_addr *);
-extern struct rip_peer *rip_peer_lookup_next(struct in_addr *);
+extern int rip_show_network_config(struct vty *vty, struct rip *rip);
+extern void rip_show_redistribute_config(struct vty *vty, struct rip *rip);
+
+extern void rip_peer_update(struct rip *rip, struct sockaddr_in *from,
+                           uint8_t version);
+extern void rip_peer_bad_route(struct rip *rip, struct sockaddr_in *from);
+extern void rip_peer_bad_packet(struct rip *rip, struct sockaddr_in *from);
+extern void rip_peer_display(struct vty *vty, struct rip *rip);
+extern struct rip_peer *rip_peer_lookup(struct rip *rip, struct in_addr *addr);
+extern struct rip_peer *rip_peer_lookup_next(struct rip *rip,
+                                            struct in_addr *addr);
+extern int rip_peer_list_cmp(struct rip_peer *p1, struct rip_peer *p2);
+extern void rip_peer_list_del(void *arg);
 
 extern void rip_info_free(struct rip_info *);
+extern struct rip *rip_info_get_instance(const struct rip_info *rinfo);
 extern struct rip_distance *rip_distance_new(void);
 extern void rip_distance_free(struct rip_distance *rdistance);
-extern uint8_t rip_distance_apply(struct rip_info *);
-extern void rip_redistribute_clean(void);
+extern uint8_t rip_distance_apply(struct rip *rip, struct rip_info *rinfo);
+extern void rip_redistribute_enable(struct rip *rip);
+extern void rip_redistribute_disable(struct rip *rip);
 
 extern int rip_route_rte(struct rip_info *rinfo);
-extern struct rip_info *rip_ecmp_add(struct rip_info *);
-extern struct rip_info *rip_ecmp_replace(struct rip_info *);
-extern struct rip_info *rip_ecmp_delete(struct rip_info *);
-
-extern struct rip_offset_list *rip_offset_list_new(const char *ifname);
+extern struct rip_info *rip_ecmp_add(struct rip *rip,
+                                    struct rip_info *rinfo_new);
+extern struct rip_info *rip_ecmp_replace(struct rip *rip,
+                                        struct rip_info *rinfo_new);
+extern struct rip_info *rip_ecmp_delete(struct rip *rip,
+                                       struct rip_info *rinfo);
+
+extern struct rip_offset_list *rip_offset_list_new(struct rip *rip,
+                                                  const char *ifname);
 extern void offset_list_del(struct rip_offset_list *offset);
-extern struct rip_offset_list *rip_offset_list_lookup(const char *ifname);
+extern struct rip_offset_list *rip_offset_list_lookup(struct rip *rip,
+                                                     const char *ifname);
 extern int rip_offset_list_apply_in(struct prefix_ipv4 *, struct interface *,
                                    uint32_t *);
 extern int rip_offset_list_apply_out(struct prefix_ipv4 *, struct interface *,
                                     uint32_t *);
-extern void rip_offset_init(void);
-extern void rip_offset_clean(void);
+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);
 
-/* There is only one rip strucutre. */
-extern struct rip *rip;
-
 extern struct zebra_privs_t ripd_privs;
+extern struct rip_instance_head rip_instances;
 
 /* Master thread strucutre. */
 extern struct thread_master *master;
 
-/* RIP statistics for SNMP. */
-extern long rip_global_route_changes;
-extern long rip_global_queries;
-
 DECLARE_HOOK(rip_ifaddr_add, (struct connected * ifc), (ifc))
 DECLARE_HOOK(rip_ifaddr_del, (struct connected * ifc), (ifc))
 
-extern struct list *peer_list;
-extern struct route_table *rip_distance_table;
-extern vector Vrip_passive_nondefault;
-
 /* Northbound. */
 extern void rip_cli_init(void);
 extern const struct frr_yang_module_info frr_ripd_info;
index 23a48031704a45b8b48801814116146222647b12..e95c0e95d672395000498b75d535717e99260fe6 100644 (file)
  */
 DEFPY_NOSH (router_ripng,
        router_ripng_cmd,
-       "router ripng",
+       "router ripng [vrf NAME]",
        "Enable a routing process\n"
-       "Make RIPng instance command\n")
+       "Make RIPng instance command\n"
+       VRF_CMD_HELP_STR)
 {
+       char xpath[XPATH_MAXLEN];
        int ret;
 
-       nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_CREATE,
-                             NULL);
+       /* Build RIPng instance XPath. */
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
+       snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/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(RIPNG_NODE, "/frr-ripngd:ripngd/instance");
+               VTY_PUSH_XPATH(RIPNG_NODE, xpath);
 
        return ret;
 }
 
 DEFPY (no_router_ripng,
        no_router_ripng_cmd,
-       "no router ripng",
+       "no router ripng [vrf NAME]",
        NO_STR
        "Enable a routing process\n"
-       "Make RIPng instance command\n")
+       "Make RIPng instance command\n"
+       VRF_CMD_HELP_STR)
 {
-       nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DESTROY,
-                             NULL);
+       char xpath[XPATH_MAXLEN];
+
+       /* Build RIPng instance XPath. */
+       if (!vrf)
+               vrf = VRF_DEFAULT_NAME;
+       snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']",
+                vrf);
+
+       nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
 
        return nb_cli_apply_changes(vty, NULL);
 }
@@ -71,8 +86,15 @@ DEFPY (no_router_ripng,
 void cli_show_router_ripng(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 ripng\n");
+       vty_out(vty, "router ripng");
+       if (!strmatch(vrf_name, VRF_DEFAULT_NAME))
+               vty_out(vty, " vrf %s", vrf_name);
+       vty_out(vty, "\n");
 }
 
 /*
@@ -456,12 +478,24 @@ void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode,
  */
 DEFPY (clear_ipv6_rip,
        clear_ipv6_rip_cmd,
-       "clear ipv6 ripng",
+       "clear ipv6 ripng [vrf WORD]",
        CLEAR_STR
        IPV6_STR
-       "Clear IPv6 RIP database\n")
+       "Clear IPv6 RIP database\n"
+       VRF_CMD_HELP_STR)
 {
-       return nb_cli_rpc("/frr-ripngd:clear-ripng-route", NULL, NULL);
+       struct list *input;
+
+       input = list_new();
+       if (vrf) {
+               struct yang_data *yang_vrf;
+
+               yang_vrf = yang_data_new(
+                       "/frr-ripngd:clear-ripng-route/input/vrf", vrf);
+               listnode_add(input, yang_vrf);
+       }
+
+       return nb_cli_rpc("/frr-ripngd:clear-ripng-route", input, NULL);
 }
 
 void ripng_cli_init(void)
index e5dc6e6af69ccefb906185ca3804b0d623c13a90..43fa6632079de7023c4c1cf26348eaf66cfc3422 100644 (file)
 /* Static utility function. */
 static void ripng_enable_apply(struct interface *);
 static void ripng_passive_interface_apply(struct interface *);
-static int ripng_enable_if_lookup(const char *);
+static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname);
 static int ripng_enable_network_lookup2(struct connected *);
-static void ripng_enable_apply_all(void);
+static void ripng_enable_apply_all(struct ripng *ripng);
 
 /* Join to the all rip routers multicast group. */
-static int ripng_multicast_join(struct interface *ifp)
+static int ripng_multicast_join(struct interface *ifp, int sock)
 {
        int ret;
        struct ipv6_mreq mreq;
@@ -75,8 +75,7 @@ static int ripng_multicast_join(struct interface *ifp)
                 */
                frr_elevate_privs(&ripngd_privs) {
 
-                       ret = setsockopt(ripng->sock, IPPROTO_IPV6,
-                                        IPV6_JOIN_GROUP,
+                       ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP,
                                         (char *)&mreq, sizeof(mreq));
                        save_errno = errno;
 
@@ -111,7 +110,7 @@ static int ripng_multicast_join(struct interface *ifp)
 }
 
 /* Leave from the all rip routers multicast group. */
-static int ripng_multicast_leave(struct interface *ifp)
+static int ripng_multicast_leave(struct interface *ifp, int sock)
 {
        int ret;
        struct ipv6_mreq mreq;
@@ -121,7 +120,7 @@ static int ripng_multicast_leave(struct interface *ifp)
                inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
                mreq.ipv6mr_interface = ifp->ifindex;
 
-               ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+               ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
                                 (char *)&mreq, sizeof(mreq));
                if (ret < 0)
                        zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
@@ -163,9 +162,13 @@ static int ripng_if_down(struct interface *ifp)
        struct agg_node *rp;
        struct ripng_info *rinfo;
        struct ripng_interface *ri;
+       struct ripng *ripng;
        struct list *list = NULL;
        struct listnode *listnode = NULL, *nextnode = NULL;
 
+       ri = ifp->info;
+       ripng = ri->ripng;
+
        if (ripng)
                for (rp = agg_route_top(ripng->table); rp;
                     rp = agg_route_next(rp))
@@ -173,16 +176,15 @@ static int ripng_if_down(struct interface *ifp)
                                for (ALL_LIST_ELEMENTS(list, listnode, nextnode,
                                                       rinfo))
                                        if (rinfo->ifindex == ifp->ifindex)
-                                               ripng_ecmp_delete(rinfo);
+                                               ripng_ecmp_delete(ripng, rinfo);
 
-       ri = ifp->info;
 
        if (ri->running) {
                if (IS_RIPNG_DEBUG_EVENT)
                        zlog_debug("turn off %s", ifp->name);
 
                /* Leave from multicast group. */
-               ripng_multicast_leave(ifp);
+               ripng_multicast_leave(ifp, ripng->sock);
 
                ri->running = 0;
        }
@@ -207,9 +209,11 @@ int ripng_interface_up(int command, struct zclient *zclient,
 
        if (IS_RIPNG_DEBUG_ZEBRA)
                zlog_debug(
-                       "interface up %s index %d flags %llx metric %d mtu %d",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu6);
+                       "interface up %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->mtu6);
+
+       ripng_interface_sync(ifp);
 
        /* Check if this interface is RIPng enabled or not. */
        ripng_enable_apply(ifp);
@@ -238,13 +242,14 @@ int ripng_interface_down(int command, struct zclient *zclient,
        if (ifp == NULL)
                return 0;
 
+       ripng_interface_sync(ifp);
        ripng_if_down(ifp);
 
        if (IS_RIPNG_DEBUG_ZEBRA)
                zlog_debug(
-                       "interface down %s index %d flags %#llx metric %d mtu %d",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu6);
+                       "interface down %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->mtu6);
 
        return 0;
 }
@@ -256,12 +261,13 @@ int ripng_interface_add(int command, struct zclient *zclient,
        struct interface *ifp;
 
        ifp = zebra_interface_add_read(zclient->ibuf, vrf_id);
+       ripng_interface_sync(ifp);
 
        if (IS_RIPNG_DEBUG_ZEBRA)
                zlog_debug(
-                       "RIPng interface add %s index %d flags %#llx metric %d mtu %d",
-                       ifp->name, ifp->ifindex, (unsigned long long)ifp->flags,
-                       ifp->metric, ifp->mtu6);
+                       "RIPng 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->mtu6);
 
        /* Check is this interface is RIP enabled or not.*/
        ripng_enable_apply(ifp);
@@ -289,13 +295,15 @@ int ripng_interface_delete(int command, struct zclient *zclient,
        if (ifp == NULL)
                return 0;
 
+       ripng_interface_sync(ifp);
        if (if_is_up(ifp)) {
                ripng_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->mtu6);
+       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->mtu6);
 
        /* To support pseudo interface do not free interface structure.  */
        /* if_delete(ifp); */
@@ -304,13 +312,34 @@ int ripng_interface_delete(int command, struct zclient *zclient,
        return 0;
 }
 
-void ripng_interface_clean(void)
+/* VRF update for an interface. */
+int ripng_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_RIPNG_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);
+       ripng_interface_sync(ifp);
+
+       return 0;
+}
+
+void ripng_interface_clean(struct ripng *ripng)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
        struct ripng_interface *ri;
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (ripng->vrf, ifp) {
                ri = ifp->info;
 
                ri->enable_network = 0;
@@ -326,6 +355,8 @@ void ripng_interface_clean(void)
 
 static void ripng_apply_address_add(struct connected *ifc)
 {
+       struct ripng_interface *ri = ifc->ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct prefix_ipv6 address;
        struct prefix *p;
 
@@ -345,9 +376,9 @@ static void ripng_apply_address_add(struct connected *ifc)
 
        /* Check if this interface is RIP enabled or not
           or  Check if this address's prefix is RIP enabled */
-       if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0)
+       if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0)
            || (ripng_enable_network_lookup2(ifc) >= 0))
-               ripng_redistribute_add(ZEBRA_ROUTE_CONNECT,
+               ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT,
                                       RIPNG_ROUTE_INTERFACE, &address,
                                       ifc->ifp->ifindex, NULL, 0);
 }
@@ -395,6 +426,8 @@ int ripng_interface_address_add(int command, struct zclient *zclient,
 
 static void ripng_apply_address_del(struct connected *ifc)
 {
+       struct ripng_interface *ri = ifc->ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct prefix_ipv6 address;
        struct prefix *p;
 
@@ -412,8 +445,9 @@ static void ripng_apply_address_del(struct connected *ifc)
        address.prefixlen = p->prefixlen;
        apply_mask_ipv6(&address);
 
-       ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
-                                 &address, ifc->ifp->ifindex);
+       ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
+                                 RIPNG_ROUTE_INTERFACE, &address,
+                                 ifc->ifp->ifindex);
 }
 
 int ripng_interface_address_delete(int command, struct zclient *zclient,
@@ -446,21 +480,20 @@ int ripng_interface_address_delete(int command, struct zclient *zclient,
        return 0;
 }
 
-/* RIPng enable interface vector. */
-vector ripng_enable_if;
-
-/* RIPng enable network table. */
-struct agg_table *ripng_enable_network;
-
 /* Lookup RIPng enable network. */
 /* Check wether the interface has at least a connected prefix that
- * is within the ripng_enable_network table. */
+ * is within the ripng->enable_network table. */
 static int ripng_enable_network_lookup_if(struct interface *ifp)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct listnode *node;
        struct connected *connected;
        struct prefix_ipv6 address;
 
+       if (!ripng)
+               return -1;
+
        for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) {
                struct prefix *p;
                struct agg_node *n;
@@ -472,7 +505,7 @@ static int ripng_enable_network_lookup_if(struct interface *ifp)
                        address.prefix = p->u.prefix6;
                        address.prefixlen = IPV6_MAX_BITLEN;
 
-                       n = agg_node_match(ripng_enable_network,
+                       n = agg_node_match(ripng->enable_network,
                                           (struct prefix *)&address);
                        if (n) {
                                agg_unlock_node(n);
@@ -483,12 +516,17 @@ static int ripng_enable_network_lookup_if(struct interface *ifp)
        return -1;
 }
 
-/* Check wether connected is within the ripng_enable_network table. */
+/* Check wether connected is within the ripng->enable_network table. */
 static int ripng_enable_network_lookup2(struct connected *connected)
 {
+       struct ripng_interface *ri = connected->ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct prefix_ipv6 address;
        struct prefix *p;
 
+       if (!ripng)
+               return -1;
+
        p = connected->address;
 
        if (p->family == AF_INET6) {
@@ -499,8 +537,8 @@ static int ripng_enable_network_lookup2(struct connected *connected)
                address.prefixlen = IPV6_MAX_BITLEN;
 
                /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within
-                * ripng_enable_network */
-               node = agg_node_match(ripng_enable_network,
+                * ripng->enable_network */
+               node = agg_node_match(ripng->enable_network,
                                      (struct prefix *)&address);
 
                if (node) {
@@ -513,11 +551,11 @@ static int ripng_enable_network_lookup2(struct connected *connected)
 }
 
 /* Add RIPng enable network. */
-int ripng_enable_network_add(struct prefix *p)
+int ripng_enable_network_add(struct ripng *ripng, struct prefix *p)
 {
        struct agg_node *node;
 
-       node = agg_node_get(ripng_enable_network, p);
+       node = agg_node_get(ripng->enable_network, p);
 
        if (node->info) {
                agg_unlock_node(node);
@@ -526,17 +564,17 @@ int ripng_enable_network_add(struct prefix *p)
                node->info = (void *)1;
 
        /* XXX: One should find a better solution than a generic one */
-       ripng_enable_apply_all();
+       ripng_enable_apply_all(ripng);
 
        return NB_OK;
 }
 
 /* Delete RIPng enable network. */
-int ripng_enable_network_delete(struct prefix *p)
+int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p)
 {
        struct agg_node *node;
 
-       node = agg_node_lookup(ripng_enable_network, p);
+       node = agg_node_lookup(ripng->enable_network, p);
        if (node) {
                node->info = NULL;
 
@@ -553,49 +591,50 @@ int ripng_enable_network_delete(struct prefix *p)
 }
 
 /* Lookup function. */
-static int ripng_enable_if_lookup(const char *ifname)
+static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(ripng_enable_if); i++)
-               if ((str = vector_slot(ripng_enable_if, i)) != NULL)
+       if (!ripng)
+               return -1;
+
+       for (i = 0; i < vector_active(ripng->enable_if); i++)
+               if ((str = vector_slot(ripng->enable_if, i)) != NULL)
                        if (strcmp(str, ifname) == 0)
                                return i;
        return -1;
 }
 
-/* Add interface to ripng_enable_if. */
-int ripng_enable_if_add(const char *ifname)
+int ripng_enable_if_add(struct ripng *ripng, const char *ifname)
 {
        int ret;
 
-       ret = ripng_enable_if_lookup(ifname);
+       ret = ripng_enable_if_lookup(ripng, ifname);
        if (ret >= 0)
                return NB_ERR_INCONSISTENCY;
 
-       vector_set(ripng_enable_if, strdup(ifname));
+       vector_set(ripng->enable_if, strdup(ifname));
 
-       ripng_enable_apply_all();
+       ripng_enable_apply_all(ripng);
 
        return NB_OK;
 }
 
-/* Delete interface from ripng_enable_if. */
-int ripng_enable_if_delete(const char *ifname)
+int ripng_enable_if_delete(struct ripng *ripng, const char *ifname)
 {
        int index;
        char *str;
 
-       index = ripng_enable_if_lookup(ifname);
+       index = ripng_enable_if_lookup(ripng, ifname);
        if (index < 0)
                return NB_ERR_INCONSISTENCY;
 
-       str = vector_slot(ripng_enable_if, index);
+       str = vector_slot(ripng->enable_if, index);
        free(str);
-       vector_unset(ripng_enable_if, index);
+       vector_unset(ripng->enable_if, index);
 
-       ripng_enable_apply_all();
+       ripng_enable_apply_all(ripng);
 
        return NB_OK;
 }
@@ -613,7 +652,7 @@ static int ripng_interface_wakeup(struct thread *t)
        ri->t_wakeup = NULL;
 
        /* Join to multicast group. */
-       if (ripng_multicast_join(ifp) < 0) {
+       if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) {
                flog_err_sys(EC_LIB_SOCKET,
                             "multicast join failed, interface %s not running",
                             ifp->name);
@@ -631,6 +670,8 @@ static int ripng_interface_wakeup(struct thread *t)
 
 static void ripng_connect_set(struct interface *ifp, int set)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct listnode *node, *nnode;
        struct connected *connected;
        struct prefix_ipv6 address;
@@ -650,19 +691,22 @@ static void ripng_connect_set(struct interface *ifp, int set)
                if (set) {
                        /* Check once more wether this prefix is within a
                         * "network IF_OR_PREF" one */
-                       if ((ripng_enable_if_lookup(connected->ifp->name) >= 0)
+                       if ((ripng_enable_if_lookup(ripng, connected->ifp->name)
+                            >= 0)
                            || (ripng_enable_network_lookup2(connected) >= 0))
                                ripng_redistribute_add(
-                                       ZEBRA_ROUTE_CONNECT,
+                                       ripng, ZEBRA_ROUTE_CONNECT,
                                        RIPNG_ROUTE_INTERFACE, &address,
                                        connected->ifp->ifindex, NULL, 0);
                } else {
-                       ripng_redistribute_delete(
-                               ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE,
-                               &address, connected->ifp->ifindex);
-                       if (ripng_redistribute_check(ZEBRA_ROUTE_CONNECT))
+                       ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT,
+                                                 RIPNG_ROUTE_INTERFACE,
+                                                 &address,
+                                                 connected->ifp->ifindex);
+                       if (ripng_redistribute_check(ripng,
+                                                    ZEBRA_ROUTE_CONNECT))
                                ripng_redistribute_add(
-                                       ZEBRA_ROUTE_CONNECT,
+                                       ripng, ZEBRA_ROUTE_CONNECT,
                                        RIPNG_ROUTE_REDISTRIBUTE, &address,
                                        connected->ifp->ifindex, NULL, 0);
                }
@@ -691,7 +735,7 @@ void ripng_enable_apply(struct interface *ifp)
                ri->enable_network = 0;
 
        /* Check interface name configuration. */
-       ret = ripng_enable_if_lookup(ifp->name);
+       ret = ripng_enable_if_lookup(ri->ripng, ifp->name);
        if (ret >= 0)
                ri->enable_interface = 1;
        else
@@ -729,49 +773,46 @@ void ripng_enable_apply(struct interface *ifp)
 }
 
 /* Set distribute list to all interfaces. */
-static void ripng_enable_apply_all(void)
+static void ripng_enable_apply_all(struct ripng *ripng)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (ripng->vrf, ifp)
                ripng_enable_apply(ifp);
 }
 
 /* Clear all network and neighbor configuration */
-void ripng_clean_network(void)
+void ripng_clean_network(struct ripng *ripng)
 {
        unsigned int i;
        char *str;
        struct agg_node *rn;
 
-       /* ripng_enable_network */
-       for (rn = agg_route_top(ripng_enable_network); rn;
+       /* ripng->enable_network */
+       for (rn = agg_route_top(ripng->enable_network); rn;
             rn = agg_route_next(rn))
                if (rn->info) {
                        rn->info = NULL;
                        agg_unlock_node(rn);
                }
 
-       /* ripng_enable_if */
-       for (i = 0; i < vector_active(ripng_enable_if); i++)
-               if ((str = vector_slot(ripng_enable_if, i)) != NULL) {
+       /* ripng->enable_if */
+       for (i = 0; i < vector_active(ripng->enable_if); i++)
+               if ((str = vector_slot(ripng->enable_if, i)) != NULL) {
                        free(str);
-                       vector_slot(ripng_enable_if, i) = NULL;
+                       vector_slot(ripng->enable_if, i) = NULL;
                }
 }
 
-/* Vector to store passive-interface name. */
-vector Vripng_passive_interface;
-
 /* Utility function for looking up passive interface settings. */
-static int ripng_passive_interface_lookup(const char *ifname)
+static int ripng_passive_interface_lookup(struct ripng *ripng,
+                                         const char *ifname)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(Vripng_passive_interface); i++)
-               if ((str = vector_slot(Vripng_passive_interface, i)) != NULL)
+       for (i = 0; i < vector_active(ripng->passive_interface); i++)
+               if ((str = vector_slot(ripng->passive_interface, i)) != NULL)
                        if (strcmp(str, ifname) == 0)
                                return i;
        return -1;
@@ -781,72 +822,75 @@ void ripng_passive_interface_apply(struct interface *ifp)
 {
        int ret;
        struct ripng_interface *ri;
+       struct ripng *ripng;
 
        ri = ifp->info;
+       ripng = ri->ripng;
+       if (!ripng)
+               return;
 
-       ret = ripng_passive_interface_lookup(ifp->name);
+       ret = ripng_passive_interface_lookup(ripng, ifp->name);
        if (ret < 0)
                ri->passive = 0;
        else
                ri->passive = 1;
 }
 
-static void ripng_passive_interface_apply_all(void)
+static void ripng_passive_interface_apply_all(struct ripng *ripng)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
        struct interface *ifp;
 
-       FOR_ALL_INTERFACES (vrf, ifp)
+       FOR_ALL_INTERFACES (ripng->vrf, ifp)
                ripng_passive_interface_apply(ifp);
 }
 
 /* Passive interface. */
-int ripng_passive_interface_set(const char *ifname)
+int ripng_passive_interface_set(struct ripng *ripng, const char *ifname)
 {
-       if (ripng_passive_interface_lookup(ifname) >= 0)
+       if (ripng_passive_interface_lookup(ripng, ifname) >= 0)
                return NB_ERR_INCONSISTENCY;
 
-       vector_set(Vripng_passive_interface, strdup(ifname));
+       vector_set(ripng->passive_interface, strdup(ifname));
 
-       ripng_passive_interface_apply_all();
+       ripng_passive_interface_apply_all(ripng);
 
        return NB_OK;
 }
 
-int ripng_passive_interface_unset(const char *ifname)
+int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname)
 {
        int i;
        char *str;
 
-       i = ripng_passive_interface_lookup(ifname);
+       i = ripng_passive_interface_lookup(ripng, ifname);
        if (i < 0)
                return NB_ERR_INCONSISTENCY;
 
-       str = vector_slot(Vripng_passive_interface, i);
+       str = vector_slot(ripng->passive_interface, i);
        free(str);
-       vector_unset(Vripng_passive_interface, i);
+       vector_unset(ripng->passive_interface, i);
 
-       ripng_passive_interface_apply_all();
+       ripng_passive_interface_apply_all(ripng);
 
        return NB_OK;
 }
 
 /* Free all configured RIP passive-interface settings. */
-void ripng_passive_interface_clean(void)
+void ripng_passive_interface_clean(struct ripng *ripng)
 {
        unsigned int i;
        char *str;
 
-       for (i = 0; i < vector_active(Vripng_passive_interface); i++)
-               if ((str = vector_slot(Vripng_passive_interface, i)) != NULL) {
+       for (i = 0; i < vector_active(ripng->passive_interface); i++)
+               if ((str = vector_slot(ripng->passive_interface, i)) != NULL) {
                        free(str);
-                       vector_slot(Vripng_passive_interface, i) = NULL;
+                       vector_slot(ripng->passive_interface, i) = NULL;
                }
-       ripng_passive_interface_apply_all();
+       ripng_passive_interface_apply_all(ripng);
 }
 
 /* Write RIPng enable network and interface to the vty. */
-int ripng_network_write(struct vty *vty)
+int ripng_network_write(struct vty *vty, struct ripng *ripng)
 {
        unsigned int i;
        const char *ifname;
@@ -854,7 +898,7 @@ int ripng_network_write(struct vty *vty)
        char buf[BUFSIZ];
 
        /* Write enable network. */
-       for (node = agg_route_top(ripng_enable_network); node;
+       for (node = agg_route_top(ripng->enable_network); node;
             node = agg_route_next(node))
                if (node->info) {
                        struct prefix *p = &node->p;
@@ -864,8 +908,8 @@ int ripng_network_write(struct vty *vty)
                }
 
        /* Write enable interface. */
-       for (i = 0; i < vector_active(ripng_enable_if); i++)
-               if ((ifname = vector_slot(ripng_enable_if, i)) != NULL)
+       for (i = 0; i < vector_active(ripng->enable_if); i++)
+               if ((ifname = vector_slot(ripng->enable_if, i)) != NULL)
                        vty_out(vty, "    %s\n", ifname);
 
        return 0;
@@ -874,6 +918,7 @@ int ripng_network_write(struct vty *vty)
 static struct ripng_interface *ri_new(void)
 {
        struct ripng_interface *ri;
+
        ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface));
 
        /* Set default split-horizon behavior.  If the interface is Frame
@@ -886,9 +931,25 @@ static struct ripng_interface *ri_new(void)
        return ri;
 }
 
+void ripng_interface_sync(struct interface *ifp)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(ifp->vrf_id);
+       if (vrf) {
+               struct ripng_interface *ri;
+
+               ri = ifp->info;
+               if (ri)
+                       ri->ripng = vrf->info;
+       }
+}
+
 static int ripng_if_new_hook(struct interface *ifp)
 {
        ifp->info = ri_new();
+       ripng_interface_sync(ifp);
+
        return 0;
 }
 
@@ -903,22 +964,25 @@ static int ripng_if_delete_hook(struct interface *ifp)
 /* Configuration write function for ripngd. */
 static int 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;
 
-               write = 1;
-               nb_cli_show_dnode_cmds(vty, dnode, false);
+                       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);
+               }
        }
 
        return write;
@@ -936,15 +1000,6 @@ void ripng_if_init(void)
        hook_register_prio(if_add, 0, ripng_if_new_hook);
        hook_register_prio(if_del, 0, ripng_if_delete_hook);
 
-       /* RIPng enable network init. */
-       ripng_enable_network = agg_table_init();
-
-       /* RIPng enable interface init. */
-       ripng_enable_if = vector_init(1);
-
-       /* RIPng passive interface. */
-       Vripng_passive_interface = vector_init(1);
-
        /* Install interface node. */
        install_node(&interface_node, interface_config_write);
        if_cmd_init();
index 10e19efe77f6962fc39cea79f2378adcb0a52f1c..c755bd83ce5c4d757e2bb80644f18c982375d13e 100644 (file)
@@ -35,6 +35,7 @@
 #include "privs.h"
 #include "sigevent.h"
 #include "vrf.h"
+#include "if_rmap.h"
 #include "libfrr.h"
 
 #include "ripngd/ripngd.h"
@@ -46,7 +47,7 @@
 struct option longopts[] = {{"retain", no_argument, NULL, 'r'}, {0}};
 
 /* ripngd 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 ripngd_privs = {
 #if defined(FRR_USER)
@@ -59,7 +60,7 @@ struct zebra_privs_t ripngd_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};
 
 
@@ -82,8 +83,8 @@ static void sigint(void)
 {
        zlog_notice("Terminating on signal");
 
-       ripng_clean();
-
+       ripng_vrf_terminate();
+       if_rmap_terminate();
        ripng_zebra_stop();
        frr_fini();
        exit(0);
@@ -170,13 +171,12 @@ int main(int argc, char **argv)
        master = frr_init();
 
        /* Library inits. */
-       vrf_init(NULL, NULL, NULL, NULL, NULL);
+       ripng_vrf_init();
 
        /* RIPngd inits. */
        ripng_init();
        ripng_cli_init();
        zebra_init(master);
-       ripng_peer_init();
 
        frr_config_fork();
        frr_run(master);
index 0cb24052e60c9b0abbd6d1c02a4ea53411c6fd39..f459566bed35c89ba6b81de59fe04d70bdcb0954 100644 (file)
@@ -27,6 +27,7 @@
 
 DEFINE_MGROUP(RIPNGD, "ripngd")
 DEFINE_MTYPE(RIPNGD, RIPNG, "RIPng structure")
+DEFINE_MTYPE(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name")
 DEFINE_MTYPE(RIPNGD, RIPNG_ROUTE, "RIPng route info")
 DEFINE_MTYPE(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate")
 DEFINE_MTYPE(RIPNGD, RIPNG_PEER, "RIPng peer")
index a4102086c7f50ad858732b4f9a2d0afc9aefe7fe..3dfc57b3ffdb1afcb5111e026da61a664cf71305 100644 (file)
@@ -26,6 +26,7 @@
 
 DECLARE_MGROUP(RIPNGD)
 DECLARE_MTYPE(RIPNG)
+DECLARE_MTYPE(RIPNG_VRF_NAME)
 DECLARE_MTYPE(RIPNG_ROUTE)
 DECLARE_MTYPE(RIPNG_AGGREGATE)
 DECLARE_MTYPE(RIPNG_PEER)
index 74a132aa941eb05dfa88f007353d15dcef9023b1..882c2fbc8c56182ad4ad7bb3e9107b0a0320c3a0 100644 (file)
@@ -114,7 +114,8 @@ void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
 void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
                    struct sockaddr_in6 *to)
 {
-
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct ripng_rte_data *data;
        struct listnode *node, *nnode;
 
index b6998b4ddbd20f20ffaf68b233e2b9b2ba151e1f..66b9e13d7f58a8eb5f21e9d7a119b821c874a9d9 100644 (file)
@@ -32,6 +32,7 @@
 #include "libfrr.h"
 
 #include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
 #include "ripngd/ripng_route.h"
 #include "ripngd/ripng_cli.h"
 
@@ -42,24 +43,45 @@ static int ripngd_instance_create(enum nb_event event,
                                  const struct lyd_node *dnode,
                                  union nb_resource *resource)
 {
+       struct ripng *ripng;
+       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 RIPng socket only if the VRF is enabled, otherwise
+        * create a disabled RIPng instance and wait for the VRF to be enabled.
+        */
        switch (event) {
        case NB_EV_VALIDATE:
                break;
        case NB_EV_PREPARE:
-               socket = ripng_make_socket();
+               if (!vrf || !vrf_is_enabled(vrf))
+                       break;
+
+               socket = ripng_make_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:
-               socket = resource->fd;
-               ripng_create(socket);
+               if (vrf && vrf_is_enabled(vrf))
+                       socket = resource->fd;
+               else
+                       socket = -1;
+
+               ripng = ripng_create(vrf_name, vrf, socket);
+               yang_dnode_set_entry(dnode, ripng);
                break;
        }
 
@@ -69,14 +91,50 @@ static int ripngd_instance_create(enum nb_event event,
 static int ripngd_instance_delete(enum nb_event event,
                                  const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
-       ripng_clean();
+       ripng = yang_dnode_get_entry(dnode, true);
+       ripng_clean(ripng);
+
+       return NB_OK;
+}
+
+static const void *ripngd_instance_get_next(const void *parent_list_entry,
+                                           const void *list_entry)
+{
+       const struct ripng *ripng = list_entry;
+
+       if (list_entry == NULL)
+               ripng = RB_MIN(ripng_instance_head, &ripng_instances);
+       else
+               ripng = RB_NEXT(ripng_instance_head, (struct ripng *)ripng);
+
+       return ripng;
+}
+
+static int ripngd_instance_get_keys(const void *list_entry,
+                                   struct yang_list_keys *keys)
+{
+       const struct ripng *ripng = list_entry;
+
+       keys->num = 1;
+       strlcpy(keys->key[0], ripng->vrf_name, sizeof(keys->key[0]));
 
        return NB_OK;
 }
 
+static const void *
+ripngd_instance_lookup_entry(const void *parent_list_entry,
+                            const struct yang_list_keys *keys)
+{
+       const char *vrf_name = keys->key[0];
+
+       return ripng_lookup_by_vrf_name(vrf_name);
+}
+
 /*
  * XPath: /frr-ripngd:ripngd/instance/allow-ecmp
  */
@@ -84,12 +142,15 @@ static int ripngd_instance_allow_ecmp_modify(enum nb_event event,
                                             const struct lyd_node *dnode,
                                             union nb_resource *resource)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ripng->ecmp = yang_dnode_get_bool(dnode, NULL);
        if (!ripng->ecmp)
-               ripng_ecmp_disable();
+               ripng_ecmp_disable(ripng);
 
        return NB_OK;
 }
@@ -101,19 +162,22 @@ static int ripngd_instance_default_information_originate_modify(
        enum nb_event event, const struct lyd_node *dnode,
        union nb_resource *resource)
 {
+       struct ripng *ripng;
        bool default_information;
        struct prefix_ipv6 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        default_information = yang_dnode_get_bool(dnode, NULL);
+
        str2prefix_ipv6("::/0", &p);
        if (default_information) {
-               ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT,
-                                      &p, 0, NULL, 0);
+               ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG,
+                                      RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0);
        } else {
-               ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG,
+               ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG,
                                          RIPNG_ROUTE_DEFAULT, &p, 0);
        }
 
@@ -127,9 +191,12 @@ static int ripngd_instance_default_metric_modify(enum nb_event event,
                                                 const struct lyd_node *dnode,
                                                 union nb_resource *resource)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ripng->default_metric = yang_dnode_get_uint8(dnode, NULL);
 
        return NB_OK;
@@ -142,29 +209,33 @@ static int ripngd_instance_network_create(enum nb_event event,
                                          const struct lyd_node *dnode,
                                          union nb_resource *resource)
 {
+       struct ripng *ripng;
        struct prefix p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6((struct prefix_ipv6 *)&p);
 
-       return ripng_enable_network_add(&p);
+       return ripng_enable_network_add(ripng, &p);
 }
 
 static int ripngd_instance_network_delete(enum nb_event event,
                                          const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        struct prefix p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6((struct prefix_ipv6 *)&p);
 
-       return ripng_enable_network_delete(&p);
+       return ripng_enable_network_delete(ripng, &p);
 }
 
 /*
@@ -174,27 +245,31 @@ static int ripngd_instance_interface_create(enum nb_event event,
                                            const struct lyd_node *dnode,
                                            union nb_resource *resource)
 {
+       struct ripng *ripng;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return ripng_enable_if_add(ifname);
+       return ripng_enable_if_add(ripng, ifname);
 }
 
 static int ripngd_instance_interface_delete(enum nb_event event,
                                            const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return ripng_enable_if_delete(ifname);
+       return ripng_enable_if_delete(ripng, ifname);
 }
 
 /*
@@ -204,15 +279,17 @@ static int ripngd_instance_offset_list_create(enum nb_event event,
                                              const struct lyd_node *dnode,
                                              union nb_resource *resource)
 {
+       struct ripng *ripng;
        const char *ifname;
        struct ripng_offset_list *offset;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, "./interface");
 
-       offset = ripng_offset_list_new(ifname);
+       offset = ripng_offset_list_new(ripng, ifname);
        yang_dnode_set_entry(dnode, offset);
 
        return NB_OK;
@@ -299,28 +376,32 @@ ripngd_instance_passive_interface_create(enum nb_event event,
                                         const struct lyd_node *dnode,
                                         union nb_resource *resource)
 {
+       struct ripng *ripng;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return ripng_passive_interface_set(ifname);
+       return ripng_passive_interface_set(ripng, ifname);
 }
 
 static int
 ripngd_instance_passive_interface_delete(enum nb_event event,
                                         const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        const char *ifname;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ifname = yang_dnode_get_string(dnode, NULL);
 
-       return ripng_passive_interface_unset(ifname);
+       return ripng_passive_interface_unset(ripng, ifname);
 }
 
 /*
@@ -330,20 +411,43 @@ static int ripngd_instance_redistribute_create(enum nb_event event,
                                               const struct lyd_node *dnode,
                                               union nb_resource *resource)
 {
+       struct ripng *ripng;
+       int type;
+
+       if (event != NB_EV_APPLY)
+               return NB_OK;
+
+       ripng = yang_dnode_get_entry(dnode, true);
+       type = yang_dnode_get_enum(dnode, "./protocol");
+
+       ripng->redist[type].enabled = true;
+
        return NB_OK;
 }
 
 static int ripngd_instance_redistribute_delete(enum nb_event event,
                                               const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
 
-       ripng_redistribute_conf_delete(type);
+       ripng->redist[type].enabled = false;
+       if (ripng->redist[type].route_map.name) {
+               free(ripng->redist[type].route_map.name);
+               ripng->redist[type].route_map.name = NULL;
+               ripng->redist[type].route_map.map = NULL;
+       }
+       ripng->redist[type].metric_config = false;
+       ripng->redist[type].metric = 0;
+
+       if (ripng->enabled)
+               ripng_redistribute_conf_delete(ripng, type);
 
        return NB_OK;
 }
@@ -351,10 +455,14 @@ static int ripngd_instance_redistribute_delete(enum nb_event event,
 static void
 ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        int type;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "./protocol");
-       ripng_redistribute_conf_update(type);
+
+       if (ripng->enabled)
+               ripng_redistribute_conf_update(ripng, type);
 }
 
 /*
@@ -365,19 +473,21 @@ ripngd_instance_redistribute_route_map_modify(enum nb_event event,
                                              const struct lyd_node *dnode,
                                              union nb_resource *resource)
 {
+       struct ripng *ripng;
        int type;
        const char *rmap_name;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        rmap_name = yang_dnode_get_string(dnode, NULL);
 
-       if (ripng->route_map[type].name)
-               free(ripng->route_map[type].name);
-       ripng->route_map[type].name = strdup(rmap_name);
-       ripng->route_map[type].map = route_map_lookup_by_name(rmap_name);
+       if (ripng->redist[type].route_map.name)
+               free(ripng->redist[type].route_map.name);
+       ripng->redist[type].route_map.name = strdup(rmap_name);
+       ripng->redist[type].route_map.map = route_map_lookup_by_name(rmap_name);
 
        return NB_OK;
 }
@@ -386,16 +496,18 @@ static int
 ripngd_instance_redistribute_route_map_delete(enum nb_event event,
                                              const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
-       free(ripng->route_map[type].name);
-       ripng->route_map[type].name = NULL;
-       ripng->route_map[type].map = NULL;
+       free(ripng->redist[type].route_map.name);
+       ripng->redist[type].route_map.name = NULL;
+       ripng->redist[type].route_map.map = NULL;
 
        return NB_OK;
 }
@@ -408,17 +520,19 @@ ripngd_instance_redistribute_metric_modify(enum nb_event event,
                                           const struct lyd_node *dnode,
                                           union nb_resource *resource)
 {
+       struct ripng *ripng;
        int type;
        uint8_t metric;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
        metric = yang_dnode_get_uint8(dnode, NULL);
 
-       ripng->route_map[type].metric_config = true;
-       ripng->route_map[type].metric = metric;
+       ripng->redist[type].metric_config = true;
+       ripng->redist[type].metric = metric;
 
        return NB_OK;
 }
@@ -427,15 +541,17 @@ static int
 ripngd_instance_redistribute_metric_delete(enum nb_event event,
                                           const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        int type;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        type = yang_dnode_get_enum(dnode, "../protocol");
 
-       ripng->route_map[type].metric_config = false;
-       ripng->route_map[type].metric = 0;
+       ripng->redist[type].metric_config = false;
+       ripng->redist[type].metric = 0;
 
        return NB_OK;
 }
@@ -447,16 +563,18 @@ static int ripngd_instance_static_route_create(enum nb_event event,
                                               const struct lyd_node *dnode,
                                               union nb_resource *resource)
 {
+       struct ripng *ripng;
        struct prefix_ipv6 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
-       ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0,
-                              NULL, 0);
+       ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p,
+                              0, NULL, 0);
 
        return NB_OK;
 }
@@ -464,15 +582,18 @@ static int ripngd_instance_static_route_create(enum nb_event event,
 static int ripngd_instance_static_route_delete(enum nb_event event,
                                               const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        struct prefix_ipv6 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
-       ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0);
+       ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC,
+                                 &p, 0);
 
        return NB_OK;
 }
@@ -485,15 +606,17 @@ ripngd_instance_aggregate_address_create(enum nb_event event,
                                         const struct lyd_node *dnode,
                                         union nb_resource *resource)
 {
+       struct ripng *ripng;
        struct prefix_ipv6 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
-       ripng_aggregate_add((struct prefix *)&p);
+       ripng_aggregate_add(ripng, (struct prefix *)&p);
 
        return NB_OK;
 }
@@ -502,15 +625,17 @@ static int
 ripngd_instance_aggregate_address_delete(enum nb_event event,
                                         const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
        struct prefix_ipv6 p;
 
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        yang_dnode_get_ipv6p(&p, dnode, NULL);
        apply_mask_ipv6(&p);
 
-       ripng_aggregate_delete((struct prefix *)&p);
+       ripng_aggregate_delete(ripng, (struct prefix *)&p);
 
        return NB_OK;
 }
@@ -520,8 +645,12 @@ ripngd_instance_aggregate_address_delete(enum nb_event event,
  */
 static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode)
 {
+       struct ripng *ripng;
+
+       ripng = yang_dnode_get_entry(dnode, true);
+
        /* Reset update timer thread. */
-       ripng_event(RIPNG_UPDATE_EVENT, 0);
+       ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
 }
 
 /*
@@ -532,9 +661,12 @@ ripngd_instance_timers_flush_interval_modify(enum nb_event event,
                                             const struct lyd_node *dnode,
                                             union nb_resource *resource)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -548,9 +680,12 @@ ripngd_instance_timers_holddown_interval_modify(enum nb_event event,
                                                const struct lyd_node *dnode,
                                                union nb_resource *resource)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
@@ -564,33 +699,38 @@ ripngd_instance_timers_update_interval_modify(enum nb_event event,
                                              const struct lyd_node *dnode,
                                              union nb_resource *resource)
 {
+       struct ripng *ripng;
+
        if (event != NB_EV_APPLY)
                return NB_OK;
 
+       ripng = yang_dnode_get_entry(dnode, true);
        ripng->update_time = yang_dnode_get_uint16(dnode, NULL);
 
        return NB_OK;
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor
  */
 static const void *
-ripngd_state_neighbors_neighbor_get_next(const void *parent_list_entry,
-                                        const void *list_entry)
+ripngd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry,
+                                                 const void *list_entry)
 {
+       const struct ripng *ripng = parent_list_entry;
        struct listnode *node;
 
        if (list_entry == NULL)
-               node = listhead(peer_list);
+               node = listhead(ripng->peer_list);
        else
                node = listnextnode((struct listnode *)list_entry);
 
        return node;
 }
 
-static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry,
-                                                   struct yang_list_keys *keys)
+static int
+ripngd_instance_state_neighbors_neighbor_get_keys(const void *list_entry,
+                                                 struct yang_list_keys *keys)
 {
        const struct listnode *node = list_entry;
        const struct ripng_peer *peer = listgetdata(node);
@@ -602,17 +742,17 @@ static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry,
        return NB_OK;
 }
 
-static const void *
-ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry,
-                                            const struct yang_list_keys *keys)
+static const void *ripngd_instance_state_neighbors_neighbor_lookup_entry(
+       const void *parent_list_entry, const struct yang_list_keys *keys)
 {
+       const struct ripng *ripng = parent_list_entry;
        struct in6_addr address;
        struct ripng_peer *peer;
        struct listnode *node;
 
        yang_str2ipv6(keys->key[0], &address);
 
-       for (ALL_LIST_ELEMENTS_RO(peer_list, node, peer)) {
+       for (ALL_LIST_ELEMENTS_RO(ripng->peer_list, node, peer)) {
                if (IPV6_ADDR_SAME(&peer->addr, &address))
                        return node;
        }
@@ -621,11 +761,11 @@ ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/address
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/address
  */
 static struct yang_data *
-ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath,
-                                                const void *list_entry)
+ripngd_instance_state_neighbors_neighbor_address_get_elem(
+       const char *xpath, const void *list_entry)
 {
        const struct listnode *node = list_entry;
        const struct ripng_peer *peer = listgetdata(node);
@@ -634,21 +774,21 @@ ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/last-update
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update
  */
 static struct yang_data *
-ripngd_state_neighbors_neighbor_last_update_get_elem(const char *xpath,
-                                                    const void *list_entry)
+ripngd_instance_state_neighbors_neighbor_last_update_get_elem(
+       const char *xpath, const void *list_entry)
 {
        /* TODO: yang:date-and-time is tricky */
        return NULL;
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd
  */
 static struct yang_data *
-ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
+ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
        const char *xpath, const void *list_entry)
 {
        const struct listnode *node = list_entry;
@@ -658,11 +798,11 @@ ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem(
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd
+ * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd
  */
 static struct yang_data *
-ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath,
-                                                        const void *list_entry)
+ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem(
+       const char *xpath, const void *list_entry)
 {
        const struct listnode *node = list_entry;
        const struct ripng_peer *peer = listgetdata(node);
@@ -671,17 +811,15 @@ ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/routes/route
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route
  */
 static const void *
-ripngd_state_routes_route_get_next(const void *parent_list_entry,
-                                  const void *list_entry)
+ripngd_instance_state_routes_route_get_next(const void *parent_list_entry,
+                                           const void *list_entry)
 {
+       const struct ripng *ripng = parent_list_entry;
        struct agg_node *rn;
 
-       if (ripng == NULL)
-               return NULL;
-
        if (list_entry == NULL)
                rn = agg_route_top(ripng->table);
        else
@@ -692,8 +830,9 @@ ripngd_state_routes_route_get_next(const void *parent_list_entry,
        return rn;
 }
 
-static int ripngd_state_routes_route_get_keys(const void *list_entry,
-                                             struct yang_list_keys *keys)
+static int
+ripngd_instance_state_routes_route_get_keys(const void *list_entry,
+                                           struct yang_list_keys *keys)
 {
        const struct agg_node *rn = list_entry;
 
@@ -703,10 +842,10 @@ static int ripngd_state_routes_route_get_keys(const void *list_entry,
        return NB_OK;
 }
 
-static const void *
-ripngd_state_routes_route_lookup_entry(const void *parent_list_entry,
-                                      const struct yang_list_keys *keys)
+static const void *ripngd_instance_state_routes_route_lookup_entry(
+       const void *parent_list_entry, const struct yang_list_keys *keys)
 {
+       const struct ripng *ripng = parent_list_entry;
        struct prefix prefix;
        struct agg_node *rn;
 
@@ -722,11 +861,11 @@ ripngd_state_routes_route_lookup_entry(const void *parent_list_entry,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/routes/route/prefix
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/prefix
  */
 static struct yang_data *
-ripngd_state_routes_route_prefix_get_elem(const char *xpath,
-                                         const void *list_entry)
+ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath,
+                                                  const void *list_entry)
 {
        const struct agg_node *rn = list_entry;
        const struct ripng_info *rinfo = listnode_head(rn->info);
@@ -735,11 +874,11 @@ ripngd_state_routes_route_prefix_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/routes/route/next-hop
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/next-hop
  */
 static struct yang_data *
-ripngd_state_routes_route_next_hop_get_elem(const char *xpath,
-                                           const void *list_entry)
+ripngd_instance_state_routes_route_next_hop_get_elem(const char *xpath,
+                                                    const void *list_entry)
 {
        const struct agg_node *rn = list_entry;
        const struct ripng_info *rinfo = listnode_head(rn->info);
@@ -748,25 +887,26 @@ ripngd_state_routes_route_next_hop_get_elem(const char *xpath,
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/routes/route/interface
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/interface
  */
 static struct yang_data *
-ripngd_state_routes_route_interface_get_elem(const char *xpath,
-                                            const void *list_entry)
+ripngd_instance_state_routes_route_interface_get_elem(const char *xpath,
+                                                     const void *list_entry)
 {
        const struct agg_node *rn = list_entry;
        const struct ripng_info *rinfo = listnode_head(rn->info);
+       const struct ripng *ripng = ripng_info_get_instance(rinfo);
 
        return yang_data_new_string(
-               xpath, ifindex2ifname(rinfo->ifindex, VRF_DEFAULT));
+               xpath, ifindex2ifname(rinfo->ifindex, ripng->vrf->vrf_id));
 }
 
 /*
- * XPath: /frr-ripngd:ripngd/state/routes/route/metric
+ * XPath: /frr-ripngd:ripngd/instance/state/routes/route/metric
  */
 static struct yang_data *
-ripngd_state_routes_route_metric_get_elem(const char *xpath,
-                                         const void *list_entry)
+ripngd_instance_state_routes_route_metric_get_elem(const char *xpath,
+                                                  const void *list_entry)
 {
        const struct agg_node *rn = list_entry;
        const struct ripng_info *rinfo = listnode_head(rn->info);
@@ -777,16 +917,20 @@ ripngd_state_routes_route_metric_get_elem(const char *xpath,
 /*
  * XPath: /frr-ripngd:clear-ripng-route
  */
-static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
-                                struct list *output)
+static void clear_ripng_route(struct ripng *ripng)
 {
        struct agg_node *rp;
-       struct ripng_info *rinfo;
-       struct list *list;
-       struct listnode *listnode;
+
+       if (IS_RIPNG_DEBUG_EVENT)
+               zlog_debug("Clearing all RIPng routes (VRF %s)",
+                          ripng->vrf_name);
 
        /* Clear received RIPng routes */
        for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
+               struct list *list;
+               struct listnode *listnode;
+               struct ripng_info *rinfo;
+
                list = rp->info;
                if (list == NULL)
                        continue;
@@ -796,7 +940,7 @@ static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
                                continue;
 
                        if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
-                               ripng_zebra_ipv6_delete(rp);
+                               ripng_zebra_ipv6_delete(ripng, rp);
                        break;
                }
 
@@ -813,6 +957,30 @@ static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
                        agg_unlock_node(rp);
                }
        }
+}
+
+static int clear_ripng_route_rpc(const char *xpath, const struct list *input,
+                                struct list *output)
+{
+       struct ripng *ripng;
+       struct yang_data *yang_vrf;
+
+       yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf");
+       if (yang_vrf) {
+               ripng = ripng_lookup_by_vrf_name(yang_vrf->value);
+               if (ripng)
+                       clear_ripng_route(ripng);
+       } else {
+               struct vrf *vrf;
+
+               RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+                       ripng = vrf->info;
+                       if (!ripng)
+                               continue;
+
+                       clear_ripng_route(ripng);
+               }
+       }
 
        return NB_OK;
 }
@@ -846,6 +1014,9 @@ const struct frr_yang_module_info frr_ripngd_info = {
                        .xpath = "/frr-ripngd:ripngd/instance",
                        .cbs.create = ripngd_instance_create,
                        .cbs.destroy = ripngd_instance_delete,
+                       .cbs.get_next = ripngd_instance_get_next,
+                       .cbs.get_keys = ripngd_instance_get_keys,
+                       .cbs.lookup_entry = ripngd_instance_lookup_entry,
                        .cbs.cli_show = cli_show_router_ripng,
                },
                {
@@ -942,48 +1113,48 @@ const struct frr_yang_module_info frr_ripngd_info = {
                        .cbs.modify = ripngd_instance_timers_update_interval_modify,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor",
-                       .cbs.get_next = ripngd_state_neighbors_neighbor_get_next,
-                       .cbs.get_keys = ripngd_state_neighbors_neighbor_get_keys,
-                       .cbs.lookup_entry = ripngd_state_neighbors_neighbor_lookup_entry,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor",
+                       .cbs.get_next = ripngd_instance_state_neighbors_neighbor_get_next,
+                       .cbs.get_keys = ripngd_instance_state_neighbors_neighbor_get_keys,
+                       .cbs.lookup_entry = ripngd_instance_state_neighbors_neighbor_lookup_entry,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/address",
-                       .cbs.get_elem = ripngd_state_neighbors_neighbor_address_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/address",
+                       .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_address_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/last-update",
-                       .cbs.get_elem = ripngd_state_neighbors_neighbor_last_update_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update",
+                       .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_last_update_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd",
-                       .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd",
+                       .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd",
-                       .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd",
+                       .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/routes/route",
-                       .cbs.get_next = ripngd_state_routes_route_get_next,
-                       .cbs.get_keys = ripngd_state_routes_route_get_keys,
-                       .cbs.lookup_entry = ripngd_state_routes_route_lookup_entry,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/routes/route",
+                       .cbs.get_next = ripngd_instance_state_routes_route_get_next,
+                       .cbs.get_keys = ripngd_instance_state_routes_route_get_keys,
+                       .cbs.lookup_entry = ripngd_instance_state_routes_route_lookup_entry,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/routes/route/prefix",
-                       .cbs.get_elem = ripngd_state_routes_route_prefix_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/prefix",
+                       .cbs.get_elem = ripngd_instance_state_routes_route_prefix_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/routes/route/next-hop",
-                       .cbs.get_elem = ripngd_state_routes_route_next_hop_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/next-hop",
+                       .cbs.get_elem = ripngd_instance_state_routes_route_next_hop_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/routes/route/interface",
-                       .cbs.get_elem = ripngd_state_routes_route_interface_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/interface",
+                       .cbs.get_elem = ripngd_instance_state_routes_route_interface_get_elem,
                },
                {
-                       .xpath = "/frr-ripngd:ripngd/state/routes/route/metric",
-                       .cbs.get_elem = ripngd_state_routes_route_metric_get_elem,
+                       .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/metric",
+                       .cbs.get_elem = ripngd_instance_state_routes_route_metric_get_elem,
                },
                {
                        .xpath = "/frr-ripngd:clear-ripng-route",
index 278df758924164116f9a21c7f48f0a4af5416cca..41ba2360ba07d5b4510328dc23fc33efacc661d5 100644 (file)
 
 #include "ripngd/ripngd.h"
 
-static struct list *ripng_offset_list_master;
-
 #define OFFSET_LIST_IN_NAME(O)  ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name)
 #define OFFSET_LIST_IN_METRIC(O)  ((O)->direct[RIPNG_OFFSET_LIST_IN].metric)
 
 #define OFFSET_LIST_OUT_NAME(O)  ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name)
 #define OFFSET_LIST_OUT_METRIC(O)  ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric)
 
-struct ripng_offset_list *ripng_offset_list_new(const char *ifname)
+struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng,
+                                               const char *ifname)
 {
        struct ripng_offset_list *new;
 
        new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST,
                      sizeof(struct ripng_offset_list));
+       new->ripng = ripng;
        new->ifname = strdup(ifname);
-       listnode_add_sort(ripng_offset_list_master, new);
+       listnode_add_sort(ripng->offset_list_master, new);
 
        return new;
 }
 
 void ripng_offset_list_del(struct ripng_offset_list *offset)
 {
-       listnode_delete(ripng_offset_list_master, offset);
+       listnode_delete(offset->ripng->offset_list_master, offset);
        if (OFFSET_LIST_IN_NAME(offset))
                free(OFFSET_LIST_IN_NAME(offset));
        if (OFFSET_LIST_OUT_NAME(offset))
@@ -64,12 +64,14 @@ void ripng_offset_list_del(struct ripng_offset_list *offset)
        XFREE(MTYPE_RIPNG_OFFSET_LIST, offset);
 }
 
-struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname)
+struct ripng_offset_list *ripng_offset_list_lookup(struct ripng *ripng,
+                                                  const char *ifname)
 {
        struct ripng_offset_list *offset;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) {
+       for (ALL_LIST_ELEMENTS(ripng->offset_list_master, node, nnode,
+                              offset)) {
                if (strcmp(offset->ifname, ifname) == 0)
                        return offset;
        }
@@ -77,14 +79,14 @@ struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname)
 }
 
 /* If metric is modifed return 1. */
-int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp,
-                              uint8_t *metric)
+int ripng_offset_list_apply_in(struct ripng *ripng, struct prefix_ipv6 *p,
+                              struct interface *ifp, uint8_t *metric)
 {
        struct ripng_offset_list *offset;
        struct access_list *alist;
 
        /* Look up offset-list with interface name. */
-       offset = ripng_offset_list_lookup(ifp->name);
+       offset = ripng_offset_list_lookup(ripng, ifp->name);
        if (offset && OFFSET_LIST_IN_NAME(offset)) {
                alist = access_list_lookup(AFI_IP6,
                                           OFFSET_LIST_IN_NAME(offset));
@@ -98,7 +100,7 @@ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp,
                return 0;
        }
        /* Look up offset-list without interface name. */
-       offset = ripng_offset_list_lookup("*");
+       offset = ripng_offset_list_lookup(ripng, "*");
        if (offset && OFFSET_LIST_IN_NAME(offset)) {
                alist = access_list_lookup(AFI_IP6,
                                           OFFSET_LIST_IN_NAME(offset));
@@ -115,14 +117,14 @@ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp,
 }
 
 /* If metric is modifed return 1. */
-int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp,
-                               uint8_t *metric)
+int ripng_offset_list_apply_out(struct ripng *ripng, struct prefix_ipv6 *p,
+                               struct interface *ifp, uint8_t *metric)
 {
        struct ripng_offset_list *offset;
        struct access_list *alist;
 
        /* Look up offset-list with interface name. */
-       offset = ripng_offset_list_lookup(ifp->name);
+       offset = ripng_offset_list_lookup(ripng, ifp->name);
        if (offset && OFFSET_LIST_OUT_NAME(offset)) {
                alist = access_list_lookup(AFI_IP6,
                                           OFFSET_LIST_OUT_NAME(offset));
@@ -137,7 +139,7 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp,
        }
 
        /* Look up offset-list without interface name. */
-       offset = ripng_offset_list_lookup("*");
+       offset = ripng_offset_list_lookup(ripng, "*");
        if (offset && OFFSET_LIST_OUT_NAME(offset)) {
                alist = access_list_lookup(AFI_IP6,
                                           OFFSET_LIST_OUT_NAME(offset));
@@ -153,26 +155,7 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp,
        return 0;
 }
 
-static int offset_list_cmp(struct ripng_offset_list *o1,
-                          struct ripng_offset_list *o2)
+int offset_list_cmp(struct ripng_offset_list *o1, struct ripng_offset_list *o2)
 {
        return strcmp(o1->ifname, o2->ifname);
 }
-
-void ripng_offset_init(void)
-{
-       ripng_offset_list_master = list_new();
-       ripng_offset_list_master->cmp =
-               (int (*)(void *, void *))offset_list_cmp;
-       ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del;
-}
-
-void ripng_offset_clean(void)
-{
-       list_delete(&ripng_offset_list_master);
-
-       ripng_offset_list_master = list_new();
-       ripng_offset_list_master->cmp =
-               (int (*)(void *, void *))offset_list_cmp;
-       ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del;
-}
index 756162d65c5d4ecfb232c51cf987790d3cecc040..5376007747cdc81c34ed6f7f673c6b8438f2d97c 100644 (file)
 #include "ripngd/ripngd.h"
 #include "ripngd/ripng_nexthop.h"
 
-
-/* Linked list of RIPng peer. */
-struct list *peer_list;
-
 static struct ripng_peer *ripng_peer_new(void)
 {
        return XCALLOC(MTYPE_RIPNG_PEER, sizeof(struct ripng_peer));
@@ -45,27 +41,29 @@ static struct ripng_peer *ripng_peer_new(void)
 
 static void ripng_peer_free(struct ripng_peer *peer)
 {
+       RIPNG_TIMER_OFF(peer->t_timeout);
        XFREE(MTYPE_RIPNG_PEER, peer);
 }
 
-struct ripng_peer *ripng_peer_lookup(struct in6_addr *addr)
+struct ripng_peer *ripng_peer_lookup(struct ripng *ripng, struct in6_addr *addr)
 {
        struct ripng_peer *peer;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) {
                if (IPV6_ADDR_SAME(&peer->addr, addr))
                        return peer;
        }
        return NULL;
 }
 
-struct ripng_peer *ripng_peer_lookup_next(struct in6_addr *addr)
+struct ripng_peer *ripng_peer_lookup_next(struct ripng *ripng,
+                                         struct in6_addr *addr)
 {
        struct ripng_peer *peer;
        struct listnode *node, *nnode;
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) {
                if (addr6_cmp(&peer->addr, addr) > 0)
                        return peer;
        }
@@ -80,26 +78,28 @@ static int ripng_peer_timeout(struct thread *t)
        struct ripng_peer *peer;
 
        peer = THREAD_ARG(t);
-       listnode_delete(peer_list, peer);
+       listnode_delete(peer->ripng->peer_list, peer);
        ripng_peer_free(peer);
 
        return 0;
 }
 
 /* Get RIPng peer.  At the same time update timeout thread. */
-static struct ripng_peer *ripng_peer_get(struct in6_addr *addr)
+static struct ripng_peer *ripng_peer_get(struct ripng *ripng,
+                                        struct in6_addr *addr)
 {
        struct ripng_peer *peer;
 
-       peer = ripng_peer_lookup(addr);
+       peer = ripng_peer_lookup(ripng, addr);
 
        if (peer) {
                if (peer->t_timeout)
                        thread_cancel(peer->t_timeout);
        } else {
                peer = ripng_peer_new();
-               peer->addr = *addr; /* XXX */
-               listnode_add_sort(peer_list, peer);
+               peer->ripng = ripng;
+               peer->addr = *addr;
+               listnode_add_sort(ripng->peer_list, peer);
        }
 
        /* Update timeout thread. */
@@ -113,24 +113,25 @@ static struct ripng_peer *ripng_peer_get(struct in6_addr *addr)
        return peer;
 }
 
-void ripng_peer_update(struct sockaddr_in6 *from, uint8_t version)
+void ripng_peer_update(struct ripng *ripng, struct sockaddr_in6 *from,
+                      uint8_t version)
 {
        struct ripng_peer *peer;
-       peer = ripng_peer_get(&from->sin6_addr);
+       peer = ripng_peer_get(ripng, &from->sin6_addr);
        peer->version = version;
 }
 
-void ripng_peer_bad_route(struct sockaddr_in6 *from)
+void ripng_peer_bad_route(struct ripng *ripng, struct sockaddr_in6 *from)
 {
        struct ripng_peer *peer;
-       peer = ripng_peer_get(&from->sin6_addr);
+       peer = ripng_peer_get(ripng, &from->sin6_addr);
        peer->recv_badroutes++;
 }
 
-void ripng_peer_bad_packet(struct sockaddr_in6 *from)
+void ripng_peer_bad_packet(struct ripng *ripng, struct sockaddr_in6 *from)
 {
        struct ripng_peer *peer;
-       peer = ripng_peer_get(&from->sin6_addr);
+       peer = ripng_peer_get(ripng, &from->sin6_addr);
        peer->recv_badpackets++;
 }
 
@@ -163,14 +164,14 @@ static char *ripng_peer_uptime(struct ripng_peer *peer, char *buf, size_t len)
        return buf;
 }
 
-void ripng_peer_display(struct vty *vty)
+void ripng_peer_display(struct vty *vty, struct ripng *ripng)
 {
        struct ripng_peer *peer;
        struct listnode *node, *nnode;
 #define RIPNG_UPTIME_LEN 25
        char timebuf[RIPNG_UPTIME_LEN];
 
-       for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) {
+       for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) {
                vty_out(vty, "    %s \n%14s %10d %10d %10d      %s\n",
                        inet6_ntoa(peer->addr), " ", peer->recv_badpackets,
                        peer->recv_badroutes, ZEBRA_RIPNG_DISTANCE_DEFAULT,
@@ -178,13 +179,12 @@ void ripng_peer_display(struct vty *vty)
        }
 }
 
-static int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2)
+int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2)
 {
        return memcmp(&p1->addr, &p2->addr, sizeof(struct in6_addr));
 }
 
-void ripng_peer_init(void)
+void ripng_peer_list_del(void *arg)
 {
-       peer_list = list_new();
-       peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp;
+       ripng_peer_free(arg);
 }
index f66a0b95272b48fb3b85e579abf1f67c59cb3a84..1bf1007fecd5a22bd635f17f1c5714802a27f8b4 100644 (file)
@@ -86,7 +86,7 @@ void ripng_aggregate_decrement_list(struct agg_node *child, struct list *list)
 }
 
 /* RIPng routes treatment. */
-int ripng_aggregate_add(struct prefix *p)
+int ripng_aggregate_add(struct ripng *ripng, struct prefix *p)
 {
        struct agg_node *top;
        struct agg_node *rp;
@@ -124,7 +124,7 @@ int ripng_aggregate_add(struct prefix *p)
 }
 
 /* Delete RIPng static route. */
-int ripng_aggregate_delete(struct prefix *p)
+int ripng_aggregate_delete(struct ripng *ripng, struct prefix *p)
 {
        struct agg_node *top;
        struct agg_node *rp;
index e402f4a66c850a7016eb097cadb30ec64ea4049b..afc1d1cbc533714be9e4d52816b34a0ba430b9c7 100644 (file)
@@ -48,8 +48,8 @@ extern void ripng_aggregate_decrement(struct agg_node *rp,
                                      struct ripng_info *rinfo);
 extern void ripng_aggregate_decrement_list(struct agg_node *rp,
                                           struct list *list);
-extern int ripng_aggregate_add(struct prefix *p);
-extern int ripng_aggregate_delete(struct prefix *p);
+extern int ripng_aggregate_add(struct ripng *ripng, struct prefix *p);
+extern int ripng_aggregate_delete(struct ripng *ripng, struct prefix *p);
 extern void ripng_aggregate_free(struct ripng_aggregate *aggregate);
 
 #endif /* _ZEBRA_RIPNG_ROUTE_H */
index 28a57f25d007bbbcf6814d82e733df6d92b50f98..e2dcc023845c5dddcd6a9f1b13311722ff7cbaea 100644 (file)
@@ -37,7 +37,8 @@
 struct zclient *zclient = NULL;
 
 /* Send ECMP routes to zebra. */
-static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd)
+static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp,
+                                 uint8_t cmd)
 {
        struct list *list = (struct list *)rp->info;
        struct zapi_route api;
@@ -47,7 +48,7 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd)
        int count = 0;
 
        memset(&api, 0, sizeof(api));
-       api.vrf_id = VRF_DEFAULT;
+       api.vrf_id = ripng->vrf->vrf_id;
        api.type = ZEBRA_ROUTE_RIPNG;
        api.safi = SAFI_UNICAST;
        api.prefix = rp->p;
@@ -57,7 +58,7 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd)
                if (count >= MULTIPATH_NUM)
                        break;
                api_nh = &api.nexthops[count];
-               api_nh->vrf_id = VRF_DEFAULT;
+               api_nh->vrf_id = ripng->vrf->vrf_id;
                api_nh->gate.ipv6 = rinfo->nexthop;
                api_nh->ifindex = rinfo->ifindex;
                api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
@@ -100,25 +101,30 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd)
 }
 
 /* Add/update ECMP routes to zebra. */
-void ripng_zebra_ipv6_add(struct agg_node *rp)
+void ripng_zebra_ipv6_add(struct ripng *ripng, struct agg_node *rp)
 {
-       ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_ADD);
+       ripng_zebra_ipv6_send(ripng, rp, ZEBRA_ROUTE_ADD);
 }
 
 /* Delete ECMP routes from zebra. */
-void ripng_zebra_ipv6_delete(struct agg_node *rp)
+void ripng_zebra_ipv6_delete(struct ripng *ripng, struct agg_node *rp)
 {
-       ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_DELETE);
+       ripng_zebra_ipv6_send(ripng, rp, ZEBRA_ROUTE_DELETE);
 }
 
 /* Zebra route add and delete treatment. */
 static int ripng_zebra_read_route(int command, struct zclient *zclient,
                                  zebra_size_t length, vrf_id_t vrf_id)
 {
+       struct ripng *ripng;
        struct zapi_route api;
        struct in6_addr nexthop;
        unsigned long ifindex;
 
+       ripng = ripng_lookup_by_vrf_id(vrf_id);
+       if (!ripng)
+               return 0;
+
        if (zapi_route_decode(zclient->ibuf, &api) < 0)
                return -1;
 
@@ -130,69 +136,97 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient,
        ifindex = api.nexthops[0].ifindex;
 
        if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
-               ripng_redistribute_add(api.type, RIPNG_ROUTE_REDISTRIBUTE,
+               ripng_redistribute_add(ripng, api.type,
+                                      RIPNG_ROUTE_REDISTRIBUTE,
                                       (struct prefix_ipv6 *)&api.prefix,
                                       ifindex, &nexthop, api.tag);
        else
-               ripng_redistribute_delete(api.type, RIPNG_ROUTE_REDISTRIBUTE,
-                                         (struct prefix_ipv6 *)&api.prefix,
-                                         ifindex);
+               ripng_redistribute_delete(
+                       ripng, api.type, RIPNG_ROUTE_REDISTRIBUTE,
+                       (struct prefix_ipv6 *)&api.prefix, ifindex);
 
        return 0;
 }
 
-void ripng_redistribute_conf_update(int type)
+void ripng_redistribute_conf_update(struct ripng *ripng, int type)
 {
        zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0,
-                            VRF_DEFAULT);
+                            ripng->vrf->vrf_id);
 }
 
-void ripng_redistribute_conf_delete(int type)
+void ripng_redistribute_conf_delete(struct ripng *ripng, int type)
 {
        if (zclient->sock > 0)
                zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
-                                       AFI_IP6, type, 0, VRF_DEFAULT);
+                                       AFI_IP6, type, 0, ripng->vrf->vrf_id);
 
-       ripng_redistribute_withdraw(type);
+       ripng_redistribute_withdraw(ripng, type);
 }
 
-int ripng_redistribute_check(int type)
+int ripng_redistribute_check(struct ripng *ripng, int type)
 {
-       return vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT);
+       return ripng->redist[type].enabled;
 }
 
-void ripng_redistribute_clean(void)
+void ripng_redistribute_enable(struct ripng *ripng)
 {
        for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-               if (!vrf_bitmap_check(zclient->redist[AFI_IP6][i], VRF_DEFAULT))
+               if (!ripng_redistribute_check(ripng, i))
                        continue;
 
-               if (zclient->sock > 0)
-                       zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE,
-                                               zclient, AFI_IP6, i, 0,
-                                               VRF_DEFAULT);
+               zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient,
+                                       AFI_IP6, i, 0, ripng->vrf->vrf_id);
+       }
+}
 
-               vrf_bitmap_unset(zclient->redist[AFI_IP6][i], VRF_DEFAULT);
+void ripng_redistribute_disable(struct ripng *ripng)
+{
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+               if (!ripng_redistribute_check(ripng, i))
+                       continue;
 
-               /* Remove the routes from RIP table. */
-               ripng_redistribute_withdraw(i);
+               zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient,
+                                       AFI_IP6, i, 0, ripng->vrf->vrf_id);
        }
 }
 
-void ripng_redistribute_write(struct vty *vty)
+void ripng_redistribute_write(struct vty *vty, struct ripng *ripng)
 {
        int i;
 
        for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
                if (i == zclient->redist_default
-                   || !vrf_bitmap_check(zclient->redist[AFI_IP6][i],
-                                        VRF_DEFAULT))
+                   || !ripng_redistribute_check(ripng, i))
                        continue;
 
                vty_out(vty, "    %s", zebra_route_string(i));
        }
 }
 
+void ripng_zebra_vrf_register(struct vrf *vrf)
+{
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return;
+
+       if (IS_RIPNG_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 ripng_zebra_vrf_deregister(struct vrf *vrf)
+{
+       if (vrf->vrf_id == VRF_DEFAULT)
+               return;
+
+       if (IS_RIPNG_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 ripng_zebra_connected(struct zclient *zclient)
 {
        zclient_send_reg_requests(zclient, VRF_DEFAULT);
@@ -212,6 +246,7 @@ void zebra_init(struct thread_master *master)
        zclient->interface_delete = ripng_interface_delete;
        zclient->interface_address_add = ripng_interface_address_add;
        zclient->interface_address_delete = ripng_interface_address_delete;
+       zclient->interface_vrf_update = ripng_interface_vrf_update;
        zclient->redistribute_route_add = ripng_zebra_read_route;
        zclient->redistribute_route_del = ripng_zebra_read_route;
 }
index 9faebcf0d0e54e8fa3f4f2d26be3407c4dcc1fcb..b36cee2c5d5a1f156b3c0654e72d577362e0d48f 100644 (file)
 #include "ripngd/ripng_debug.h"
 #include "ripngd/ripng_nexthop.h"
 
-/* RIPng structure which includes many parameters related to RIPng
-   protocol. If ripng couldn't active or ripng doesn't configured,
-   ripng->fd must be negative value. */
-struct ripng *ripng = NULL;
-
 enum { ripng_all_route,
        ripng_changed_route,
 };
@@ -57,12 +52,23 @@ static void ripng_distribute_update(struct distribute_ctx *ctx,
 
 /* Prototypes. */
 void ripng_output_process(struct interface *, struct sockaddr_in6 *, int);
-
+static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
+                                 int sock);
+static void ripng_instance_disable(struct ripng *ripng);
 int ripng_triggered_update(struct thread *);
-
 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
                                 struct if_rmap *if_rmap);
 
+/* Generate rb-tree of RIPng instances. */
+static inline int ripng_instance_compare(const struct ripng *a,
+                                        const struct ripng *b)
+{
+       return strcmp(a->vrf_name, b->vrf_name);
+}
+RB_GENERATE(ripng_instance_head, ripng, entry, ripng_instance_compare)
+
+struct ripng_instance_head ripng_instances = RB_INITIALIZER(&ripng_instances);
+
 /* RIPng next hop specification. */
 struct ripng_nexthop {
        enum ripng_nexthop_type {
@@ -93,19 +99,36 @@ void ripng_info_free(struct ripng_info *rinfo)
        XFREE(MTYPE_RIPNG_ROUTE, rinfo);
 }
 
+struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo)
+{
+       return agg_get_table_info(agg_get_table(rinfo->rp));
+}
+
 /* Create ripng socket. */
-int ripng_make_socket(void)
+int ripng_make_socket(struct vrf *vrf)
 {
        int ret;
        int sock;
        struct sockaddr_in6 ripaddr;
-
-       sock = socket(AF_INET6, SOCK_DGRAM, 0);
-       if (sock < 0) {
-               flog_err_sys(EC_LIB_SOCKET, "Can't make ripng socket");
-               return sock;
+       const char *vrf_dev = NULL;
+
+       /* Make datagram socket. */
+       if (vrf->vrf_id != VRF_DEFAULT)
+               vrf_dev = vrf->name;
+       frr_elevate_privs(&ripngd_privs)
+       {
+               sock = vrf_socket(AF_INET6, 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_reuseaddr(sock);
+       sockopt_reuseport(sock);
        setsockopt_so_recvbuf(sock, 8096);
        ret = setsockopt_ipv6_pktinfo(sock, 1);
        if (ret < 0)
@@ -151,11 +174,13 @@ error:
 int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to,
                      struct interface *ifp)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        int ret;
        struct msghdr msg;
        struct iovec iov;
        struct cmsghdr *cmsgptr;
-       char adata[256];
+       char adata[256] = {};
        struct in6_pktinfo *pkt;
        struct sockaddr_in6 addr;
 
@@ -424,13 +449,14 @@ static int ripng_garbage_collect(struct thread *t)
        return 0;
 }
 
-static void ripng_timeout_update(struct ripng_info *rinfo);
+static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo);
 
 /* Add new route to the ECMP list.
  * RETURN: the new entry added in the list, or NULL if it is not the first
  *         entry and ECMP is not allowed.
  */
-struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new)
+struct ripng_info *ripng_ecmp_add(struct ripng *ripng,
+                                 struct ripng_info *rinfo_new)
 {
        struct agg_node *rp = rinfo_new->rp;
        struct ripng_info *rinfo = NULL;
@@ -450,8 +476,8 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new)
        listnode_add(list, rinfo);
 
        if (ripng_route_rte(rinfo)) {
-               ripng_timeout_update(rinfo);
-               ripng_zebra_ipv6_add(rp);
+               ripng_timeout_update(ripng, rinfo);
+               ripng_zebra_ipv6_add(ripng, rp);
        }
 
        ripng_aggregate_increment(rp, rinfo);
@@ -461,7 +487,7 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new)
        SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
 
        /* Signal the output process to trigger an update. */
-       ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+       ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -469,7 +495,8 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new)
 /* Replace the ECMP list with the new route.
  * RETURN: the new entry added in the list
  */
-struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
+struct ripng_info *ripng_ecmp_replace(struct ripng *ripng,
+                                     struct ripng_info *rinfo_new)
 {
        struct agg_node *rp = rinfo_new->rp;
        struct list *list = (struct list *)rp->info;
@@ -477,7 +504,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
        struct listnode *node = NULL, *nextnode = NULL;
 
        if (list == NULL || listcount(list) == 0)
-               return ripng_ecmp_add(rinfo_new);
+               return ripng_ecmp_add(ripng, rinfo_new);
 
        /* Get the first entry */
        rinfo = listgetdata(listhead(list));
@@ -485,7 +512,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
        /* Learnt route replaced by a local one. Delete it from zebra. */
        if (ripng_route_rte(rinfo) && !ripng_route_rte(rinfo_new))
                if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
-                       ripng_zebra_ipv6_delete(rp);
+                       ripng_zebra_ipv6_delete(ripng, rp);
 
        if (rinfo->metric != RIPNG_METRIC_INFINITY)
                ripng_aggregate_decrement_list(rp, list);
@@ -504,9 +531,9 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
        memcpy(rinfo, rinfo_new, sizeof(struct ripng_info));
 
        if (ripng_route_rte(rinfo)) {
-               ripng_timeout_update(rinfo);
+               ripng_timeout_update(ripng, rinfo);
                /* The ADD message implies an update. */
-               ripng_zebra_ipv6_add(rp);
+               ripng_zebra_ipv6_add(ripng, rp);
        }
 
        ripng_aggregate_increment(rp, rinfo);
@@ -515,7 +542,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
        SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
 
        /* Signal the output process to trigger an update. */
-       ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+       ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -526,7 +553,8 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new)
  *  the entry - the entry is the last one in the list; its metric is set
  *              to INFINITY, and the garbage collector is started for it
  */
-struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
+struct ripng_info *ripng_ecmp_delete(struct ripng *ripng,
+                                    struct ripng_info *rinfo)
 {
        struct agg_node *rp = rinfo->rp;
        struct list *list = (struct list *)rp->info;
@@ -544,7 +572,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
                if (ripng_route_rte(rinfo)
                    && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
                        /* The ADD message implies the update. */
-                       ripng_zebra_ipv6_add(rp);
+                       ripng_zebra_ipv6_add(ripng, rp);
                ripng_info_free(rinfo);
                rinfo = NULL;
        } else {
@@ -560,7 +588,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
 
                if (ripng_route_rte(rinfo)
                    && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
-                       ripng_zebra_ipv6_delete(rp);
+                       ripng_zebra_ipv6_delete(ripng, rp);
        }
 
        /* Set the route change flag on the first entry. */
@@ -568,7 +596,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
        SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
 
        /* Signal the output process to trigger an update. */
-       ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+       ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
 
        return rinfo;
 }
@@ -576,16 +604,20 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo)
 /* Timeout RIPng routes. */
 static int ripng_timeout(struct thread *t)
 {
-       ripng_ecmp_delete((struct ripng_info *)THREAD_ARG(t));
+       struct ripng_info *rinfo = THREAD_ARG(t);
+       struct ripng *ripng = ripng_info_get_instance(rinfo);
+
+       ripng_ecmp_delete(ripng, rinfo);
+
        return 0;
 }
 
-static void ripng_timeout_update(struct ripng_info *rinfo)
+static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo)
 {
        if (rinfo->metric != RIPNG_METRIC_INFINITY) {
                RIPNG_TIMER_OFF(rinfo->t_timeout);
-               RIPNG_TIMER_ON(rinfo->t_timeout, ripng_timeout,
-                              ripng->timeout_time);
+               thread_add_timer(master, ripng_timeout, rinfo,
+                                ripng->timeout_time, &rinfo->t_timeout);
        }
 }
 
@@ -625,7 +657,7 @@ static int ripng_filter(int ripng_distribute, struct prefix_ipv6 *p,
        }
 
        /* All interface filter check. */
-       dist = distribute_lookup(ripng->distribute_ctx, NULL);
+       dist = distribute_lookup(ri->ripng->distribute_ctx, NULL);
        if (dist) {
                if (dist->list[distribute]) {
                        alist = access_list_lookup(AFI_IP6,
@@ -673,6 +705,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
        struct agg_node *rp;
        struct ripng_info *rinfo = NULL, newinfo;
        struct ripng_interface *ri;
+       struct ripng *ripng;
        struct in6_addr *nexthop;
        int same = 0;
        struct list *list = NULL;
@@ -690,9 +723,10 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
           apply_mask_ipv6. */
        apply_mask_ipv6(&p);
 
-       /* Apply input filters. */
        ri = ifp->info;
+       ripng = ri->ripng;
 
+       /* Apply input filters. */
        ret = ripng_filter(RIPNG_FILTER_IN, &p, ri);
        if (ret < 0)
                return;
@@ -760,7 +794,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
         **/
 
        /* Zebra ripngd can handle offset-list in. */
-       ret = ripng_offset_list_apply_in(&p, ifp, &rte->metric);
+       ret = ripng_offset_list_apply_in(ripng, &p, ifp, &rte->metric);
 
        /* If offset-list does not modify the metric use interface's
         * one. */
@@ -846,7 +880,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
                   infinity (there is no point in adding a route which
                   unusable). */
                if (rte->metric != RIPNG_METRIC_INFINITY)
-                       ripng_ecmp_add(&newinfo);
+                       ripng_ecmp_add(ripng, &newinfo);
                else
                        agg_unlock_node(rp);
        } else {
@@ -871,7 +905,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
                    && rinfo->t_timeout
                    && (thread_timer_remain_second(rinfo->t_timeout)
                        < (ripng->timeout_time / 2))) {
-                       ripng_ecmp_replace(&newinfo);
+                       ripng_ecmp_replace(ripng, &newinfo);
                }
                /* Next, compare the metrics.  If the datagram is from the same
                   router as the existing route, and the new metric is different
@@ -881,17 +915,17 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
                         || rte->metric < rinfo->metric) {
                        if (listcount(list) == 1) {
                                if (newinfo.metric != RIPNG_METRIC_INFINITY)
-                                       ripng_ecmp_replace(&newinfo);
+                                       ripng_ecmp_replace(ripng, &newinfo);
                                else
-                                       ripng_ecmp_delete(rinfo);
+                                       ripng_ecmp_delete(ripng, rinfo);
                        } else {
                                if (newinfo.metric < rinfo->metric)
-                                       ripng_ecmp_replace(&newinfo);
+                                       ripng_ecmp_replace(ripng, &newinfo);
                                else /* newinfo.metric > rinfo->metric */
-                                       ripng_ecmp_delete(rinfo);
+                                       ripng_ecmp_delete(ripng, rinfo);
                        }
                } else /* same & no change */
-                       ripng_timeout_update(rinfo);
+                       ripng_timeout_update(ripng, rinfo);
 
                /* Unlock tempolary lock of the route. */
                agg_unlock_node(rp);
@@ -899,9 +933,9 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from,
 }
 
 /* Add redistributed route to RIPng table. */
-void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p,
-                           ifindex_t ifindex, struct in6_addr *nexthop,
-                           route_tag_t tag)
+void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type,
+                           struct prefix_ipv6 *p, ifindex_t ifindex,
+                           struct in6_addr *nexthop, route_tag_t tag)
 {
        struct agg_node *rp;
        struct ripng_info *rinfo = NULL, newinfo;
@@ -950,31 +984,31 @@ void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p,
                        }
                }
 
-               ripng_ecmp_replace(&newinfo);
+               ripng_ecmp_replace(ripng, &newinfo);
                agg_unlock_node(rp);
        } else
-               ripng_ecmp_add(&newinfo);
+               ripng_ecmp_add(ripng, &newinfo);
 
        if (IS_RIPNG_DEBUG_EVENT) {
                if (!nexthop)
                        zlog_debug(
                                "Redistribute new prefix %s/%d on the interface %s",
                                inet6_ntoa(p->prefix), p->prefixlen,
-                               ifindex2ifname(ifindex, VRF_DEFAULT));
+                               ifindex2ifname(ifindex, ripng->vrf->vrf_id));
                else
                        zlog_debug(
                                "Redistribute new prefix %s/%d with nexthop %s on the interface %s",
                                inet6_ntoa(p->prefix), p->prefixlen,
                                inet6_ntoa(*nexthop),
-                               ifindex2ifname(ifindex, VRF_DEFAULT));
+                               ifindex2ifname(ifindex, ripng->vrf->vrf_id));
        }
 
-       ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+       ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
 }
 
 /* Delete redistributed route to RIPng table. */
-void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p,
-                              ifindex_t ifindex)
+void ripng_redistribute_delete(struct ripng *ripng, int type, int sub_type,
+                              struct prefix_ipv6 *p, ifindex_t ifindex)
 {
        struct agg_node *rp;
        struct ripng_info *rinfo;
@@ -1012,10 +1046,11 @@ void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p,
                                                "infinity metric [delete]",
                                                inet6_ntoa(p->prefix),
                                                p->prefixlen,
-                                               ifindex2ifname(ifindex,
-                                                              VRF_DEFAULT));
+                                               ifindex2ifname(
+                                                       ifindex,
+                                                       ripng->vrf->vrf_id));
 
-                               ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+                               ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
                        }
                }
                agg_unlock_node(rp);
@@ -1023,15 +1058,12 @@ void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p,
 }
 
 /* Withdraw redistributed route. */
-void ripng_redistribute_withdraw(int type)
+void ripng_redistribute_withdraw(struct ripng *ripng, int type)
 {
        struct agg_node *rp;
        struct ripng_info *rinfo = NULL;
        struct list *list = NULL;
 
-       if (!ripng)
-               return;
-
        for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp))
                if ((list = rp->info) != NULL) {
                        rinfo = listgetdata(listhead(list));
@@ -1057,11 +1089,12 @@ void ripng_redistribute_withdraw(int type)
                                                "Poisone %s/%d on the interface %s [withdraw]",
                                                inet6_ntoa(p->prefix),
                                                p->prefixlen,
-                                               ifindex2ifname(rinfo->ifindex,
-                                                              VRF_DEFAULT));
+                                               ifindex2ifname(
+                                                       rinfo->ifindex,
+                                                       ripng->vrf->vrf_id));
                                }
 
-                               ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+                               ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
                        }
                }
 }
@@ -1071,6 +1104,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                                   struct sockaddr_in6 *from,
                                   struct interface *ifp, int hoplimit)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        caddr_t lim;
        struct rte *rte;
        struct ripng_nexthop nexthop;
@@ -1080,7 +1115,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
        if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) {
                zlog_warn("RIPng packet comes from non RIPng port %d from %s",
                          ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr));
-               ripng_peer_bad_packet(from);
+               ripng_peer_bad_packet(ripng, from);
                return;
        }
 
@@ -1090,7 +1125,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
        if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) {
                zlog_warn("RIPng packet comes from non link local address %s",
                          inet6_ntoa(from->sin6_addr));
-               ripng_peer_bad_packet(from);
+               ripng_peer_bad_packet(ripng, from);
                return;
        }
 
@@ -1103,7 +1138,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                zlog_warn(
                        "RIPng packet comes from my own link local address %s",
                        inet6_ntoa(from->sin6_addr));
-               ripng_peer_bad_packet(from);
+               ripng_peer_bad_packet(ripng, from);
                return;
        }
 
@@ -1115,12 +1150,12 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                zlog_warn(
                        "RIPng packet comes with non 255 hop count %d from %s",
                        hoplimit, inet6_ntoa(from->sin6_addr));
-               ripng_peer_bad_packet(from);
+               ripng_peer_bad_packet(ripng, from);
                return;
        }
 
        /* Update RIPng peer. */
-       ripng_peer_update(from, packet->version);
+       ripng_peer_update(ripng, from, packet->version);
 
        /* Reset nexthop. */
        memset(&nexthop, 0, sizeof(struct ripng_nexthop));
@@ -1148,7 +1183,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                                "Destination prefix is a multicast address %s/%d [%d]",
                                inet6_ntoa(rte->addr), rte->prefixlen,
                                rte->metric);
-                       ripng_peer_bad_route(from);
+                       ripng_peer_bad_route(ripng, from);
                        continue;
                }
                if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) {
@@ -1156,7 +1191,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                                "Destination prefix is a link-local address %s/%d [%d]",
                                inet6_ntoa(rte->addr), rte->prefixlen,
                                rte->metric);
-                       ripng_peer_bad_route(from);
+                       ripng_peer_bad_route(ripng, from);
                        continue;
                }
                if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) {
@@ -1164,7 +1199,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                                "Destination prefix is a loopback address %s/%d [%d]",
                                inet6_ntoa(rte->addr), rte->prefixlen,
                                rte->metric);
-                       ripng_peer_bad_route(from);
+                       ripng_peer_bad_route(ripng, from);
                        continue;
                }
 
@@ -1174,7 +1209,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                        zlog_warn("Invalid prefix length %s/%d from %s%%%s",
                                  inet6_ntoa(rte->addr), rte->prefixlen,
                                  inet6_ntoa(from->sin6_addr), ifp->name);
-                       ripng_peer_bad_route(from);
+                       ripng_peer_bad_route(ripng, from);
                        continue;
                }
 
@@ -1182,7 +1217,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size,
                if (!(rte->metric >= 1 && rte->metric <= 16)) {
                        zlog_warn("Invalid metric %d from %s%%%s", rte->metric,
                                  inet6_ntoa(from->sin6_addr), ifp->name);
-                       ripng_peer_bad_route(from);
+                       ripng_peer_bad_route(ripng, from);
                        continue;
                }
 
@@ -1200,6 +1235,7 @@ static void ripng_request_process(struct ripng_packet *packet, int size,
                                  struct sockaddr_in6 *from,
                                  struct interface *ifp)
 {
+       struct ripng *ripng;
        caddr_t lim;
        struct rte *rte;
        struct prefix_ipv6 p;
@@ -1215,13 +1251,14 @@ static void ripng_request_process(struct ripng_packet *packet, int size,
        ri = ifp->info;
        if (!ri->running)
                return;
+       ripng = ri->ripng;
 
        /* When passive interface is specified, suppress responses */
        if (ri->passive)
                return;
 
        /* RIPng peer update. */
-       ripng_peer_update(from, packet->version);
+       ripng_peer_update(ripng, from, packet->version);
 
        lim = ((caddr_t)packet) + size;
        rte = packet->rte;
@@ -1278,6 +1315,7 @@ static void ripng_request_process(struct ripng_packet *packet, int size,
 /* First entry point of reading RIPng packet. */
 static int ripng_read(struct thread *thread)
 {
+       struct ripng *ripng = THREAD_ARG(thread);
        int len;
        int sock;
        struct sockaddr_in6 from;
@@ -1296,34 +1334,36 @@ static int ripng_read(struct thread *thread)
        ripng->t_read = NULL;
 
        /* Add myself to the next event. */
-       ripng_event(RIPNG_READ, sock);
+       ripng_event(ripng, RIPNG_READ, sock);
 
        /* Read RIPng packet. */
        len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf),
                                STREAM_SIZE(ripng->ibuf), &from, &ifindex,
                                &hoplimit);
        if (len < 0) {
-               zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno));
+               zlog_warn("RIPng recvfrom failed (VRF %s): %s.",
+                         ripng->vrf_name, safe_strerror(errno));
                return len;
        }
 
        /* Check RTE boundary.  RTE size (Packet length - RIPng header size
           (4)) must be multiple size of one RTE size (20). */
        if (((len - 4) % 20) != 0) {
-               zlog_warn("RIPng invalid packet size %d from %s", len,
-                         inet6_ntoa(from.sin6_addr));
-               ripng_peer_bad_packet(&from);
+               zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len,
+                         inet6_ntoa(from.sin6_addr), ripng->vrf_name);
+               ripng_peer_bad_packet(ripng, &from);
                return 0;
        }
 
        packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf);
-       ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
+       ifp = if_lookup_by_index(ifindex, ripng->vrf->vrf_id);
 
        /* RIPng packet received. */
        if (IS_RIPNG_DEBUG_EVENT)
-               zlog_debug("RIPng packet received from %s port %d on %s",
-                          inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
-                          ifp ? ifp->name : "unknown");
+               zlog_debug(
+                       "RIPng packet received from %s port %d on %s (VRF %s)",
+                       inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port),
+                       ifp ? ifp->name : "unknown", ripng->vrf_name);
 
        /* Logging before packet checking. */
        if (IS_RIPNG_DEBUG_RECV)
@@ -1331,17 +1371,18 @@ static int ripng_read(struct thread *thread)
 
        /* Packet comes from unknown interface. */
        if (ifp == NULL) {
-               zlog_warn("RIPng packet comes from unknown interface %d",
-                         ifindex);
+               zlog_warn(
+                       "RIPng packet comes from unknown interface %d (VRF %s)",
+                       ifindex, ripng->vrf_name);
                return 0;
        }
 
        /* Packet version mismatch checking. */
        if (packet->version != ripng->version) {
                zlog_warn(
-                       "RIPng packet version %d doesn't fit to my version %d",
-                       packet->version, ripng->version);
-               ripng_peer_bad_packet(&from);
+                       "RIPng packet version %d doesn't fit to my version %d (VRF %s)",
+                       packet->version, ripng->version, ripng->vrf_name);
+               ripng_peer_bad_packet(ripng, &from);
                return 0;
        }
 
@@ -1354,15 +1395,16 @@ static int ripng_read(struct thread *thread)
                ripng_response_process(packet, len, &from, ifp, hoplimit);
                break;
        default:
-               zlog_warn("Invalid RIPng command %d", packet->command);
-               ripng_peer_bad_packet(&from);
+               zlog_warn("Invalid RIPng command %d (VRF %s)", packet->command,
+                         ripng->vrf_name);
+               ripng_peer_bad_packet(ripng, &from);
                break;
        }
        return 0;
 }
 
 /* Walk down the RIPng routing table then clear changed flag. */
-static void ripng_clear_changed_flag(void)
+static void ripng_clear_changed_flag(struct ripng *ripng)
 {
        struct agg_node *rp;
        struct ripng_info *rinfo = NULL;
@@ -1383,7 +1425,7 @@ static void ripng_clear_changed_flag(void)
    enabled interface. */
 static int ripng_update(struct thread *t)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct ripng *ripng = THREAD_ARG(t);
        struct interface *ifp;
        struct ripng_interface *ri;
 
@@ -1395,7 +1437,7 @@ static int ripng_update(struct thread *t)
                zlog_debug("RIPng update timer expired!");
 
        /* Supply routes to each interface. */
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (ripng->vrf, ifp) {
                ri = ifp->info;
 
                if (if_is_loopback(ifp) || !if_is_up(ifp))
@@ -1431,7 +1473,7 @@ static int ripng_update(struct thread *t)
        ripng->trigger = 0;
 
        /* Reset flush event. */
-       ripng_event(RIPNG_UPDATE_EVENT, 0);
+       ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
 
        return 0;
 }
@@ -1439,6 +1481,8 @@ static int ripng_update(struct thread *t)
 /* Triggered update interval timer. */
 static int ripng_triggered_interval(struct thread *t)
 {
+       struct ripng *ripng = THREAD_ARG(t);
+
        ripng->t_triggered_interval = NULL;
 
        if (ripng->trigger) {
@@ -1451,7 +1495,7 @@ static int ripng_triggered_interval(struct thread *t)
 /* Execute triggered update. */
 int ripng_triggered_update(struct thread *t)
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct ripng *ripng = THREAD_ARG(t);
        struct interface *ifp;
        struct ripng_interface *ri;
        int interval;
@@ -1471,7 +1515,7 @@ int ripng_triggered_update(struct thread *t)
 
        /* Split Horizon processing is done when generating triggered
           updates as well as normal updates (see section 2.6). */
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (ripng->vrf, ifp) {
                ri = ifp->info;
 
                if (if_is_loopback(ifp) || !if_is_up(ifp))
@@ -1490,7 +1534,7 @@ int ripng_triggered_update(struct thread *t)
 
        /* Once all of the triggered updates have been generated, the route
           change flags should be cleared. */
-       ripng_clear_changed_flag();
+       ripng_clear_changed_flag(ripng);
 
        /* After a triggered update is sent, a timer should be set for a
           random interval between 1 and 5 seconds.  If other changes that
@@ -1499,7 +1543,7 @@ int ripng_triggered_update(struct thread *t)
        interval = (random() % 5) + 1;
 
        ripng->t_triggered_interval = NULL;
-       thread_add_timer(master, ripng_triggered_interval, NULL, interval,
+       thread_add_timer(master, ripng_triggered_interval, ripng, interval,
                         &ripng->t_triggered_interval);
 
        return 0;
@@ -1537,6 +1581,7 @@ int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
 void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
                          int route_type)
 {
+       struct ripng *ripng;
        int ret;
        struct agg_node *rp;
        struct ripng_info *rinfo;
@@ -1556,8 +1601,9 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
                                   ifp->name);
        }
 
-       /* Get RIPng interface. */
+       /* Get RIPng interface and instance. */
        ri = ifp->info;
+       ripng = ri->ripng;
 
        ripng_rte_list = ripng_rte_new();
 
@@ -1637,10 +1683,11 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
                        }
 
                        /* Redistribute route-map. */
-                       if (ripng->route_map[rinfo->type].name) {
-                               ret = route_map_apply(
-                                       ripng->route_map[rinfo->type].map,
-                                       (struct prefix *)p, RMAP_RIPNG, rinfo);
+                       if (ripng->redist[rinfo->type].route_map.name) {
+                               ret = route_map_apply(ripng->redist[rinfo->type]
+                                                             .route_map.map,
+                                                     (struct prefix *)p,
+                                                     RMAP_RIPNG, rinfo);
 
                                if (ret == RMAP_DENYMATCH) {
                                        if (IS_RIPNG_DEBUG_PACKET)
@@ -1655,10 +1702,10 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
                        /* When the route-map does not set metric. */
                        if (!rinfo->metric_set) {
                                /* If the redistribute metric is set. */
-                               if (ripng->route_map[rinfo->type].metric_config
+                               if (ripng->redist[rinfo->type].metric_config
                                    && rinfo->metric != RIPNG_METRIC_INFINITY) {
                                        rinfo->metric_out =
-                                               ripng->route_map[rinfo->type]
+                                               ripng->redist[rinfo->type]
                                                        .metric;
                                } else {
                                        /* If the route is not connected or
@@ -1676,7 +1723,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
 
                        /* Apply offset-list */
                        if (rinfo->metric_out != RIPNG_METRIC_INFINITY)
-                               ripng_offset_list_apply_out(p, ifp,
+                               ripng_offset_list_apply_out(ripng, p, ifp,
                                                            &rinfo->metric_out);
 
                        if (rinfo->metric_out > RIPNG_METRIC_INFINITY)
@@ -1769,7 +1816,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
                        /* Apply offset-list */
                        if (aggregate->metric_out != RIPNG_METRIC_INFINITY)
                                ripng_offset_list_apply_out(
-                                       p, ifp, &aggregate->metric_out);
+                                       ripng, p, ifp, &aggregate->metric_out);
 
                        if (aggregate->metric_out > RIPNG_METRIC_INFINITY)
                                aggregate->metric_out = RIPNG_METRIC_INFINITY;
@@ -1784,14 +1831,34 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to,
        ripng_rte_free(ripng_rte_list);
 }
 
+struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id)
+{
+       struct vrf *vrf;
+
+       vrf = vrf_lookup_by_id(vrf_id);
+       if (!vrf)
+               return NULL;
+
+       return vrf->info;
+}
+
+struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name)
+{
+       struct ripng ripng;
+
+       ripng.vrf_name = (char *)vrf_name;
+
+       return RB_FIND(ripng_instance_head, &ripng_instances, &ripng);
+}
+
 /* Create new RIPng instance and set it to global variable. */
-int ripng_create(int socket)
+struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket)
 {
-       /* ripng should be NULL. */
-       assert(ripng == NULL);
+       struct ripng *ripng;
 
        /* Allocaste RIPng instance. */
        ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng));
+       ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf_name);
 
        /* Default version and timer values. */
        ripng->version = RIPNG_V1;
@@ -1809,30 +1876,42 @@ int ripng_create(int socket)
        ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5);
        ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE);
 
-       /* Initialize RIPng routig table. */
+       /* Initialize RIPng data structures. */
        ripng->table = agg_table_init();
-
-       /* Distribute list install. */
-       ripng->distribute_ctx = distribute_list_ctx_create(
-                                          vrf_lookup_by_id(VRF_DEFAULT));
+       agg_set_table_info(ripng->table, ripng);
+       ripng->peer_list = list_new();
+       ripng->peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp;
+       ripng->peer_list->del = ripng_peer_list_del;
+       ripng->enable_if = vector_init(1);
+       ripng->enable_network = agg_table_init();
+       ripng->passive_interface = vector_init(1);
+       ripng->offset_list_master = list_new();
+       ripng->offset_list_master->cmp =
+               (int (*)(void *, void *))offset_list_cmp;
+       ripng->offset_list_master->del =
+               (void (*)(void *))ripng_offset_list_del;
+       ripng->distribute_ctx = distribute_list_ctx_create(vrf);
        distribute_list_add_hook(ripng->distribute_ctx,
                                 ripng_distribute_update);
        distribute_list_delete_hook(ripng->distribute_ctx,
                                    ripng_distribute_update);
 
        /* if rmap install. */
-       ripng->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME);
+       ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name);
        if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update);
        if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update);
 
-       /* Make socket. */
-       ripng->sock = socket;
+       /* Enable the routing instance if possible. */
+       if (vrf && vrf_is_enabled(vrf))
+               ripng_instance_enable(ripng, vrf, socket);
+       else {
+               ripng->vrf = NULL;
+               ripng->sock = -1;
+       }
 
-       /* Threads. */
-       ripng_event(RIPNG_READ, ripng->sock);
-       ripng_event(RIPNG_UPDATE_EVENT, 1);
+       RB_INSERT(ripng_instance_head, &ripng_instances, ripng);
 
-       return 0;
+       return ripng;
 }
 
 /* Send RIPng request to the interface. */
@@ -1869,13 +1948,14 @@ static int ripng_update_jitter(int time)
        return ((random() % (time + 1)) - (time / 2));
 }
 
-void ripng_event(enum ripng_event event, int sock)
+void ripng_event(struct ripng *ripng, enum ripng_event event, int sock)
 {
        int jitter = 0;
 
        switch (event) {
        case RIPNG_READ:
-               thread_add_read(master, ripng_read, NULL, sock, &ripng->t_read);
+               thread_add_read(master, ripng_read, ripng, sock,
+                               &ripng->t_read);
                break;
        case RIPNG_UPDATE_EVENT:
                if (ripng->t_update) {
@@ -1886,7 +1966,7 @@ void ripng_event(enum ripng_event event, int sock)
                jitter = ripng_update_jitter(ripng->update_time);
 
                ripng->t_update = NULL;
-               thread_add_timer(master, ripng_update, NULL,
+               thread_add_timer(master, ripng_update, ripng,
                                 sock ? 2 : ripng->update_time + jitter,
                                 &ripng->t_update);
                break;
@@ -1894,7 +1974,7 @@ void ripng_event(enum ripng_event event, int sock)
                if (ripng->t_triggered_interval)
                        ripng->trigger = 1;
                else
-                       thread_add_event(master, ripng_triggered_update, NULL,
+                       thread_add_event(master, ripng_triggered_update, ripng,
                                         0, &ripng->t_triggered_update);
                break;
        default:
@@ -1959,11 +2039,13 @@ static char *ripng_route_subtype_print(struct ripng_info *rinfo)
 
 DEFUN (show_ipv6_ripng,
        show_ipv6_ripng_cmd,
-       "show ipv6 ripng",
+       "show ipv6 ripng [vrf NAME]",
        SHOW_STR
        IPV6_STR
-       "Show RIPng routes\n")
+       "Show RIPng routes\n"
+       VRF_CMD_HELP_STR)
 {
+       struct ripng *ripng;
        struct agg_node *rp;
        struct ripng_info *rinfo;
        struct ripng_aggregate *aggregate;
@@ -1971,9 +2053,23 @@ DEFUN (show_ipv6_ripng,
        struct list *list = NULL;
        struct listnode *listnode = NULL;
        int len;
+       const char *vrf_name;
+       int idx = 0;
 
-       if (!ripng)
+       if (argv_find(argv, argc, "vrf", &idx))
+               vrf_name = argv[idx + 1]->arg;
+       else
+               vrf_name = VRF_DEFAULT_NAME;
+
+       ripng = ripng_lookup_by_vrf_name(vrf_name);
+       if (!ripng) {
+               vty_out(vty, "%% RIPng instance not found\n");
+               return CMD_SUCCESS;
+       }
+       if (!ripng->enabled) {
+               vty_out(vty, "%% RIPng instance is disabled\n");
                return CMD_SUCCESS;
+       }
 
        /* Header of display. */
        vty_out(vty,
@@ -2033,8 +2129,9 @@ DEFUN (show_ipv6_ripng,
                                    && (rinfo->sub_type == RIPNG_ROUTE_RTE)) {
                                        len = vty_out(
                                                vty, "%s",
-                                               ifindex2ifname(rinfo->ifindex,
-                                                              VRF_DEFAULT));
+                                               ifindex2ifname(
+                                                       rinfo->ifindex,
+                                                       ripng->vrf->vrf_id));
                                } else if (rinfo->metric
                                           == RIPNG_METRIC_INFINITY) {
                                        len = vty_out(vty, "kill");
@@ -2068,17 +2165,32 @@ DEFUN (show_ipv6_ripng,
 
 DEFUN (show_ipv6_ripng_status,
        show_ipv6_ripng_status_cmd,
-       "show ipv6 ripng status",
+       "show ipv6 ripng [vrf NAME] status",
        SHOW_STR
        IPV6_STR
        "Show RIPng routes\n"
+       VRF_CMD_HELP_STR
        "IPv6 routing protocol process parameters and statistics\n")
 {
-       struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct ripng *ripng;
        struct interface *ifp;
+       const char *vrf_name;
+       int idx = 0;
 
-       if (!ripng)
+       if (argv_find(argv, argc, "vrf", &idx))
+               vrf_name = argv[idx + 1]->arg;
+       else
+               vrf_name = VRF_DEFAULT_NAME;
+
+       ripng = ripng_lookup_by_vrf_name(vrf_name);
+       if (!ripng) {
+               vty_out(vty, "%% RIPng instance not found\n");
+               return CMD_SUCCESS;
+       }
+       if (!ripng->enabled) {
+               vty_out(vty, "%% RIPng instance is disabled\n");
                return CMD_SUCCESS;
+       }
 
        vty_out(vty, "Routing Protocol is \"RIPng\"\n");
        vty_out(vty, "  Sending updates every %u seconds with +/-50%%,",
@@ -2098,7 +2210,7 @@ DEFUN (show_ipv6_ripng_status,
 
        /* Redistribute information. */
        vty_out(vty, "  Redistributing:");
-       ripng_redistribute_write(vty);
+       ripng_redistribute_write(vty, ripng);
        vty_out(vty, "\n");
 
        vty_out(vty, "  Default version control: send version %d,",
@@ -2107,7 +2219,7 @@ DEFUN (show_ipv6_ripng_status,
 
        vty_out(vty, "    Interface        Send  Recv\n");
 
-       FOR_ALL_INTERFACES (vrf, ifp) {
+       FOR_ALL_INTERFACES (ripng->vrf, ifp) {
                struct ripng_interface *ri;
 
                ri = ifp->info;
@@ -2120,12 +2232,12 @@ DEFUN (show_ipv6_ripng_status,
        }
 
        vty_out(vty, "  Routing for Networks:\n");
-       ripng_network_write(vty);
+       ripng_network_write(vty, ripng);
 
        vty_out(vty, "  Routing Information Sources:\n");
        vty_out(vty,
                "    Gateway          BadPackets BadRoutes  Distance Last Update\n");
-       ripng_peer_display(vty);
+       ripng_peer_display(vty, ripng);
 
        return CMD_SUCCESS;
 }
@@ -2261,7 +2373,7 @@ DEFUN (show_ipv6_protocols,
 #endif
 
 /* Update ECMP routes to zebra when ECMP is disabled. */
-void ripng_ecmp_disable(void)
+void ripng_ecmp_disable(struct ripng *ripng)
 {
        struct agg_node *rp;
        struct ripng_info *rinfo, *tmp_rinfo;
@@ -2288,30 +2400,36 @@ void ripng_ecmp_disable(void)
                                }
 
                        /* Update zebra. */
-                       ripng_zebra_ipv6_add(rp);
+                       ripng_zebra_ipv6_add(ripng, rp);
 
                        /* Set the route change flag. */
                        SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED);
 
                        /* Signal the output process to trigger an update. */
-                       ripng_event(RIPNG_TRIGGERED_UPDATE, 0);
+                       ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0);
                }
 }
 
 /* RIPng configuration write function. */
 static int ripng_config_write(struct vty *vty)
 {
-       struct lyd_node *dnode;
+       struct ripng *ripng;
        int write = 0;
 
-       dnode = yang_dnode_get(running_config->dnode,
-                              "/frr-ripngd:ripngd/instance");
-       if (dnode) {
-               nb_cli_show_dnode_cmds(vty, dnode, false);
+       RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) {
+               char xpath[XPATH_MAXLEN];
+               struct lyd_node *dnode;
 
-               config_write_distribute(vty,
-                                       ripng->distribute_ctx);
+               snprintf(xpath, sizeof(xpath),
+                        "/frr-ripngd:ripngd/instance[vrf='%s']",
+                        ripng->vrf_name);
 
+               dnode = yang_dnode_get(running_config->dnode, xpath);
+               assert(dnode);
+
+               nb_cli_show_dnode_cmds(vty, dnode, false);
+
+               config_write_distribute(vty, ripng->distribute_ctx);
                config_write_if_rmap(vty, ripng->if_rmap_ctx);
 
                write = 1;
@@ -2333,10 +2451,10 @@ static void ripng_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;
 
@@ -2385,6 +2503,8 @@ static void ripng_distribute_update(struct distribute_ctx *ctx,
 
 void ripng_distribute_update_interface(struct interface *ifp)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct distribute *dist;
 
        if (!ripng)
@@ -2410,80 +2530,34 @@ static void ripng_distribute_update_all_wrapper(struct access_list *notused)
 }
 
 /* delete all the added ripng routes. */
-void ripng_clean(void)
+void ripng_clean(struct ripng *ripng)
 {
-       int i;
-       struct agg_node *rp;
-       struct ripng_info *rinfo;
-       struct ripng_aggregate *aggregate;
-       struct list *list = NULL;
-       struct listnode *listnode = NULL;
-
-       if (ripng) {
-               /* Clear RIPng routes */
-               for (rp = agg_route_top(ripng->table); rp;
-                    rp = agg_route_next(rp)) {
-                       if ((list = rp->info) != NULL) {
-                               rinfo = listgetdata(listhead(list));
-                               if (ripng_route_rte(rinfo))
-                                       ripng_zebra_ipv6_delete(rp);
-
-                               for (ALL_LIST_ELEMENTS_RO(list, listnode,
-                                                         rinfo)) {
-                                       RIPNG_TIMER_OFF(rinfo->t_timeout);
-                                       RIPNG_TIMER_OFF(
-                                               rinfo->t_garbage_collect);
-                                       ripng_info_free(rinfo);
-                               }
-                               list_delete(&list);
-                               rp->info = NULL;
-                               agg_unlock_node(rp);
-                       }
-
-                       if ((aggregate = rp->aggregate) != NULL) {
-                               ripng_aggregate_free(aggregate);
-                               rp->aggregate = NULL;
-                               agg_unlock_node(rp);
-                       }
-               }
-
-               /* Cancel the RIPng timers */
-               RIPNG_TIMER_OFF(ripng->t_update);
-               RIPNG_TIMER_OFF(ripng->t_triggered_update);
-               RIPNG_TIMER_OFF(ripng->t_triggered_interval);
-
-               /* Cancel the read thread */
-               if (ripng->t_read) {
-                       thread_cancel(ripng->t_read);
-                       ripng->t_read = NULL;
-               }
-
-               /* Close the RIPng socket */
-               if (ripng->sock >= 0) {
-                       close(ripng->sock);
-                       ripng->sock = -1;
-               }
-
-               for (i = 0; i < ZEBRA_ROUTE_MAX; i++)
-                       if (ripng->route_map[i].name)
-                               free(ripng->route_map[i].name);
-
-               agg_table_finish(ripng->table);
-
-               stream_free(ripng->ibuf);
-               stream_free(ripng->obuf);
-
-               distribute_list_delete(&ripng->distribute_ctx);
-               XFREE(MTYPE_RIPNG, ripng);
-               ripng = NULL;
-       } /* if (ripng) */
-
-       ripng_clean_network();
-       ripng_passive_interface_clean();
-       ripng_offset_clean();
-       ripng_interface_clean();
-       ripng_redistribute_clean();
-       if_rmap_terminate();
+       if (ripng->enabled)
+               ripng_instance_disable(ripng);
+
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++)
+               if (ripng->redist[i].route_map.name)
+                       free(ripng->redist[i].route_map.name);
+
+       agg_table_finish(ripng->table);
+       list_delete(&ripng->peer_list);
+       distribute_list_delete(&ripng->distribute_ctx);
+       if_rmap_ctx_delete(ripng->if_rmap_ctx);
+
+       stream_free(ripng->ibuf);
+       stream_free(ripng->obuf);
+
+       ripng_clean_network(ripng);
+       ripng_passive_interface_clean(ripng);
+       vector_free(ripng->enable_if);
+       agg_table_finish(ripng->enable_network);
+       vector_free(ripng->passive_interface);
+       list_delete(&ripng->offset_list_master);
+       ripng_interface_clean(ripng);
+
+       RB_REMOVE(ripng_instance_head, &ripng_instances, ripng);
+       XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name);
+       XFREE(MTYPE_RIPNG, ripng);
 }
 
 static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
@@ -2524,11 +2598,11 @@ static void ripng_if_rmap_update(struct if_rmap_ctx *ctx,
 
 void ripng_if_rmap_update_interface(struct interface *ifp)
 {
+       struct ripng_interface *ri = ifp->info;
+       struct ripng *ripng = ri->ripng;
        struct if_rmap *if_rmap;
        struct if_rmap_ctx *ctx;
 
-       if (ifp->vrf_id != VRF_DEFAULT)
-               return;
        if (!ripng)
                return;
        ctx = ripng->if_rmap_ctx;
@@ -2539,19 +2613,15 @@ void ripng_if_rmap_update_interface(struct interface *ifp)
                ripng_if_rmap_update(ctx, if_rmap);
 }
 
-static void ripng_routemap_update_redistribute(void)
+static void ripng_routemap_update_redistribute(struct ripng *ripng)
 {
-       int i;
-
-       if (ripng) {
-               for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
-                       if (ripng->route_map[i].name) {
-                               ripng->route_map[i].map =
-                                       route_map_lookup_by_name(
-                                               ripng->route_map[i].name);
-                               route_map_counter_increment(
-                                       ripng->route_map[i].map);
-                       }
+       for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
+               if (ripng->redist[i].route_map.name) {
+                       ripng->redist[i].route_map.map =
+                               route_map_lookup_by_name(
+                                       ripng->redist[i].route_map.name);
+                       route_map_counter_increment(
+                               ripng->redist[i].route_map.map);
                }
        }
 }
@@ -2559,12 +2629,196 @@ static void ripng_routemap_update_redistribute(void)
 static void ripng_routemap_update(const char *unused)
 {
        struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT);
+       struct ripng *ripng;
        struct interface *ifp;
 
        FOR_ALL_INTERFACES (vrf, ifp)
                ripng_if_rmap_update_interface(ifp);
 
-       ripng_routemap_update_redistribute();
+       ripng = vrf->info;
+       if (ripng)
+               ripng_routemap_update_redistribute(ripng);
+}
+
+/* Link RIPng instance to VRF. */
+static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf)
+{
+       struct interface *ifp;
+
+       ripng->vrf = vrf;
+       ripng->distribute_ctx->vrf = vrf;
+       vrf->info = ripng;
+
+       FOR_ALL_INTERFACES (vrf, ifp)
+               ripng_interface_sync(ifp);
+}
+
+/* Unlink RIPng instance from VRF. */
+static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf)
+{
+       struct interface *ifp;
+
+       ripng->vrf = NULL;
+       ripng->distribute_ctx->vrf = NULL;
+       vrf->info = NULL;
+
+       FOR_ALL_INTERFACES (vrf, ifp)
+               ripng_interface_sync(ifp);
+}
+
+static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf,
+                                 int sock)
+{
+       ripng->sock = sock;
+
+       ripng_vrf_link(ripng, vrf);
+       ripng->enabled = true;
+
+       /* Resend all redistribute requests. */
+       ripng_redistribute_enable(ripng);
+
+       /* Create read and timer thread. */
+       ripng_event(ripng, RIPNG_READ, ripng->sock);
+       ripng_event(ripng, RIPNG_UPDATE_EVENT, 1);
+
+       ripng_zebra_vrf_register(vrf);
+}
+
+static void ripng_instance_disable(struct ripng *ripng)
+{
+       struct vrf *vrf = ripng->vrf;
+       struct agg_node *rp;
+
+       /* Clear RIPng routes */
+       for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) {
+               struct ripng_aggregate *aggregate;
+               struct list *list;
+
+               if ((list = rp->info) != NULL) {
+                       struct ripng_info *rinfo;
+                       struct listnode *listnode;
+
+                       rinfo = listgetdata(listhead(list));
+                       if (ripng_route_rte(rinfo))
+                               ripng_zebra_ipv6_delete(ripng, rp);
+
+                       for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) {
+                               RIPNG_TIMER_OFF(rinfo->t_timeout);
+                               RIPNG_TIMER_OFF(rinfo->t_garbage_collect);
+                               ripng_info_free(rinfo);
+                       }
+                       list_delete(&list);
+                       rp->info = NULL;
+                       agg_unlock_node(rp);
+               }
+
+               if ((aggregate = rp->aggregate) != NULL) {
+                       ripng_aggregate_free(aggregate);
+                       rp->aggregate = NULL;
+                       agg_unlock_node(rp);
+               }
+       }
+
+       /* Flush all redistribute requests. */
+       ripng_redistribute_disable(ripng);
+
+       /* Cancel the RIPng timers */
+       RIPNG_TIMER_OFF(ripng->t_update);
+       RIPNG_TIMER_OFF(ripng->t_triggered_update);
+       RIPNG_TIMER_OFF(ripng->t_triggered_interval);
+
+       /* Cancel the read thread */
+       if (ripng->t_read) {
+               thread_cancel(ripng->t_read);
+               ripng->t_read = NULL;
+       }
+
+       /* Close the RIPng socket */
+       if (ripng->sock >= 0) {
+               close(ripng->sock);
+               ripng->sock = -1;
+       }
+
+       /* Clear existing peers. */
+       list_delete_all_node(ripng->peer_list);
+
+       ripng_zebra_vrf_deregister(vrf);
+
+       ripng_vrf_unlink(ripng, vrf);
+       ripng->enabled = false;
+}
+
+static int ripng_vrf_new(struct vrf *vrf)
+{
+       if (IS_RIPNG_DEBUG_EVENT)
+               zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       return 0;
+}
+
+static int ripng_vrf_delete(struct vrf *vrf)
+{
+       if (IS_RIPNG_DEBUG_EVENT)
+               zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       return 0;
+}
+
+static int ripng_vrf_enable(struct vrf *vrf)
+{
+       struct ripng *ripng;
+       int socket;
+
+       ripng = ripng_lookup_by_vrf_name(vrf->name);
+       if (!ripng || ripng->enabled)
+               return 0;
+
+       if (IS_RIPNG_DEBUG_EVENT)
+               zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       /* Activate the VRF RIPng instance. */
+       if (!ripng->enabled) {
+               socket = ripng_make_socket(vrf);
+               if (socket < 0)
+                       return -1;
+
+               ripng_instance_enable(ripng, vrf, socket);
+       }
+
+       return 0;
+}
+
+static int ripng_vrf_disable(struct vrf *vrf)
+{
+       struct ripng *ripng;
+
+       ripng = ripng_lookup_by_vrf_name(vrf->name);
+       if (!ripng || !ripng->enabled)
+               return 0;
+
+       if (IS_RIPNG_DEBUG_EVENT)
+               zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name,
+                          vrf->vrf_id);
+
+       /* Deactivate the VRF RIPng instance. */
+       if (ripng->enabled)
+               ripng_instance_disable(ripng);
+
+       return 0;
+}
+
+void ripng_vrf_init(void)
+{
+       vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable,
+                ripng_vrf_delete, NULL);
+}
+
+void ripng_vrf_terminate(void)
+{
+       vrf_terminate();
 }
 
 /* Initialize ripng structure and set commands. */
@@ -2607,7 +2861,6 @@ void ripng_init(void)
 
        /* Route-map for interface. */
        ripng_route_map_init();
-       ripng_offset_init();
 
        route_map_add_hook(ripng_routemap_update);
        route_map_delete_hook(ripng_routemap_update);
index 3f0ef13a05b81cea53911422464d1e5298037c89..dcc61ae58a0e6249b2d98011179a962d6961c262 100644 (file)
@@ -25,6 +25,7 @@
 #include <zclient.h>
 #include <vty.h>
 #include <distribute.h>
+#include <vector.h>
 
 #include "ripng_memory.h"
 
 
 /* RIPng structure. */
 struct ripng {
+       RB_ENTRY(ripng) 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;
+
        /* RIPng socket. */
        int sock;
 
@@ -107,6 +119,21 @@ struct ripng {
        /* RIPng routing information base. */
        struct agg_table *table;
 
+       /* Linked list of RIPng peers. */
+       struct list *peer_list;
+
+       /* RIPng enabled interfaces. */
+       vector enable_if;
+
+       /* RIPng enabled networks. */
+       struct agg_table *enable_network;
+
+       /* Vector to store passive-interface name. */
+       vector passive_interface;
+
+       /* RIPng offset-lists. */
+       struct list *offset_list_master;
+
        /* RIPng threads. */
        struct thread *t_read;
        struct thread *t_write;
@@ -122,13 +149,16 @@ struct ripng {
        /* RIPng ECMP flag */
        bool ecmp;
 
-       /* For redistribute route map. */
+       /* RIPng redistribute configuration. */
        struct {
-               char *name;
-               struct route_map *map;
+               bool enabled;
+               struct {
+                       char *name;
+                       struct route_map *map;
+               } route_map;
                bool metric_config;
                uint8_t metric;
-       } route_map[ZEBRA_ROUTE_MAX];
+       } redist[ZEBRA_ROUTE_MAX];
 
        /* For distribute-list container */
        struct distribute_ctx *distribute_ctx;
@@ -136,6 +166,8 @@ struct ripng {
        /* For if_rmap container */
        struct if_rmap_ctx *if_rmap_ctx;
 };
+RB_HEAD(ripng_instance_head, ripng);
+RB_PROTOTYPE(ripng_instance_head, ripng, entry, ripng_instance_compare)
 
 /* Routing table entry. */
 struct rte {
@@ -234,6 +266,9 @@ typedef enum {
 
 /* RIPng specific interface configuration. */
 struct ripng_interface {
+       /* Parent routing instance. */
+       struct ripng *ripng;
+
        /* RIPng is enabled on this interface. */
        int enable_network;
        int enable_interface;
@@ -280,6 +315,9 @@ struct ripng_interface {
 
 /* RIPng peer information. */
 struct ripng_peer {
+       /* Parent routing instance. */
+       struct ripng *ripng;
+
        /* Peer address. */
        struct in6_addr addr;
 
@@ -325,6 +363,9 @@ enum ripng_event {
 #define RIPNG_OFFSET_LIST_MAX 2
 
 struct ripng_offset_list {
+       /* Parent routing instance. */
+       struct ripng *ripng;
+
        char *ifname;
 
        struct {
@@ -335,72 +376,87 @@ struct ripng_offset_list {
 };
 
 /* Extern variables. */
-extern struct ripng *ripng;
-extern struct list *peer_list;
 extern struct zebra_privs_t ripngd_privs;
 extern struct thread_master *master;
+extern struct ripng_instance_head ripng_instances;
 
 /* Prototypes. */
 extern void ripng_init(void);
-extern void ripng_clean(void);
-extern void ripng_clean_network(void);
-extern void ripng_interface_clean(void);
-extern int ripng_enable_network_add(struct prefix *p);
-extern int ripng_enable_network_delete(struct prefix *p);
-extern int ripng_enable_if_add(const char *ifname);
-extern int ripng_enable_if_delete(const char *ifname);
-extern int ripng_passive_interface_set(const char *ifname);
-extern int ripng_passive_interface_unset(const char *ifname);
-extern void ripng_passive_interface_clean(void);
+extern void ripng_clean(struct ripng *ripng);
+extern void ripng_clean_network(struct ripng *ripng);
+extern void ripng_interface_clean(struct ripng *ripng);
+extern int ripng_enable_network_add(struct ripng *ripng, struct prefix *p);
+extern int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p);
+extern int ripng_enable_if_add(struct ripng *ripng, const char *ifname);
+extern int ripng_enable_if_delete(struct ripng *ripng, const char *ifname);
+extern int ripng_passive_interface_set(struct ripng *ripng, const char *ifname);
+extern int ripng_passive_interface_unset(struct ripng *ripng,
+                                        const char *ifname);
+extern void ripng_passive_interface_clean(struct ripng *ripng);
 extern void ripng_if_init(void);
 extern void ripng_route_map_init(void);
+extern void ripng_zebra_vrf_register(struct vrf *vrf);
+extern void ripng_zebra_vrf_deregister(struct vrf *vrf);
 extern void ripng_terminate(void);
 /* zclient_init() is done by ripng_zebra.c:zebra_init() */
 extern void zebra_init(struct thread_master *);
 extern void ripng_zebra_stop(void);
-extern void ripng_redistribute_conf_update(int type);
-extern void ripng_redistribute_conf_delete(int type);
-
-extern void ripng_peer_init(void);
-extern void ripng_peer_update(struct sockaddr_in6 *, uint8_t);
-extern void ripng_peer_bad_route(struct sockaddr_in6 *);
-extern void ripng_peer_bad_packet(struct sockaddr_in6 *);
-extern void ripng_peer_display(struct vty *);
-extern struct ripng_peer *ripng_peer_lookup(struct in6_addr *);
-extern struct ripng_peer *ripng_peer_lookup_next(struct in6_addr *);
-
-extern struct ripng_offset_list *ripng_offset_list_new(const char *ifname);
+extern void ripng_redistribute_conf_update(struct ripng *ripng, int type);
+extern void ripng_redistribute_conf_delete(struct ripng *ripng, int type);
+
+extern void ripng_peer_update(struct ripng *ripng, struct sockaddr_in6 *from,
+                             uint8_t version);
+extern void ripng_peer_bad_route(struct ripng *ripng,
+                                struct sockaddr_in6 *from);
+extern void ripng_peer_bad_packet(struct ripng *ripng,
+                                 struct sockaddr_in6 *from);
+extern void ripng_peer_display(struct vty *vty, struct ripng *ripng);
+extern struct ripng_peer *ripng_peer_lookup(struct ripng *ripng,
+                                           struct in6_addr *addr);
+extern struct ripng_peer *ripng_peer_lookup_next(struct ripng *ripng,
+                                                struct in6_addr *addr);
+extern int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2);
+extern void ripng_peer_list_del(void *arg);
+
+extern struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng,
+                                                      const char *ifname);
 extern void ripng_offset_list_del(struct ripng_offset_list *offset);
-extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname);
-extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname);
-extern int ripng_offset_list_apply_in(struct prefix_ipv6 *, struct interface *,
-                                     uint8_t *);
-extern int ripng_offset_list_apply_out(struct prefix_ipv6 *, struct interface *,
-                                      uint8_t *);
-extern void ripng_offset_init(void);
-extern void ripng_offset_clean(void);
+extern struct ripng_offset_list *ripng_offset_list_lookup(struct ripng *ripng,
+                                                         const char *ifname);
+extern int ripng_offset_list_apply_in(struct ripng *ripng,
+                                     struct prefix_ipv6 *p,
+                                     struct interface *ifp, uint8_t *metric);
+extern int ripng_offset_list_apply_out(struct ripng *ripng,
+                                      struct prefix_ipv6 *p,
+                                      struct interface *ifp, uint8_t *metric);
+extern int offset_list_cmp(struct ripng_offset_list *o1,
+                          struct ripng_offset_list *o2);
 
 extern int ripng_route_rte(struct ripng_info *rinfo);
 extern struct ripng_info *ripng_info_new(void);
 extern void ripng_info_free(struct ripng_info *rinfo);
-extern void ripng_event(enum ripng_event, int);
+extern struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo);
+extern void ripng_event(struct ripng *ripng, enum ripng_event event, int sock);
 extern int ripng_request(struct interface *ifp);
-extern void ripng_redistribute_add(int, int, struct prefix_ipv6 *, ifindex_t,
-                                  struct in6_addr *, route_tag_t);
-extern void ripng_redistribute_delete(int, int, struct prefix_ipv6 *,
-                                     ifindex_t);
-extern void ripng_redistribute_withdraw(int type);
-
-extern void ripng_ecmp_disable(void);
+extern void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type,
+                                  struct prefix_ipv6 *p, ifindex_t ifindex,
+                                  struct in6_addr *nexthop, route_tag_t tag);
+extern void ripng_redistribute_delete(struct ripng *ripng, int type,
+                                     int sub_type, struct prefix_ipv6 *p,
+                                     ifindex_t ifindex);
+extern void ripng_redistribute_withdraw(struct ripng *ripng, int type);
+
+extern void ripng_ecmp_disable(struct ripng *ripng);
 extern void ripng_distribute_update_interface(struct interface *);
 extern void ripng_if_rmap_update_interface(struct interface *);
 
-extern void ripng_zebra_ipv6_add(struct agg_node *node);
-extern void ripng_zebra_ipv6_delete(struct agg_node *node);
+extern void ripng_zebra_ipv6_add(struct ripng *ripng, struct agg_node *node);
+extern void ripng_zebra_ipv6_delete(struct ripng *ripng, struct agg_node *node);
 
-extern void ripng_redistribute_clean(void);
-extern int ripng_redistribute_check(int);
-extern void ripng_redistribute_write(struct vty *);
+extern void ripng_redistribute_enable(struct ripng *ripng);
+extern void ripng_redistribute_disable(struct ripng *ripng);
+extern int ripng_redistribute_check(struct ripng *ripng, int type);
+extern void ripng_redistribute_write(struct vty *vty, struct ripng *ripng);
 
 extern int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p,
                           struct in6_addr *nexthop, uint16_t tag,
@@ -423,14 +479,26 @@ extern int ripng_interface_address_add(int command, struct zclient *,
                                       zebra_size_t, vrf_id_t);
 extern int ripng_interface_address_delete(int command, struct zclient *,
                                          zebra_size_t, vrf_id_t);
-
-extern int ripng_create(int socket);
-extern int ripng_make_socket(void);
-extern int ripng_network_write(struct vty *);
-
-extern struct ripng_info *ripng_ecmp_add(struct ripng_info *);
-extern struct ripng_info *ripng_ecmp_replace(struct ripng_info *);
-extern struct ripng_info *ripng_ecmp_delete(struct ripng_info *);
+extern int ripng_interface_vrf_update(int command, struct zclient *zclient,
+                                     zebra_size_t length, vrf_id_t vrf_id);
+extern void ripng_interface_sync(struct interface *ifp);
+
+extern struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id);
+extern struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name);
+extern struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf,
+                                 int socket);
+extern int ripng_make_socket(struct vrf *vrf);
+extern int ripng_network_write(struct vty *vty, struct ripng *ripng);
+
+extern struct ripng_info *ripng_ecmp_add(struct ripng *ripng,
+                                        struct ripng_info *rinfo);
+extern struct ripng_info *ripng_ecmp_replace(struct ripng *ripng,
+                                            struct ripng_info *rinfo);
+extern struct ripng_info *ripng_ecmp_delete(struct ripng *ripng,
+                                           struct ripng_info *rinfo);
+
+extern void ripng_vrf_init(void);
+extern void ripng_vrf_terminate(void);
 
 /* Northbound. */
 extern void ripng_cli_init(void);
index 1f1152d364a3eda07b4df1c8e6c39cbfbd8cf87b..b8da90ca8e8ad63dd3af4c2506da84e59b00e06a 100644 (file)
@@ -1521,15 +1521,15 @@ 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;
 }
 
-DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng",
-       ROUTER_STR "RIPng\n")
+DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]",
+       ROUTER_STR "RIPng\n" VRF_CMD_HELP_STR)
 {
        vty->node = RIPNG_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..07690793f0343c22d20bba79777f47fc8aeba332 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";
@@ -293,83 +298,83 @@ module frr-ripd {
           '(./receive = "2" and ./send = "2") or ' +
           '(./receive = "1-2" and ./send = "2")';
       }
-    }
-
-    /*
-     * Operational data.
-     */
-    container state {
-      config false;
-      description
-        "Operational data.";
 
-      container neighbors {
+      /*
+       * Operational data.
+       */
+      container state {
+        config false;
         description
-          "Neighbor information.";
-        list neighbor {
-          key "address";
+          "Operational data.";
+
+        container neighbors {
           description
-            "A RIP neighbor.";
-          leaf address {
-            type inet:ipv4-address;
-            description
-              "IP address that a RIP neighbor is using as its
-               source address.";
-          }
-          leaf last-update {
-            type yang:date-and-time;
-            description
-              "The time when the most recent RIP update was
-               received from this neighbor.";
-          }
-          leaf bad-packets-rcvd {
-            type yang:counter32;
+            "Neighbor information.";
+          list neighbor {
+            key "address";
             description
-              "The number of RIP invalid packets received from
-               this neighbor which were subsequently discarded
-               for any reason (e.g. a version 0 packet, or an
-               unknown command type).";
-          }
-          leaf bad-routes-rcvd {
-            type yang:counter32;
-            description
-              "The number of routes received from this neighbor,
-               in valid RIP packets, which were ignored for any
-               reason (e.g. unknown address family, or invalid
-               metric).";
+              "A RIP neighbor.";
+            leaf address {
+              type inet:ipv4-address;
+              description
+                "IP address that a RIP neighbor is using as its
+                 source address.";
+            }
+            leaf last-update {
+              type yang:date-and-time;
+              description
+                "The time when the most recent RIP update was
+                 received from this neighbor.";
+            }
+            leaf bad-packets-rcvd {
+              type yang:counter32;
+              description
+                "The number of RIP invalid packets received from
+                 this neighbor which were subsequently discarded
+                 for any reason (e.g. a version 0 packet, or an
+                 unknown command type).";
+            }
+            leaf bad-routes-rcvd {
+              type yang:counter32;
+              description
+                "The number of routes received from this neighbor,
+                 in valid RIP packets, which were ignored for any
+                 reason (e.g. unknown address family, or invalid
+                 metric).";
+            }
           }
         }
-      }
-      container routes {
-        description
-          "Route information.";
-        list route {
-          key "prefix";
+        container routes {
           description
-            "A RIP IPv4 route.";
-          leaf prefix {
-            type inet:ipv4-prefix;
-            description
-              "IP address (in the form A.B.C.D) and prefix length,
-               separated by the slash (/) character. The range of
-               values for the prefix-length is 0 to 32.";
-          }
-          leaf next-hop {
-            type inet:ipv4-address;
+            "Route information.";
+          list route {
+            key "prefix";
             description
-              "Next hop IPv4 address.";
-          }
-          leaf interface {
-            type string;
-            description
-              "The interface that the route uses.";
-          }
-          leaf metric {
-            type uint8 {
-              range "0..16";
+              "A RIP IPv4 route.";
+            leaf prefix {
+              type inet:ipv4-prefix;
+              description
+                "IP address (in the form A.B.C.D) and prefix length,
+                 separated by the slash (/) character. The range of
+                 values for the prefix-length is 0 to 32.";
+            }
+            leaf next-hop {
+              type inet:ipv4-address;
+              description
+                "Next hop IPv4 address.";
+            }
+            leaf interface {
+              type string;
+              description
+                "The interface that the route uses.";
+            }
+            leaf metric {
+              type uint8 {
+                range "0..16";
+              }
+              description
+                "Route metric.";
             }
-            description
-              "Route metric.";
           }
         }
       }
@@ -547,6 +552,19 @@ module frr-ripd {
     description
       "Clears RIP routes from the IP routing table and routes
        redistributed into the RIP protocol.";
+
+    input {
+      leaf vrf {
+        type string;
+        description
+          "VRF name identifying a specific RIP instance.
+           This leaf is optional for the rpc.
+           If it is specified, the rpc will clear all routes in the
+           specified RIP instance;
+           if it is not specified, the rpc will clear all routes in
+           all RIP instances.";
+      }
+    }
   }
 
   /*
index 0cc5f18a5f6d3535cd30945557d3d1cbbfc4ca50..b341b438a4d5a95cbb278cfb1ce04f4e81377bb4 100644 (file)
@@ -33,13 +33,18 @@ module frr-ripngd {
 
   container ripngd {
     /*
-     * Global configuration data
+     * Routing instance configuration.
      */
-    container instance {
-      presence "Present if the RIPng protocol is enabled.";
+    list instance {
+      key "vrf";
       description
         "RIPng routing instance.";
 
+      leaf vrf {
+        type string;
+        description
+          "VRF name.";
+      }
       leaf allow-ecmp {
         type boolean;
         default "false";
@@ -194,82 +199,82 @@ module frr-ripngd {
             "Interval at which RIPng updates are sent.";
         }
       }
-    }
 
-    /*
-     * Operational data.
-     */
-    container state {
-      config false;
-      description
-        "Operational data.";
-
-      container neighbors {
+      /*
+       * Operational data.
+       */
+      container state {
+        config false;
         description
-          "Neighbor information.";
-        list neighbor {
-          key "address";
+          "Operational data.";
+
+        container neighbors {
           description
-            "A RIPng neighbor.";
-          leaf address {
-            type inet:ipv6-address;
+            "Neighbor information.";
+          list neighbor {
+            key "address";
             description
-              "IPv6 address that a RIPng neighbor is using as its
-               source address.";
-          }
-          leaf last-update {
-            type yang:date-and-time;
-            description
-              "The time when the most recent RIPng update was
-               received from this neighbor.";
-          }
-          leaf bad-packets-rcvd {
-            type yang:counter32;
-            description
-              "The number of RIPng invalid packets received from
-               this neighbor which were subsequently discarded
-               for any reason (e.g. a version 0 packet, or an
-               unknown command type).";
-          }
-          leaf bad-routes-rcvd {
-            type yang:counter32;
-            description
-              "The number of routes received from this neighbor,
-               in valid RIPng packets, which were ignored for any
-               reason (e.g. unknown address family, or invalid
-               metric).";
+              "A RIPng neighbor.";
+            leaf address {
+              type inet:ipv6-address;
+              description
+                "IPv6 address that a RIPng neighbor is using as its
+                 source address.";
+            }
+            leaf last-update {
+              type yang:date-and-time;
+              description
+                "The time when the most recent RIPng update was
+                 received from this neighbor.";
+            }
+            leaf bad-packets-rcvd {
+              type yang:counter32;
+              description
+                "The number of RIPng invalid packets received from
+                 this neighbor which were subsequently discarded
+                 for any reason (e.g. a version 0 packet, or an
+                 unknown command type).";
+            }
+            leaf bad-routes-rcvd {
+              type yang:counter32;
+              description
+                "The number of routes received from this neighbor,
+                 in valid RIPng packets, which were ignored for any
+                 reason (e.g. unknown address family, or invalid
+                 metric).";
+            }
           }
         }
-      }
-      container routes {
-        description
-          "Route information.";
-        list route {
-          key "prefix";
+        container routes {
           description
-            "A RIPng IPv6 route.";
-          leaf prefix {
-            type inet:ipv6-prefix;
-            description
-              "IPv6 address and prefix length, in the format
-               specified in RFC6991.";
-          }
-          leaf next-hop {
-            type inet:ipv6-address;
+            "Route information.";
+          list route {
+            key "prefix";
             description
-              "Next hop IPv6 address.";
-          }
-          leaf interface {
-            type string;
-            description
-              "The interface that the route uses.";
-          }
-          leaf metric {
-            type uint8 {
-              range "0..16";
+              "A RIPng IPv6 route.";
+            leaf prefix {
+              type inet:ipv6-prefix;
+              description
+                "IPv6 address and prefix length, in the format
+                 specified in RFC6991.";
+            }
+            leaf next-hop {
+              type inet:ipv6-address;
+              description
+                "Next hop IPv6 address.";
+            }
+            leaf interface {
+              type string;
+              description
+                "The interface that the route uses.";
+            }
+            leaf metric {
+              type uint8 {
+                range "0..16";
+              }
+              description
+                "Route metric.";
             }
-            description
-              "Route metric.";
           }
         }
       }
@@ -317,5 +322,18 @@ module frr-ripngd {
     description
       "Clears RIPng routes from the IPv6 routing table and routes
        redistributed into the RIPng protocol.";
+
+    input {
+      leaf vrf {
+        type string;
+        description
+          "VRF name identifying a specific RIPng instance.
+           This leaf is optional for the rpc.
+           If it is specified, the rpc will clear all routes in the
+           specified RIPng instance;
+           if it is not specified, the rpc will clear all routes in
+           all RIPng instances.";
+      }
+    }
   }
 }
index 9855480b45e14b0d8317e03f988bc358bb290303..38a609982fa9afba3dbf6e38f2b826c5664df7ab 100644 (file)
@@ -22,7 +22,7 @@
         "mappings": [
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']",
-            "native": "/frr-ripd:ripd/instance"
+            "native": "/frr-ripd:ripd/instance[vrf='default']"
           }
         ]
       },
         "mappings": [
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/default-metric",
-            "native": "/frr-ripd:ripd/instance/default-metric"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/default-metric"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/distance",
-            "native": "/frr-ripd:ripd/instance/distance/default"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/distance/default"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/originate-default-route/enabled",
-            "native": "/frr-ripd:ripd/instance/default-information-originate"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/default-information-originate"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/update-interval",
-            "native": "/frr-ripd:ripd/instance/timers/update-interval"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/timers/update-interval"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/holddown-interval",
-            "native": "/frr-ripd:ripd/instance/timers/holddown-interval"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/timers/holddown-interval"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/flush-interval",
-            "native": "/frr-ripd:ripd/instance/timers/flush-interval"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/timers/flush-interval"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']",
-            "native": "/frr-ripd:ripd/instance/interface[.='KEY1']"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/interface[.='KEY1']"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']/split-horizon",
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']",
-            "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/ipv4-address",
-            "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/address"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/address"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/last-update",
-            "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/last-update"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/last-update"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-packets-rcvd",
-            "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-routes-rcvd",
-            "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']",
-            "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/ipv4-prefix",
-            "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/prefix"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/prefix"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/next-hop",
-            "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/next-hop"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/next-hop"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/interface",
-            "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/interface"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/interface"
           },
           {
             "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/metric",
-            "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/metric"
+            "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/metric"
           },
           {
             "custom": "/ietf-rip:clear-rip-route",