*/
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_DELETE,
- 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_DELETE, 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");
}
/*
static void rip_interface_reset(struct rip_interface *);
/* Allocate new RIP's interface configuration. */
-static struct rip_interface *rip_interface_new(struct interface *ifp)
+static struct rip_interface *rip_interface_new(void)
{
- struct vrf *vrf;
struct rip_interface *ri;
ri = XCALLOC(MTYPE_RIP_INTERFACE, sizeof(struct rip_interface));
- vrf = vrf_lookup_by_id(ifp->vrf_id);
- if (vrf)
- ri->rip = vrf->info;
-
rip_interface_reset(ri);
return ri;
/* Does this address belongs to me ? */
int if_check_address(struct rip *rip, struct in_addr addr)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
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(struct rip *rip)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
struct interface *ifp;
- FOR_ALL_INTERFACES (vrf, ifp)
+ FOR_ALL_INTERFACES (rip->vrf, ifp)
rip_interface_clean(ifp->info);
}
/* Apply network configuration to all interface. */
static void rip_enable_apply_all(struct rip *rip)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
struct interface *ifp;
/* Check each interface. */
- FOR_ALL_INTERFACES (vrf, ifp)
+ FOR_ALL_INTERFACES (rip->vrf, ifp)
rip_enable_apply(ifp);
}
static void rip_passive_interface_apply_all(struct rip *rip)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
struct interface *ifp;
- FOR_ALL_INTERFACES (vrf, ifp)
+ FOR_ALL_INTERFACES (rip->vrf, ifp)
rip_passive_interface_apply(ifp);
}
/* 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;
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(ifp);
+ ifp->info = rip_interface_new();
+ rip_interface_sync(ifp);
+
return 0;
}
#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 */
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. */
/* SIGINT handler. */
static void sigint(void)
{
- struct vrf *vrf;
-
zlog_notice("Terminating on signal");
- RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) {
- struct rip *rip;
-
- rip = vrf->info;
- if (rip)
- rip_clean(rip);
- }
-
+ rip_vrf_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();
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)
{
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:
- vrf = vrf_lookup_by_id(VRF_DEFAULT);
- socket = resource->fd;
- rip = rip_create(vrf, 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;
}
int count = 0;
memset(&api, 0, sizeof(api));
- api.vrf_id = rip->vrf_id;
+ 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 = rip->vrf_id;
+ 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)
void rip_redistribute_conf_update(struct rip *rip, int type)
{
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, AFI_IP, type,
- 0, rip->vrf_id);
+ 0, rip->vrf->vrf_id);
}
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, rip->vrf_id);
+ AFI_IP, type, 0, rip->vrf->vrf_id);
/* Remove the routes from RIP table. */
rip_redistribute_withdraw(rip, type);
int rip_redistribute_check(struct rip *rip, int type)
{
- return vrf_bitmap_check(zclient->redist[AFI_IP][type], rip->vrf_id);
+ return vrf_bitmap_check(zclient->redist[AFI_IP][type],
+ rip->vrf->vrf_id);
}
void rip_redistribute_clean(struct rip *rip)
{
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
- if (!vrf_bitmap_check(zclient->redist[AFI_IP][i], rip->vrf_id))
+ if (!vrf_bitmap_check(zclient->redist[AFI_IP][i],
+ rip->vrf->vrf_id))
continue;
if (zclient->sock > 0)
zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE,
zclient, AFI_IP, i, 0,
- rip->vrf_id);
+ rip->vrf->vrf_id);
- vrf_bitmap_unset(zclient->redist[AFI_IP][i], rip->vrf_id);
+ vrf_bitmap_unset(zclient->redist[AFI_IP][i], rip->vrf->vrf_id);
}
}
for (int i = 0; i < ZEBRA_ROUTE_MAX; i++) {
if (i == zclient->redist_default
|| !vrf_bitmap_check(zclient->redist[AFI_IP][i],
- rip->vrf_id))
+ rip->vrf->vrf_id))
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
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)
{
/* Check nexthop address validity. */
static int rip_nexthop_check(struct rip *rip, struct in_addr *addr)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
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;
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, rip->vrf_id)
+ 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",
}
if (!if_lookup_address((void *)&rte->nexthop, AF_INET,
- rip->vrf_id)) {
+ rip->vrf->vrf_id)) {
struct route_node *rn;
struct rip_info *rinfo;
}
/* 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));
- return -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);
"infinity metric [delete]",
inet_ntoa(p->prefix),
p->prefixlen,
- ifindex2ifname(ifindex,
- rip->vrf_id));
+ ifindex2ifname(
+ ifindex,
+ rip->vrf->vrf_id));
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
}
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(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, rip->vrf_id);
+ 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;
}
/* Update send to all interface and neighbor. */
static void rip_update_process(struct rip *rip, int route_type)
{
- struct vrf *vrf = vrf_lookup_by_id(rip->vrf_id);
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,
- rip->vrf_id);
+ rip->vrf->vrf_id);
if (!connected) {
zlog_warn(
"Neighbor %s doesn't have connected interface!",
p->prefixlen,
ifindex2ifname(
rinfo->nh.ifindex,
- rip->vrf_id));
+ rip->vrf->vrf_id));
}
rip_event(rip, RIP_TRIGGERED_UPDATE, 0);
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. */
-struct rip *rip_create(struct vrf *vrf, int socket)
+struct rip *rip_create(const char *vrf_name, struct vrf *vrf, int socket)
{
struct rip *rip;
- struct interface *ifp;
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->offset_list_master->del = (void (*)(void *))offset_list_del;
/* Distribute list install. */
- rip->distribute_ctx =
- distribute_list_ctx_create(vrf_lookup_by_id(VRF_DEFAULT));
+ 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);
/* Make output stream. */
rip->obuf = stream_new(1500);
- /* Set socket. */
- rip->sock = socket;
-
- /* Create read and timer thread. */
- rip_event(rip, RIP_READ, rip->sock);
- rip_event(rip, RIP_UPDATE_EVENT, 1);
-
- /* Link RIP instance to VRF. */
- rip->vrf_id = vrf->vrf_id;
- vrf->info = rip;
- FOR_ALL_INTERFACES (vrf, ifp) {
- struct rip_interface *ri;
-
- ri = ifp->info;
- ri->rip = rip;
+ /* 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;
}
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;
- rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
- 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 rip *rip;
- struct vrf *vrf;
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;
- rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
- 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%%,",
vty_out(vty, " Interface Send Recv Key-chain\n");
- vrf = vrf_lookup_by_id(rip->vrf_id);
- FOR_ALL_INTERFACES (vrf, ifp) {
+ FOR_ALL_INTERFACES (rip->vrf, ifp) {
ri = ifp->info;
if (!ri->running)
{
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)
/* 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) {
- struct rip *rip;
+ RB_FOREACH(rip, rip_instance_head, &rip_instances) {
+ char xpath[XPATH_MAXLEN];
+ struct lyd_node *dnode;
- write++;
+ 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);
- rip = rip_lookup_by_vrf_id(VRF_DEFAULT);
- if (rip) {
- /* Distribute configuration. */
- write += config_write_distribute(vty,
- rip->distribute_ctx);
+ /* Distribute configuration. */
+ config_write_distribute(vty, rip->distribute_ctx);
- /* Interface routemap configuration */
- write += config_write_if_rmap(vty);
- }
+ /* Interface routemap configuration */
+ if (strmatch(rip->vrf_name, VRF_DEFAULT_NAME))
+ config_write_if_rmap(vty);
+
+ 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;
/* Delete all added rip route. */
void rip_clean(struct rip *rip)
{
- struct vrf *vrf;
- struct interface *ifp;
- 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);
- }
-
- /* 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;
- }
+ if (rip->enabled)
+ rip_instance_disable(rip);
stream_free(rip->obuf);
route_table_finish(rip->distance_table);
rip_redistribute_clean(rip);
- vrf = vrf_lookup_by_id(rip->vrf_id);
- vrf->info = NULL;
-
- FOR_ALL_INTERFACES (vrf, ifp) {
- struct rip_interface *ri;
-
- ri = ifp->info;
- ri->rip = NULL;
- }
-
+ RB_REMOVE(rip_instance_head, &rip_instances, rip);
+ XFREE(MTYPE_RIP_VRF_NAME, rip->vrf_name);
XFREE(MTYPE_RIP, 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;
+
+ /* 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);
+ }
+
+ /* 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. */
void rip_init(void)
{
/* RIP structure. */
struct rip {
- /* VRF ID. */
- vrf_id_t vrf_id;
+ 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;
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 {
extern void rip_passive_nondefault_clean(struct rip *rip);
extern void rip_if_init(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 rip *rip, struct in_addr addr);
extern struct rip *rip_lookup_by_vrf_id(vrf_id_t vrf_id);
-extern struct rip *rip_create(struct vrf *vrf, int socket);
+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 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(void);
+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 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);
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;
]
},
"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";