diff options
39 files changed, 2901 insertions, 1715 deletions
@@ -1310,8 +1310,8 @@ static int lib_interface_create(enum nb_event event, return NB_OK; } -static int lib_interface_delete(enum nb_event event, - const struct lyd_node *dnode) +static int lib_interface_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct interface *ifp; @@ -1357,8 +1357,8 @@ static int lib_interface_description_modify(enum nb_event event, return NB_OK; } -static int lib_interface_description_delete(enum nb_event event, - const struct lyd_node *dnode) +static int lib_interface_description_destroy(enum nb_event event, + const struct lyd_node *dnode) { struct interface *ifp; @@ -1378,13 +1378,13 @@ const struct frr_yang_module_info frr_interface_info = { { .xpath = "/frr-interface:lib/interface", .cbs.create = lib_interface_create, - .cbs.destroy = lib_interface_delete, + .cbs.destroy = lib_interface_destroy, .cbs.cli_show = cli_show_interface, }, { .xpath = "/frr-interface:lib/interface/description", .cbs.modify = lib_interface_description_modify, - .cbs.destroy = lib_interface_description_delete, + .cbs.destroy = lib_interface_description_destroy, .cbs.cli_show = cli_show_interface_desc, }, { diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 33035de31..917b04810 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -1297,7 +1297,7 @@ DEFPY (show_yang_operational_data, yang_dnode_free(dnode); return CMD_WARNING; } - lyd_validate(&dnode, LYD_OPT_DATA | LYD_OPT_DATA_NO_YANGLIB, ly_ctx); + lyd_validate(&dnode, LYD_OPT_GET, ly_ctx); /* Display the data. */ if (lyd_print_mem(&strp, dnode, format, @@ -573,7 +573,7 @@ static int vrf_default_accepts_vrf(int type) /* Create a socket for the VRF. */ int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, - char *interfacename) + const char *interfacename) { int ret, save_errno, ret2; @@ -944,7 +944,7 @@ vrf_id_t vrf_get_default_id(void) return VRF_DEFAULT_INTERNAL; } -int vrf_bind(vrf_id_t vrf_id, int fd, char *name) +int vrf_bind(vrf_id_t vrf_id, int fd, const char *name) { int ret = 0; @@ -1003,7 +1003,7 @@ int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *params) } int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id, - char *interfacename) + const char *interfacename) { int ret, save_errno, ret2; @@ -220,12 +220,12 @@ extern void vrf_terminate(void); /* Create a socket serving for the given VRF */ extern int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, - char *name); + const char *name); extern int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id, - char *name); + const char *name); -extern int vrf_bind(vrf_id_t vrf_id, int fd, char *name); +extern int vrf_bind(vrf_id_t vrf_id, int fd, const char *name); /* VRF ioctl operations */ extern int vrf_getaddrinfo(const char *node, const char *service, diff --git a/lib/yang.c b/lib/yang.c index 1d8e82eb2..7982d14fd 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -610,6 +610,25 @@ struct list *yang_data_list_new(void) return list; } +struct yang_data *yang_data_list_find(const struct list *list, + const char *xpath_fmt, ...) +{ + char xpath[XPATH_MAXLEN]; + struct yang_data *data; + struct listnode *node; + va_list ap; + + va_start(ap, xpath_fmt); + vsnprintf(xpath, sizeof(xpath), xpath_fmt, ap); + va_end(ap); + + for (ALL_LIST_ELEMENTS_RO(list, node, data)) + if (strmatch(data->xpath, xpath)) + return data; + + return NULL; +} + static void *ly_dup_cb(const void *priv) { /* Make a shallow copy of the priv pointer. */ diff --git a/lib/yang.h b/lib/yang.h index 885218272..15f0ec7ae 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -514,6 +514,21 @@ extern void yang_data_free(struct yang_data *data); extern struct list *yang_data_list_new(void); /* + * Find the yang_data structure corresponding to an XPath in a list. + * + * list + * list of yang_data structures to operate on. + * + * xpath_fmt + * XPath to search for (format string). + * + * Returns: + * Pointer to yang_data if found, NULL otherwise. + */ +extern struct yang_data *yang_data_list_find(const struct list *list, + const char *xpath_fmt, ...); + +/* * Create and set up a libyang context (for use by the translator) */ extern struct ly_ctx *yang_ctx_new_setup(void); 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; diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index 23a480317..e95c0e95d 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -39,31 +39,46 @@ */ DEFPY_NOSH (router_ripng, router_ripng_cmd, - "router ripng", + "router ripng [vrf NAME]", "Enable a routing process\n" - "Make RIPng instance command\n") + "Make RIPng instance command\n" + VRF_CMD_HELP_STR) { + char xpath[XPATH_MAXLEN]; int ret; - nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_CREATE, - NULL); + /* Build RIPng instance XPath. */ + if (!vrf) + vrf = VRF_DEFAULT_NAME; + snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", + vrf); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); ret = nb_cli_apply_changes(vty, NULL); if (ret == CMD_SUCCESS) - VTY_PUSH_XPATH(RIPNG_NODE, "/frr-ripngd:ripngd/instance"); + VTY_PUSH_XPATH(RIPNG_NODE, xpath); return ret; } DEFPY (no_router_ripng, no_router_ripng_cmd, - "no router ripng", + "no router ripng [vrf NAME]", NO_STR "Enable a routing process\n" - "Make RIPng instance command\n") + "Make RIPng instance command\n" + VRF_CMD_HELP_STR) { - nb_cli_enqueue_change(vty, "/frr-ripngd:ripngd/instance", NB_OP_DESTROY, - NULL); + char xpath[XPATH_MAXLEN]; + + /* Build RIPng instance XPath. */ + if (!vrf) + vrf = VRF_DEFAULT_NAME; + snprintf(xpath, sizeof(xpath), "/frr-ripngd:ripngd/instance[vrf='%s']", + vrf); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -71,8 +86,15 @@ DEFPY (no_router_ripng, void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, bool show_defaults) { + const char *vrf_name; + + vrf_name = yang_dnode_get_string(dnode, "./vrf"); + vty_out(vty, "!\n"); - vty_out(vty, "router ripng\n"); + vty_out(vty, "router ripng"); + if (!strmatch(vrf_name, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrf_name); + vty_out(vty, "\n"); } /* @@ -456,12 +478,24 @@ void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode, */ DEFPY (clear_ipv6_rip, clear_ipv6_rip_cmd, - "clear ipv6 ripng", + "clear ipv6 ripng [vrf WORD]", CLEAR_STR IPV6_STR - "Clear IPv6 RIP database\n") + "Clear IPv6 RIP database\n" + VRF_CMD_HELP_STR) { - return nb_cli_rpc("/frr-ripngd:clear-ripng-route", NULL, NULL); + struct list *input; + + input = list_new(); + if (vrf) { + struct yang_data *yang_vrf; + + yang_vrf = yang_data_new( + "/frr-ripngd:clear-ripng-route/input/vrf", vrf); + listnode_add(input, yang_vrf); + } + + return nb_cli_rpc("/frr-ripngd:clear-ripng-route", input, NULL); } void ripng_cli_init(void) diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index ea32b622a..e35652b1a 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -52,12 +52,12 @@ /* Static utility function. */ static void ripng_enable_apply(struct interface *); static void ripng_passive_interface_apply(struct interface *); -static int ripng_enable_if_lookup(const char *); +static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname); static int ripng_enable_network_lookup2(struct connected *); -static void ripng_enable_apply_all(void); +static void ripng_enable_apply_all(struct ripng *ripng); /* Join to the all rip routers multicast group. */ -static int ripng_multicast_join(struct interface *ifp) +static int ripng_multicast_join(struct interface *ifp, int sock) { int ret; struct ipv6_mreq mreq; @@ -75,8 +75,7 @@ static int ripng_multicast_join(struct interface *ifp) */ frr_elevate_privs(&ripngd_privs) { - ret = setsockopt(ripng->sock, IPPROTO_IPV6, - IPV6_JOIN_GROUP, + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq, sizeof(mreq)); save_errno = errno; @@ -111,7 +110,7 @@ static int ripng_multicast_join(struct interface *ifp) } /* Leave from the all rip routers multicast group. */ -static int ripng_multicast_leave(struct interface *ifp) +static int ripng_multicast_leave(struct interface *ifp, int sock) { int ret; struct ipv6_mreq mreq; @@ -121,7 +120,7 @@ static int ripng_multicast_leave(struct interface *ifp) inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr); mreq.ipv6mr_interface = ifp->ifindex; - ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, + ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq, sizeof(mreq)); if (ret < 0) zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s", @@ -163,9 +162,13 @@ static int ripng_if_down(struct interface *ifp) struct agg_node *rp; struct ripng_info *rinfo; struct ripng_interface *ri; + struct ripng *ripng; struct list *list = NULL; struct listnode *listnode = NULL, *nextnode = NULL; + ri = ifp->info; + ripng = ri->ripng; + if (ripng) for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) @@ -173,16 +176,15 @@ static int ripng_if_down(struct interface *ifp) for (ALL_LIST_ELEMENTS(list, listnode, nextnode, rinfo)) if (rinfo->ifindex == ifp->ifindex) - ripng_ecmp_delete(rinfo); + ripng_ecmp_delete(ripng, rinfo); - ri = ifp->info; if (ri->running) { if (IS_RIPNG_DEBUG_EVENT) zlog_debug("turn off %s", ifp->name); /* Leave from multicast group. */ - ripng_multicast_leave(ifp); + ripng_multicast_leave(ifp, ripng->sock); ri->running = 0; } @@ -207,9 +209,11 @@ int ripng_interface_up(int command, struct zclient *zclient, if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( - "interface up %s index %d flags %llx metric %d mtu %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6); + "interface up %s vrf %u index %d flags %llx metric %d mtu %d", + ifp->name, ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); + + ripng_interface_sync(ifp); /* Check if this interface is RIPng enabled or not. */ ripng_enable_apply(ifp); @@ -238,13 +242,14 @@ int ripng_interface_down(int command, struct zclient *zclient, if (ifp == NULL) return 0; + ripng_interface_sync(ifp); ripng_if_down(ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( - "interface down %s index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6); + "interface down %s vrf %u index %d flags %#llx metric %d mtu %d", + ifp->name, ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); return 0; } @@ -256,12 +261,13 @@ int ripng_interface_add(int command, struct zclient *zclient, struct interface *ifp; ifp = zebra_interface_add_read(zclient->ibuf, vrf_id); + ripng_interface_sync(ifp); if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( - "RIPng interface add %s index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6); + "RIPng interface add %s vrf %u index %d flags %#llx metric %d mtu %d", + ifp->name, ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* Check is this interface is RIP enabled or not.*/ ripng_enable_apply(ifp); @@ -289,13 +295,15 @@ int ripng_interface_delete(int command, struct zclient *zclient, if (ifp == NULL) return 0; + ripng_interface_sync(ifp); if (if_is_up(ifp)) { ripng_if_down(ifp); } - zlog_info("interface delete %s index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->ifindex, (unsigned long long)ifp->flags, - ifp->metric, ifp->mtu6); + zlog_info( + "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d", + ifp->name, ifp->vrf_id, ifp->ifindex, + (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); /* To support pseudo interface do not free interface structure. */ /* if_delete(ifp); */ @@ -304,13 +312,34 @@ int ripng_interface_delete(int command, struct zclient *zclient, return 0; } -void ripng_interface_clean(void) +/* VRF update for an interface. */ +int ripng_interface_vrf_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id) +{ + struct interface *ifp; + vrf_id_t new_vrf_id; + + ifp = zebra_interface_vrf_update_read(zclient->ibuf, vrf_id, + &new_vrf_id); + if (!ifp) + return 0; + + if (IS_RIPNG_DEBUG_ZEBRA) + zlog_debug("interface %s VRF change vrf_id %u new vrf id %u", + ifp->name, vrf_id, new_vrf_id); + + if_update_to_new_vrf(ifp, new_vrf_id); + ripng_interface_sync(ifp); + + return 0; +} + +void ripng_interface_clean(struct ripng *ripng) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; struct ripng_interface *ri; - FOR_ALL_INTERFACES (vrf, ifp) { + FOR_ALL_INTERFACES (ripng->vrf, ifp) { ri = ifp->info; ri->enable_network = 0; @@ -326,6 +355,8 @@ void ripng_interface_clean(void) static void ripng_apply_address_add(struct connected *ifc) { + struct ripng_interface *ri = ifc->ifp->info; + struct ripng *ripng = ri->ripng; struct prefix_ipv6 address; struct prefix *p; @@ -345,9 +376,9 @@ static void ripng_apply_address_add(struct connected *ifc) /* Check if this interface is RIP enabled or not or Check if this address's prefix is RIP enabled */ - if ((ripng_enable_if_lookup(ifc->ifp->name) >= 0) + if ((ripng_enable_if_lookup(ripng, ifc->ifp->name) >= 0) || (ripng_enable_network_lookup2(ifc) >= 0)) - ripng_redistribute_add(ZEBRA_ROUTE_CONNECT, + ripng_redistribute_add(ripng, ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, ifc->ifp->ifindex, NULL, 0); } @@ -395,6 +426,8 @@ int ripng_interface_address_add(int command, struct zclient *zclient, static void ripng_apply_address_del(struct connected *ifc) { + struct ripng_interface *ri = ifc->ifp->info; + struct ripng *ripng = ri->ripng; struct prefix_ipv6 address; struct prefix *p; @@ -412,8 +445,9 @@ static void ripng_apply_address_del(struct connected *ifc) address.prefixlen = p->prefixlen; apply_mask_ipv6(&address); - ripng_redistribute_delete(ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, - &address, ifc->ifp->ifindex); + ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT, + RIPNG_ROUTE_INTERFACE, &address, + ifc->ifp->ifindex); } int ripng_interface_address_delete(int command, struct zclient *zclient, @@ -446,21 +480,20 @@ int ripng_interface_address_delete(int command, struct zclient *zclient, return 0; } -/* RIPng enable interface vector. */ -vector ripng_enable_if; - -/* RIPng enable network table. */ -struct agg_table *ripng_enable_network; - /* Lookup RIPng enable network. */ /* Check wether the interface has at least a connected prefix that - * is within the ripng_enable_network table. */ + * is within the ripng->enable_network table. */ static int ripng_enable_network_lookup_if(struct interface *ifp) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct listnode *node; struct connected *connected; struct prefix_ipv6 address; + if (!ripng) + return -1; + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, connected)) { struct prefix *p; struct agg_node *n; @@ -472,7 +505,7 @@ static int ripng_enable_network_lookup_if(struct interface *ifp) address.prefix = p->u.prefix6; address.prefixlen = IPV6_MAX_BITLEN; - n = agg_node_match(ripng_enable_network, + n = agg_node_match(ripng->enable_network, (struct prefix *)&address); if (n) { agg_unlock_node(n); @@ -483,12 +516,17 @@ static int ripng_enable_network_lookup_if(struct interface *ifp) return -1; } -/* Check wether connected is within the ripng_enable_network table. */ +/* Check wether connected is within the ripng->enable_network table. */ static int ripng_enable_network_lookup2(struct connected *connected) { + struct ripng_interface *ri = connected->ifp->info; + struct ripng *ripng = ri->ripng; struct prefix_ipv6 address; struct prefix *p; + if (!ripng) + return -1; + p = connected->address; if (p->family == AF_INET6) { @@ -499,8 +537,8 @@ static int ripng_enable_network_lookup2(struct connected *connected) address.prefixlen = IPV6_MAX_BITLEN; /* LPM on p->family, p->u.prefix6/IPV6_MAX_BITLEN within - * ripng_enable_network */ - node = agg_node_match(ripng_enable_network, + * ripng->enable_network */ + node = agg_node_match(ripng->enable_network, (struct prefix *)&address); if (node) { @@ -513,11 +551,11 @@ static int ripng_enable_network_lookup2(struct connected *connected) } /* Add RIPng enable network. */ -int ripng_enable_network_add(struct prefix *p) +int ripng_enable_network_add(struct ripng *ripng, struct prefix *p) { struct agg_node *node; - node = agg_node_get(ripng_enable_network, p); + node = agg_node_get(ripng->enable_network, p); if (node->info) { agg_unlock_node(node); @@ -526,17 +564,17 @@ int ripng_enable_network_add(struct prefix *p) node->info = (void *)1; /* XXX: One should find a better solution than a generic one */ - ripng_enable_apply_all(); + ripng_enable_apply_all(ripng); return NB_OK; } /* Delete RIPng enable network. */ -int ripng_enable_network_delete(struct prefix *p) +int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p) { struct agg_node *node; - node = agg_node_lookup(ripng_enable_network, p); + node = agg_node_lookup(ripng->enable_network, p); if (node) { node->info = NULL; @@ -553,49 +591,50 @@ int ripng_enable_network_delete(struct prefix *p) } /* Lookup function. */ -static int ripng_enable_if_lookup(const char *ifname) +static int ripng_enable_if_lookup(struct ripng *ripng, const char *ifname) { unsigned int i; char *str; - for (i = 0; i < vector_active(ripng_enable_if); i++) - if ((str = vector_slot(ripng_enable_if, i)) != NULL) + if (!ripng) + return -1; + + for (i = 0; i < vector_active(ripng->enable_if); i++) + if ((str = vector_slot(ripng->enable_if, i)) != NULL) if (strcmp(str, ifname) == 0) return i; return -1; } -/* Add interface to ripng_enable_if. */ -int ripng_enable_if_add(const char *ifname) +int ripng_enable_if_add(struct ripng *ripng, const char *ifname) { int ret; - ret = ripng_enable_if_lookup(ifname); + ret = ripng_enable_if_lookup(ripng, ifname); if (ret >= 0) return NB_ERR_INCONSISTENCY; - vector_set(ripng_enable_if, strdup(ifname)); + vector_set(ripng->enable_if, strdup(ifname)); - ripng_enable_apply_all(); + ripng_enable_apply_all(ripng); return NB_OK; } -/* Delete interface from ripng_enable_if. */ -int ripng_enable_if_delete(const char *ifname) +int ripng_enable_if_delete(struct ripng *ripng, const char *ifname) { int index; char *str; - index = ripng_enable_if_lookup(ifname); + index = ripng_enable_if_lookup(ripng, ifname); if (index < 0) return NB_ERR_INCONSISTENCY; - str = vector_slot(ripng_enable_if, index); + str = vector_slot(ripng->enable_if, index); free(str); - vector_unset(ripng_enable_if, index); + vector_unset(ripng->enable_if, index); - ripng_enable_apply_all(); + ripng_enable_apply_all(ripng); return NB_OK; } @@ -613,7 +652,7 @@ static int ripng_interface_wakeup(struct thread *t) ri->t_wakeup = NULL; /* Join to multicast group. */ - if (ripng_multicast_join(ifp) < 0) { + if (ripng_multicast_join(ifp, ri->ripng->sock) < 0) { flog_err_sys(EC_LIB_SOCKET, "multicast join failed, interface %s not running", ifp->name); @@ -631,6 +670,8 @@ static int ripng_interface_wakeup(struct thread *t) static void ripng_connect_set(struct interface *ifp, int set) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct listnode *node, *nnode; struct connected *connected; struct prefix_ipv6 address; @@ -650,19 +691,22 @@ static void ripng_connect_set(struct interface *ifp, int set) if (set) { /* Check once more wether this prefix is within a * "network IF_OR_PREF" one */ - if ((ripng_enable_if_lookup(connected->ifp->name) >= 0) + if ((ripng_enable_if_lookup(ripng, connected->ifp->name) + >= 0) || (ripng_enable_network_lookup2(connected) >= 0)) ripng_redistribute_add( - ZEBRA_ROUTE_CONNECT, + ripng, ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, &address, connected->ifp->ifindex, NULL, 0); } else { - ripng_redistribute_delete( - ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_INTERFACE, - &address, connected->ifp->ifindex); - if (ripng_redistribute_check(ZEBRA_ROUTE_CONNECT)) + ripng_redistribute_delete(ripng, ZEBRA_ROUTE_CONNECT, + RIPNG_ROUTE_INTERFACE, + &address, + connected->ifp->ifindex); + if (ripng_redistribute_check(ripng, + ZEBRA_ROUTE_CONNECT)) ripng_redistribute_add( - ZEBRA_ROUTE_CONNECT, + ripng, ZEBRA_ROUTE_CONNECT, RIPNG_ROUTE_REDISTRIBUTE, &address, connected->ifp->ifindex, NULL, 0); } @@ -691,7 +735,7 @@ void ripng_enable_apply(struct interface *ifp) ri->enable_network = 0; /* Check interface name configuration. */ - ret = ripng_enable_if_lookup(ifp->name); + ret = ripng_enable_if_lookup(ri->ripng, ifp->name); if (ret >= 0) ri->enable_interface = 1; else @@ -729,49 +773,46 @@ void ripng_enable_apply(struct interface *ifp) } /* Set distribute list to all interfaces. */ -static void ripng_enable_apply_all(void) +static void ripng_enable_apply_all(struct ripng *ripng) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; - FOR_ALL_INTERFACES (vrf, ifp) + FOR_ALL_INTERFACES (ripng->vrf, ifp) ripng_enable_apply(ifp); } /* Clear all network and neighbor configuration */ -void ripng_clean_network(void) +void ripng_clean_network(struct ripng *ripng) { unsigned int i; char *str; struct agg_node *rn; - /* ripng_enable_network */ - for (rn = agg_route_top(ripng_enable_network); rn; + /* ripng->enable_network */ + for (rn = agg_route_top(ripng->enable_network); rn; rn = agg_route_next(rn)) if (rn->info) { rn->info = NULL; agg_unlock_node(rn); } - /* ripng_enable_if */ - for (i = 0; i < vector_active(ripng_enable_if); i++) - if ((str = vector_slot(ripng_enable_if, i)) != NULL) { + /* ripng->enable_if */ + for (i = 0; i < vector_active(ripng->enable_if); i++) + if ((str = vector_slot(ripng->enable_if, i)) != NULL) { free(str); - vector_slot(ripng_enable_if, i) = NULL; + vector_slot(ripng->enable_if, i) = NULL; } } -/* Vector to store passive-interface name. */ -vector Vripng_passive_interface; - /* Utility function for looking up passive interface settings. */ -static int ripng_passive_interface_lookup(const char *ifname) +static int ripng_passive_interface_lookup(struct ripng *ripng, + const char *ifname) { unsigned int i; char *str; - for (i = 0; i < vector_active(Vripng_passive_interface); i++) - if ((str = vector_slot(Vripng_passive_interface, i)) != NULL) + for (i = 0; i < vector_active(ripng->passive_interface); i++) + if ((str = vector_slot(ripng->passive_interface, i)) != NULL) if (strcmp(str, ifname) == 0) return i; return -1; @@ -781,72 +822,75 @@ void ripng_passive_interface_apply(struct interface *ifp) { int ret; struct ripng_interface *ri; + struct ripng *ripng; ri = ifp->info; + ripng = ri->ripng; + if (!ripng) + return; - ret = ripng_passive_interface_lookup(ifp->name); + ret = ripng_passive_interface_lookup(ripng, ifp->name); if (ret < 0) ri->passive = 0; else ri->passive = 1; } -static void ripng_passive_interface_apply_all(void) +static void ripng_passive_interface_apply_all(struct ripng *ripng) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; - FOR_ALL_INTERFACES (vrf, ifp) + FOR_ALL_INTERFACES (ripng->vrf, ifp) ripng_passive_interface_apply(ifp); } /* Passive interface. */ -int ripng_passive_interface_set(const char *ifname) +int ripng_passive_interface_set(struct ripng *ripng, const char *ifname) { - if (ripng_passive_interface_lookup(ifname) >= 0) + if (ripng_passive_interface_lookup(ripng, ifname) >= 0) return NB_ERR_INCONSISTENCY; - vector_set(Vripng_passive_interface, strdup(ifname)); + vector_set(ripng->passive_interface, strdup(ifname)); - ripng_passive_interface_apply_all(); + ripng_passive_interface_apply_all(ripng); return NB_OK; } -int ripng_passive_interface_unset(const char *ifname) +int ripng_passive_interface_unset(struct ripng *ripng, const char *ifname) { int i; char *str; - i = ripng_passive_interface_lookup(ifname); + i = ripng_passive_interface_lookup(ripng, ifname); if (i < 0) return NB_ERR_INCONSISTENCY; - str = vector_slot(Vripng_passive_interface, i); + str = vector_slot(ripng->passive_interface, i); free(str); - vector_unset(Vripng_passive_interface, i); + vector_unset(ripng->passive_interface, i); - ripng_passive_interface_apply_all(); + ripng_passive_interface_apply_all(ripng); return NB_OK; } /* Free all configured RIP passive-interface settings. */ -void ripng_passive_interface_clean(void) +void ripng_passive_interface_clean(struct ripng *ripng) { unsigned int i; char *str; - for (i = 0; i < vector_active(Vripng_passive_interface); i++) - if ((str = vector_slot(Vripng_passive_interface, i)) != NULL) { + for (i = 0; i < vector_active(ripng->passive_interface); i++) + if ((str = vector_slot(ripng->passive_interface, i)) != NULL) { free(str); - vector_slot(Vripng_passive_interface, i) = NULL; + vector_slot(ripng->passive_interface, i) = NULL; } - ripng_passive_interface_apply_all(); + ripng_passive_interface_apply_all(ripng); } /* Write RIPng enable network and interface to the vty. */ -int ripng_network_write(struct vty *vty) +int ripng_network_write(struct vty *vty, struct ripng *ripng) { unsigned int i; const char *ifname; @@ -854,7 +898,7 @@ int ripng_network_write(struct vty *vty) char buf[BUFSIZ]; /* Write enable network. */ - for (node = agg_route_top(ripng_enable_network); node; + for (node = agg_route_top(ripng->enable_network); node; node = agg_route_next(node)) if (node->info) { struct prefix *p = &node->p; @@ -864,8 +908,8 @@ int ripng_network_write(struct vty *vty) } /* Write enable interface. */ - for (i = 0; i < vector_active(ripng_enable_if); i++) - if ((ifname = vector_slot(ripng_enable_if, i)) != NULL) + for (i = 0; i < vector_active(ripng->enable_if); i++) + if ((ifname = vector_slot(ripng->enable_if, i)) != NULL) vty_out(vty, " %s\n", ifname); return 0; @@ -874,6 +918,7 @@ int ripng_network_write(struct vty *vty) static struct ripng_interface *ri_new(void) { struct ripng_interface *ri; + ri = XCALLOC(MTYPE_IF, sizeof(struct ripng_interface)); /* Set default split-horizon behavior. If the interface is Frame @@ -886,9 +931,25 @@ static struct ripng_interface *ri_new(void) return ri; } +void ripng_interface_sync(struct interface *ifp) +{ + struct vrf *vrf; + + vrf = vrf_lookup_by_id(ifp->vrf_id); + if (vrf) { + struct ripng_interface *ri; + + ri = ifp->info; + if (ri) + ri->ripng = vrf->info; + } +} + static int ripng_if_new_hook(struct interface *ifp) { ifp->info = ri_new(); + ripng_interface_sync(ifp); + return 0; } @@ -903,22 +964,25 @@ static int ripng_if_delete_hook(struct interface *ifp) /* Configuration write function for ripngd. */ static int interface_config_write(struct vty *vty) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); - struct interface *ifp; + struct vrf *vrf; int write = 0; - FOR_ALL_INTERFACES (vrf, ifp) { - struct lyd_node *dnode; + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + struct interface *ifp; - dnode = yang_dnode_get( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; + FOR_ALL_INTERFACES (vrf, ifp) { + struct lyd_node *dnode; - write = 1; - nb_cli_show_dnode_cmds(vty, dnode, false); + dnode = yang_dnode_get( + running_config->dnode, + "/frr-interface:lib/interface[name='%s'][vrf='%s']", + ifp->name, vrf->name); + if (dnode == NULL) + continue; + + write = 1; + nb_cli_show_dnode_cmds(vty, dnode, false); + } } return write; @@ -936,15 +1000,6 @@ void ripng_if_init(void) hook_register_prio(if_add, 0, ripng_if_new_hook); hook_register_prio(if_del, 0, ripng_if_delete_hook); - /* RIPng enable network init. */ - ripng_enable_network = agg_table_init(); - - /* RIPng enable interface init. */ - ripng_enable_if = vector_init(1); - - /* RIPng passive interface. */ - Vripng_passive_interface = vector_init(1); - /* Install interface node. */ install_node(&interface_node, interface_config_write); if_cmd_init(); diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 10e19efe7..c755bd83c 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -35,6 +35,7 @@ #include "privs.h" #include "sigevent.h" #include "vrf.h" +#include "if_rmap.h" #include "libfrr.h" #include "ripngd/ripngd.h" @@ -46,7 +47,7 @@ struct option longopts[] = {{"retain", no_argument, NULL, 'r'}, {0}}; /* ripngd privileges */ -zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND}; +zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_SYS_ADMIN}; struct zebra_privs_t ripngd_privs = { #if defined(FRR_USER) @@ -59,7 +60,7 @@ struct zebra_privs_t ripngd_privs = { .vty_group = VTY_GROUP, #endif .caps_p = _caps_p, - .cap_num_p = 2, + .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; @@ -82,8 +83,8 @@ static void sigint(void) { zlog_notice("Terminating on signal"); - ripng_clean(); - + ripng_vrf_terminate(); + if_rmap_terminate(); ripng_zebra_stop(); frr_fini(); exit(0); @@ -170,13 +171,12 @@ int main(int argc, char **argv) master = frr_init(); /* Library inits. */ - vrf_init(NULL, NULL, NULL, NULL, NULL); + ripng_vrf_init(); /* RIPngd inits. */ ripng_init(); ripng_cli_init(); zebra_init(master); - ripng_peer_init(); frr_config_fork(); frr_run(master); diff --git a/ripngd/ripng_memory.c b/ripngd/ripng_memory.c index 0cb24052e..f459566be 100644 --- a/ripngd/ripng_memory.c +++ b/ripngd/ripng_memory.c @@ -27,6 +27,7 @@ DEFINE_MGROUP(RIPNGD, "ripngd") DEFINE_MTYPE(RIPNGD, RIPNG, "RIPng structure") +DEFINE_MTYPE(RIPNGD, RIPNG_VRF_NAME, "RIPng VRF name") DEFINE_MTYPE(RIPNGD, RIPNG_ROUTE, "RIPng route info") DEFINE_MTYPE(RIPNGD, RIPNG_AGGREGATE, "RIPng aggregate") DEFINE_MTYPE(RIPNGD, RIPNG_PEER, "RIPng peer") diff --git a/ripngd/ripng_memory.h b/ripngd/ripng_memory.h index a4102086c..3dfc57b3f 100644 --- a/ripngd/ripng_memory.h +++ b/ripngd/ripng_memory.h @@ -26,6 +26,7 @@ DECLARE_MGROUP(RIPNGD) DECLARE_MTYPE(RIPNG) +DECLARE_MTYPE(RIPNG_VRF_NAME) DECLARE_MTYPE(RIPNG_ROUTE) DECLARE_MTYPE(RIPNG_AGGREGATE) DECLARE_MTYPE(RIPNG_PEER) diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c index 74a132aa9..882c2fbc8 100644 --- a/ripngd/ripng_nexthop.c +++ b/ripngd/ripng_nexthop.c @@ -114,7 +114,8 @@ void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, struct sockaddr_in6 *to) { - + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct ripng_rte_data *data; struct listnode *node, *nnode; diff --git a/ripngd/ripng_northbound.c b/ripngd/ripng_northbound.c index b6998b4dd..c483ad65f 100644 --- a/ripngd/ripng_northbound.c +++ b/ripngd/ripng_northbound.c @@ -32,6 +32,7 @@ #include "libfrr.h" #include "ripngd/ripngd.h" +#include "ripngd/ripng_debug.h" #include "ripngd/ripng_route.h" #include "ripngd/ripng_cli.h" @@ -42,41 +43,98 @@ static int ripngd_instance_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + struct vrf *vrf; + const char *vrf_name; int socket; + vrf_name = yang_dnode_get_string(dnode, "./vrf"); + vrf = vrf_lookup_by_name(vrf_name); + + /* + * Try to create a RIPng socket only if the VRF is enabled, otherwise + * create a disabled RIPng instance and wait for the VRF to be enabled. + */ switch (event) { case NB_EV_VALIDATE: break; case NB_EV_PREPARE: - socket = ripng_make_socket(); + if (!vrf || !vrf_is_enabled(vrf)) + break; + + socket = ripng_make_socket(vrf); if (socket < 0) return NB_ERR_RESOURCE; resource->fd = socket; break; case NB_EV_ABORT: + if (!vrf || !vrf_is_enabled(vrf)) + break; + socket = resource->fd; close(socket); break; case NB_EV_APPLY: - socket = resource->fd; - ripng_create(socket); + if (vrf && vrf_is_enabled(vrf)) + socket = resource->fd; + else + socket = -1; + + ripng = ripng_create(vrf_name, vrf, socket); + yang_dnode_set_entry(dnode, ripng); break; } return NB_OK; } -static int ripngd_instance_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; - ripng_clean(); + ripng = yang_dnode_get_entry(dnode, true); + ripng_clean(ripng); return NB_OK; } +static const void *ripngd_instance_get_next(const void *parent_list_entry, + const void *list_entry) +{ + const struct ripng *ripng = list_entry; + + if (list_entry == NULL) + ripng = RB_MIN(ripng_instance_head, &ripng_instances); + else + ripng = RB_NEXT(ripng_instance_head, (struct ripng *)ripng); + + return ripng; +} + +static int ripngd_instance_get_keys(const void *list_entry, + struct yang_list_keys *keys) +{ + const struct ripng *ripng = list_entry; + + keys->num = 1; + strlcpy(keys->key[0], ripng->vrf_name, sizeof(keys->key[0])); + + return NB_OK; +} + +static const void * +ripngd_instance_lookup_entry(const void *parent_list_entry, + const struct yang_list_keys *keys) +{ + const char *vrf_name = keys->key[0]; + + return ripng_lookup_by_vrf_name(vrf_name); +} + /* * XPath: /frr-ripngd:ripngd/instance/allow-ecmp */ @@ -84,12 +142,15 @@ static int ripngd_instance_allow_ecmp_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ripng->ecmp = yang_dnode_get_bool(dnode, NULL); if (!ripng->ecmp) - ripng_ecmp_disable(); + ripng_ecmp_disable(ripng); return NB_OK; } @@ -101,19 +162,22 @@ static int ripngd_instance_default_information_originate_modify( enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; bool default_information; struct prefix_ipv6 p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); default_information = yang_dnode_get_bool(dnode, NULL); + str2prefix_ipv6("::/0", &p); if (default_information) { - ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, - &p, 0, NULL, 0); + ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, + RIPNG_ROUTE_DEFAULT, &p, 0, NULL, 0); } else { - ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, + ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_DEFAULT, &p, 0); } @@ -127,9 +191,12 @@ static int ripngd_instance_default_metric_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ripng->default_metric = yang_dnode_get_uint8(dnode, NULL); return NB_OK; @@ -142,29 +209,33 @@ static int ripngd_instance_network_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; struct prefix p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6((struct prefix_ipv6 *)&p); - return ripng_enable_network_add(&p); + return ripng_enable_network_add(ripng, &p); } -static int ripngd_instance_network_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_network_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; struct prefix p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6((struct prefix_ipv6 *)&p); - return ripng_enable_network_delete(&p); + return ripng_enable_network_delete(ripng, &p); } /* @@ -174,27 +245,31 @@ static int ripngd_instance_interface_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; const char *ifname; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ifname = yang_dnode_get_string(dnode, NULL); - return ripng_enable_if_add(ifname); + return ripng_enable_if_add(ripng, ifname); } -static int ripngd_instance_interface_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_interface_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; const char *ifname; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ifname = yang_dnode_get_string(dnode, NULL); - return ripng_enable_if_delete(ifname); + return ripng_enable_if_delete(ripng, ifname); } /* @@ -204,22 +279,24 @@ static int ripngd_instance_offset_list_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; const char *ifname; struct ripng_offset_list *offset; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ifname = yang_dnode_get_string(dnode, "./interface"); - offset = ripng_offset_list_new(ifname); + offset = ripng_offset_list_new(ripng, ifname); yang_dnode_set_entry(dnode, offset); return NB_OK; } -static int ripngd_instance_offset_list_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_offset_list_destroy(enum nb_event event, + const struct lyd_node *dnode) { int direct; struct ripng_offset_list *offset; @@ -299,28 +376,32 @@ ripngd_instance_passive_interface_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; const char *ifname; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ifname = yang_dnode_get_string(dnode, NULL); - return ripng_passive_interface_set(ifname); + return ripng_passive_interface_set(ripng, ifname); } static int -ripngd_instance_passive_interface_delete(enum nb_event event, - const struct lyd_node *dnode) +ripngd_instance_passive_interface_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; const char *ifname; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ifname = yang_dnode_get_string(dnode, NULL); - return ripng_passive_interface_unset(ifname); + return ripng_passive_interface_unset(ripng, ifname); } /* @@ -330,20 +411,43 @@ static int ripngd_instance_redistribute_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + int type; + + if (event != NB_EV_APPLY) + return NB_OK; + + ripng = yang_dnode_get_entry(dnode, true); + type = yang_dnode_get_enum(dnode, "./protocol"); + + ripng->redist[type].enabled = true; + return NB_OK; } -static int ripngd_instance_redistribute_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_redistribute_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; int type; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "./protocol"); - ripng_redistribute_conf_delete(type); + ripng->redist[type].enabled = false; + if (ripng->redist[type].route_map.name) { + free(ripng->redist[type].route_map.name); + ripng->redist[type].route_map.name = NULL; + ripng->redist[type].route_map.map = NULL; + } + ripng->redist[type].metric_config = false; + ripng->redist[type].metric = 0; + + if (ripng->enabled) + ripng_redistribute_conf_delete(ripng, type); return NB_OK; } @@ -351,10 +455,14 @@ static int ripngd_instance_redistribute_delete(enum nb_event event, static void ripngd_instance_redistribute_apply_finish(const struct lyd_node *dnode) { + struct ripng *ripng; int type; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "./protocol"); - ripng_redistribute_conf_update(type); + + if (ripng->enabled) + ripng_redistribute_conf_update(ripng, type); } /* @@ -365,37 +473,41 @@ ripngd_instance_redistribute_route_map_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; int type; const char *rmap_name; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "../protocol"); rmap_name = yang_dnode_get_string(dnode, NULL); - if (ripng->route_map[type].name) - free(ripng->route_map[type].name); - ripng->route_map[type].name = strdup(rmap_name); - ripng->route_map[type].map = route_map_lookup_by_name(rmap_name); + if (ripng->redist[type].route_map.name) + free(ripng->redist[type].route_map.name); + ripng->redist[type].route_map.name = strdup(rmap_name); + ripng->redist[type].route_map.map = route_map_lookup_by_name(rmap_name); return NB_OK; } static int -ripngd_instance_redistribute_route_map_delete(enum nb_event event, - const struct lyd_node *dnode) +ripngd_instance_redistribute_route_map_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; int type; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "../protocol"); - free(ripng->route_map[type].name); - ripng->route_map[type].name = NULL; - ripng->route_map[type].map = NULL; + free(ripng->redist[type].route_map.name); + ripng->redist[type].route_map.name = NULL; + ripng->redist[type].route_map.map = NULL; return NB_OK; } @@ -408,34 +520,38 @@ ripngd_instance_redistribute_metric_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; int type; uint8_t metric; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "../protocol"); metric = yang_dnode_get_uint8(dnode, NULL); - ripng->route_map[type].metric_config = true; - ripng->route_map[type].metric = metric; + ripng->redist[type].metric_config = true; + ripng->redist[type].metric = metric; return NB_OK; } static int -ripngd_instance_redistribute_metric_delete(enum nb_event event, - const struct lyd_node *dnode) +ripngd_instance_redistribute_metric_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; int type; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); type = yang_dnode_get_enum(dnode, "../protocol"); - ripng->route_map[type].metric_config = false; - ripng->route_map[type].metric = 0; + ripng->redist[type].metric_config = false; + ripng->redist[type].metric = 0; return NB_OK; } @@ -447,32 +563,37 @@ static int ripngd_instance_static_route_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; struct prefix_ipv6 p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6(&p); - ripng_redistribute_add(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0, - NULL, 0); + ripng_redistribute_add(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, + 0, NULL, 0); return NB_OK; } -static int ripngd_instance_static_route_delete(enum nb_event event, - const struct lyd_node *dnode) +static int ripngd_instance_static_route_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; struct prefix_ipv6 p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6(&p); - ripng_redistribute_delete(ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, &p, 0); + ripng_redistribute_delete(ripng, ZEBRA_ROUTE_RIPNG, RIPNG_ROUTE_STATIC, + &p, 0); return NB_OK; } @@ -485,32 +606,36 @@ ripngd_instance_aggregate_address_create(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; struct prefix_ipv6 p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6(&p); - ripng_aggregate_add((struct prefix *)&p); + ripng_aggregate_add(ripng, (struct prefix *)&p); return NB_OK; } static int -ripngd_instance_aggregate_address_delete(enum nb_event event, - const struct lyd_node *dnode) +ripngd_instance_aggregate_address_destroy(enum nb_event event, + const struct lyd_node *dnode) { + struct ripng *ripng; struct prefix_ipv6 p; if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); yang_dnode_get_ipv6p(&p, dnode, NULL); apply_mask_ipv6(&p); - ripng_aggregate_delete((struct prefix *)&p); + ripng_aggregate_delete(ripng, (struct prefix *)&p); return NB_OK; } @@ -520,8 +645,12 @@ ripngd_instance_aggregate_address_delete(enum nb_event event, */ static void ripngd_instance_timers_apply_finish(const struct lyd_node *dnode) { + struct ripng *ripng; + + ripng = yang_dnode_get_entry(dnode, true); + /* Reset update timer thread. */ - ripng_event(RIPNG_UPDATE_EVENT, 0); + ripng_event(ripng, RIPNG_UPDATE_EVENT, 0); } /* @@ -532,9 +661,12 @@ ripngd_instance_timers_flush_interval_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ripng->garbage_time = yang_dnode_get_uint16(dnode, NULL); return NB_OK; @@ -548,9 +680,12 @@ ripngd_instance_timers_holddown_interval_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ripng->timeout_time = yang_dnode_get_uint16(dnode, NULL); return NB_OK; @@ -564,33 +699,38 @@ ripngd_instance_timers_update_interval_modify(enum nb_event event, const struct lyd_node *dnode, union nb_resource *resource) { + struct ripng *ripng; + if (event != NB_EV_APPLY) return NB_OK; + ripng = yang_dnode_get_entry(dnode, true); ripng->update_time = yang_dnode_get_uint16(dnode, NULL); return NB_OK; } /* - * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor + * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor */ static const void * -ripngd_state_neighbors_neighbor_get_next(const void *parent_list_entry, - const void *list_entry) +ripngd_instance_state_neighbors_neighbor_get_next(const void *parent_list_entry, + const void *list_entry) { + const struct ripng *ripng = parent_list_entry; struct listnode *node; if (list_entry == NULL) - node = listhead(peer_list); + node = listhead(ripng->peer_list); else node = listnextnode((struct listnode *)list_entry); return node; } -static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry, - struct yang_list_keys *keys) +static int +ripngd_instance_state_neighbors_neighbor_get_keys(const void *list_entry, + struct yang_list_keys *keys) { const struct listnode *node = list_entry; const struct ripng_peer *peer = listgetdata(node); @@ -602,17 +742,17 @@ static int ripngd_state_neighbors_neighbor_get_keys(const void *list_entry, return NB_OK; } -static const void * -ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry, - const struct yang_list_keys *keys) +static const void *ripngd_instance_state_neighbors_neighbor_lookup_entry( + const void *parent_list_entry, const struct yang_list_keys *keys) { + const struct ripng *ripng = parent_list_entry; struct in6_addr address; struct ripng_peer *peer; struct listnode *node; yang_str2ipv6(keys->key[0], &address); - for (ALL_LIST_ELEMENTS_RO(peer_list, node, peer)) { + for (ALL_LIST_ELEMENTS_RO(ripng->peer_list, node, peer)) { if (IPV6_ADDR_SAME(&peer->addr, &address)) return node; } @@ -621,11 +761,11 @@ ripngd_state_neighbors_neighbor_lookup_entry(const void *parent_list_entry, } /* - * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/address + * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/address */ static struct yang_data * -ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_neighbors_neighbor_address_get_elem( + const char *xpath, const void *list_entry) { const struct listnode *node = list_entry; const struct ripng_peer *peer = listgetdata(node); @@ -634,21 +774,21 @@ ripngd_state_neighbors_neighbor_address_get_elem(const char *xpath, } /* - * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/last-update + * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update */ static struct yang_data * -ripngd_state_neighbors_neighbor_last_update_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_neighbors_neighbor_last_update_get_elem( + const char *xpath, const void *list_entry) { /* TODO: yang:date-and-time is tricky */ return NULL; } /* - * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd + * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd */ static struct yang_data * -ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem( +ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem( const char *xpath, const void *list_entry) { const struct listnode *node = list_entry; @@ -658,11 +798,11 @@ ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem( } /* - * XPath: /frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd + * XPath: /frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd */ static struct yang_data * -ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem( + const char *xpath, const void *list_entry) { const struct listnode *node = list_entry; const struct ripng_peer *peer = listgetdata(node); @@ -671,17 +811,15 @@ ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem(const char *xpath, } /* - * XPath: /frr-ripngd:ripngd/state/routes/route + * XPath: /frr-ripngd:ripngd/instance/state/routes/route */ static const void * -ripngd_state_routes_route_get_next(const void *parent_list_entry, - const void *list_entry) +ripngd_instance_state_routes_route_get_next(const void *parent_list_entry, + const void *list_entry) { + const struct ripng *ripng = parent_list_entry; struct agg_node *rn; - if (ripng == NULL) - return NULL; - if (list_entry == NULL) rn = agg_route_top(ripng->table); else @@ -692,8 +830,9 @@ ripngd_state_routes_route_get_next(const void *parent_list_entry, return rn; } -static int ripngd_state_routes_route_get_keys(const void *list_entry, - struct yang_list_keys *keys) +static int +ripngd_instance_state_routes_route_get_keys(const void *list_entry, + struct yang_list_keys *keys) { const struct agg_node *rn = list_entry; @@ -703,10 +842,10 @@ static int ripngd_state_routes_route_get_keys(const void *list_entry, return NB_OK; } -static const void * -ripngd_state_routes_route_lookup_entry(const void *parent_list_entry, - const struct yang_list_keys *keys) +static const void *ripngd_instance_state_routes_route_lookup_entry( + const void *parent_list_entry, const struct yang_list_keys *keys) { + const struct ripng *ripng = parent_list_entry; struct prefix prefix; struct agg_node *rn; @@ -722,11 +861,11 @@ ripngd_state_routes_route_lookup_entry(const void *parent_list_entry, } /* - * XPath: /frr-ripngd:ripngd/state/routes/route/prefix + * XPath: /frr-ripngd:ripngd/instance/state/routes/route/prefix */ static struct yang_data * -ripngd_state_routes_route_prefix_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_routes_route_prefix_get_elem(const char *xpath, + const void *list_entry) { const struct agg_node *rn = list_entry; const struct ripng_info *rinfo = listnode_head(rn->info); @@ -735,11 +874,11 @@ ripngd_state_routes_route_prefix_get_elem(const char *xpath, } /* - * XPath: /frr-ripngd:ripngd/state/routes/route/next-hop + * XPath: /frr-ripngd:ripngd/instance/state/routes/route/next-hop */ static struct yang_data * -ripngd_state_routes_route_next_hop_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_routes_route_next_hop_get_elem(const char *xpath, + const void *list_entry) { const struct agg_node *rn = list_entry; const struct ripng_info *rinfo = listnode_head(rn->info); @@ -748,25 +887,26 @@ ripngd_state_routes_route_next_hop_get_elem(const char *xpath, } /* - * XPath: /frr-ripngd:ripngd/state/routes/route/interface + * XPath: /frr-ripngd:ripngd/instance/state/routes/route/interface */ static struct yang_data * -ripngd_state_routes_route_interface_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_routes_route_interface_get_elem(const char *xpath, + const void *list_entry) { const struct agg_node *rn = list_entry; const struct ripng_info *rinfo = listnode_head(rn->info); + const struct ripng *ripng = ripng_info_get_instance(rinfo); return yang_data_new_string( - xpath, ifindex2ifname(rinfo->ifindex, VRF_DEFAULT)); + xpath, ifindex2ifname(rinfo->ifindex, ripng->vrf->vrf_id)); } /* - * XPath: /frr-ripngd:ripngd/state/routes/route/metric + * XPath: /frr-ripngd:ripngd/instance/state/routes/route/metric */ static struct yang_data * -ripngd_state_routes_route_metric_get_elem(const char *xpath, - const void *list_entry) +ripngd_instance_state_routes_route_metric_get_elem(const char *xpath, + const void *list_entry) { const struct agg_node *rn = list_entry; const struct ripng_info *rinfo = listnode_head(rn->info); @@ -777,16 +917,20 @@ ripngd_state_routes_route_metric_get_elem(const char *xpath, /* * XPath: /frr-ripngd:clear-ripng-route */ -static int clear_ripng_route_rpc(const char *xpath, const struct list *input, - struct list *output) +static void clear_ripng_route(struct ripng *ripng) { struct agg_node *rp; - struct ripng_info *rinfo; - struct list *list; - struct listnode *listnode; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("Clearing all RIPng routes (VRF %s)", + ripng->vrf_name); /* Clear received RIPng routes */ for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { + struct list *list; + struct listnode *listnode; + struct ripng_info *rinfo; + list = rp->info; if (list == NULL) continue; @@ -796,7 +940,7 @@ static int clear_ripng_route_rpc(const char *xpath, const struct list *input, continue; if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) - ripng_zebra_ipv6_delete(rp); + ripng_zebra_ipv6_delete(ripng, rp); break; } @@ -813,6 +957,30 @@ static int clear_ripng_route_rpc(const char *xpath, const struct list *input, agg_unlock_node(rp); } } +} + +static int clear_ripng_route_rpc(const char *xpath, const struct list *input, + struct list *output) +{ + struct ripng *ripng; + struct yang_data *yang_vrf; + + yang_vrf = yang_data_list_find(input, "%s/%s", xpath, "input/vrf"); + if (yang_vrf) { + ripng = ripng_lookup_by_vrf_name(yang_vrf->value); + if (ripng) + clear_ripng_route(ripng); + } else { + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + ripng = vrf->info; + if (!ripng) + continue; + + clear_ripng_route(ripng); + } + } return NB_OK; } @@ -845,7 +1013,10 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance", .cbs.create = ripngd_instance_create, - .cbs.destroy = ripngd_instance_delete, + .cbs.destroy = ripngd_instance_destroy, + .cbs.get_next = ripngd_instance_get_next, + .cbs.get_keys = ripngd_instance_get_keys, + .cbs.lookup_entry = ripngd_instance_lookup_entry, .cbs.cli_show = cli_show_router_ripng, }, { @@ -866,19 +1037,19 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/network", .cbs.create = ripngd_instance_network_create, - .cbs.destroy = ripngd_instance_network_delete, + .cbs.destroy = ripngd_instance_network_destroy, .cbs.cli_show = cli_show_ripng_network_prefix, }, { .xpath = "/frr-ripngd:ripngd/instance/interface", .cbs.create = ripngd_instance_interface_create, - .cbs.destroy = ripngd_instance_interface_delete, + .cbs.destroy = ripngd_instance_interface_destroy, .cbs.cli_show = cli_show_ripng_network_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/offset-list", .cbs.create = ripngd_instance_offset_list_create, - .cbs.destroy = ripngd_instance_offset_list_delete, + .cbs.destroy = ripngd_instance_offset_list_destroy, .cbs.cli_show = cli_show_ripng_offset_list, }, { @@ -892,36 +1063,36 @@ const struct frr_yang_module_info frr_ripngd_info = { { .xpath = "/frr-ripngd:ripngd/instance/passive-interface", .cbs.create = ripngd_instance_passive_interface_create, - .cbs.destroy = ripngd_instance_passive_interface_delete, + .cbs.destroy = ripngd_instance_passive_interface_destroy, .cbs.cli_show = cli_show_ripng_passive_interface, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute", .cbs.create = ripngd_instance_redistribute_create, - .cbs.destroy = ripngd_instance_redistribute_delete, + .cbs.destroy = ripngd_instance_redistribute_destroy, .cbs.apply_finish = ripngd_instance_redistribute_apply_finish, .cbs.cli_show = cli_show_ripng_redistribute, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/route-map", .cbs.modify = ripngd_instance_redistribute_route_map_modify, - .cbs.destroy = ripngd_instance_redistribute_route_map_delete, + .cbs.destroy = ripngd_instance_redistribute_route_map_destroy, }, { .xpath = "/frr-ripngd:ripngd/instance/redistribute/metric", .cbs.modify = ripngd_instance_redistribute_metric_modify, - .cbs.destroy = ripngd_instance_redistribute_metric_delete, + .cbs.destroy = ripngd_instance_redistribute_metric_destroy, }, { .xpath = "/frr-ripngd:ripngd/instance/static-route", .cbs.create = ripngd_instance_static_route_create, - .cbs.destroy = ripngd_instance_static_route_delete, + .cbs.destroy = ripngd_instance_static_route_destroy, .cbs.cli_show = cli_show_ripng_route, }, { .xpath = "/frr-ripngd:ripngd/instance/aggregate-address", .cbs.create = ripngd_instance_aggregate_address_create, - .cbs.destroy = ripngd_instance_aggregate_address_delete, + .cbs.destroy = ripngd_instance_aggregate_address_destroy, .cbs.cli_show = cli_show_ripng_aggregate_address, }, { @@ -942,48 +1113,48 @@ const struct frr_yang_module_info frr_ripngd_info = { .cbs.modify = ripngd_instance_timers_update_interval_modify, }, { - .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor", - .cbs.get_next = ripngd_state_neighbors_neighbor_get_next, - .cbs.get_keys = ripngd_state_neighbors_neighbor_get_keys, - .cbs.lookup_entry = ripngd_state_neighbors_neighbor_lookup_entry, + .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor", + .cbs.get_next = ripngd_instance_state_neighbors_neighbor_get_next, + .cbs.get_keys = ripngd_instance_state_neighbors_neighbor_get_keys, + .cbs.lookup_entry = ripngd_instance_state_neighbors_neighbor_lookup_entry, }, { - .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/address", - .cbs.get_elem = ripngd_state_neighbors_neighbor_address_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/address", + .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_address_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/last-update", - .cbs.get_elem = ripngd_state_neighbors_neighbor_last_update_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/last-update", + .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_last_update_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-packets-rcvd", - .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_packets_rcvd_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-packets-rcvd", + .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_bad_packets_rcvd_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/neighbors/neighbor/bad-routes-rcvd", - .cbs.get_elem = ripngd_state_neighbors_neighbor_bad_routes_rcvd_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/neighbors/neighbor/bad-routes-rcvd", + .cbs.get_elem = ripngd_instance_state_neighbors_neighbor_bad_routes_rcvd_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/routes/route", - .cbs.get_next = ripngd_state_routes_route_get_next, - .cbs.get_keys = ripngd_state_routes_route_get_keys, - .cbs.lookup_entry = ripngd_state_routes_route_lookup_entry, + .xpath = "/frr-ripngd:ripngd/instance/state/routes/route", + .cbs.get_next = ripngd_instance_state_routes_route_get_next, + .cbs.get_keys = ripngd_instance_state_routes_route_get_keys, + .cbs.lookup_entry = ripngd_instance_state_routes_route_lookup_entry, }, { - .xpath = "/frr-ripngd:ripngd/state/routes/route/prefix", - .cbs.get_elem = ripngd_state_routes_route_prefix_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/prefix", + .cbs.get_elem = ripngd_instance_state_routes_route_prefix_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/routes/route/next-hop", - .cbs.get_elem = ripngd_state_routes_route_next_hop_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/next-hop", + .cbs.get_elem = ripngd_instance_state_routes_route_next_hop_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/routes/route/interface", - .cbs.get_elem = ripngd_state_routes_route_interface_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/interface", + .cbs.get_elem = ripngd_instance_state_routes_route_interface_get_elem, }, { - .xpath = "/frr-ripngd:ripngd/state/routes/route/metric", - .cbs.get_elem = ripngd_state_routes_route_metric_get_elem, + .xpath = "/frr-ripngd:ripngd/instance/state/routes/route/metric", + .cbs.get_elem = ripngd_instance_state_routes_route_metric_get_elem, }, { .xpath = "/frr-ripngd:clear-ripng-route", diff --git a/ripngd/ripng_offset.c b/ripngd/ripng_offset.c index 278df7589..41ba2360b 100644 --- a/ripngd/ripng_offset.c +++ b/ripngd/ripng_offset.c @@ -33,29 +33,29 @@ #include "ripngd/ripngd.h" -static struct list *ripng_offset_list_master; - #define OFFSET_LIST_IN_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].alist_name) #define OFFSET_LIST_IN_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_IN].metric) #define OFFSET_LIST_OUT_NAME(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].alist_name) #define OFFSET_LIST_OUT_METRIC(O) ((O)->direct[RIPNG_OFFSET_LIST_OUT].metric) -struct ripng_offset_list *ripng_offset_list_new(const char *ifname) +struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng, + const char *ifname) { struct ripng_offset_list *new; new = XCALLOC(MTYPE_RIPNG_OFFSET_LIST, sizeof(struct ripng_offset_list)); + new->ripng = ripng; new->ifname = strdup(ifname); - listnode_add_sort(ripng_offset_list_master, new); + listnode_add_sort(ripng->offset_list_master, new); return new; } void ripng_offset_list_del(struct ripng_offset_list *offset) { - listnode_delete(ripng_offset_list_master, offset); + listnode_delete(offset->ripng->offset_list_master, offset); if (OFFSET_LIST_IN_NAME(offset)) free(OFFSET_LIST_IN_NAME(offset)); if (OFFSET_LIST_OUT_NAME(offset)) @@ -64,12 +64,14 @@ void ripng_offset_list_del(struct ripng_offset_list *offset) XFREE(MTYPE_RIPNG_OFFSET_LIST, offset); } -struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) +struct ripng_offset_list *ripng_offset_list_lookup(struct ripng *ripng, + const char *ifname) { struct ripng_offset_list *offset; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(ripng_offset_list_master, node, nnode, offset)) { + for (ALL_LIST_ELEMENTS(ripng->offset_list_master, node, nnode, + offset)) { if (strcmp(offset->ifname, ifname) == 0) return offset; } @@ -77,14 +79,14 @@ struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname) } /* If metric is modifed return 1. */ -int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, - uint8_t *metric) +int ripng_offset_list_apply_in(struct ripng *ripng, struct prefix_ipv6 *p, + struct interface *ifp, uint8_t *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ - offset = ripng_offset_list_lookup(ifp->name); + offset = ripng_offset_list_lookup(ripng, ifp->name); if (offset && OFFSET_LIST_IN_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_IN_NAME(offset)); @@ -98,7 +100,7 @@ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, return 0; } /* Look up offset-list without interface name. */ - offset = ripng_offset_list_lookup("*"); + offset = ripng_offset_list_lookup(ripng, "*"); if (offset && OFFSET_LIST_IN_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_IN_NAME(offset)); @@ -115,14 +117,14 @@ int ripng_offset_list_apply_in(struct prefix_ipv6 *p, struct interface *ifp, } /* If metric is modifed return 1. */ -int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, - uint8_t *metric) +int ripng_offset_list_apply_out(struct ripng *ripng, struct prefix_ipv6 *p, + struct interface *ifp, uint8_t *metric) { struct ripng_offset_list *offset; struct access_list *alist; /* Look up offset-list with interface name. */ - offset = ripng_offset_list_lookup(ifp->name); + offset = ripng_offset_list_lookup(ripng, ifp->name); if (offset && OFFSET_LIST_OUT_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_OUT_NAME(offset)); @@ -137,7 +139,7 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, } /* Look up offset-list without interface name. */ - offset = ripng_offset_list_lookup("*"); + offset = ripng_offset_list_lookup(ripng, "*"); if (offset && OFFSET_LIST_OUT_NAME(offset)) { alist = access_list_lookup(AFI_IP6, OFFSET_LIST_OUT_NAME(offset)); @@ -153,26 +155,7 @@ int ripng_offset_list_apply_out(struct prefix_ipv6 *p, struct interface *ifp, return 0; } -static int offset_list_cmp(struct ripng_offset_list *o1, - struct ripng_offset_list *o2) +int offset_list_cmp(struct ripng_offset_list *o1, struct ripng_offset_list *o2) { return strcmp(o1->ifname, o2->ifname); } - -void ripng_offset_init(void) -{ - ripng_offset_list_master = list_new(); - ripng_offset_list_master->cmp = - (int (*)(void *, void *))offset_list_cmp; - ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del; -} - -void ripng_offset_clean(void) -{ - list_delete(&ripng_offset_list_master); - - ripng_offset_list_master = list_new(); - ripng_offset_list_master->cmp = - (int (*)(void *, void *))offset_list_cmp; - ripng_offset_list_master->del = (void (*)(void *))ripng_offset_list_del; -} diff --git a/ripngd/ripng_peer.c b/ripngd/ripng_peer.c index 756162d65..537600774 100644 --- a/ripngd/ripng_peer.c +++ b/ripngd/ripng_peer.c @@ -34,10 +34,6 @@ #include "ripngd/ripngd.h" #include "ripngd/ripng_nexthop.h" - -/* Linked list of RIPng peer. */ -struct list *peer_list; - static struct ripng_peer *ripng_peer_new(void) { return XCALLOC(MTYPE_RIPNG_PEER, sizeof(struct ripng_peer)); @@ -45,27 +41,29 @@ static struct ripng_peer *ripng_peer_new(void) static void ripng_peer_free(struct ripng_peer *peer) { + RIPNG_TIMER_OFF(peer->t_timeout); XFREE(MTYPE_RIPNG_PEER, peer); } -struct ripng_peer *ripng_peer_lookup(struct in6_addr *addr) +struct ripng_peer *ripng_peer_lookup(struct ripng *ripng, struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) { + for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) { if (IPV6_ADDR_SAME(&peer->addr, addr)) return peer; } return NULL; } -struct ripng_peer *ripng_peer_lookup_next(struct in6_addr *addr) +struct ripng_peer *ripng_peer_lookup_next(struct ripng *ripng, + struct in6_addr *addr) { struct ripng_peer *peer; struct listnode *node, *nnode; - for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) { + for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) { if (addr6_cmp(&peer->addr, addr) > 0) return peer; } @@ -80,26 +78,28 @@ static int ripng_peer_timeout(struct thread *t) struct ripng_peer *peer; peer = THREAD_ARG(t); - listnode_delete(peer_list, peer); + listnode_delete(peer->ripng->peer_list, peer); ripng_peer_free(peer); return 0; } /* Get RIPng peer. At the same time update timeout thread. */ -static struct ripng_peer *ripng_peer_get(struct in6_addr *addr) +static struct ripng_peer *ripng_peer_get(struct ripng *ripng, + struct in6_addr *addr) { struct ripng_peer *peer; - peer = ripng_peer_lookup(addr); + peer = ripng_peer_lookup(ripng, addr); if (peer) { if (peer->t_timeout) thread_cancel(peer->t_timeout); } else { peer = ripng_peer_new(); - peer->addr = *addr; /* XXX */ - listnode_add_sort(peer_list, peer); + peer->ripng = ripng; + peer->addr = *addr; + listnode_add_sort(ripng->peer_list, peer); } /* Update timeout thread. */ @@ -113,24 +113,25 @@ static struct ripng_peer *ripng_peer_get(struct in6_addr *addr) return peer; } -void ripng_peer_update(struct sockaddr_in6 *from, uint8_t version) +void ripng_peer_update(struct ripng *ripng, struct sockaddr_in6 *from, + uint8_t version) { struct ripng_peer *peer; - peer = ripng_peer_get(&from->sin6_addr); + peer = ripng_peer_get(ripng, &from->sin6_addr); peer->version = version; } -void ripng_peer_bad_route(struct sockaddr_in6 *from) +void ripng_peer_bad_route(struct ripng *ripng, struct sockaddr_in6 *from) { struct ripng_peer *peer; - peer = ripng_peer_get(&from->sin6_addr); + peer = ripng_peer_get(ripng, &from->sin6_addr); peer->recv_badroutes++; } -void ripng_peer_bad_packet(struct sockaddr_in6 *from) +void ripng_peer_bad_packet(struct ripng *ripng, struct sockaddr_in6 *from) { struct ripng_peer *peer; - peer = ripng_peer_get(&from->sin6_addr); + peer = ripng_peer_get(ripng, &from->sin6_addr); peer->recv_badpackets++; } @@ -163,14 +164,14 @@ static char *ripng_peer_uptime(struct ripng_peer *peer, char *buf, size_t len) return buf; } -void ripng_peer_display(struct vty *vty) +void ripng_peer_display(struct vty *vty, struct ripng *ripng) { struct ripng_peer *peer; struct listnode *node, *nnode; #define RIPNG_UPTIME_LEN 25 char timebuf[RIPNG_UPTIME_LEN]; - for (ALL_LIST_ELEMENTS(peer_list, node, nnode, peer)) { + for (ALL_LIST_ELEMENTS(ripng->peer_list, node, nnode, peer)) { vty_out(vty, " %s \n%14s %10d %10d %10d %s\n", inet6_ntoa(peer->addr), " ", peer->recv_badpackets, peer->recv_badroutes, ZEBRA_RIPNG_DISTANCE_DEFAULT, @@ -178,13 +179,12 @@ void ripng_peer_display(struct vty *vty) } } -static int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2) +int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2) { return memcmp(&p1->addr, &p2->addr, sizeof(struct in6_addr)); } -void ripng_peer_init(void) +void ripng_peer_list_del(void *arg) { - peer_list = list_new(); - peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp; + ripng_peer_free(arg); } diff --git a/ripngd/ripng_route.c b/ripngd/ripng_route.c index f66a0b952..1bf1007fe 100644 --- a/ripngd/ripng_route.c +++ b/ripngd/ripng_route.c @@ -86,7 +86,7 @@ void ripng_aggregate_decrement_list(struct agg_node *child, struct list *list) } /* RIPng routes treatment. */ -int ripng_aggregate_add(struct prefix *p) +int ripng_aggregate_add(struct ripng *ripng, struct prefix *p) { struct agg_node *top; struct agg_node *rp; @@ -124,7 +124,7 @@ int ripng_aggregate_add(struct prefix *p) } /* Delete RIPng static route. */ -int ripng_aggregate_delete(struct prefix *p) +int ripng_aggregate_delete(struct ripng *ripng, struct prefix *p) { struct agg_node *top; struct agg_node *rp; diff --git a/ripngd/ripng_route.h b/ripngd/ripng_route.h index e402f4a66..afc1d1cbc 100644 --- a/ripngd/ripng_route.h +++ b/ripngd/ripng_route.h @@ -48,8 +48,8 @@ extern void ripng_aggregate_decrement(struct agg_node *rp, struct ripng_info *rinfo); extern void ripng_aggregate_decrement_list(struct agg_node *rp, struct list *list); -extern int ripng_aggregate_add(struct prefix *p); -extern int ripng_aggregate_delete(struct prefix *p); +extern int ripng_aggregate_add(struct ripng *ripng, struct prefix *p); +extern int ripng_aggregate_delete(struct ripng *ripng, struct prefix *p); extern void ripng_aggregate_free(struct ripng_aggregate *aggregate); #endif /* _ZEBRA_RIPNG_ROUTE_H */ diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index c68c066f0..cf60de2de 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -37,7 +37,8 @@ struct zclient *zclient = NULL; /* Send ECMP routes to zebra. */ -static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd) +static void ripng_zebra_ipv6_send(struct ripng *ripng, struct agg_node *rp, + uint8_t cmd) { struct list *list = (struct list *)rp->info; struct zapi_route api; @@ -47,7 +48,7 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd) int count = 0; memset(&api, 0, sizeof(api)); - api.vrf_id = VRF_DEFAULT; + api.vrf_id = ripng->vrf->vrf_id; api.type = ZEBRA_ROUTE_RIPNG; api.safi = SAFI_UNICAST; api.prefix = rp->p; @@ -57,7 +58,7 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd) if (count >= MULTIPATH_NUM) break; api_nh = &api.nexthops[count]; - api_nh->vrf_id = VRF_DEFAULT; + api_nh->vrf_id = ripng->vrf->vrf_id; api_nh->gate.ipv6 = rinfo->nexthop; api_nh->ifindex = rinfo->ifindex; api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX; @@ -100,25 +101,30 @@ static void ripng_zebra_ipv6_send(struct agg_node *rp, uint8_t cmd) } /* Add/update ECMP routes to zebra. */ -void ripng_zebra_ipv6_add(struct agg_node *rp) +void ripng_zebra_ipv6_add(struct ripng *ripng, struct agg_node *rp) { - ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_ADD); + ripng_zebra_ipv6_send(ripng, rp, ZEBRA_ROUTE_ADD); } /* Delete ECMP routes from zebra. */ -void ripng_zebra_ipv6_delete(struct agg_node *rp) +void ripng_zebra_ipv6_delete(struct ripng *ripng, struct agg_node *rp) { - ripng_zebra_ipv6_send(rp, ZEBRA_ROUTE_DELETE); + ripng_zebra_ipv6_send(ripng, rp, ZEBRA_ROUTE_DELETE); } /* Zebra route add and delete treatment. */ static int ripng_zebra_read_route(int command, struct zclient *zclient, zebra_size_t length, vrf_id_t vrf_id) { + struct ripng *ripng; struct zapi_route api; struct in6_addr nexthop; unsigned long ifindex; + ripng = ripng_lookup_by_vrf_id(vrf_id); + if (!ripng) + return 0; + if (zapi_route_decode(zclient->ibuf, &api) < 0) return -1; @@ -133,69 +139,97 @@ static int ripng_zebra_read_route(int command, struct zclient *zclient, ifindex = api.nexthops[0].ifindex; if (command == ZEBRA_REDISTRIBUTE_ROUTE_ADD) - ripng_redistribute_add(api.type, RIPNG_ROUTE_REDISTRIBUTE, + ripng_redistribute_add(ripng, api.type, + RIPNG_ROUTE_REDISTRIBUTE, (struct prefix_ipv6 *)&api.prefix, ifindex, &nexthop, api.tag); else - ripng_redistribute_delete(api.type, RIPNG_ROUTE_REDISTRIBUTE, - (struct prefix_ipv6 *)&api.prefix, - ifindex); + ripng_redistribute_delete( + ripng, api.type, RIPNG_ROUTE_REDISTRIBUTE, + (struct prefix_ipv6 *)&api.prefix, ifindex); return 0; } -void ripng_redistribute_conf_update(int type) +void ripng_redistribute_conf_update(struct ripng *ripng, int type) { zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP6, type, 0, - VRF_DEFAULT); + ripng->vrf->vrf_id); } -void ripng_redistribute_conf_delete(int type) +void ripng_redistribute_conf_delete(struct ripng *ripng, int type) { if (zclient->sock > 0) zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, - AFI_IP6, type, 0, VRF_DEFAULT); + AFI_IP6, type, 0, ripng->vrf->vrf_id); - ripng_redistribute_withdraw(type); + ripng_redistribute_withdraw(ripng, type); } -int ripng_redistribute_check(int type) +int ripng_redistribute_check(struct ripng *ripng, int type) { - return vrf_bitmap_check(zclient->redist[AFI_IP6][type], VRF_DEFAULT); + return ripng->redist[type].enabled; } -void ripng_redistribute_clean(void) +void ripng_redistribute_enable(struct ripng *ripng) { for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (!vrf_bitmap_check(zclient->redist[AFI_IP6][i], VRF_DEFAULT)) + if (!ripng_redistribute_check(ripng, i)) continue; - if (zclient->sock > 0) - zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, - zclient, AFI_IP6, i, 0, - VRF_DEFAULT); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_ADD, zclient, + AFI_IP6, i, 0, ripng->vrf->vrf_id); + } +} - vrf_bitmap_unset(zclient->redist[AFI_IP6][i], VRF_DEFAULT); +void ripng_redistribute_disable(struct ripng *ripng) +{ + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (!ripng_redistribute_check(ripng, i)) + continue; - /* Remove the routes from RIP table. */ - ripng_redistribute_withdraw(i); + zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, + AFI_IP6, i, 0, ripng->vrf->vrf_id); } } -void ripng_redistribute_write(struct vty *vty) +void ripng_redistribute_write(struct vty *vty, struct ripng *ripng) { int i; for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { if (i == zclient->redist_default - || !vrf_bitmap_check(zclient->redist[AFI_IP6][i], - VRF_DEFAULT)) + || !ripng_redistribute_check(ripng, i)) continue; vty_out(vty, " %s", zebra_route_string(i)); } } +void ripng_zebra_vrf_register(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: register VRF %s(%u) to zebra", __func__, + vrf->name, vrf->vrf_id); + + zclient_send_reg_requests(zclient, vrf->vrf_id); +} + +void ripng_zebra_vrf_deregister(struct vrf *vrf) +{ + if (vrf->vrf_id == VRF_DEFAULT) + return; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: deregister VRF %s(%u) from zebra.", __func__, + vrf->name, vrf->vrf_id); + + zclient_send_dereg_requests(zclient, vrf->vrf_id); +} + static void ripng_zebra_connected(struct zclient *zclient) { zclient_send_reg_requests(zclient, VRF_DEFAULT); @@ -215,6 +249,7 @@ void zebra_init(struct thread_master *master) zclient->interface_delete = ripng_interface_delete; zclient->interface_address_add = ripng_interface_address_add; zclient->interface_address_delete = ripng_interface_address_delete; + zclient->interface_vrf_update = ripng_interface_vrf_update; zclient->redistribute_route_add = ripng_zebra_read_route; zclient->redistribute_route_del = ripng_zebra_read_route; } diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 9faebcf0d..b36cee2c5 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -43,11 +43,6 @@ #include "ripngd/ripng_debug.h" #include "ripngd/ripng_nexthop.h" -/* RIPng structure which includes many parameters related to RIPng - protocol. If ripng couldn't active or ripng doesn't configured, - ripng->fd must be negative value. */ -struct ripng *ripng = NULL; - enum { ripng_all_route, ripng_changed_route, }; @@ -57,12 +52,23 @@ static void ripng_distribute_update(struct distribute_ctx *ctx, /* Prototypes. */ void ripng_output_process(struct interface *, struct sockaddr_in6 *, int); - +static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf, + int sock); +static void ripng_instance_disable(struct ripng *ripng); int ripng_triggered_update(struct thread *); - static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, struct if_rmap *if_rmap); +/* Generate rb-tree of RIPng instances. */ +static inline int ripng_instance_compare(const struct ripng *a, + const struct ripng *b) +{ + return strcmp(a->vrf_name, b->vrf_name); +} +RB_GENERATE(ripng_instance_head, ripng, entry, ripng_instance_compare) + +struct ripng_instance_head ripng_instances = RB_INITIALIZER(&ripng_instances); + /* RIPng next hop specification. */ struct ripng_nexthop { enum ripng_nexthop_type { @@ -93,19 +99,36 @@ void ripng_info_free(struct ripng_info *rinfo) XFREE(MTYPE_RIPNG_ROUTE, rinfo); } +struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo) +{ + return agg_get_table_info(agg_get_table(rinfo->rp)); +} + /* Create ripng socket. */ -int ripng_make_socket(void) +int ripng_make_socket(struct vrf *vrf) { int ret; int sock; struct sockaddr_in6 ripaddr; - - sock = socket(AF_INET6, SOCK_DGRAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "Can't make ripng socket"); - return sock; + const char *vrf_dev = NULL; + + /* Make datagram socket. */ + if (vrf->vrf_id != VRF_DEFAULT) + vrf_dev = vrf->name; + frr_elevate_privs(&ripngd_privs) + { + sock = vrf_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP, + vrf->vrf_id, vrf_dev); + if (sock < 0) { + flog_err_sys(EC_LIB_SOCKET, + "Cannot create UDP socket: %s", + safe_strerror(errno)); + return -1; + } } + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); setsockopt_so_recvbuf(sock, 8096); ret = setsockopt_ipv6_pktinfo(sock, 1); if (ret < 0) @@ -151,11 +174,13 @@ error: int ripng_send_packet(caddr_t buf, int bufsize, struct sockaddr_in6 *to, struct interface *ifp) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; int ret; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsgptr; - char adata[256]; + char adata[256] = {}; struct in6_pktinfo *pkt; struct sockaddr_in6 addr; @@ -424,13 +449,14 @@ static int ripng_garbage_collect(struct thread *t) return 0; } -static void ripng_timeout_update(struct ripng_info *rinfo); +static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo); /* Add new route to the ECMP list. * RETURN: the new entry added in the list, or NULL if it is not the first * entry and ECMP is not allowed. */ -struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new) +struct ripng_info *ripng_ecmp_add(struct ripng *ripng, + struct ripng_info *rinfo_new) { struct agg_node *rp = rinfo_new->rp; struct ripng_info *rinfo = NULL; @@ -450,8 +476,8 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new) listnode_add(list, rinfo); if (ripng_route_rte(rinfo)) { - ripng_timeout_update(rinfo); - ripng_zebra_ipv6_add(rp); + ripng_timeout_update(ripng, rinfo); + ripng_zebra_ipv6_add(ripng, rp); } ripng_aggregate_increment(rp, rinfo); @@ -461,7 +487,7 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new) SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } @@ -469,7 +495,8 @@ struct ripng_info *ripng_ecmp_add(struct ripng_info *rinfo_new) /* Replace the ECMP list with the new route. * RETURN: the new entry added in the list */ -struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) +struct ripng_info *ripng_ecmp_replace(struct ripng *ripng, + struct ripng_info *rinfo_new) { struct agg_node *rp = rinfo_new->rp; struct list *list = (struct list *)rp->info; @@ -477,7 +504,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) struct listnode *node = NULL, *nextnode = NULL; if (list == NULL || listcount(list) == 0) - return ripng_ecmp_add(rinfo_new); + return ripng_ecmp_add(ripng, rinfo_new); /* Get the first entry */ rinfo = listgetdata(listhead(list)); @@ -485,7 +512,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) /* Learnt route replaced by a local one. Delete it from zebra. */ if (ripng_route_rte(rinfo) && !ripng_route_rte(rinfo_new)) if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) - ripng_zebra_ipv6_delete(rp); + ripng_zebra_ipv6_delete(ripng, rp); if (rinfo->metric != RIPNG_METRIC_INFINITY) ripng_aggregate_decrement_list(rp, list); @@ -504,9 +531,9 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) memcpy(rinfo, rinfo_new, sizeof(struct ripng_info)); if (ripng_route_rte(rinfo)) { - ripng_timeout_update(rinfo); + ripng_timeout_update(ripng, rinfo); /* The ADD message implies an update. */ - ripng_zebra_ipv6_add(rp); + ripng_zebra_ipv6_add(ripng, rp); } ripng_aggregate_increment(rp, rinfo); @@ -515,7 +542,7 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } @@ -526,7 +553,8 @@ struct ripng_info *ripng_ecmp_replace(struct ripng_info *rinfo_new) * the entry - the entry is the last one in the list; its metric is set * to INFINITY, and the garbage collector is started for it */ -struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo) +struct ripng_info *ripng_ecmp_delete(struct ripng *ripng, + struct ripng_info *rinfo) { struct agg_node *rp = rinfo->rp; struct list *list = (struct list *)rp->info; @@ -544,7 +572,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo) if (ripng_route_rte(rinfo) && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) /* The ADD message implies the update. */ - ripng_zebra_ipv6_add(rp); + ripng_zebra_ipv6_add(ripng, rp); ripng_info_free(rinfo); rinfo = NULL; } else { @@ -560,7 +588,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo) if (ripng_route_rte(rinfo) && CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB)) - ripng_zebra_ipv6_delete(rp); + ripng_zebra_ipv6_delete(ripng, rp); } /* Set the route change flag on the first entry. */ @@ -568,7 +596,7 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo) SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); return rinfo; } @@ -576,16 +604,20 @@ struct ripng_info *ripng_ecmp_delete(struct ripng_info *rinfo) /* Timeout RIPng routes. */ static int ripng_timeout(struct thread *t) { - ripng_ecmp_delete((struct ripng_info *)THREAD_ARG(t)); + struct ripng_info *rinfo = THREAD_ARG(t); + struct ripng *ripng = ripng_info_get_instance(rinfo); + + ripng_ecmp_delete(ripng, rinfo); + return 0; } -static void ripng_timeout_update(struct ripng_info *rinfo) +static void ripng_timeout_update(struct ripng *ripng, struct ripng_info *rinfo) { if (rinfo->metric != RIPNG_METRIC_INFINITY) { RIPNG_TIMER_OFF(rinfo->t_timeout); - RIPNG_TIMER_ON(rinfo->t_timeout, ripng_timeout, - ripng->timeout_time); + thread_add_timer(master, ripng_timeout, rinfo, + ripng->timeout_time, &rinfo->t_timeout); } } @@ -625,7 +657,7 @@ static int ripng_filter(int ripng_distribute, struct prefix_ipv6 *p, } /* All interface filter check. */ - dist = distribute_lookup(ripng->distribute_ctx, NULL); + dist = distribute_lookup(ri->ripng->distribute_ctx, NULL); if (dist) { if (dist->list[distribute]) { alist = access_list_lookup(AFI_IP6, @@ -673,6 +705,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, struct agg_node *rp; struct ripng_info *rinfo = NULL, newinfo; struct ripng_interface *ri; + struct ripng *ripng; struct in6_addr *nexthop; int same = 0; struct list *list = NULL; @@ -690,9 +723,10 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, apply_mask_ipv6. */ apply_mask_ipv6(&p); - /* Apply input filters. */ ri = ifp->info; + ripng = ri->ripng; + /* Apply input filters. */ ret = ripng_filter(RIPNG_FILTER_IN, &p, ri); if (ret < 0) return; @@ -760,7 +794,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, **/ /* Zebra ripngd can handle offset-list in. */ - ret = ripng_offset_list_apply_in(&p, ifp, &rte->metric); + ret = ripng_offset_list_apply_in(ripng, &p, ifp, &rte->metric); /* If offset-list does not modify the metric use interface's * one. */ @@ -846,7 +880,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, infinity (there is no point in adding a route which unusable). */ if (rte->metric != RIPNG_METRIC_INFINITY) - ripng_ecmp_add(&newinfo); + ripng_ecmp_add(ripng, &newinfo); else agg_unlock_node(rp); } else { @@ -871,7 +905,7 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, && rinfo->t_timeout && (thread_timer_remain_second(rinfo->t_timeout) < (ripng->timeout_time / 2))) { - ripng_ecmp_replace(&newinfo); + ripng_ecmp_replace(ripng, &newinfo); } /* Next, compare the metrics. If the datagram is from the same router as the existing route, and the new metric is different @@ -881,17 +915,17 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, || rte->metric < rinfo->metric) { if (listcount(list) == 1) { if (newinfo.metric != RIPNG_METRIC_INFINITY) - ripng_ecmp_replace(&newinfo); + ripng_ecmp_replace(ripng, &newinfo); else - ripng_ecmp_delete(rinfo); + ripng_ecmp_delete(ripng, rinfo); } else { if (newinfo.metric < rinfo->metric) - ripng_ecmp_replace(&newinfo); + ripng_ecmp_replace(ripng, &newinfo); else /* newinfo.metric > rinfo->metric */ - ripng_ecmp_delete(rinfo); + ripng_ecmp_delete(ripng, rinfo); } } else /* same & no change */ - ripng_timeout_update(rinfo); + ripng_timeout_update(ripng, rinfo); /* Unlock tempolary lock of the route. */ agg_unlock_node(rp); @@ -899,9 +933,9 @@ static void ripng_route_process(struct rte *rte, struct sockaddr_in6 *from, } /* Add redistributed route to RIPng table. */ -void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p, - ifindex_t ifindex, struct in6_addr *nexthop, - route_tag_t tag) +void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type, + struct prefix_ipv6 *p, ifindex_t ifindex, + struct in6_addr *nexthop, route_tag_t tag) { struct agg_node *rp; struct ripng_info *rinfo = NULL, newinfo; @@ -950,31 +984,31 @@ void ripng_redistribute_add(int type, int sub_type, struct prefix_ipv6 *p, } } - ripng_ecmp_replace(&newinfo); + ripng_ecmp_replace(ripng, &newinfo); agg_unlock_node(rp); } else - ripng_ecmp_add(&newinfo); + ripng_ecmp_add(ripng, &newinfo); if (IS_RIPNG_DEBUG_EVENT) { if (!nexthop) zlog_debug( "Redistribute new prefix %s/%d on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex, VRF_DEFAULT)); + ifindex2ifname(ifindex, ripng->vrf->vrf_id)); else zlog_debug( "Redistribute new prefix %s/%d with nexthop %s on the interface %s", inet6_ntoa(p->prefix), p->prefixlen, inet6_ntoa(*nexthop), - ifindex2ifname(ifindex, VRF_DEFAULT)); + ifindex2ifname(ifindex, ripng->vrf->vrf_id)); } - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); } /* Delete redistributed route to RIPng table. */ -void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p, - ifindex_t ifindex) +void ripng_redistribute_delete(struct ripng *ripng, int type, int sub_type, + struct prefix_ipv6 *p, ifindex_t ifindex) { struct agg_node *rp; struct ripng_info *rinfo; @@ -1012,10 +1046,11 @@ void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p, "infinity metric [delete]", inet6_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(ifindex, - VRF_DEFAULT)); + ifindex2ifname( + ifindex, + ripng->vrf->vrf_id)); - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); } } agg_unlock_node(rp); @@ -1023,15 +1058,12 @@ void ripng_redistribute_delete(int type, int sub_type, struct prefix_ipv6 *p, } /* Withdraw redistributed route. */ -void ripng_redistribute_withdraw(int type) +void ripng_redistribute_withdraw(struct ripng *ripng, int type) { struct agg_node *rp; struct ripng_info *rinfo = NULL; struct list *list = NULL; - if (!ripng) - return; - for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) if ((list = rp->info) != NULL) { rinfo = listgetdata(listhead(list)); @@ -1057,11 +1089,12 @@ void ripng_redistribute_withdraw(int type) "Poisone %s/%d on the interface %s [withdraw]", inet6_ntoa(p->prefix), p->prefixlen, - ifindex2ifname(rinfo->ifindex, - VRF_DEFAULT)); + ifindex2ifname( + rinfo->ifindex, + ripng->vrf->vrf_id)); } - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); } } } @@ -1071,6 +1104,8 @@ static void ripng_response_process(struct ripng_packet *packet, int size, struct sockaddr_in6 *from, struct interface *ifp, int hoplimit) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; caddr_t lim; struct rte *rte; struct ripng_nexthop nexthop; @@ -1080,7 +1115,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, if (ntohs(from->sin6_port) != RIPNG_PORT_DEFAULT) { zlog_warn("RIPng packet comes from non RIPng port %d from %s", ntohs(from->sin6_port), inet6_ntoa(from->sin6_addr)); - ripng_peer_bad_packet(from); + ripng_peer_bad_packet(ripng, from); return; } @@ -1090,7 +1125,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, if (!IN6_IS_ADDR_LINKLOCAL(&from->sin6_addr)) { zlog_warn("RIPng packet comes from non link local address %s", inet6_ntoa(from->sin6_addr)); - ripng_peer_bad_packet(from); + ripng_peer_bad_packet(ripng, from); return; } @@ -1103,7 +1138,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, zlog_warn( "RIPng packet comes from my own link local address %s", inet6_ntoa(from->sin6_addr)); - ripng_peer_bad_packet(from); + ripng_peer_bad_packet(ripng, from); return; } @@ -1115,12 +1150,12 @@ static void ripng_response_process(struct ripng_packet *packet, int size, zlog_warn( "RIPng packet comes with non 255 hop count %d from %s", hoplimit, inet6_ntoa(from->sin6_addr)); - ripng_peer_bad_packet(from); + ripng_peer_bad_packet(ripng, from); return; } /* Update RIPng peer. */ - ripng_peer_update(from, packet->version); + ripng_peer_update(ripng, from, packet->version); /* Reset nexthop. */ memset(&nexthop, 0, sizeof(struct ripng_nexthop)); @@ -1148,7 +1183,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, "Destination prefix is a multicast address %s/%d [%d]", inet6_ntoa(rte->addr), rte->prefixlen, rte->metric); - ripng_peer_bad_route(from); + ripng_peer_bad_route(ripng, from); continue; } if (IN6_IS_ADDR_LINKLOCAL(&rte->addr)) { @@ -1156,7 +1191,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, "Destination prefix is a link-local address %s/%d [%d]", inet6_ntoa(rte->addr), rte->prefixlen, rte->metric); - ripng_peer_bad_route(from); + ripng_peer_bad_route(ripng, from); continue; } if (IN6_IS_ADDR_LOOPBACK(&rte->addr)) { @@ -1164,7 +1199,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, "Destination prefix is a loopback address %s/%d [%d]", inet6_ntoa(rte->addr), rte->prefixlen, rte->metric); - ripng_peer_bad_route(from); + ripng_peer_bad_route(ripng, from); continue; } @@ -1174,7 +1209,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, zlog_warn("Invalid prefix length %s/%d from %s%%%s", inet6_ntoa(rte->addr), rte->prefixlen, inet6_ntoa(from->sin6_addr), ifp->name); - ripng_peer_bad_route(from); + ripng_peer_bad_route(ripng, from); continue; } @@ -1182,7 +1217,7 @@ static void ripng_response_process(struct ripng_packet *packet, int size, if (!(rte->metric >= 1 && rte->metric <= 16)) { zlog_warn("Invalid metric %d from %s%%%s", rte->metric, inet6_ntoa(from->sin6_addr), ifp->name); - ripng_peer_bad_route(from); + ripng_peer_bad_route(ripng, from); continue; } @@ -1200,6 +1235,7 @@ static void ripng_request_process(struct ripng_packet *packet, int size, struct sockaddr_in6 *from, struct interface *ifp) { + struct ripng *ripng; caddr_t lim; struct rte *rte; struct prefix_ipv6 p; @@ -1215,13 +1251,14 @@ static void ripng_request_process(struct ripng_packet *packet, int size, ri = ifp->info; if (!ri->running) return; + ripng = ri->ripng; /* When passive interface is specified, suppress responses */ if (ri->passive) return; /* RIPng peer update. */ - ripng_peer_update(from, packet->version); + ripng_peer_update(ripng, from, packet->version); lim = ((caddr_t)packet) + size; rte = packet->rte; @@ -1278,6 +1315,7 @@ static void ripng_request_process(struct ripng_packet *packet, int size, /* First entry point of reading RIPng packet. */ static int ripng_read(struct thread *thread) { + struct ripng *ripng = THREAD_ARG(thread); int len; int sock; struct sockaddr_in6 from; @@ -1296,34 +1334,36 @@ static int ripng_read(struct thread *thread) ripng->t_read = NULL; /* Add myself to the next event. */ - ripng_event(RIPNG_READ, sock); + ripng_event(ripng, RIPNG_READ, sock); /* Read RIPng packet. */ len = ripng_recv_packet(sock, STREAM_DATA(ripng->ibuf), STREAM_SIZE(ripng->ibuf), &from, &ifindex, &hoplimit); if (len < 0) { - zlog_warn("RIPng recvfrom failed: %s.", safe_strerror(errno)); + zlog_warn("RIPng recvfrom failed (VRF %s): %s.", + ripng->vrf_name, safe_strerror(errno)); return len; } /* Check RTE boundary. RTE size (Packet length - RIPng header size (4)) must be multiple size of one RTE size (20). */ if (((len - 4) % 20) != 0) { - zlog_warn("RIPng invalid packet size %d from %s", len, - inet6_ntoa(from.sin6_addr)); - ripng_peer_bad_packet(&from); + zlog_warn("RIPng invalid packet size %d from %s (VRF %s)", len, + inet6_ntoa(from.sin6_addr), ripng->vrf_name); + ripng_peer_bad_packet(ripng, &from); return 0; } packet = (struct ripng_packet *)STREAM_DATA(ripng->ibuf); - ifp = if_lookup_by_index(ifindex, VRF_DEFAULT); + ifp = if_lookup_by_index(ifindex, ripng->vrf->vrf_id); /* RIPng packet received. */ if (IS_RIPNG_DEBUG_EVENT) - zlog_debug("RIPng packet received from %s port %d on %s", - inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port), - ifp ? ifp->name : "unknown"); + zlog_debug( + "RIPng packet received from %s port %d on %s (VRF %s)", + inet6_ntoa(from.sin6_addr), ntohs(from.sin6_port), + ifp ? ifp->name : "unknown", ripng->vrf_name); /* Logging before packet checking. */ if (IS_RIPNG_DEBUG_RECV) @@ -1331,17 +1371,18 @@ static int ripng_read(struct thread *thread) /* Packet comes from unknown interface. */ if (ifp == NULL) { - zlog_warn("RIPng packet comes from unknown interface %d", - ifindex); + zlog_warn( + "RIPng packet comes from unknown interface %d (VRF %s)", + ifindex, ripng->vrf_name); return 0; } /* Packet version mismatch checking. */ if (packet->version != ripng->version) { zlog_warn( - "RIPng packet version %d doesn't fit to my version %d", - packet->version, ripng->version); - ripng_peer_bad_packet(&from); + "RIPng packet version %d doesn't fit to my version %d (VRF %s)", + packet->version, ripng->version, ripng->vrf_name); + ripng_peer_bad_packet(ripng, &from); return 0; } @@ -1354,15 +1395,16 @@ static int ripng_read(struct thread *thread) ripng_response_process(packet, len, &from, ifp, hoplimit); break; default: - zlog_warn("Invalid RIPng command %d", packet->command); - ripng_peer_bad_packet(&from); + zlog_warn("Invalid RIPng command %d (VRF %s)", packet->command, + ripng->vrf_name); + ripng_peer_bad_packet(ripng, &from); break; } return 0; } /* Walk down the RIPng routing table then clear changed flag. */ -static void ripng_clear_changed_flag(void) +static void ripng_clear_changed_flag(struct ripng *ripng) { struct agg_node *rp; struct ripng_info *rinfo = NULL; @@ -1383,7 +1425,7 @@ static void ripng_clear_changed_flag(void) enabled interface. */ static int ripng_update(struct thread *t) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct ripng *ripng = THREAD_ARG(t); struct interface *ifp; struct ripng_interface *ri; @@ -1395,7 +1437,7 @@ static int ripng_update(struct thread *t) zlog_debug("RIPng update timer expired!"); /* Supply routes to each interface. */ - FOR_ALL_INTERFACES (vrf, ifp) { + FOR_ALL_INTERFACES (ripng->vrf, ifp) { ri = ifp->info; if (if_is_loopback(ifp) || !if_is_up(ifp)) @@ -1431,7 +1473,7 @@ static int ripng_update(struct thread *t) ripng->trigger = 0; /* Reset flush event. */ - ripng_event(RIPNG_UPDATE_EVENT, 0); + ripng_event(ripng, RIPNG_UPDATE_EVENT, 0); return 0; } @@ -1439,6 +1481,8 @@ static int ripng_update(struct thread *t) /* Triggered update interval timer. */ static int ripng_triggered_interval(struct thread *t) { + struct ripng *ripng = THREAD_ARG(t); + ripng->t_triggered_interval = NULL; if (ripng->trigger) { @@ -1451,7 +1495,7 @@ static int ripng_triggered_interval(struct thread *t) /* Execute triggered update. */ int ripng_triggered_update(struct thread *t) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct ripng *ripng = THREAD_ARG(t); struct interface *ifp; struct ripng_interface *ri; int interval; @@ -1471,7 +1515,7 @@ int ripng_triggered_update(struct thread *t) /* Split Horizon processing is done when generating triggered updates as well as normal updates (see section 2.6). */ - FOR_ALL_INTERFACES (vrf, ifp) { + FOR_ALL_INTERFACES (ripng->vrf, ifp) { ri = ifp->info; if (if_is_loopback(ifp) || !if_is_up(ifp)) @@ -1490,7 +1534,7 @@ int ripng_triggered_update(struct thread *t) /* Once all of the triggered updates have been generated, the route change flags should be cleared. */ - ripng_clear_changed_flag(); + ripng_clear_changed_flag(ripng); /* After a triggered update is sent, a timer should be set for a random interval between 1 and 5 seconds. If other changes that @@ -1499,7 +1543,7 @@ int ripng_triggered_update(struct thread *t) interval = (random() % 5) + 1; ripng->t_triggered_interval = NULL; - thread_add_timer(master, ripng_triggered_interval, NULL, interval, + thread_add_timer(master, ripng_triggered_interval, ripng, interval, &ripng->t_triggered_interval); return 0; @@ -1537,6 +1581,7 @@ int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p, void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, int route_type) { + struct ripng *ripng; int ret; struct agg_node *rp; struct ripng_info *rinfo; @@ -1556,8 +1601,9 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, ifp->name); } - /* Get RIPng interface. */ + /* Get RIPng interface and instance. */ ri = ifp->info; + ripng = ri->ripng; ripng_rte_list = ripng_rte_new(); @@ -1637,10 +1683,11 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, } /* Redistribute route-map. */ - if (ripng->route_map[rinfo->type].name) { - ret = route_map_apply( - ripng->route_map[rinfo->type].map, - (struct prefix *)p, RMAP_RIPNG, rinfo); + if (ripng->redist[rinfo->type].route_map.name) { + ret = route_map_apply(ripng->redist[rinfo->type] + .route_map.map, + (struct prefix *)p, + RMAP_RIPNG, rinfo); if (ret == RMAP_DENYMATCH) { if (IS_RIPNG_DEBUG_PACKET) @@ -1655,10 +1702,10 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, /* When the route-map does not set metric. */ if (!rinfo->metric_set) { /* If the redistribute metric is set. */ - if (ripng->route_map[rinfo->type].metric_config + if (ripng->redist[rinfo->type].metric_config && rinfo->metric != RIPNG_METRIC_INFINITY) { rinfo->metric_out = - ripng->route_map[rinfo->type] + ripng->redist[rinfo->type] .metric; } else { /* If the route is not connected or @@ -1676,7 +1723,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, /* Apply offset-list */ if (rinfo->metric_out != RIPNG_METRIC_INFINITY) - ripng_offset_list_apply_out(p, ifp, + ripng_offset_list_apply_out(ripng, p, ifp, &rinfo->metric_out); if (rinfo->metric_out > RIPNG_METRIC_INFINITY) @@ -1769,7 +1816,7 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, /* Apply offset-list */ if (aggregate->metric_out != RIPNG_METRIC_INFINITY) ripng_offset_list_apply_out( - p, ifp, &aggregate->metric_out); + ripng, p, ifp, &aggregate->metric_out); if (aggregate->metric_out > RIPNG_METRIC_INFINITY) aggregate->metric_out = RIPNG_METRIC_INFINITY; @@ -1784,14 +1831,34 @@ void ripng_output_process(struct interface *ifp, struct sockaddr_in6 *to, ripng_rte_free(ripng_rte_list); } +struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id) +{ + struct vrf *vrf; + + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf) + return NULL; + + return vrf->info; +} + +struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name) +{ + struct ripng ripng; + + ripng.vrf_name = (char *)vrf_name; + + return RB_FIND(ripng_instance_head, &ripng_instances, &ripng); +} + /* Create new RIPng instance and set it to global variable. */ -int ripng_create(int socket) +struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, int socket) { - /* ripng should be NULL. */ - assert(ripng == NULL); + struct ripng *ripng; /* Allocaste RIPng instance. */ ripng = XCALLOC(MTYPE_RIPNG, sizeof(struct ripng)); + ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf_name); /* Default version and timer values. */ ripng->version = RIPNG_V1; @@ -1809,30 +1876,42 @@ int ripng_create(int socket) ripng->ibuf = stream_new(RIPNG_MAX_PACKET_SIZE * 5); ripng->obuf = stream_new(RIPNG_MAX_PACKET_SIZE); - /* Initialize RIPng routig table. */ + /* Initialize RIPng data structures. */ ripng->table = agg_table_init(); - - /* Distribute list install. */ - ripng->distribute_ctx = distribute_list_ctx_create( - vrf_lookup_by_id(VRF_DEFAULT)); + agg_set_table_info(ripng->table, ripng); + ripng->peer_list = list_new(); + ripng->peer_list->cmp = (int (*)(void *, void *))ripng_peer_list_cmp; + ripng->peer_list->del = ripng_peer_list_del; + ripng->enable_if = vector_init(1); + ripng->enable_network = agg_table_init(); + ripng->passive_interface = vector_init(1); + ripng->offset_list_master = list_new(); + ripng->offset_list_master->cmp = + (int (*)(void *, void *))offset_list_cmp; + ripng->offset_list_master->del = + (void (*)(void *))ripng_offset_list_del; + ripng->distribute_ctx = distribute_list_ctx_create(vrf); distribute_list_add_hook(ripng->distribute_ctx, ripng_distribute_update); distribute_list_delete_hook(ripng->distribute_ctx, ripng_distribute_update); /* if rmap install. */ - ripng->if_rmap_ctx = if_rmap_ctx_create(VRF_DEFAULT_NAME); + ripng->if_rmap_ctx = if_rmap_ctx_create(vrf_name); if_rmap_hook_add(ripng->if_rmap_ctx, ripng_if_rmap_update); if_rmap_hook_delete(ripng->if_rmap_ctx, ripng_if_rmap_update); - /* Make socket. */ - ripng->sock = socket; + /* Enable the routing instance if possible. */ + if (vrf && vrf_is_enabled(vrf)) + ripng_instance_enable(ripng, vrf, socket); + else { + ripng->vrf = NULL; + ripng->sock = -1; + } - /* Threads. */ - ripng_event(RIPNG_READ, ripng->sock); - ripng_event(RIPNG_UPDATE_EVENT, 1); + RB_INSERT(ripng_instance_head, &ripng_instances, ripng); - return 0; + return ripng; } /* Send RIPng request to the interface. */ @@ -1869,13 +1948,14 @@ static int ripng_update_jitter(int time) return ((random() % (time + 1)) - (time / 2)); } -void ripng_event(enum ripng_event event, int sock) +void ripng_event(struct ripng *ripng, enum ripng_event event, int sock) { int jitter = 0; switch (event) { case RIPNG_READ: - thread_add_read(master, ripng_read, NULL, sock, &ripng->t_read); + thread_add_read(master, ripng_read, ripng, sock, + &ripng->t_read); break; case RIPNG_UPDATE_EVENT: if (ripng->t_update) { @@ -1886,7 +1966,7 @@ void ripng_event(enum ripng_event event, int sock) jitter = ripng_update_jitter(ripng->update_time); ripng->t_update = NULL; - thread_add_timer(master, ripng_update, NULL, + thread_add_timer(master, ripng_update, ripng, sock ? 2 : ripng->update_time + jitter, &ripng->t_update); break; @@ -1894,7 +1974,7 @@ void ripng_event(enum ripng_event event, int sock) if (ripng->t_triggered_interval) ripng->trigger = 1; else - thread_add_event(master, ripng_triggered_update, NULL, + thread_add_event(master, ripng_triggered_update, ripng, 0, &ripng->t_triggered_update); break; default: @@ -1959,11 +2039,13 @@ static char *ripng_route_subtype_print(struct ripng_info *rinfo) DEFUN (show_ipv6_ripng, show_ipv6_ripng_cmd, - "show ipv6 ripng", + "show ipv6 ripng [vrf NAME]", SHOW_STR IPV6_STR - "Show RIPng routes\n") + "Show RIPng routes\n" + VRF_CMD_HELP_STR) { + struct ripng *ripng; struct agg_node *rp; struct ripng_info *rinfo; struct ripng_aggregate *aggregate; @@ -1971,9 +2053,23 @@ DEFUN (show_ipv6_ripng, struct list *list = NULL; struct listnode *listnode = NULL; int len; + const char *vrf_name; + int idx = 0; - if (!ripng) + if (argv_find(argv, argc, "vrf", &idx)) + vrf_name = argv[idx + 1]->arg; + else + vrf_name = VRF_DEFAULT_NAME; + + ripng = ripng_lookup_by_vrf_name(vrf_name); + if (!ripng) { + vty_out(vty, "%% RIPng instance not found\n"); + return CMD_SUCCESS; + } + if (!ripng->enabled) { + vty_out(vty, "%% RIPng instance is disabled\n"); return CMD_SUCCESS; + } /* Header of display. */ vty_out(vty, @@ -2033,8 +2129,9 @@ DEFUN (show_ipv6_ripng, && (rinfo->sub_type == RIPNG_ROUTE_RTE)) { len = vty_out( vty, "%s", - ifindex2ifname(rinfo->ifindex, - VRF_DEFAULT)); + ifindex2ifname( + rinfo->ifindex, + ripng->vrf->vrf_id)); } else if (rinfo->metric == RIPNG_METRIC_INFINITY) { len = vty_out(vty, "kill"); @@ -2068,17 +2165,32 @@ DEFUN (show_ipv6_ripng, DEFUN (show_ipv6_ripng_status, show_ipv6_ripng_status_cmd, - "show ipv6 ripng status", + "show ipv6 ripng [vrf NAME] status", SHOW_STR IPV6_STR "Show RIPng routes\n" + VRF_CMD_HELP_STR "IPv6 routing protocol process parameters and statistics\n") { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct ripng *ripng; struct interface *ifp; + const char *vrf_name; + int idx = 0; - if (!ripng) + if (argv_find(argv, argc, "vrf", &idx)) + vrf_name = argv[idx + 1]->arg; + else + vrf_name = VRF_DEFAULT_NAME; + + ripng = ripng_lookup_by_vrf_name(vrf_name); + if (!ripng) { + vty_out(vty, "%% RIPng instance not found\n"); + return CMD_SUCCESS; + } + if (!ripng->enabled) { + vty_out(vty, "%% RIPng instance is disabled\n"); return CMD_SUCCESS; + } vty_out(vty, "Routing Protocol is \"RIPng\"\n"); vty_out(vty, " Sending updates every %u seconds with +/-50%%,", @@ -2098,7 +2210,7 @@ DEFUN (show_ipv6_ripng_status, /* Redistribute information. */ vty_out(vty, " Redistributing:"); - ripng_redistribute_write(vty); + ripng_redistribute_write(vty, ripng); vty_out(vty, "\n"); vty_out(vty, " Default version control: send version %d,", @@ -2107,7 +2219,7 @@ DEFUN (show_ipv6_ripng_status, vty_out(vty, " Interface Send Recv\n"); - FOR_ALL_INTERFACES (vrf, ifp) { + FOR_ALL_INTERFACES (ripng->vrf, ifp) { struct ripng_interface *ri; ri = ifp->info; @@ -2120,12 +2232,12 @@ DEFUN (show_ipv6_ripng_status, } vty_out(vty, " Routing for Networks:\n"); - ripng_network_write(vty); + ripng_network_write(vty, ripng); vty_out(vty, " Routing Information Sources:\n"); vty_out(vty, " Gateway BadPackets BadRoutes Distance Last Update\n"); - ripng_peer_display(vty); + ripng_peer_display(vty, ripng); return CMD_SUCCESS; } @@ -2261,7 +2373,7 @@ DEFUN (show_ipv6_protocols, #endif /* Update ECMP routes to zebra when ECMP is disabled. */ -void ripng_ecmp_disable(void) +void ripng_ecmp_disable(struct ripng *ripng) { struct agg_node *rp; struct ripng_info *rinfo, *tmp_rinfo; @@ -2288,30 +2400,36 @@ void ripng_ecmp_disable(void) } /* Update zebra. */ - ripng_zebra_ipv6_add(rp); + ripng_zebra_ipv6_add(ripng, rp); /* Set the route change flag. */ SET_FLAG(rinfo->flags, RIPNG_RTF_CHANGED); /* Signal the output process to trigger an update. */ - ripng_event(RIPNG_TRIGGERED_UPDATE, 0); + ripng_event(ripng, RIPNG_TRIGGERED_UPDATE, 0); } } /* RIPng configuration write function. */ static int ripng_config_write(struct vty *vty) { - struct lyd_node *dnode; + struct ripng *ripng; int write = 0; - dnode = yang_dnode_get(running_config->dnode, - "/frr-ripngd:ripngd/instance"); - if (dnode) { - nb_cli_show_dnode_cmds(vty, dnode, false); + RB_FOREACH(ripng, ripng_instance_head, &ripng_instances) { + char xpath[XPATH_MAXLEN]; + struct lyd_node *dnode; - config_write_distribute(vty, - ripng->distribute_ctx); + snprintf(xpath, sizeof(xpath), + "/frr-ripngd:ripngd/instance[vrf='%s']", + ripng->vrf_name); + dnode = yang_dnode_get(running_config->dnode, xpath); + assert(dnode); + + nb_cli_show_dnode_cmds(vty, dnode, false); + + config_write_distribute(vty, ripng->distribute_ctx); config_write_if_rmap(vty, ripng->if_rmap_ctx); write = 1; @@ -2333,10 +2451,10 @@ static void ripng_distribute_update(struct distribute_ctx *ctx, struct access_list *alist; struct prefix_list *plist; - if (!dist->ifname) + if (!ctx->vrf || !dist->ifname) return; - ifp = if_lookup_by_name(dist->ifname, VRF_DEFAULT); + ifp = if_lookup_by_name(dist->ifname, ctx->vrf->vrf_id); if (ifp == NULL) return; @@ -2385,6 +2503,8 @@ static void ripng_distribute_update(struct distribute_ctx *ctx, void ripng_distribute_update_interface(struct interface *ifp) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct distribute *dist; if (!ripng) @@ -2410,80 +2530,34 @@ static void ripng_distribute_update_all_wrapper(struct access_list *notused) } /* delete all the added ripng routes. */ -void ripng_clean(void) +void ripng_clean(struct ripng *ripng) { - int i; - struct agg_node *rp; - struct ripng_info *rinfo; - struct ripng_aggregate *aggregate; - struct list *list = NULL; - struct listnode *listnode = NULL; - - if (ripng) { - /* Clear RIPng routes */ - for (rp = agg_route_top(ripng->table); rp; - rp = agg_route_next(rp)) { - if ((list = rp->info) != NULL) { - rinfo = listgetdata(listhead(list)); - if (ripng_route_rte(rinfo)) - ripng_zebra_ipv6_delete(rp); - - for (ALL_LIST_ELEMENTS_RO(list, listnode, - rinfo)) { - RIPNG_TIMER_OFF(rinfo->t_timeout); - RIPNG_TIMER_OFF( - rinfo->t_garbage_collect); - ripng_info_free(rinfo); - } - list_delete(&list); - rp->info = NULL; - agg_unlock_node(rp); - } - - if ((aggregate = rp->aggregate) != NULL) { - ripng_aggregate_free(aggregate); - rp->aggregate = NULL; - agg_unlock_node(rp); - } - } - - /* Cancel the RIPng timers */ - RIPNG_TIMER_OFF(ripng->t_update); - RIPNG_TIMER_OFF(ripng->t_triggered_update); - RIPNG_TIMER_OFF(ripng->t_triggered_interval); - - /* Cancel the read thread */ - if (ripng->t_read) { - thread_cancel(ripng->t_read); - ripng->t_read = NULL; - } - - /* Close the RIPng socket */ - if (ripng->sock >= 0) { - close(ripng->sock); - ripng->sock = -1; - } - - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) - if (ripng->route_map[i].name) - free(ripng->route_map[i].name); - - agg_table_finish(ripng->table); - - stream_free(ripng->ibuf); - stream_free(ripng->obuf); - - distribute_list_delete(&ripng->distribute_ctx); - XFREE(MTYPE_RIPNG, ripng); - ripng = NULL; - } /* if (ripng) */ - - ripng_clean_network(); - ripng_passive_interface_clean(); - ripng_offset_clean(); - ripng_interface_clean(); - ripng_redistribute_clean(); - if_rmap_terminate(); + if (ripng->enabled) + ripng_instance_disable(ripng); + + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) + if (ripng->redist[i].route_map.name) + free(ripng->redist[i].route_map.name); + + agg_table_finish(ripng->table); + list_delete(&ripng->peer_list); + distribute_list_delete(&ripng->distribute_ctx); + if_rmap_ctx_delete(ripng->if_rmap_ctx); + + stream_free(ripng->ibuf); + stream_free(ripng->obuf); + + ripng_clean_network(ripng); + ripng_passive_interface_clean(ripng); + vector_free(ripng->enable_if); + agg_table_finish(ripng->enable_network); + vector_free(ripng->passive_interface); + list_delete(&ripng->offset_list_master); + ripng_interface_clean(ripng); + + RB_REMOVE(ripng_instance_head, &ripng_instances, ripng); + XFREE(MTYPE_RIPNG_VRF_NAME, ripng->vrf_name); + XFREE(MTYPE_RIPNG, ripng); } static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, @@ -2524,11 +2598,11 @@ static void ripng_if_rmap_update(struct if_rmap_ctx *ctx, void ripng_if_rmap_update_interface(struct interface *ifp) { + struct ripng_interface *ri = ifp->info; + struct ripng *ripng = ri->ripng; struct if_rmap *if_rmap; struct if_rmap_ctx *ctx; - if (ifp->vrf_id != VRF_DEFAULT) - return; if (!ripng) return; ctx = ripng->if_rmap_ctx; @@ -2539,19 +2613,15 @@ void ripng_if_rmap_update_interface(struct interface *ifp) ripng_if_rmap_update(ctx, if_rmap); } -static void ripng_routemap_update_redistribute(void) +static void ripng_routemap_update_redistribute(struct ripng *ripng) { - int i; - - if (ripng) { - for (i = 0; i < ZEBRA_ROUTE_MAX; i++) { - if (ripng->route_map[i].name) { - ripng->route_map[i].map = - route_map_lookup_by_name( - ripng->route_map[i].name); - route_map_counter_increment( - ripng->route_map[i].map); - } + for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) { + if (ripng->redist[i].route_map.name) { + ripng->redist[i].route_map.map = + route_map_lookup_by_name( + ripng->redist[i].route_map.name); + route_map_counter_increment( + ripng->redist[i].route_map.map); } } } @@ -2559,12 +2629,196 @@ static void ripng_routemap_update_redistribute(void) static void ripng_routemap_update(const char *unused) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct ripng *ripng; struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) ripng_if_rmap_update_interface(ifp); - ripng_routemap_update_redistribute(); + ripng = vrf->info; + if (ripng) + ripng_routemap_update_redistribute(ripng); +} + +/* Link RIPng instance to VRF. */ +static void ripng_vrf_link(struct ripng *ripng, struct vrf *vrf) +{ + struct interface *ifp; + + ripng->vrf = vrf; + ripng->distribute_ctx->vrf = vrf; + vrf->info = ripng; + + FOR_ALL_INTERFACES (vrf, ifp) + ripng_interface_sync(ifp); +} + +/* Unlink RIPng instance from VRF. */ +static void ripng_vrf_unlink(struct ripng *ripng, struct vrf *vrf) +{ + struct interface *ifp; + + ripng->vrf = NULL; + ripng->distribute_ctx->vrf = NULL; + vrf->info = NULL; + + FOR_ALL_INTERFACES (vrf, ifp) + ripng_interface_sync(ifp); +} + +static void ripng_instance_enable(struct ripng *ripng, struct vrf *vrf, + int sock) +{ + ripng->sock = sock; + + ripng_vrf_link(ripng, vrf); + ripng->enabled = true; + + /* Resend all redistribute requests. */ + ripng_redistribute_enable(ripng); + + /* Create read and timer thread. */ + ripng_event(ripng, RIPNG_READ, ripng->sock); + ripng_event(ripng, RIPNG_UPDATE_EVENT, 1); + + ripng_zebra_vrf_register(vrf); +} + +static void ripng_instance_disable(struct ripng *ripng) +{ + struct vrf *vrf = ripng->vrf; + struct agg_node *rp; + + /* Clear RIPng routes */ + for (rp = agg_route_top(ripng->table); rp; rp = agg_route_next(rp)) { + struct ripng_aggregate *aggregate; + struct list *list; + + if ((list = rp->info) != NULL) { + struct ripng_info *rinfo; + struct listnode *listnode; + + rinfo = listgetdata(listhead(list)); + if (ripng_route_rte(rinfo)) + ripng_zebra_ipv6_delete(ripng, rp); + + for (ALL_LIST_ELEMENTS_RO(list, listnode, rinfo)) { + RIPNG_TIMER_OFF(rinfo->t_timeout); + RIPNG_TIMER_OFF(rinfo->t_garbage_collect); + ripng_info_free(rinfo); + } + list_delete(&list); + rp->info = NULL; + agg_unlock_node(rp); + } + + if ((aggregate = rp->aggregate) != NULL) { + ripng_aggregate_free(aggregate); + rp->aggregate = NULL; + agg_unlock_node(rp); + } + } + + /* Flush all redistribute requests. */ + ripng_redistribute_disable(ripng); + + /* Cancel the RIPng timers */ + RIPNG_TIMER_OFF(ripng->t_update); + RIPNG_TIMER_OFF(ripng->t_triggered_update); + RIPNG_TIMER_OFF(ripng->t_triggered_interval); + + /* Cancel the read thread */ + if (ripng->t_read) { + thread_cancel(ripng->t_read); + ripng->t_read = NULL; + } + + /* Close the RIPng socket */ + if (ripng->sock >= 0) { + close(ripng->sock); + ripng->sock = -1; + } + + /* Clear existing peers. */ + list_delete_all_node(ripng->peer_list); + + ripng_zebra_vrf_deregister(vrf); + + ripng_vrf_unlink(ripng, vrf); + ripng->enabled = false; +} + +static int ripng_vrf_new(struct vrf *vrf) +{ + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: VRF created: %s(%u)", __func__, vrf->name, + vrf->vrf_id); + + return 0; +} + +static int ripng_vrf_delete(struct vrf *vrf) +{ + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name, + vrf->vrf_id); + + return 0; +} + +static int ripng_vrf_enable(struct vrf *vrf) +{ + struct ripng *ripng; + int socket; + + ripng = ripng_lookup_by_vrf_name(vrf->name); + if (!ripng || ripng->enabled) + return 0; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: VRF %s(%u) enabled", __func__, vrf->name, + vrf->vrf_id); + + /* Activate the VRF RIPng instance. */ + if (!ripng->enabled) { + socket = ripng_make_socket(vrf); + if (socket < 0) + return -1; + + ripng_instance_enable(ripng, vrf, socket); + } + + return 0; +} + +static int ripng_vrf_disable(struct vrf *vrf) +{ + struct ripng *ripng; + + ripng = ripng_lookup_by_vrf_name(vrf->name); + if (!ripng || !ripng->enabled) + return 0; + + if (IS_RIPNG_DEBUG_EVENT) + zlog_debug("%s: VRF %s(%u) disabled", __func__, vrf->name, + vrf->vrf_id); + + /* Deactivate the VRF RIPng instance. */ + if (ripng->enabled) + ripng_instance_disable(ripng); + + return 0; +} + +void ripng_vrf_init(void) +{ + vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable, + ripng_vrf_delete, NULL); +} + +void ripng_vrf_terminate(void) +{ + vrf_terminate(); } /* Initialize ripng structure and set commands. */ @@ -2607,7 +2861,6 @@ void ripng_init(void) /* Route-map for interface. */ ripng_route_map_init(); - ripng_offset_init(); route_map_add_hook(ripng_routemap_update); route_map_delete_hook(ripng_routemap_update); diff --git a/ripngd/ripngd.h b/ripngd/ripngd.h index 3f0ef13a0..dcc61ae58 100644 --- a/ripngd/ripngd.h +++ b/ripngd/ripngd.h @@ -25,6 +25,7 @@ #include <zclient.h> #include <vty.h> #include <distribute.h> +#include <vector.h> #include "ripng_memory.h" @@ -88,6 +89,17 @@ /* RIPng structure. */ struct ripng { + RB_ENTRY(ripng) entry; + + /* VRF this routing instance is associated with. */ + char *vrf_name; + + /* VRF backpointer (might be NULL if the VRF doesn't exist). */ + struct vrf *vrf; + + /* Status of the routing instance. */ + bool enabled; + /* RIPng socket. */ int sock; @@ -107,6 +119,21 @@ struct ripng { /* RIPng routing information base. */ struct agg_table *table; + /* Linked list of RIPng peers. */ + struct list *peer_list; + + /* RIPng enabled interfaces. */ + vector enable_if; + + /* RIPng enabled networks. */ + struct agg_table *enable_network; + + /* Vector to store passive-interface name. */ + vector passive_interface; + + /* RIPng offset-lists. */ + struct list *offset_list_master; + /* RIPng threads. */ struct thread *t_read; struct thread *t_write; @@ -122,13 +149,16 @@ struct ripng { /* RIPng ECMP flag */ bool ecmp; - /* For redistribute route map. */ + /* RIPng redistribute configuration. */ struct { - char *name; - struct route_map *map; + bool enabled; + struct { + char *name; + struct route_map *map; + } route_map; bool metric_config; uint8_t metric; - } route_map[ZEBRA_ROUTE_MAX]; + } redist[ZEBRA_ROUTE_MAX]; /* For distribute-list container */ struct distribute_ctx *distribute_ctx; @@ -136,6 +166,8 @@ struct ripng { /* For if_rmap container */ struct if_rmap_ctx *if_rmap_ctx; }; +RB_HEAD(ripng_instance_head, ripng); +RB_PROTOTYPE(ripng_instance_head, ripng, entry, ripng_instance_compare) /* Routing table entry. */ struct rte { @@ -234,6 +266,9 @@ typedef enum { /* RIPng specific interface configuration. */ struct ripng_interface { + /* Parent routing instance. */ + struct ripng *ripng; + /* RIPng is enabled on this interface. */ int enable_network; int enable_interface; @@ -280,6 +315,9 @@ struct ripng_interface { /* RIPng peer information. */ struct ripng_peer { + /* Parent routing instance. */ + struct ripng *ripng; + /* Peer address. */ struct in6_addr addr; @@ -325,6 +363,9 @@ enum ripng_event { #define RIPNG_OFFSET_LIST_MAX 2 struct ripng_offset_list { + /* Parent routing instance. */ + struct ripng *ripng; + char *ifname; struct { @@ -335,72 +376,87 @@ struct ripng_offset_list { }; /* Extern variables. */ -extern struct ripng *ripng; -extern struct list *peer_list; extern struct zebra_privs_t ripngd_privs; extern struct thread_master *master; +extern struct ripng_instance_head ripng_instances; /* Prototypes. */ extern void ripng_init(void); -extern void ripng_clean(void); -extern void ripng_clean_network(void); -extern void ripng_interface_clean(void); -extern int ripng_enable_network_add(struct prefix *p); -extern int ripng_enable_network_delete(struct prefix *p); -extern int ripng_enable_if_add(const char *ifname); -extern int ripng_enable_if_delete(const char *ifname); -extern int ripng_passive_interface_set(const char *ifname); -extern int ripng_passive_interface_unset(const char *ifname); -extern void ripng_passive_interface_clean(void); +extern void ripng_clean(struct ripng *ripng); +extern void ripng_clean_network(struct ripng *ripng); +extern void ripng_interface_clean(struct ripng *ripng); +extern int ripng_enable_network_add(struct ripng *ripng, struct prefix *p); +extern int ripng_enable_network_delete(struct ripng *ripng, struct prefix *p); +extern int ripng_enable_if_add(struct ripng *ripng, const char *ifname); +extern int ripng_enable_if_delete(struct ripng *ripng, const char *ifname); +extern int ripng_passive_interface_set(struct ripng *ripng, const char *ifname); +extern int ripng_passive_interface_unset(struct ripng *ripng, + const char *ifname); +extern void ripng_passive_interface_clean(struct ripng *ripng); extern void ripng_if_init(void); extern void ripng_route_map_init(void); +extern void ripng_zebra_vrf_register(struct vrf *vrf); +extern void ripng_zebra_vrf_deregister(struct vrf *vrf); extern void ripng_terminate(void); /* zclient_init() is done by ripng_zebra.c:zebra_init() */ extern void zebra_init(struct thread_master *); extern void ripng_zebra_stop(void); -extern void ripng_redistribute_conf_update(int type); -extern void ripng_redistribute_conf_delete(int type); - -extern void ripng_peer_init(void); -extern void ripng_peer_update(struct sockaddr_in6 *, uint8_t); -extern void ripng_peer_bad_route(struct sockaddr_in6 *); -extern void ripng_peer_bad_packet(struct sockaddr_in6 *); -extern void ripng_peer_display(struct vty *); -extern struct ripng_peer *ripng_peer_lookup(struct in6_addr *); -extern struct ripng_peer *ripng_peer_lookup_next(struct in6_addr *); - -extern struct ripng_offset_list *ripng_offset_list_new(const char *ifname); +extern void ripng_redistribute_conf_update(struct ripng *ripng, int type); +extern void ripng_redistribute_conf_delete(struct ripng *ripng, int type); + +extern void ripng_peer_update(struct ripng *ripng, struct sockaddr_in6 *from, + uint8_t version); +extern void ripng_peer_bad_route(struct ripng *ripng, + struct sockaddr_in6 *from); +extern void ripng_peer_bad_packet(struct ripng *ripng, + struct sockaddr_in6 *from); +extern void ripng_peer_display(struct vty *vty, struct ripng *ripng); +extern struct ripng_peer *ripng_peer_lookup(struct ripng *ripng, + struct in6_addr *addr); +extern struct ripng_peer *ripng_peer_lookup_next(struct ripng *ripng, + struct in6_addr *addr); +extern int ripng_peer_list_cmp(struct ripng_peer *p1, struct ripng_peer *p2); +extern void ripng_peer_list_del(void *arg); + +extern struct ripng_offset_list *ripng_offset_list_new(struct ripng *ripng, + const char *ifname); extern void ripng_offset_list_del(struct ripng_offset_list *offset); -extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname); -extern struct ripng_offset_list *ripng_offset_list_lookup(const char *ifname); -extern int ripng_offset_list_apply_in(struct prefix_ipv6 *, struct interface *, - uint8_t *); -extern int ripng_offset_list_apply_out(struct prefix_ipv6 *, struct interface *, - uint8_t *); -extern void ripng_offset_init(void); -extern void ripng_offset_clean(void); +extern struct ripng_offset_list *ripng_offset_list_lookup(struct ripng *ripng, + const char *ifname); +extern int ripng_offset_list_apply_in(struct ripng *ripng, + struct prefix_ipv6 *p, + struct interface *ifp, uint8_t *metric); +extern int ripng_offset_list_apply_out(struct ripng *ripng, + struct prefix_ipv6 *p, + struct interface *ifp, uint8_t *metric); +extern int offset_list_cmp(struct ripng_offset_list *o1, + struct ripng_offset_list *o2); extern int ripng_route_rte(struct ripng_info *rinfo); extern struct ripng_info *ripng_info_new(void); extern void ripng_info_free(struct ripng_info *rinfo); -extern void ripng_event(enum ripng_event, int); +extern struct ripng *ripng_info_get_instance(const struct ripng_info *rinfo); +extern void ripng_event(struct ripng *ripng, enum ripng_event event, int sock); extern int ripng_request(struct interface *ifp); -extern void ripng_redistribute_add(int, int, struct prefix_ipv6 *, ifindex_t, - struct in6_addr *, route_tag_t); -extern void ripng_redistribute_delete(int, int, struct prefix_ipv6 *, - ifindex_t); -extern void ripng_redistribute_withdraw(int type); - -extern void ripng_ecmp_disable(void); +extern void ripng_redistribute_add(struct ripng *ripng, int type, int sub_type, + struct prefix_ipv6 *p, ifindex_t ifindex, + struct in6_addr *nexthop, route_tag_t tag); +extern void ripng_redistribute_delete(struct ripng *ripng, int type, + int sub_type, struct prefix_ipv6 *p, + ifindex_t ifindex); +extern void ripng_redistribute_withdraw(struct ripng *ripng, int type); + +extern void ripng_ecmp_disable(struct ripng *ripng); extern void ripng_distribute_update_interface(struct interface *); extern void ripng_if_rmap_update_interface(struct interface *); -extern void ripng_zebra_ipv6_add(struct agg_node *node); -extern void ripng_zebra_ipv6_delete(struct agg_node *node); +extern void ripng_zebra_ipv6_add(struct ripng *ripng, struct agg_node *node); +extern void ripng_zebra_ipv6_delete(struct ripng *ripng, struct agg_node *node); -extern void ripng_redistribute_clean(void); -extern int ripng_redistribute_check(int); -extern void ripng_redistribute_write(struct vty *); +extern void ripng_redistribute_enable(struct ripng *ripng); +extern void ripng_redistribute_disable(struct ripng *ripng); +extern int ripng_redistribute_check(struct ripng *ripng, int type); +extern void ripng_redistribute_write(struct vty *vty, struct ripng *ripng); extern int ripng_write_rte(int num, struct stream *s, struct prefix_ipv6 *p, struct in6_addr *nexthop, uint16_t tag, @@ -423,14 +479,26 @@ extern int ripng_interface_address_add(int command, struct zclient *, zebra_size_t, vrf_id_t); extern int ripng_interface_address_delete(int command, struct zclient *, zebra_size_t, vrf_id_t); - -extern int ripng_create(int socket); -extern int ripng_make_socket(void); -extern int ripng_network_write(struct vty *); - -extern struct ripng_info *ripng_ecmp_add(struct ripng_info *); -extern struct ripng_info *ripng_ecmp_replace(struct ripng_info *); -extern struct ripng_info *ripng_ecmp_delete(struct ripng_info *); +extern int ripng_interface_vrf_update(int command, struct zclient *zclient, + zebra_size_t length, vrf_id_t vrf_id); +extern void ripng_interface_sync(struct interface *ifp); + +extern struct ripng *ripng_lookup_by_vrf_id(vrf_id_t vrf_id); +extern struct ripng *ripng_lookup_by_vrf_name(const char *vrf_name); +extern struct ripng *ripng_create(const char *vrf_name, struct vrf *vrf, + int socket); +extern int ripng_make_socket(struct vrf *vrf); +extern int ripng_network_write(struct vty *vty, struct ripng *ripng); + +extern struct ripng_info *ripng_ecmp_add(struct ripng *ripng, + struct ripng_info *rinfo); +extern struct ripng_info *ripng_ecmp_replace(struct ripng *ripng, + struct ripng_info *rinfo); +extern struct ripng_info *ripng_ecmp_delete(struct ripng *ripng, + struct ripng_info *rinfo); + +extern void ripng_vrf_init(void); +extern void ripng_vrf_terminate(void); /* Northbound. */ extern void ripng_cli_init(void); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index 1f1152d36..b8da90ca8 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1521,15 +1521,15 @@ DEFUNSH(VTYSH_KEYS, key, key_cmd, "key (0-2147483647)", return CMD_SUCCESS; } -DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip", - ROUTER_STR "RIP\n") +DEFUNSH(VTYSH_RIPD, router_rip, router_rip_cmd, "router rip [vrf NAME]", + ROUTER_STR "RIP\n" VRF_CMD_HELP_STR) { vty->node = RIP_NODE; return CMD_SUCCESS; } -DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng", - ROUTER_STR "RIPng\n") +DEFUNSH(VTYSH_RIPNGD, router_ripng, router_ripng_cmd, "router ripng [vrf NAME]", + ROUTER_STR "RIPng\n" VRF_CMD_HELP_STR) { vty->node = RIPNG_NODE; return CMD_SUCCESS; diff --git a/yang/example/ripd.json b/yang/example/ripd.json index 888c52b93..00040622e 100644 --- a/yang/example/ripd.json +++ b/yang/example/ripd.json @@ -20,25 +20,28 @@ ] }, "frr-ripd:ripd": { - "instance": { - "allow-ecmp": "true", - "distance": { - "source": [ + "instance": [ + { + "vrf": "default", + "allow-ecmp": "true", + "distance": { + "source": [ + { + "distance": "25", + "prefix": "172.16.1.0/24" + } + ] + }, + "redistribute": [ { - "prefix": "172.16.1.0/24", - "distance": "25" + "metric": "3", + "protocol": "ospf" } + ], + "static-route": [ + "10.0.1.0/24" ] - }, - "redistribute": [ - { - "protocol": "ospf", - "metric": "3" - } - ], - "static-route": [ - "10.0.1.0/24" - ] - } + } + ] } } diff --git a/yang/example/ripd.xml b/yang/example/ripd.xml index 756e382bd..2feddde2d 100644 --- a/yang/example/ripd.xml +++ b/yang/example/ripd.xml @@ -18,6 +18,7 @@ </lib> <ripd xmlns="http://frrouting.org/yang/ripd"> <instance> + <vrf>default</vrf> <allow-ecmp>true</allow-ecmp> <static-route>10.0.1.0/24</static-route> <distance> diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang index 8073fba77..07690793f 100644 --- a/yang/frr-ripd.yang +++ b/yang/frr-ripd.yang @@ -34,13 +34,18 @@ module frr-ripd { container ripd { /* - * Global configuration data + * Routing instance configuration. */ - container instance { - presence "Present if the RIP protocol is enabled."; + list instance { + key "vrf"; description "RIP routing instance."; + leaf vrf { + type string; + description + "VRF name."; + } leaf allow-ecmp { type boolean; default "false"; @@ -293,83 +298,83 @@ module frr-ripd { '(./receive = "2" and ./send = "2") or ' + '(./receive = "1-2" and ./send = "2")'; } - } - - /* - * Operational data. - */ - container state { - config false; - description - "Operational data."; - container neighbors { + /* + * Operational data. + */ + container state { + config false; description - "Neighbor information."; - list neighbor { - key "address"; + "Operational data."; + + container neighbors { description - "A RIP neighbor."; - leaf address { - type inet:ipv4-address; - description - "IP address that a RIP neighbor is using as its - source address."; - } - leaf last-update { - type yang:date-and-time; - description - "The time when the most recent RIP update was - received from this neighbor."; - } - leaf bad-packets-rcvd { - type yang:counter32; + "Neighbor information."; + list neighbor { + key "address"; description - "The number of RIP invalid packets received from - this neighbor which were subsequently discarded - for any reason (e.g. a version 0 packet, or an - unknown command type)."; - } - leaf bad-routes-rcvd { - type yang:counter32; - description - "The number of routes received from this neighbor, - in valid RIP packets, which were ignored for any - reason (e.g. unknown address family, or invalid - metric)."; + "A RIP neighbor."; + leaf address { + type inet:ipv4-address; + description + "IP address that a RIP neighbor is using as its + source address."; + } + leaf last-update { + type yang:date-and-time; + description + "The time when the most recent RIP update was + received from this neighbor."; + } + leaf bad-packets-rcvd { + type yang:counter32; + description + "The number of RIP invalid packets received from + this neighbor which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)."; + } + leaf bad-routes-rcvd { + type yang:counter32; + description + "The number of routes received from this neighbor, + in valid RIP packets, which were ignored for any + reason (e.g. unknown address family, or invalid + metric)."; + } } } - } - container routes { - description - "Route information."; - list route { - key "prefix"; + container routes { description - "A RIP IPv4 route."; - leaf prefix { - type inet:ipv4-prefix; - description - "IP address (in the form A.B.C.D) and prefix length, - separated by the slash (/) character. The range of - values for the prefix-length is 0 to 32."; - } - leaf next-hop { - type inet:ipv4-address; + "Route information."; + list route { + key "prefix"; description - "Next hop IPv4 address."; - } - leaf interface { - type string; - description - "The interface that the route uses."; - } - leaf metric { - type uint8 { - range "0..16"; + "A RIP IPv4 route."; + leaf prefix { + type inet:ipv4-prefix; + description + "IP address (in the form A.B.C.D) and prefix length, + separated by the slash (/) character. The range of + values for the prefix-length is 0 to 32."; + } + leaf next-hop { + type inet:ipv4-address; + description + "Next hop IPv4 address."; + } + leaf interface { + type string; + description + "The interface that the route uses."; + } + leaf metric { + type uint8 { + range "0..16"; + } + description + "Route metric."; } - description - "Route metric."; } } } @@ -547,6 +552,19 @@ module frr-ripd { description "Clears RIP routes from the IP routing table and routes redistributed into the RIP protocol."; + + input { + leaf vrf { + type string; + description + "VRF name identifying a specific RIP instance. + This leaf is optional for the rpc. + If it is specified, the rpc will clear all routes in the + specified RIP instance; + if it is not specified, the rpc will clear all routes in + all RIP instances."; + } + } } /* diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang index 0cc5f18a5..b341b438a 100644 --- a/yang/frr-ripngd.yang +++ b/yang/frr-ripngd.yang @@ -33,13 +33,18 @@ module frr-ripngd { container ripngd { /* - * Global configuration data + * Routing instance configuration. */ - container instance { - presence "Present if the RIPng protocol is enabled."; + list instance { + key "vrf"; description "RIPng routing instance."; + leaf vrf { + type string; + description + "VRF name."; + } leaf allow-ecmp { type boolean; default "false"; @@ -194,82 +199,82 @@ module frr-ripngd { "Interval at which RIPng updates are sent."; } } - } - /* - * Operational data. - */ - container state { - config false; - description - "Operational data."; - - container neighbors { + /* + * Operational data. + */ + container state { + config false; description - "Neighbor information."; - list neighbor { - key "address"; + "Operational data."; + + container neighbors { description - "A RIPng neighbor."; - leaf address { - type inet:ipv6-address; + "Neighbor information."; + list neighbor { + key "address"; description - "IPv6 address that a RIPng neighbor is using as its - source address."; - } - leaf last-update { - type yang:date-and-time; - description - "The time when the most recent RIPng update was - received from this neighbor."; - } - leaf bad-packets-rcvd { - type yang:counter32; - description - "The number of RIPng invalid packets received from - this neighbor which were subsequently discarded - for any reason (e.g. a version 0 packet, or an - unknown command type)."; - } - leaf bad-routes-rcvd { - type yang:counter32; - description - "The number of routes received from this neighbor, - in valid RIPng packets, which were ignored for any - reason (e.g. unknown address family, or invalid - metric)."; + "A RIPng neighbor."; + leaf address { + type inet:ipv6-address; + description + "IPv6 address that a RIPng neighbor is using as its + source address."; + } + leaf last-update { + type yang:date-and-time; + description + "The time when the most recent RIPng update was + received from this neighbor."; + } + leaf bad-packets-rcvd { + type yang:counter32; + description + "The number of RIPng invalid packets received from + this neighbor which were subsequently discarded + for any reason (e.g. a version 0 packet, or an + unknown command type)."; + } + leaf bad-routes-rcvd { + type yang:counter32; + description + "The number of routes received from this neighbor, + in valid RIPng packets, which were ignored for any + reason (e.g. unknown address family, or invalid + metric)."; + } } } - } - container routes { - description - "Route information."; - list route { - key "prefix"; + container routes { description - "A RIPng IPv6 route."; - leaf prefix { - type inet:ipv6-prefix; - description - "IPv6 address and prefix length, in the format - specified in RFC6991."; - } - leaf next-hop { - type inet:ipv6-address; + "Route information."; + list route { + key "prefix"; description - "Next hop IPv6 address."; - } - leaf interface { - type string; - description - "The interface that the route uses."; - } - leaf metric { - type uint8 { - range "0..16"; + "A RIPng IPv6 route."; + leaf prefix { + type inet:ipv6-prefix; + description + "IPv6 address and prefix length, in the format + specified in RFC6991."; + } + leaf next-hop { + type inet:ipv6-address; + description + "Next hop IPv6 address."; + } + leaf interface { + type string; + description + "The interface that the route uses."; + } + leaf metric { + type uint8 { + range "0..16"; + } + description + "Route metric."; } - description - "Route metric."; } } } @@ -317,5 +322,18 @@ module frr-ripngd { description "Clears RIPng routes from the IPv6 routing table and routes redistributed into the RIPng protocol."; + + input { + leaf vrf { + type string; + description + "VRF name identifying a specific RIPng instance. + This leaf is optional for the rpc. + If it is specified, the rpc will clear all routes in the + specified RIPng instance; + if it is not specified, the rpc will clear all routes in + all RIPng instances."; + } + } } } diff --git a/yang/ietf/frr-ietf-translator.json b/yang/ietf/frr-ietf-translator.json index 9855480b4..38a609982 100644 --- a/yang/ietf/frr-ietf-translator.json +++ b/yang/ietf/frr-ietf-translator.json @@ -22,7 +22,7 @@ "mappings": [ { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']", - "native": "/frr-ripd:ripd/instance" + "native": "/frr-ripd:ripd/instance[vrf='default']" } ] }, @@ -32,31 +32,31 @@ "mappings": [ { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/default-metric", - "native": "/frr-ripd:ripd/instance/default-metric" + "native": "/frr-ripd:ripd/instance[vrf='default']/default-metric" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/distance", - "native": "/frr-ripd:ripd/instance/distance/default" + "native": "/frr-ripd:ripd/instance[vrf='default']/distance/default" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/originate-default-route/enabled", - "native": "/frr-ripd:ripd/instance/default-information-originate" + "native": "/frr-ripd:ripd/instance[vrf='default']/default-information-originate" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/update-interval", - "native": "/frr-ripd:ripd/instance/timers/update-interval" + "native": "/frr-ripd:ripd/instance[vrf='default']/timers/update-interval" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/holddown-interval", - "native": "/frr-ripd:ripd/instance/timers/holddown-interval" + "native": "/frr-ripd:ripd/instance[vrf='default']/timers/holddown-interval" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/flush-interval", - "native": "/frr-ripd:ripd/instance/timers/flush-interval" + "native": "/frr-ripd:ripd/instance[vrf='default']/timers/flush-interval" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']", - "native": "/frr-ripd:ripd/instance/interface[.='KEY1']" + "native": "/frr-ripd:ripd/instance[vrf='default']/interface[.='KEY1']" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']/split-horizon", @@ -64,43 +64,43 @@ }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']", - "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/ipv4-address", - "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/address" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/address" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/last-update", - "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/last-update" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/last-update" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-packets-rcvd", - "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-routes-rcvd", - "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']", - "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/ipv4-prefix", - "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/prefix" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/prefix" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/next-hop", - "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/next-hop" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/next-hop" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/interface", - "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/interface" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/interface" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/metric", - "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/metric" + "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/metric" }, { "custom": "/ietf-rip:clear-rip-route", |