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,
/* 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;
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;
}
int vrf_sockunion_socket(const union sockunion *su, vrf_id_t vrf_id,
- char *interfacename)
+ const char *interfacename)
{
int ret, save_errno, ret2;
/* 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,
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. */
*/
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)
*/
*/
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);
}
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");
}
/*
"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");
*/
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)
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"},
{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)
/* 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);
/* 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;
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;
}
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);
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);
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); */
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;
}
}
-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);
}
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)
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;
/* 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,
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;
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);
}
* 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;
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);
}
/* 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;
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) {
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);
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;
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;
}
}
/* 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;
}
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);
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;
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);
}
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
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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);
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
*/
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",
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. */
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;
}
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();
#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);
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 */
#include "sigevent.h"
#include "zclient.h"
#include "vrf.h"
+#include "if_rmap.h"
#include "libfrr.h"
#include "ripd/ripd.h"
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)
.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. */
{
zlog_notice("Terminating on signal");
- rip_clean();
-
+ rip_vrf_terminate();
+ if_rmap_terminate();
rip_zclient_stop();
frr_fini();
/* 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);
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")
DECLARE_MGROUP(RIPD)
DECLARE_MTYPE(RIP)
+DECLARE_MTYPE(RIP_VRF_NAME)
DECLARE_MTYPE(RIP_INFO)
DECLARE_MTYPE(RIP_INTERFACE)
DECLARE_MTYPE(RIP_INTERFACE_STRING)
#include "libfrr.h"
#include "ripd/ripd.h"
+#include "ripd/rip_debug.h"
#include "ripd/rip_cli.h"
/*
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;
}
static int ripd_instance_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
+
if (event != NB_EV_APPLY)
return NB_OK;
- rip_clean();
+ rip = yang_dnode_get_entry(dnode, true);
+ rip_clean(rip);
+
+ return NB_OK;
+}
+
+static const void *ripd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct rip *rip = list_entry;
+
+ if (list_entry == NULL)
+ rip = RB_MIN(rip_instance_head, &rip_instances);
+ else
+ rip = RB_NEXT(rip_instance_head, (struct rip *)rip);
+
+ return rip;
+}
+
+static int ripd_instance_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct rip *rip = list_entry;
+
+ keys->num = 1;
+ strlcpy(keys->key[0], rip->vrf_name, sizeof(keys->key[0]));
return NB_OK;
}
+static const void *ripd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *vrf_name = keys->key[0];
+
+ return rip_lookup_by_vrf_name(vrf_name);
+}
+
/*
* XPath: /frr-ripd:ripd/instance/allow-ecmp
*/
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;
}
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));
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;
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 (); */
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;
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
struct prefix_ipv4 prefix;
struct route_node *rn;
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);
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);
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
struct prefix_ipv4 p;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
- return rip_neighbor_add(&p);
+ return rip_neighbor_add(rip, &p);
}
static int ripd_instance_explicit_neighbor_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
struct prefix_ipv4 p;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
p.family = AF_INET;
p.prefixlen = IPV4_MAX_BITLEN;
yang_dnode_get_ipv4(&p.prefix, dnode, NULL);
- return rip_neighbor_delete(&p);
+ return rip_neighbor_delete(rip, &p);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
struct prefix p;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
yang_dnode_get_ipv4p(&p, dnode, NULL);
apply_mask_ipv4((struct prefix_ipv4 *)&p);
- return rip_enable_network_add(&p);
+ return rip_enable_network_add(rip, &p);
}
static int ripd_instance_network_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
struct prefix p;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
yang_dnode_get_ipv4p(&p, dnode, NULL);
apply_mask_ipv4((struct prefix_ipv4 *)&p);
- return rip_enable_network_delete(&p);
+ return rip_enable_network_delete(rip, &p);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_enable_if_add(ifname);
+ return rip_enable_if_add(rip, ifname);
}
static int ripd_instance_interface_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_enable_if_delete(ifname);
+ return rip_enable_if_delete(rip, ifname);
}
/*
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;
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;
}
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_passive_nondefault_set(ifname);
+ return rip_passive_nondefault_set(rip, ifname);
}
static int ripd_instance_passive_interface_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_passive_nondefault_unset(ifname);
+ return rip_passive_nondefault_unset(rip, ifname);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_passive_nondefault_unset(ifname);
+ return rip_passive_nondefault_unset(rip, ifname);
}
static int
ripd_instance_non_passive_interface_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return rip_passive_nondefault_set(ifname);
+ return rip_passive_nondefault_set(rip, ifname);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct rip *rip;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ rip = yang_dnode_get_entry(dnode, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ rip->redist[type].enabled = true;
+
return NB_OK;
}
static int ripd_instance_redistribute_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "./protocol");
- rip_redistribute_conf_delete(type);
+ rip->redist[type].enabled = false;
+ if (rip->redist[type].route_map.name) {
+ free(rip->redist[type].route_map.name);
+ rip->redist[type].route_map.name = NULL;
+ rip->redist[type].route_map.map = NULL;
+ }
+ rip->redist[type].metric_config = false;
+ rip->redist[type].metric = 0;
+
+ if (rip->enabled)
+ rip_redistribute_conf_delete(rip, type);
return NB_OK;
}
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);
}
/*
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;
}
ripd_instance_redistribute_route_map_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "../protocol");
- free(rip->route_map[type].name);
- rip->route_map[type].name = NULL;
- rip->route_map[type].map = NULL;
+ free(rip->redist[type].route_map.name);
+ rip->redist[type].route_map.name = NULL;
+ rip->redist[type].route_map.map = NULL;
return NB_OK;
}
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;
}
ripd_instance_redistribute_metric_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct rip *rip;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ rip = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "../protocol");
- rip->route_map[type].metric_config = false;
- rip->route_map[type].metric = 0;
+ rip->redist[type].metric_config = false;
+ rip->redist[type].metric = 0;
return NB_OK;
}
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)
{
+ 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;
}
*/
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);
}
/*
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;
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;
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;
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;
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;
}
/*
- * 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);
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;
}
}
/*
- * 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);
}
/*
- * 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);
}
/*
- * 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);
}
/*
- * 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
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;
}
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;
}
/*
- * 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);
}
/*
- * 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);
}
/*
- * 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);
/*
* 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;
continue;
if (CHECK_FLAG(rinfo->flags, RIP_RTF_FIB))
- rip_zebra_ipv4_delete(rp);
+ rip_zebra_ipv4_delete(rip, rp);
break;
}
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;
}
.xpath = "/frr-ripd:ripd/instance",
.cbs.create = ripd_instance_create,
.cbs.destroy = ripd_instance_delete,
+ .cbs.get_next = ripd_instance_get_next,
+ .cbs.get_keys = ripd_instance_get_keys,
+ .cbs.lookup_entry = ripd_instance_lookup_entry,
.cbs.cli_show = cli_show_router_rip,
},
{
.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",
#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))
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;
}
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));
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));
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));
}
/* 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));
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;
-}
#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));
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;
}
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. */
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++;
}
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,
}
}
-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;
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);
}
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;
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)
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)])
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
return peer;
}
}
- peer = rip_peer_lookup_next(addr);
+ peer = rip_peer_lookup_next(rip, addr);
if (!peer)
return NULL;
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;
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;
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;
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;
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)
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;
/* 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);
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;
}
#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);
{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)
{
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)
{
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;
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. */
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;
}
/* 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;
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));
/* 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))
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;
}
* 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;
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 {
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. */
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;
}
/* 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);
}
}
}
/* 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,
}
/* 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;
/* 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;
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;
/* 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;
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));
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;
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;
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.
*/
|| ((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)
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);
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;
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;
}
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;
}
; /* 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;
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;
}
/* - 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;
}
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;
}
}
if (!if_lookup_address((void *)&rte->nexthop, AF_INET,
- VRF_DEFAULT)) {
+ rip->vrf->vrf_id)) {
struct route_node *rn;
struct rip_info *rinfo;
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;
}
}
/* 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;
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
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
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),
}
/* 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;
}
}
- (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;
"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);
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;
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;
(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;
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));
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;
}
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;
}
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;
}
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;
}
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;
}
/* 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;
}
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;
}
"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;
}
"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) {
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;
}
"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;
}
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;
}
}
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;
}
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;
ifc->ifp->name, ifc->ifp->ifindex);
}
+ /* Get RIP interface. */
+ ri = ifc->ifp->info;
+ rip = ri->rip;
+
/* Set output stream. */
s = rip->obuf;
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)
}
/* 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) {
/* 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
}
/* 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;
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;
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!",
/* RIP's periodical timer. */
static int rip_update(struct thread *t)
{
+ struct rip *rip = THREAD_ARG(t);
+
/* Clear timer pointer. */
rip->t_update = NULL;
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. */
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;
/* 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;
/* Execute triggered update. */
static int rip_triggered_update(struct thread *t)
{
+ struct rip *rip = THREAD_ARG(t);
int interval;
/* Clear thred pointer. */
/* 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
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));
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);
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. */
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;
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:
}
#endif
-
-struct route_table *rip_distance_table;
-
struct rip_distance *rip_distance_new(void)
{
return XCALLOC(MTYPE_RIP_DISTANCE, sizeof(struct rip_distance));
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);
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;
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,
}
/* 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));
}
/* 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);
}
}
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"
/* 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%%,",
/* 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,",
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)
}
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)
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;
}
/* 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;
}
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;
void rip_distribute_update_interface(struct interface *ifp)
{
+ struct rip_interface *ri = ifp->info;
+ struct rip *rip = ri->rip;
struct distribute *dist;
if (!rip)
}
/* 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,
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;
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);
}
}
}
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. */
/* 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();
}
/* 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;
/* 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;
/* 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 {
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 {
/* 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;
/* RIP peer information. */
struct rip_peer {
+ /* Parent routing instance. */
+ struct rip *rip;
+
/* Peer address. */
struct in_addr addr;
#define RIP_OFFSET_LIST_MAX 2
struct rip_offset_list {
+ /* Parent routing instance. */
+ struct rip *rip;
+
char *ifname;
struct {
/* 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;
*/
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);
}
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");
}
/*
*/
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)
/* 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;
*/
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;
}
/* 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;
inet_pton(AF_INET6, RIPNG_GROUP, &mreq.ipv6mr_multiaddr);
mreq.ipv6mr_interface = ifp->ifindex;
- ret = setsockopt(ripng->sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
(char *)&mreq, sizeof(mreq));
if (ret < 0)
zlog_warn("can't setsockopt IPV6_LEAVE_GROUP: %s\n",
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))
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;
}
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);
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;
}
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);
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); */
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;
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;
/* 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);
}
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;
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,
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;
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);
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) {
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) {
}
/* 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);
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;
}
/* 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;
}
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);
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;
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);
}
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
}
/* 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;
{
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;
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;
}
/* 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;
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
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;
}
/* 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;
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();
#include "privs.h"
#include "sigevent.h"
#include "vrf.h"
+#include "if_rmap.h"
#include "libfrr.h"
#include "ripngd/ripngd.h"
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)
.vty_group = VTY_GROUP,
#endif
.caps_p = _caps_p,
- .cap_num_p = 2,
+ .cap_num_p = array_size(_caps_p),
.cap_num_i = 0};
{
zlog_notice("Terminating on signal");
- ripng_clean();
-
+ ripng_vrf_terminate();
+ if_rmap_terminate();
ripng_zebra_stop();
frr_fini();
exit(0);
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);
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")
DECLARE_MGROUP(RIPNGD)
DECLARE_MTYPE(RIPNG)
+DECLARE_MTYPE(RIPNG_VRF_NAME)
DECLARE_MTYPE(RIPNG_ROUTE)
DECLARE_MTYPE(RIPNG_AGGREGATE)
DECLARE_MTYPE(RIPNG_PEER)
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;
#include "libfrr.h"
#include "ripngd/ripngd.h"
+#include "ripngd/ripng_debug.h"
#include "ripngd/ripng_route.h"
#include "ripngd/ripng_cli.h"
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;
}
static int ripngd_instance_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
+
if (event != NB_EV_APPLY)
return NB_OK;
- ripng_clean();
+ ripng = yang_dnode_get_entry(dnode, true);
+ ripng_clean(ripng);
+
+ return NB_OK;
+}
+
+static const void *ripngd_instance_get_next(const void *parent_list_entry,
+ const void *list_entry)
+{
+ const struct ripng *ripng = list_entry;
+
+ if (list_entry == NULL)
+ ripng = RB_MIN(ripng_instance_head, &ripng_instances);
+ else
+ ripng = RB_NEXT(ripng_instance_head, (struct ripng *)ripng);
+
+ return ripng;
+}
+
+static int ripngd_instance_get_keys(const void *list_entry,
+ struct yang_list_keys *keys)
+{
+ const struct ripng *ripng = list_entry;
+
+ keys->num = 1;
+ strlcpy(keys->key[0], ripng->vrf_name, sizeof(keys->key[0]));
return NB_OK;
}
+static const void *
+ripngd_instance_lookup_entry(const void *parent_list_entry,
+ const struct yang_list_keys *keys)
+{
+ const char *vrf_name = keys->key[0];
+
+ return ripng_lookup_by_vrf_name(vrf_name);
+}
+
/*
* XPath: /frr-ripngd:ripngd/instance/allow-ecmp
*/
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;
}
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);
}
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;
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct ripng *ripng;
struct prefix p;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
yang_dnode_get_ipv6p(&p, dnode, NULL);
apply_mask_ipv6((struct prefix_ipv6 *)&p);
- return ripng_enable_network_add(&p);
+ return ripng_enable_network_add(ripng, &p);
}
static int ripngd_instance_network_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
struct prefix p;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
yang_dnode_get_ipv6p(&p, dnode, NULL);
apply_mask_ipv6((struct prefix_ipv6 *)&p);
- return ripng_enable_network_delete(&p);
+ return ripng_enable_network_delete(ripng, &p);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct ripng *ripng;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return ripng_enable_if_add(ifname);
+ return ripng_enable_if_add(ripng, ifname);
}
static int ripngd_instance_interface_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return ripng_enable_if_delete(ifname);
+ return ripng_enable_if_delete(ripng, ifname);
}
/*
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;
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct ripng *ripng;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return ripng_passive_interface_set(ifname);
+ return ripng_passive_interface_set(ripng, ifname);
}
static int
ripngd_instance_passive_interface_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
const char *ifname;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
ifname = yang_dnode_get_string(dnode, NULL);
- return ripng_passive_interface_unset(ifname);
+ return ripng_passive_interface_unset(ripng, ifname);
}
/*
const struct lyd_node *dnode,
union nb_resource *resource)
{
+ struct ripng *ripng;
+ int type;
+
+ if (event != NB_EV_APPLY)
+ return NB_OK;
+
+ ripng = yang_dnode_get_entry(dnode, true);
+ type = yang_dnode_get_enum(dnode, "./protocol");
+
+ ripng->redist[type].enabled = true;
+
return NB_OK;
}
static int ripngd_instance_redistribute_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "./protocol");
- ripng_redistribute_conf_delete(type);
+ ripng->redist[type].enabled = false;
+ if (ripng->redist[type].route_map.name) {
+ free(ripng->redist[type].route_map.name);
+ ripng->redist[type].route_map.name = NULL;
+ ripng->redist[type].route_map.map = NULL;
+ }
+ ripng->redist[type].metric_config = false;
+ ripng->redist[type].metric = 0;
+
+ if (ripng->enabled)
+ ripng_redistribute_conf_delete(ripng, type);
return NB_OK;
}
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);
}
/*
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;
}
ripngd_instance_redistribute_route_map_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "../protocol");
- free(ripng->route_map[type].name);
- ripng->route_map[type].name = NULL;
- ripng->route_map[type].map = NULL;
+ free(ripng->redist[type].route_map.name);
+ ripng->redist[type].route_map.name = NULL;
+ ripng->redist[type].route_map.map = NULL;
return NB_OK;
}
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;
}
ripngd_instance_redistribute_metric_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
int type;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
type = yang_dnode_get_enum(dnode, "../protocol");
- ripng->route_map[type].metric_config = false;
- ripng->route_map[type].metric = 0;
+ ripng->redist[type].metric_config = false;
+ ripng->redist[type].metric = 0;
return NB_OK;
}
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)
{
+ 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;
}
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;
}
ripngd_instance_aggregate_address_delete(enum nb_event event,
const struct lyd_node *dnode)
{
+ struct ripng *ripng;
struct prefix_ipv6 p;
if (event != NB_EV_APPLY)
return NB_OK;
+ ripng = yang_dnode_get_entry(dnode, true);
yang_dnode_get_ipv6p(&p, dnode, NULL);
apply_mask_ipv6(&p);
- ripng_aggregate_delete((struct prefix *)&p);
+ ripng_aggregate_delete(ripng, (struct prefix *)&p);
return NB_OK;
}
*/
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);
}
/*
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;
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;
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);
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;
}
}
/*
- * 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);
}
/*
- * 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;
}
/*
- * 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);
}
/*
- * 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
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;
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;
}
/*
- * 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);
}
/*
- * 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);
}
/*
- * 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);
/*
* 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;
continue;
if (CHECK_FLAG(rinfo->flags, RIPNG_RTF_FIB))
- ripng_zebra_ipv6_delete(rp);
+ ripng_zebra_ipv6_delete(ripng, rp);
break;
}
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;
}
.xpath = "/frr-ripngd:ripngd/instance",
.cbs.create = ripngd_instance_create,
.cbs.destroy = ripngd_instance_delete,
+ .cbs.get_next = ripngd_instance_get_next,
+ .cbs.get_keys = ripngd_instance_get_keys,
+ .cbs.lookup_entry = ripngd_instance_lookup_entry,
.cbs.cli_show = cli_show_router_ripng,
},
{
.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",
#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))
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;
}
}
/* 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));
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));
}
/* 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));
}
/* 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));
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;
-}
#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));
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;
}
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. */
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++;
}
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,
}
}
-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);
}
}
/* 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;
}
/* 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;
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 */
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;
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;
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;
}
/* 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;
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);
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;
}
#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,
};
/* 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 {
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)
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;
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;
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);
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;
}
/* 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;
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));
/* 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);
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);
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;
}
* 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;
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 {
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. */
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;
}
/* 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);
}
}
}
/* 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,
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;
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;
**/
/* 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. */
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 {
&& 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
|| 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);
}
/* 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;
}
}
- 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;
"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);
}
/* 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));
"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);
}
}
}
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;
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;
}
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;
}
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;
}
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));
"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)) {
"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)) {
"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;
}
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;
}
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;
}
struct sockaddr_in6 *from,
struct interface *ifp)
{
+ struct ripng *ripng;
caddr_t lim;
struct rte *rte;
struct prefix_ipv6 p;
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;
/* 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;
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)
/* 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;
}
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;
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;
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))
ripng->trigger = 0;
/* Reset flush event. */
- ripng_event(RIPNG_UPDATE_EVENT, 0);
+ ripng_event(ripng, RIPNG_UPDATE_EVENT, 0);
return 0;
}
/* 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) {
/* 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;
/* 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))
/* 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
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;
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;
ifp->name);
}
- /* Get RIPng interface. */
+ /* Get RIPng interface and instance. */
ri = ifp->info;
+ ripng = ri->ripng;
ripng_rte_list = ripng_rte_new();
}
/* 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)
/* 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
/* 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)
/* 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;
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;
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. */
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) {
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;
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:
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;
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,
&& (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");
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%%,",
/* 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,",
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;
}
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;
}
#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;
}
/* 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;
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;
void ripng_distribute_update_interface(struct interface *ifp)
{
+ struct ripng_interface *ri = ifp->info;
+ struct ripng *ripng = ri->ripng;
struct distribute *dist;
if (!ripng)
}
/* 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,
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;
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);
}
}
}
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. */
/* 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);
#include <zclient.h>
#include <vty.h>
#include <distribute.h>
+#include <vector.h>
#include "ripng_memory.h"
/* RIPng structure. */
struct ripng {
+ RB_ENTRY(ripng) entry;
+
+ /* VRF this routing instance is associated with. */
+ char *vrf_name;
+
+ /* VRF backpointer (might be NULL if the VRF doesn't exist). */
+ struct vrf *vrf;
+
+ /* Status of the routing instance. */
+ bool enabled;
+
/* RIPng socket. */
int sock;
/* 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;
/* 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;
/* 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 {
/* 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;
/* RIPng peer information. */
struct ripng_peer {
+ /* Parent routing instance. */
+ struct ripng *ripng;
+
/* Peer address. */
struct in6_addr addr;
#define RIPNG_OFFSET_LIST_MAX 2
struct ripng_offset_list {
+ /* Parent routing instance. */
+ struct ripng *ripng;
+
char *ifname;
struct {
};
/* 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,
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);
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;
]
},
"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"
- ]
- }
+ }
+ ]
}
}
</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>
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";
'(./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.";
}
}
}
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.";
+ }
+ }
}
/*
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";
"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.";
}
}
}
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.";
+ }
+ }
}
}
"mappings": [
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']",
- "native": "/frr-ripd:ripd/instance"
+ "native": "/frr-ripd:ripd/instance[vrf='default']"
}
]
},
"mappings": [
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/default-metric",
- "native": "/frr-ripd:ripd/instance/default-metric"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/default-metric"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/distance",
- "native": "/frr-ripd:ripd/instance/distance/default"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/distance/default"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/originate-default-route/enabled",
- "native": "/frr-ripd:ripd/instance/default-information-originate"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/default-information-originate"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/update-interval",
- "native": "/frr-ripd:ripd/instance/timers/update-interval"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/timers/update-interval"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/holddown-interval",
- "native": "/frr-ripd:ripd/instance/timers/holddown-interval"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/timers/holddown-interval"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/timers/flush-interval",
- "native": "/frr-ripd:ripd/instance/timers/flush-interval"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/timers/flush-interval"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']",
- "native": "/frr-ripd:ripd/instance/interface[.='KEY1']"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/interface[.='KEY1']"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']/split-horizon",
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']",
- "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/ipv4-address",
- "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/address"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/address"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/last-update",
- "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/last-update"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/last-update"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-packets-rcvd",
- "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-packets-rcvd"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']/bad-routes-rcvd",
- "native": "/frr-ripd:ripd/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/neighbors/neighbor[address='KEY1']/bad-routes-rcvd"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']",
- "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/ipv4-prefix",
- "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/prefix"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/prefix"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/next-hop",
- "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/next-hop"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/next-hop"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/interface",
- "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/interface"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/interface"
},
{
"custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/routes/route[ipv4-prefix='KEY1']/metric",
- "native": "/frr-ripd:ripd/state/routes/route[prefix='KEY1']/metric"
+ "native": "/frr-ripd:ripd/instance[vrf='default']/state/routes/route[prefix='KEY1']/metric"
},
{
"custom": "/ietf-rip:clear-rip-route",