]> git.proxmox.com Git - mirror_frr.git/blobdiff - ripd/ripd.c
Merge pull request #4341 from donaldsharp/bgp_attr_should_actually_compile
[mirror_frr.git] / ripd / ripd.c
index d2fc9eb303271aede6cd3d9d236f6fc2b176c51c..3a1ffd17a6f47561d7b54a1e40f4c71e77509602 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,26 +1357,29 @@ 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
+       setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
 
        frr_elevate_privs(&ripd_privs) {
-               setsockopt_so_recvbuf(sock, RIP_UDP_RCV_BUF);
                if ((ret = bind(sock, (struct sockaddr *)&addr, sizeof(addr)))
                    < 0) {
                        zlog_err("%s: Can't bind socket %d to %s port %d: %s",
@@ -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_free;
 
-       /* 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();
 }