diff options
author | Donald Sharp <sharpd@cumulusnetworks.com> | 2019-04-05 01:24:14 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-04-05 01:24:14 +0200 |
commit | f61f266a0e484d3ba78a644f36a3a4f7113cfc74 (patch) | |
tree | 728ed9d219c276bbe6e01200c58594b392555c13 /ripd | |
parent | Merge pull request #3899 from ton31337/fix/remove_private_as_with_local_as (diff) | |
parent | lib, ripd, ripngd: rename remaining delete northbound callbacks (diff) | |
download | frr-f61f266a0e484d3ba78a644f36a3a4f7113cfc74.tar.xz frr-f61f266a0e484d3ba78a644f36a3a4f7113cfc74.zip |
Merge pull request #3548 from opensourcerouting/rip-vrf
rip(ng)d: add VRF support
Diffstat (limited to 'ripd')
-rw-r--r-- | ripd/rip_cli.c | 62 | ||||
-rw-r--r-- | ripd/rip_interface.c | 310 | ||||
-rw-r--r-- | ripd/rip_interface.h | 5 | ||||
-rw-r--r-- | ripd/rip_main.c | 12 | ||||
-rw-r--r-- | ripd/rip_memory.c | 1 | ||||
-rw-r--r-- | ripd/rip_memory.h | 1 | ||||
-rw-r--r-- | ripd/rip_northbound.c | 512 | ||||
-rw-r--r-- | ripd/rip_offset.c | 43 | ||||
-rw-r--r-- | ripd/rip_peer.c | 44 | ||||
-rw-r--r-- | ripd/rip_snmp.c | 29 | ||||
-rw-r--r-- | ripd/rip_zebra.c | 89 | ||||
-rw-r--r-- | ripd/ripd.c | 894 | ||||
-rw-r--r-- | ripd/ripd.h | 200 |
13 files changed, 1356 insertions, 846 deletions
diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 62aaad5d9..346e93b8e 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -39,31 +39,46 @@ */ 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"); } /* @@ -902,7 +924,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"); @@ -970,12 +992,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) diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 8bad6b8b1..b909cbcb2 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -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); } @@ -531,20 +548,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) @@ -560,18 +579,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; @@ -597,10 +608,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, @@ -634,6 +646,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; @@ -651,7 +665,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); } @@ -689,10 +703,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; @@ -704,7 +723,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); @@ -716,8 +735,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; @@ -731,8 +752,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) { @@ -744,11 +765,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); @@ -757,17 +778,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; @@ -778,7 +799,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; } @@ -787,50 +808,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; } @@ -848,7 +872,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); @@ -866,6 +890,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; @@ -890,17 +916,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); } @@ -929,7 +956,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 @@ -962,17 +989,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; @@ -991,7 +1017,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; @@ -1006,7 +1032,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; @@ -1027,50 +1053,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); @@ -1079,39 +1106,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 @@ -1119,61 +1145,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", @@ -1181,8 +1210,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. */ @@ -1197,10 +1226,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; } @@ -1220,13 +1265,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(); diff --git a/ripd/rip_interface.h b/ripd/rip_interface.h index 8723388e7..303be0315 100644 --- a/ripd/rip_interface.h +++ b/ripd/rip_interface.h @@ -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 */ diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 5db9c4b7e..65da51f83 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -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); diff --git a/ripd/rip_memory.c b/ripd/rip_memory.c index 185241074..7d703a86d 100644 --- a/ripd/rip_memory.c +++ b/ripd/rip_memory.c @@ -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") diff --git a/ripd/rip_memory.h b/ripd/rip_memory.h index 29013ecec..1f9d8f500 100644 --- a/ripd/rip_memory.h +++ b/ripd/rip_memory.h @@ -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) diff --git a/ripd/rip_northbound.c b/ripd/rip_northbound.c index f3b5dc2dc..c1ff678f2 100644 --- a/ripd/rip_northbound.c +++ b/ripd/rip_northbound.c @@ -31,6 +31,7 @@ #include "libfrr.h" #include "ripd/ripd.h" +#include "ripd/rip_debug.h" #include "ripd/rip_cli.h" /* @@ -40,41 +41,97 @@ 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; } return NB_OK; } -static int ripd_instance_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripd_instance_destroy(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,15 +242,16 @@ 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); return NB_OK; } -static int ripd_instance_distance_source_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripd_instance_distance_source_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct route_node *rn; struct rip_distance *rdistance; @@ -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); @@ -253,8 +320,8 @@ ripd_instance_distance_source_access_list_modify(enum nb_event event, } static int -ripd_instance_distance_source_access_list_delete(enum nb_event event, - const struct lyd_node *dnode) +ripd_instance_distance_source_access_list_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct route_node *rn; struct rip_distance *rdistance; @@ -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) +static int ripd_instance_explicit_neighbor_destroy(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) +static int ripd_instance_network_destroy(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) +static int ripd_instance_interface_destroy(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,22 +453,24 @@ 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; } -static int ripd_instance_offset_list_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripd_instance_offset_list_destroy(enum nb_event event, + const struct lyd_node *dnode) { int direct; struct rip_offset_list *offset; @@ -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) +static int ripd_instance_passive_interface_destroy(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) +ripd_instance_non_passive_interface_destroy(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) +static int ripd_instance_redistribute_destroy(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,37 +699,41 @@ 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; } static int -ripd_instance_redistribute_route_map_delete(enum nb_event event, - const struct lyd_node *dnode) +ripd_instance_redistribute_route_map_destroy(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,34 +746,38 @@ 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; } static int -ripd_instance_redistribute_metric_delete(enum nb_event event, - const struct lyd_node *dnode) +ripd_instance_redistribute_metric_destroy(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,35 +789,39 @@ 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; } -static int ripd_instance_static_route_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripd_instance_static_route_destroy(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; @@ -904,7 +1054,7 @@ static int lib_interface_rip_authentication_scheme_md5_auth_length_modify( return NB_OK; } -static int lib_interface_rip_authentication_scheme_md5_auth_length_delete( +static int lib_interface_rip_authentication_scheme_md5_auth_length_destroy( enum nb_event event, const struct lyd_node *dnode) { struct interface *ifp; @@ -945,8 +1095,8 @@ lib_interface_rip_authentication_password_modify(enum nb_event event, } static int -lib_interface_rip_authentication_password_delete(enum nb_event event, - const struct lyd_node *dnode) +lib_interface_rip_authentication_password_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct interface *ifp; struct rip_interface *ri; @@ -985,8 +1135,8 @@ lib_interface_rip_authentication_key_chain_modify(enum nb_event event, } static int -lib_interface_rip_authentication_key_chain_delete(enum nb_event event, - const struct lyd_node *dnode) +lib_interface_rip_authentication_key_chain_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct interface *ifp; struct rip_interface *ri; @@ -1002,24 +1152,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); @@ -1031,17 +1183,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; } @@ -1050,11 +1202,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); @@ -1063,22 +1215,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); @@ -1087,11 +1239,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); @@ -1100,17 +1252,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 @@ -1121,8 +1271,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; @@ -1133,9 +1284,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; @@ -1151,11 +1303,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); @@ -1164,11 +1316,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); @@ -1183,31 +1335,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); @@ -1218,16 +1372,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; @@ -1237,7 +1394,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; } @@ -1254,6 +1411,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; } @@ -1303,7 +1484,10 @@ 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.destroy = ripd_instance_destroy, + .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, }, { @@ -1329,7 +1513,7 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source", .cbs.create = ripd_instance_distance_source_create, - .cbs.destroy = ripd_instance_distance_source_delete, + .cbs.destroy = ripd_instance_distance_source_destroy, .cbs.cli_show = cli_show_rip_distance_source, }, { @@ -1339,30 +1523,30 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/distance/source/access-list", .cbs.modify = ripd_instance_distance_source_access_list_modify, - .cbs.destroy = ripd_instance_distance_source_access_list_delete, + .cbs.destroy = ripd_instance_distance_source_access_list_destroy, }, { .xpath = "/frr-ripd:ripd/instance/explicit-neighbor", .cbs.create = ripd_instance_explicit_neighbor_create, - .cbs.destroy = ripd_instance_explicit_neighbor_delete, + .cbs.destroy = ripd_instance_explicit_neighbor_destroy, .cbs.cli_show = cli_show_rip_neighbor, }, { .xpath = "/frr-ripd:ripd/instance/network", .cbs.create = ripd_instance_network_create, - .cbs.destroy = ripd_instance_network_delete, + .cbs.destroy = ripd_instance_network_destroy, .cbs.cli_show = cli_show_rip_network_prefix, }, { .xpath = "/frr-ripd:ripd/instance/interface", .cbs.create = ripd_instance_interface_create, - .cbs.destroy = ripd_instance_interface_delete, + .cbs.destroy = ripd_instance_interface_destroy, .cbs.cli_show = cli_show_rip_network_interface, }, { .xpath = "/frr-ripd:ripd/instance/offset-list", .cbs.create = ripd_instance_offset_list_create, - .cbs.destroy = ripd_instance_offset_list_delete, + .cbs.destroy = ripd_instance_offset_list_destroy, .cbs.cli_show = cli_show_rip_offset_list, }, { @@ -1381,36 +1565,36 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-ripd:ripd/instance/passive-interface", .cbs.create = ripd_instance_passive_interface_create, - .cbs.destroy = ripd_instance_passive_interface_delete, + .cbs.destroy = ripd_instance_passive_interface_destroy, .cbs.cli_show = cli_show_rip_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/non-passive-interface", .cbs.create = ripd_instance_non_passive_interface_create, - .cbs.destroy = ripd_instance_non_passive_interface_delete, + .cbs.destroy = ripd_instance_non_passive_interface_destroy, .cbs.cli_show = cli_show_rip_non_passive_interface, }, { .xpath = "/frr-ripd:ripd/instance/redistribute", .cbs.create = ripd_instance_redistribute_create, - .cbs.destroy = ripd_instance_redistribute_delete, + .cbs.destroy = ripd_instance_redistribute_destroy, .cbs.apply_finish = ripd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_rip_redistribute, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/route-map", .cbs.modify = ripd_instance_redistribute_route_map_modify, - .cbs.destroy = ripd_instance_redistribute_route_map_delete, + .cbs.destroy = ripd_instance_redistribute_route_map_destroy, }, { .xpath = "/frr-ripd:ripd/instance/redistribute/metric", .cbs.modify = ripd_instance_redistribute_metric_modify, - .cbs.destroy = ripd_instance_redistribute_metric_delete, + .cbs.destroy = ripd_instance_redistribute_metric_destroy, }, { .xpath = "/frr-ripd:ripd/instance/static-route", .cbs.create = ripd_instance_static_route_create, - .cbs.destroy = ripd_instance_static_route_delete, + .cbs.destroy = ripd_instance_static_route_destroy, .cbs.cli_show = cli_show_rip_route, }, { @@ -1473,63 +1657,63 @@ const struct frr_yang_module_info frr_ripd_info = { { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-scheme/md5-auth-length", .cbs.modify = lib_interface_rip_authentication_scheme_md5_auth_length_modify, - .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_delete, + .cbs.destroy = lib_interface_rip_authentication_scheme_md5_auth_length_destroy, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-password", .cbs.modify = lib_interface_rip_authentication_password_modify, - .cbs.destroy = lib_interface_rip_authentication_password_delete, + .cbs.destroy = lib_interface_rip_authentication_password_destroy, .cbs.cli_show = cli_show_ip_rip_authentication_string, }, { .xpath = "/frr-interface:lib/interface/frr-ripd:rip/authentication-key-chain", .cbs.modify = lib_interface_rip_authentication_key_chain_modify, - .cbs.destroy = lib_interface_rip_authentication_key_chain_delete, + .cbs.destroy = lib_interface_rip_authentication_key_chain_destroy, .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", diff --git a/ripd/rip_offset.c b/ripd/rip_offset.c index ca273c53b..b3f84fe50 100644 --- a/ripd/rip_offset.c +++ b/ripd/rip_offset.c @@ -29,28 +29,27 @@ #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; -} diff --git a/ripd/rip_peer.c b/ripd/rip_peer.c index 21317915d..08aa61257 100644 --- a/ripd/rip_peer.c +++ b/ripd/rip_peer.c @@ -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); } diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 19367638c..5a6b71fba 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -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; diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index fff868177..4f0df1223 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -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; } diff --git a/ripd/ripd.c b/ripd/ripd.c index d2fc9eb30..9683e26b5 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -46,27 +46,20 @@ #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(); } diff --git a/ripd/ripd.h b/ripd/ripd.h index 383df3707..7b196a16b 100644 --- a/ripd/ripd.h +++ b/ripd/ripd.h @@ -99,6 +99,17 @@ /* 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; |