summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_packet.c8
-rw-r--r--bgpd/bgp_route.c14
-rw-r--r--bgpd/bgp_route.h3
-rw-r--r--bgpd/bgp_table.c2
-rw-r--r--bgpd/bgp_zebra.c32
-rw-r--r--bgpd/bgpd.c20
-rw-r--r--doc/user/zebra.rst15
-rw-r--r--ldpd/ldpd.c3
-rw-r--r--lib/agentx.c20
-rw-r--r--lib/northbound_confd.c34
-rw-r--r--lib/northbound_sysrepo.c9
-rw-r--r--ospfd/ospf_nsm.c26
-rw-r--r--ospfd/ospf_nsm.h2
-rw-r--r--ospfd/ospf_packet.c14
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py2
-rw-r--r--tests/topotests/bgp_flowspec/r1/zebra.conf1
-rw-r--r--zebra/if_netlink.c4
-rw-r--r--zebra/table_manager.c190
-rw-r--r--zebra/table_manager.h13
-rw-r--r--zebra/zapi_msg.c15
-rw-r--r--zebra/zebra_ns.c5
-rw-r--r--zebra/zebra_vrf.c19
-rw-r--r--zebra/zebra_vrf.h2
-rw-r--r--zebra/zebra_vty.c29
24 files changed, 356 insertions, 126 deletions
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index bb2dbc9427..de9a89523b 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1961,6 +1961,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
struct update_group *updgrp;
struct peer *updgrp_peer;
uint8_t subtype;
+ bool force_update = false;
bgp_size_t msg_length =
size - (BGP_MSG_ROUTE_REFRESH_MIN_SIZE - BGP_HEADER_SIZE);
@@ -2222,7 +2223,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
/* Avoid supressing duplicate routes later
* when processing in subgroup_announce_table().
*/
- SET_FLAG(paf->subgroup->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+ force_update = true;
/* If the peer is configured for default-originate clear the
* SUBGRP_STATUS_DEFAULT_ORIGINATE flag so that we will
@@ -2354,7 +2355,7 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size)
}
/* Perform route refreshment to the peer */
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, force_update);
/* No FSM action necessary */
return BGP_PACKET_NOOP;
@@ -2457,7 +2458,8 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
peer->afc_recv[afi][safi] = 1;
if (peer->afc[afi][safi]) {
peer->afc_nego[afi][safi] = 1;
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi,
+ false);
}
} else {
peer->afc_recv[afi][safi] = 0;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 1111f867c4..0eb3cc61e3 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4588,8 +4588,11 @@ static int bgp_announce_route_timer_expired(struct thread *t)
* bgp_announce_route
*
* *Triggers* announcement of routes of a given AFI/SAFI to a peer.
+ *
+ * if force is true we will force an update even if the update
+ * limiting code is attempted to kick in.
*/
-void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi)
+void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi, bool force)
{
struct peer_af *paf;
struct update_subgroup *subgrp;
@@ -4606,6 +4609,9 @@ void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi)
if (!subgrp || paf->t_announce_route)
return;
+ if (force)
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
/*
* Start a timer to stagger/delay the announce. This serves
* two purposes - announcement can potentially be combined for
@@ -4634,7 +4640,7 @@ void bgp_announce_route_all(struct peer *peer)
safi_t safi;
FOREACH_AFI_SAFI (afi, safi)
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
}
/* Flag or unflag bgp_dest to determine whether it should be treated by
@@ -4772,7 +4778,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread)
table->soft_reconfig_peers,
peer);
bgp_announce_route(peer, table->afi,
- table->safi);
+ table->safi, false);
if (list_isempty(
table->soft_reconfig_peers)) {
list_delete(
@@ -4800,7 +4806,7 @@ static int bgp_soft_reconfig_table_task(struct thread *thread)
*/
for (ALL_LIST_ELEMENTS(table->soft_reconfig_peers, node, nnode, peer)) {
listnode_delete(table->soft_reconfig_peers, peer);
- bgp_announce_route(peer, table->afi, table->safi);
+ bgp_announce_route(peer, table->afi, table->safi, false);
}
list_delete(&table->soft_reconfig_peers);
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 7609f7196d..37bf675b67 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -608,7 +608,8 @@ extern void bgp_process_queue_init(struct bgp *bgp);
extern void bgp_route_init(void);
extern void bgp_route_finish(void);
extern void bgp_cleanup_routes(struct bgp *);
-extern void bgp_announce_route(struct peer *, afi_t, safi_t);
+extern void bgp_announce_route(struct peer *peer, afi_t afi, safi_t safi,
+ bool force);
extern void bgp_stop_announce_route_timer(struct peer_af *paf);
extern void bgp_announce_route_all(struct peer *);
extern void bgp_default_originate(struct peer *, afi_t, safi_t, int);
diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c
index 376172a6f9..4ed8c7c59b 100644
--- a/bgpd/bgp_table.c
+++ b/bgpd/bgp_table.c
@@ -88,7 +88,7 @@ struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest)
const char *bgp_dest_get_prefix_str(struct bgp_dest *dest)
{
const struct prefix *p = NULL;
- char str[PREFIX_STRLEN] = {0};
+ static char str[PREFIX_STRLEN] = {0};
p = bgp_dest_get_prefix(dest);
if (p)
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 2a67bb2f8c..09fe399c29 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -338,8 +338,11 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS)
static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
{
+ struct listnode *node, *nnode;
struct connected *ifc;
+ struct peer *peer;
struct bgp *bgp;
+ struct prefix *addr;
bgp = bgp_lookup_by_vrf_id(vrf_id);
@@ -356,6 +359,35 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS)
bgp_connected_delete(bgp, ifc);
}
+ addr = ifc->address;
+
+ if (bgp) {
+ /*
+ * When we are using the v6 global as part of the peering
+ * nexthops and we are removing it, then we need to
+ * clear the peer data saved for that nexthop and
+ * cause a re-announcement of the route. Since
+ * we do not want the peering to bounce.
+ */
+ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
+ afi_t afi;
+ safi_t safi;
+
+ if (addr->family == AF_INET)
+ continue;
+
+ if (!IN6_IS_ADDR_LINKLOCAL(&addr->u.prefix6)
+ && memcmp(&peer->nexthop.v6_global,
+ &addr->u.prefix6, 16)
+ == 0) {
+ memset(&peer->nexthop.v6_global, 0, 16);
+ FOREACH_AFI_SAFI (afi, safi)
+ bgp_announce_route(peer, afi, safi,
+ true);
+ }
+ }
+ }
+
connected_free(&ifc);
return 0;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 925af80cb7..b191029d2f 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2156,7 +2156,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi)
CAPABILITY_ACTION_SET);
if (peer->afc_recv[afi][safi]) {
peer->afc_nego[afi][safi] = 1;
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi,
+ false);
}
} else {
peer->last_reset = PEER_DOWN_AF_ACTIVATE;
@@ -4142,7 +4143,7 @@ void peer_change_action(struct peer *peer, afi_t afi, safi_t safi,
SUBGRP_STATUS_FORCE_UPDATES);
update_group_adjust_peer(paf);
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
}
}
@@ -5058,7 +5059,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
if (peer_established(peer) && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 0);
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
}
/* Skip peer-group mechanics for regular peers. */
@@ -5095,7 +5096,7 @@ int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
update_group_adjust_peer(
peer_af_find(member, afi, safi));
bgp_default_originate(member, afi, safi, 0);
- bgp_announce_route(member, afi, safi);
+ bgp_announce_route(member, afi, safi, false);
}
}
@@ -5134,7 +5135,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
if (peer_established(peer) && peer->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
bgp_default_originate(peer, afi, safi, 1);
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
}
/* Skip peer-group mechanics for regular peers. */
@@ -5165,7 +5166,7 @@ int peer_default_originate_unset(struct peer *peer, afi_t afi, safi_t safi)
if (peer_established(member) && member->afc_nego[afi][safi]) {
update_group_adjust_peer(peer_af_find(member, afi, safi));
bgp_default_originate(member, afi, safi, 1);
- bgp_announce_route(member, afi, safi);
+ bgp_announce_route(member, afi, safi, false);
}
}
@@ -5213,7 +5214,7 @@ static void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
if (outbound) {
update_group_adjust_peer(peer_af_find(peer, afi, safi));
if (peer_established(peer))
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
} else {
if (!peer_established(peer))
return;
@@ -7480,7 +7481,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
UNSET_FLAG(paf->subgroup->sflags,
SUBGRP_STATUS_DEFAULT_ORIGINATE);
- bgp_announce_route(peer, afi, safi);
+ bgp_announce_route(peer, afi, safi, false);
}
if (stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) {
@@ -7883,8 +7884,7 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
json_no, JSON_C_TO_STRING_PRETTY));
json_object_free(json_no);
} else
- vty_out(vty, "No such neighbor in %s\n",
- bgp->name_pretty);
+ vty_out(vty, "No such neighbor in this view/vrf\n");
return NULL;
}
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 3a9cd11055..5eb97ff06d 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -473,6 +473,21 @@ be updated with the new name. To illustrate, if you want to recompile with
./configure --with-defaultvrfname=global
+.. _zebra-table-allocation:
+
+Table Allocation
+================
+
+Some services like BGP flowspec allocate routing tables to perform policy
+routing based on netfilter criteria and IP rules. In order to avoid
+conflicts between VRF allocated routing tables and those services, Zebra
+proposes to define a chunk of routing tables to use by other services.
+
+Allocation configuration can be done like below, with the range of the
+chunk of routing tables to be used by the given service.
+
+.. clicmd:: ip table range <STARTTABLENO> <ENDTABLENO>
+
.. _zebra-ecmp:
ECMP
diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c
index 9d80bed77f..0ff3238ff9 100644
--- a/ldpd/ldpd.c
+++ b/ldpd/ldpd.c
@@ -243,7 +243,6 @@ main(int argc, char *argv[])
int pipe_parent2ldpe[2], pipe_parent2ldpe_sync[2];
int pipe_parent2lde[2], pipe_parent2lde_sync[2];
char *ctl_sock_name;
- struct thread *thread = NULL;
bool ctl_sock_used = false;
snprintf(ctl_sock_path, sizeof(ctl_sock_path), LDPD_SOCKET,
@@ -393,7 +392,7 @@ main(int argc, char *argv[])
frr_config_fork();
/* apply configuration */
- thread_add_event(master, ldp_config_fork_apply, NULL, 0, &thread);
+ thread_add_event(master, ldp_config_fork_apply, NULL, 0, NULL);
/* setup pipes to children */
if ((iev_ldpe = calloc(1, sizeof(struct imsgev))) == NULL ||
diff --git a/lib/agentx.c b/lib/agentx.c
index 6d4e68d651..5f865ca2b8 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -63,6 +63,8 @@ static int agentx_read(struct thread *t)
int flags, new_flags = 0;
int nonblock = false;
struct listnode *ln = THREAD_ARG(t);
+ struct thread **thr = listgetdata(ln);
+ XFREE(MTYPE_TMP, thr);
list_delete_node(events, ln);
/* fix for non blocking socket */
@@ -109,7 +111,7 @@ static void agentx_events_update(void)
struct timeval timeout = {.tv_sec = 0, .tv_usec = 0};
fd_set fds;
struct listnode *ln;
- struct thread *thr;
+ struct thread **thr;
int fd, thr_fd;
thread_cancel(&timeout_thr);
@@ -125,7 +127,7 @@ static void agentx_events_update(void)
ln = listhead(events);
thr = ln ? listgetdata(ln) : NULL;
- thr_fd = thr ? THREAD_FD(thr) : -1;
+ thr_fd = thr ? THREAD_FD(*thr) : -1;
/* "two-pointer" / two-list simultaneous iteration
* ln/thr/thr_fd point to the next existing event listener to hit while
@@ -135,20 +137,21 @@ static void agentx_events_update(void)
if (thr_fd == fd) {
struct listnode *nextln = listnextnode(ln);
if (!FD_ISSET(fd, &fds)) {
- thread_cancel(&thr);
+ thread_cancel(thr);
+ XFREE(MTYPE_TMP, thr);
list_delete_node(events, ln);
}
ln = nextln;
thr = ln ? listgetdata(ln) : NULL;
- thr_fd = thr ? THREAD_FD(thr) : -1;
+ thr_fd = thr ? THREAD_FD(*thr) : -1;
}
/* need listener, but haven't hit one where it would be */
else if (FD_ISSET(fd, &fds)) {
struct listnode *newln;
- thr = NULL;
- thread_add_read(agentx_tm, agentx_read, NULL, fd, &thr);
+ thr = XCALLOC(MTYPE_TMP, sizeof(struct thread *));
+ thread_add_read(agentx_tm, agentx_read, NULL, fd, thr);
newln = listnode_add_before(events, ln, thr);
- thr->arg = newln;
+ (*thr)->arg = newln;
}
}
@@ -157,7 +160,8 @@ static void agentx_events_update(void)
while (ln) {
struct listnode *nextln = listnextnode(ln);
thr = listgetdata(ln);
- thread_cancel(&thr);
+ thread_cancel(thr);
+ XFREE(MTYPE_TMP, thr);
list_delete_node(events, ln);
ln = nextln;
}
diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c
index 76af494e30..e62a83cee2 100644
--- a/lib/northbound_confd.c
+++ b/lib/northbound_confd.c
@@ -425,8 +425,7 @@ static int frr_confd_cdb_read_cb(struct thread *thread)
int *subp = NULL;
int reslen = 0;
- thread = NULL;
- thread_add_read(master, frr_confd_cdb_read_cb, NULL, fd, &thread);
+ thread_add_read(master, frr_confd_cdb_read_cb, NULL, fd, &t_cdb_sub);
if (cdb_read_subscription_socket2(fd, &cdb_ev, &flags, &subp, &reslen)
!= CONFD_OK) {
@@ -1164,15 +1163,10 @@ exit:
}
-static int frr_confd_dp_read(struct thread *thread)
+static int frr_confd_dp_read(struct confd_daemon_ctx *dctx, int fd)
{
- struct confd_daemon_ctx *dctx = THREAD_ARG(thread);
- int fd = THREAD_FD(thread);
int ret;
- thread = NULL;
- thread_add_read(master, frr_confd_dp_read, dctx, fd, &thread);
-
ret = confd_fd_ready(dctx, fd);
if (ret == CONFD_EOF) {
flog_err_confd("confd_fd_ready");
@@ -1187,6 +1181,26 @@ static int frr_confd_dp_read(struct thread *thread)
return 0;
}
+static int frr_confd_dp_ctl_read(struct thread *thread)
+{
+ struct confd_daemon_ctx *dctx = THREAD_ARG(thread);
+ int fd = THREAD_FD(thread);
+
+ thread_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl);
+
+ frr_confd_dp_read(dctx, fd);
+}
+
+static int frr_confd_dp_worker_read(struct thread *thread)
+{
+ struct confd_daemon_ctx *dctx = THREAD_ARG(thread);
+ int fd = THREAD_FD(thread);
+
+ thread_add_read(master, frr_confd_dp_worker_read, dctx, fd, &t_dp_worker);
+
+ frr_confd_dp_read(dctx, fd);
+}
+
static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg)
{
struct nb_node *nb_node = snode->priv;
@@ -1314,9 +1328,9 @@ static int frr_confd_init_dp(const char *program_name)
goto error;
}
- thread_add_read(master, frr_confd_dp_read, dctx, dp_ctl_sock,
+ thread_add_read(master, frr_confd_dp_ctl_read, dctx, dp_ctl_sock,
&t_dp_ctl);
- thread_add_read(master, frr_confd_dp_read, dctx, dp_worker_sock,
+ thread_add_read(master, frr_confd_dp_worker_read, dctx, dp_worker_sock,
&t_dp_worker);
return 0;
diff --git a/lib/northbound_sysrepo.c b/lib/northbound_sysrepo.c
index 7c463dd61f..86a159e507 100644
--- a/lib/northbound_sysrepo.c
+++ b/lib/northbound_sysrepo.c
@@ -528,19 +528,18 @@ static int frr_sr_notification_send(const char *xpath, struct list *arguments)
static int frr_sr_read_cb(struct thread *thread)
{
- sr_subscription_ctx_t *sr_subscription = THREAD_ARG(thread);
+ struct yang_module *module = THREAD_ARG(thread);
int fd = THREAD_FD(thread);
int ret;
- ret = sr_process_events(sr_subscription, session, NULL);
+ ret = sr_process_events(module->sr_subscription, session, NULL);
if (ret != SR_ERR_OK) {
flog_err(EC_LIB_LIBSYSREPO, "%s: sr_fd_event_process(): %s",
__func__, sr_strerror(ret));
return -1;
}
- thread = NULL;
- thread_add_read(master, frr_sr_read_cb, sr_subscription, fd, &thread);
+ thread_add_read(master, frr_sr_read_cb, module, fd, &module->sr_thread);
return 0;
}
@@ -703,7 +702,7 @@ static int frr_sr_init(void)
sr_strerror(ret));
goto cleanup;
}
- thread_add_read(master, frr_sr_read_cb, module->sr_subscription,
+ thread_add_read(master, frr_sr_read_cb, module,
event_pipe, &module->sr_thread);
}
diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c
index dee25275d6..5f84d04fed 100644
--- a/ospfd/ospf_nsm.c
+++ b/ospfd/ospf_nsm.c
@@ -176,7 +176,7 @@ int nsm_should_adj(struct ospf_neighbor *nbr)
}
/* OSPF NSM functions. */
-static int nsm_packet_received(struct ospf_neighbor *nbr)
+static int nsm_hello_received(struct ospf_neighbor *nbr)
{
/* Start or Restart Inactivity Timer. */
OSPF_NSM_TIMER_OFF(nbr->t_inactivity);
@@ -421,7 +421,7 @@ const struct {
{
/* DependUpon: dummy state. */
{NULL, NSM_DependUpon}, /* NoEvent */
- {NULL, NSM_DependUpon}, /* PacketReceived */
+ {NULL, NSM_DependUpon}, /* HelloReceived */
{NULL, NSM_DependUpon}, /* Start */
{NULL, NSM_DependUpon}, /* 2-WayReceived */
{NULL, NSM_DependUpon}, /* NegotiationDone */
@@ -438,7 +438,7 @@ const struct {
{
/* Deleted: dummy state. */
{NULL, NSM_Deleted}, /* NoEvent */
- {NULL, NSM_Deleted}, /* PacketReceived */
+ {NULL, NSM_Deleted}, /* HelloReceived */
{NULL, NSM_Deleted}, /* Start */
{NULL, NSM_Deleted}, /* 2-WayReceived */
{NULL, NSM_Deleted}, /* NegotiationDone */
@@ -455,8 +455,8 @@ const struct {
{
/* Down: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Init}, /* PacketReceived */
- {nsm_start, NSM_Attempt}, /* Start */
+ {nsm_hello_received, NSM_Init}, /* HelloReceived */
+ {nsm_start, NSM_Attempt}, /* Start */
{NULL, NSM_Down}, /* 2-WayReceived */
{NULL, NSM_Down}, /* NegotiationDone */
{NULL, NSM_Down}, /* ExchangeDone */
@@ -472,7 +472,7 @@ const struct {
{
/* Attempt: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Init}, /* PacketReceived */
+ {nsm_hello_received, NSM_Init}, /* HelloReceived */
{NULL, NSM_Attempt}, /* Start */
{NULL, NSM_Attempt}, /* 2-WayReceived */
{NULL, NSM_Attempt}, /* NegotiationDone */
@@ -489,7 +489,7 @@ const struct {
{
/* Init: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Init}, /* PacketReceived */
+ {nsm_hello_received, NSM_Init}, /* HelloReceived */
{NULL, NSM_Init}, /* Start */
{nsm_twoway_received, NSM_DependUpon}, /* 2-WayReceived */
{NULL, NSM_Init}, /* NegotiationDone */
@@ -506,7 +506,7 @@ const struct {
{
/* 2-Way: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_TwoWay}, /* HelloReceived */
+ {nsm_hello_received, NSM_TwoWay}, /* HelloReceived */
{NULL, NSM_TwoWay}, /* Start */
{NULL, NSM_TwoWay}, /* 2-WayReceived */
{NULL, NSM_TwoWay}, /* NegotiationDone */
@@ -523,7 +523,7 @@ const struct {
{
/* ExStart: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_ExStart}, /* PacaketReceived */
+ {nsm_hello_received, NSM_ExStart}, /* HelloReceived */
{NULL, NSM_ExStart}, /* Start */
{NULL, NSM_ExStart}, /* 2-WayReceived */
{nsm_negotiation_done, NSM_Exchange}, /* NegotiationDone */
@@ -540,7 +540,7 @@ const struct {
{
/* Exchange: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Exchange}, /* PacketReceived */
+ {nsm_hello_received, NSM_Exchange}, /* HelloReceived */
{NULL, NSM_Exchange}, /* Start */
{NULL, NSM_Exchange}, /* 2-WayReceived */
{NULL, NSM_Exchange}, /* NegotiationDone */
@@ -557,7 +557,7 @@ const struct {
{
/* Loading: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Loading}, /* PacketReceived */
+ {nsm_hello_received, NSM_Loading}, /* HelloReceived */
{NULL, NSM_Loading}, /* Start */
{NULL, NSM_Loading}, /* 2-WayReceived */
{NULL, NSM_Loading}, /* NegotiationDone */
@@ -574,7 +574,7 @@ const struct {
{
/* Full: */
{NULL, NSM_DependUpon}, /* NoEvent */
- {nsm_packet_received, NSM_Full}, /* PacketReceived */
+ {nsm_hello_received, NSM_Full}, /* HelloReceived */
{NULL, NSM_Full}, /* Start */
{NULL, NSM_Full}, /* 2-WayReceived */
{NULL, NSM_Full}, /* NegotiationDone */
@@ -591,7 +591,7 @@ const struct {
};
static const char *const ospf_nsm_event_str[] = {
- "NoEvent", "PacketReceived", "Start",
+ "NoEvent", "HelloReceived", "Start",
"2-WayReceived", "NegotiationDone", "ExchangeDone",
"BadLSReq", "LoadingDone", "AdjOK?",
"SeqNumberMismatch", "1-WayReceived", "KillNbr",
diff --git a/ospfd/ospf_nsm.h b/ospfd/ospf_nsm.h
index e8573c6301..798325f790 100644
--- a/ospfd/ospf_nsm.h
+++ b/ospfd/ospf_nsm.h
@@ -40,7 +40,7 @@
/* OSPF Neighbor State Machine Event. */
#define NSM_NoEvent 0
-#define NSM_PacketReceived 1 /* HelloReceived in the protocol */
+#define NSM_HelloReceived 1 /* HelloReceived in the protocol */
#define NSM_Start 2
#define NSM_TwoWayReceived 3
#define NSM_NegotiationDone 4
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 1efdfee3b4..1dcf93dcde 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -1031,7 +1031,7 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh,
old_state = nbr->state;
/* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
+ OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_HelloReceived);
/* RFC2328 Section 9.5.1
If the router is not eligible to become Designated Router,
@@ -1375,9 +1375,6 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh,
UNSET_FLAG(dd->options, OSPF_OPTION_O);
}
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
-
if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
zlog_info(
"%s:Packet[DD]: Neighbor %pI4 state is %s, seq_num:0x%x, local:0x%x",
@@ -1620,9 +1617,6 @@ static void ospf_ls_req(struct ip *iph, struct ospf_header *ospfh,
return;
}
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
-
/* Neighbor State should be Exchange or later. */
if (nbr->state != NSM_Exchange && nbr->state != NSM_Loading
&& nbr->state != NSM_Full) {
@@ -1867,9 +1861,6 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph,
return;
}
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
-
/* Check neighbor state. */
if (nbr->state < NSM_Exchange) {
if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
@@ -2256,9 +2247,6 @@ static void ospf_ls_ack(struct ip *iph, struct ospf_header *ospfh,
return;
}
- /* Add event to thread. */
- OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_PacketReceived);
-
if (nbr->state < NSM_Exchange) {
if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
zlog_debug(
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
index 1b99fcea1f..ddb7f4e16e 100644
--- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -966,7 +966,7 @@ def test_bgp_summary():
r"(192.168.7.(1|2)0|fc00:0:0:8::2000).+Active.+", "", expected
)
elif "10.0.0.1" in arguments:
- expected = "No such neighbor in VRF default"
+ expected = "No such neighbor in this view/vrf"
if "terse" in arguments:
expected = re.sub(r"BGP table version .+", "", expected)
diff --git a/tests/topotests/bgp_flowspec/r1/zebra.conf b/tests/topotests/bgp_flowspec/r1/zebra.conf
index e4d5a21194..4b103cb398 100644
--- a/tests/topotests/bgp_flowspec/r1/zebra.conf
+++ b/tests/topotests/bgp_flowspec/r1/zebra.conf
@@ -1,6 +1,7 @@
!
hostname r1
password zebra
+ip table range 500 600
interface r1-eth0
ip address 10.0.1.1/24
ipv6 address 1001::1/112
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 15645d024d..9385418655 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -1832,6 +1832,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Update link. */
zebra_if_update_link(ifp, link_ifindex, ns_id);
+ ifp->ll_type =
+ netlink_to_zebra_link_type(ifi->ifi_type);
netlink_interface_update_hw_addr(tb, ifp);
/* Inform clients, install any configured addresses. */
@@ -1899,6 +1901,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Update link. */
zebra_if_update_link(ifp, link_ifindex, ns_id);
+ ifp->ll_type =
+ netlink_to_zebra_link_type(ifi->ifi_type);
netlink_interface_update_hw_addr(tb, ifp);
if (if_is_no_ptm_operative(ifp)) {
diff --git a/zebra/table_manager.c b/zebra/table_manager.c
index bb060588d2..9f3b44f944 100644
--- a/zebra/table_manager.c
+++ b/zebra/table_manager.c
@@ -55,10 +55,9 @@
#define RT_TABLE_ID_UNRESERVED_MIN 1
#define RT_TABLE_ID_UNRESERVED_MAX 0xffffffff
-struct table_manager tbl_mgr;
-
DEFINE_MGROUP(TABLE_MGR, "Table Manager");
DEFINE_MTYPE_STATIC(TABLE_MGR, TM_CHUNK, "Table Manager Chunk");
+DEFINE_MTYPE_STATIC(TABLE_MGR, TM_TABLE, "Table Manager Context");
static void delete_table_chunk(void *val)
{
@@ -68,12 +67,21 @@ static void delete_table_chunk(void *val)
/**
* Init table manager
*/
-void table_manager_enable(ns_id_t ns_id)
+void table_manager_enable(struct zebra_vrf *zvrf)
{
- if (ns_id != NS_DEFAULT)
+
+ if (zvrf->tbl_mgr)
return;
- tbl_mgr.lc_list = list_new();
- tbl_mgr.lc_list->del = delete_table_chunk;
+ if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) {
+ struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT);
+
+ if (def)
+ zvrf->tbl_mgr = def->tbl_mgr;
+ return;
+ }
+ zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager));
+ zvrf->tbl_mgr->lc_list = list_new();
+ zvrf->tbl_mgr->lc_list->del = delete_table_chunk;
hook_register(zserv_client_close, release_daemon_table_chunks);
}
@@ -89,14 +97,19 @@ void table_manager_enable(ns_id_t ns_id)
* @return Pointer to the assigned table chunk
*/
struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
- uint32_t size)
+ uint32_t size,
+ struct zebra_vrf *zvrf)
{
struct table_manager_chunk *tmc;
struct listnode *node;
uint32_t start;
+ bool manual_conf = false;
+
+ if (!zvrf)
+ return NULL;
/* first check if there's one available */
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+ for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
if (tmc->proto == NO_PROTO
&& tmc->end - tmc->start + 1 == size) {
tmc->proto = proto;
@@ -109,17 +122,26 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
if (!tmc)
return NULL;
+ if (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end)
+ manual_conf = true;
/* table RT IDs range are [1;252] and [256;0xffffffff]
* - check if the requested range can be within the first range,
* otherwise elect second one
* - TODO : vrf-lites have their own table identifier.
* In that case, table_id should be removed from the table range.
*/
- if (list_isempty(tbl_mgr.lc_list))
- start = RT_TABLE_ID_UNRESERVED_MIN;
- else
+ if (list_isempty(zvrf->tbl_mgr->lc_list)) {
+ if (!manual_conf)
+ start = RT_TABLE_ID_UNRESERVED_MIN;
+ else
+ start = zvrf->tbl_mgr->start;
+ } else
start = ((struct table_manager_chunk *)listgetdata(
- listtail(tbl_mgr.lc_list)))->end + 1;
+ listtail(zvrf->tbl_mgr->lc_list)))
+ ->end
+ + 1;
+
+ if (!manual_conf) {
#if !defined(GNU_LINUX)
/* BSD systems
@@ -127,25 +149,35 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
#else
/* Linux Systems
*/
- /* if not enough room space between MIN and COMPAT,
- * then begin after LOCAL
- */
- if (start < RT_TABLE_ID_COMPAT && (size >
- RT_TABLE_ID_COMPAT
- - RT_TABLE_ID_UNRESERVED_MIN))
- start = RT_TABLE_ID_LOCAL + 1;
+ /* if not enough room space between MIN and COMPAT,
+ * then begin after LOCAL
+ */
+ if (start < RT_TABLE_ID_COMPAT
+ && (size > RT_TABLE_ID_COMPAT - RT_TABLE_ID_UNRESERVED_MIN))
+ start = RT_TABLE_ID_LOCAL + 1;
#endif /* !def(GNU_LINUX) */
- tmc->start = start;
- if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
- flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
- "Reached max table id. Start/Size %u/%u", start, size);
- XFREE(MTYPE_TM_CHUNK, tmc);
- return NULL;
+ tmc->start = start;
+ if (RT_TABLE_ID_UNRESERVED_MAX - size + 1 < start) {
+ flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
+ "Reached max table id. Start/Size %u/%u",
+ start, size);
+ XFREE(MTYPE_TM_CHUNK, tmc);
+ return NULL;
+ }
+ } else {
+ tmc->start = start;
+ if (zvrf->tbl_mgr->end - size + 1 < start) {
+ flog_err(EC_ZEBRA_TM_EXHAUSTED_IDS,
+ "Reached max table id. Start/Size %u/%u",
+ start, size);
+ XFREE(MTYPE_TM_CHUNK, tmc);
+ return NULL;
+ }
}
tmc->end = tmc->start + size - 1;
tmc->proto = proto;
tmc->instance = instance;
- listnode_add(tbl_mgr.lc_list, tmc);
+ listnode_add(zvrf->tbl_mgr->lc_list, tmc);
return tmc;
}
@@ -160,16 +192,23 @@ struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
* @return 0 on success, -1 otherwise
*/
int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
- uint32_t end)
+ uint32_t end, struct zebra_vrf *zvrf)
{
struct listnode *node;
struct table_manager_chunk *tmc;
int ret = -1;
+ struct table_manager *tbl_mgr;
+
+ if (!zvrf)
+ return -1;
+ tbl_mgr = zvrf->tbl_mgr;
+ if (!tbl_mgr)
+ return ret;
/* check that size matches */
zlog_debug("Releasing table chunk: %u - %u", start, end);
/* find chunk and disown */
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
+ for (ALL_LIST_ELEMENTS_RO(tbl_mgr->lc_list, node, tmc)) {
if (tmc->start != start)
continue;
if (tmc->end != end)
@@ -208,24 +247,99 @@ int release_daemon_table_chunks(struct zserv *client)
struct table_manager_chunk *tmc;
int count = 0;
int ret;
+ struct vrf *vrf;
+ struct zebra_vrf *zvrf;
- for (ALL_LIST_ELEMENTS_RO(tbl_mgr.lc_list, node, tmc)) {
- if (tmc->proto == proto && tmc->instance == instance) {
- ret = release_table_chunk(tmc->proto, tmc->instance,
- tmc->start, tmc->end);
- if (ret == 0)
- count++;
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ zvrf = vrf->info;
+
+ if (!zvrf)
+ continue;
+ if (!vrf_is_backend_netns() && vrf->vrf_id != VRF_DEFAULT)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(zvrf->tbl_mgr->lc_list, node, tmc)) {
+ if (tmc->proto == proto && tmc->instance == instance) {
+ ret = release_table_chunk(
+ tmc->proto, tmc->instance, tmc->start,
+ tmc->end, zvrf);
+ if (ret == 0)
+ count++;
+ }
}
}
-
zlog_debug("%s: Released %d table chunks", __func__, count);
return count;
}
-void table_manager_disable(ns_id_t ns_id)
+static void table_range_add(struct zebra_vrf *zvrf, uint32_t start,
+ uint32_t end)
+{
+ if (!zvrf->tbl_mgr)
+ return;
+ zvrf->tbl_mgr->start = start;
+ zvrf->tbl_mgr->end = end;
+}
+
+void table_manager_disable(struct zebra_vrf *zvrf)
{
- if (ns_id != NS_DEFAULT)
+ if (!zvrf->tbl_mgr)
+ return;
+ if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) {
+ zvrf->tbl_mgr = NULL;
return;
- list_delete(&tbl_mgr.lc_list);
+ }
+ list_delete(&zvrf->tbl_mgr->lc_list);
+ XFREE(MTYPE_TM_TABLE, zvrf->tbl_mgr);
+ zvrf->tbl_mgr = NULL;
+}
+
+int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf,
+ const char *start_table_str, const char *end_table_str)
+{
+ uint32_t start;
+ uint32_t end;
+
+ if (add) {
+ if (!start_table_str || !end_table_str) {
+ vty_out(vty, "%% Labels not specified\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ start = atoi(start_table_str);
+ end = atoi(end_table_str);
+ if (end < start) {
+ vty_out(vty, "%% End table is less than Start table\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+#if !defined(GNU_LINUX)
+/* BSD systems
+ */
+#else
+ /* Linux Systems
+ */
+ if ((start >= RT_TABLE_ID_COMPAT && start <= RT_TABLE_ID_LOCAL)
+ || (end >= RT_TABLE_ID_COMPAT
+ && end <= RT_TABLE_ID_LOCAL)) {
+ vty_out(vty, "%% Values forbidden in range [%u;%u]\n",
+ RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ if (start < RT_TABLE_ID_COMPAT && end > RT_TABLE_ID_LOCAL) {
+ vty_out(vty,
+ "%% Range overlaps range [%u;%u] forbidden\n",
+ RT_TABLE_ID_COMPAT, RT_TABLE_ID_LOCAL);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+#endif
+ if (zvrf->tbl_mgr
+ && ((zvrf->tbl_mgr->start && zvrf->tbl_mgr->start != start)
+ || (zvrf->tbl_mgr->end && zvrf->tbl_mgr->end != end))) {
+ vty_out(vty,
+ "%% New range will be taken into account at restart\n");
+ }
+ table_range_add(zvrf, start, end);
+ } else
+ table_range_add(zvrf, 0, 0);
+ return CMD_SUCCESS;
}
diff --git a/zebra/table_manager.h b/zebra/table_manager.h
index 4f78f5097e..fa1366842e 100644
--- a/zebra/table_manager.h
+++ b/zebra/table_manager.h
@@ -57,15 +57,20 @@ struct table_manager_chunk {
*/
struct table_manager {
struct list *lc_list;
+ uint32_t start;
+ uint32_t end;
};
-void table_manager_enable(ns_id_t ns_id);
+void table_manager_enable(struct zebra_vrf *zvrf);
struct table_manager_chunk *assign_table_chunk(uint8_t proto, uint16_t instance,
- uint32_t size);
+ uint32_t size,
+ struct zebra_vrf *zvrf);
int release_table_chunk(uint8_t proto, uint16_t instance, uint32_t start,
- uint32_t end);
+ uint32_t end, struct zebra_vrf *zvrf);
int release_daemon_table_chunks(struct zserv *client);
-void table_manager_disable(ns_id_t ns_id);
+void table_manager_disable(struct zebra_vrf *zvrf);
+int table_manager_range(struct vty *vty, bool add, struct zebra_vrf *zvrf,
+ const char *min, const char *max);
#ifdef __cplusplus
}
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 496849251a..ecfc7da883 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -2853,7 +2853,7 @@ static void zread_label_manager_request(ZAPI_HANDLER_ARGS)
}
static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
- vrf_id_t vrf_id)
+ struct zebra_vrf *zvrf)
{
struct stream *s;
uint32_t size;
@@ -2865,7 +2865,7 @@ static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
/* Get data. */
STREAM_GETL(s, size);
- tmc = assign_table_chunk(client->proto, client->instance, size);
+ tmc = assign_table_chunk(client->proto, client->instance, size, zvrf);
if (!tmc)
flog_err(EC_ZEBRA_TM_CANNOT_ASSIGN_CHUNK,
"%s: Unable to assign Table Chunk of size %u",
@@ -2874,13 +2874,14 @@ static void zread_get_table_chunk(struct zserv *client, struct stream *msg,
zlog_debug("Assigned Table Chunk %u - %u", tmc->start,
tmc->end);
/* send response back */
- zsend_assign_table_chunk_response(client, vrf_id, tmc);
+ zsend_assign_table_chunk_response(client, zvrf_id(zvrf), tmc);
stream_failure:
return;
}
-static void zread_release_table_chunk(struct zserv *client, struct stream *msg)
+static void zread_release_table_chunk(struct zserv *client, struct stream *msg,
+ struct zebra_vrf *zvrf)
{
struct stream *s;
uint32_t start, end;
@@ -2892,7 +2893,7 @@ static void zread_release_table_chunk(struct zserv *client, struct stream *msg)
STREAM_GETL(s, start);
STREAM_GETL(s, end);
- release_table_chunk(client->proto, client->instance, start, end);
+ release_table_chunk(client->proto, client->instance, start, end, zvrf);
stream_failure:
return;
@@ -2912,9 +2913,9 @@ static void zread_table_manager_request(ZAPI_HANDLER_ARGS)
return;
}
if (hdr->command == ZEBRA_GET_TABLE_CHUNK)
- zread_get_table_chunk(client, msg, zvrf_id(zvrf));
+ zread_get_table_chunk(client, msg, zvrf);
else if (hdr->command == ZEBRA_RELEASE_TABLE_CHUNK)
- zread_release_table_chunk(client, msg);
+ zread_release_table_chunk(client, msg, zvrf);
}
}
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 8ae677fb22..50e1d0f389 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -128,9 +128,6 @@ int zebra_ns_enable(ns_id_t ns_id, void **info)
route_read(zns);
kernel_read_pbr_rules(zns);
- /* Initiate Table Manager per ZNS */
- table_manager_enable(ns_id);
-
return 0;
}
@@ -145,8 +142,6 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
kernel_terminate(zns, complete);
- table_manager_disable(zns->ns_id);
-
zns->ns_id = NS_DEFAULT;
return 0;
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index 4fbcc6f596..e162347726 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -44,6 +44,7 @@
#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_vrf_clippy.c"
#endif
+#include "zebra/table_manager.h"
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
safi_t safi);
@@ -113,6 +114,10 @@ static int zebra_vrf_new(struct vrf *vrf)
otable_init(&zvrf->other_tables);
router_id_init(zvrf);
+
+ /* Initiate Table Manager per ZNS */
+ table_manager_enable(zvrf);
+
return 0;
}
@@ -176,6 +181,8 @@ static int zebra_vrf_disable(struct vrf *vrf)
zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf),
zvrf_id(zvrf));
+ table_manager_disable(zvrf);
+
/* Stop any VxLAN-EVPN processing. */
zebra_vxlan_vrf_disable(zvrf);
@@ -503,6 +510,12 @@ static int vrf_config_write(struct vty *vty)
if (zvrf->zebra_rnh_ipv6_default_route)
vty_out(vty, "ipv6 nht resolve-via-default\n");
+
+ if (zvrf->tbl_mgr
+ && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end))
+ vty_out(vty, "ip table range %u %u\n",
+ zvrf->tbl_mgr->start,
+ zvrf->tbl_mgr->end);
} else {
vty_frame(vty, "vrf %s\n", zvrf_name(zvrf));
if (zvrf->l3vni)
@@ -517,6 +530,12 @@ static int vrf_config_write(struct vty *vty)
if (zvrf->zebra_rnh_ipv6_default_route)
vty_out(vty, " ipv6 nht resolve-via-default\n");
+
+ if (zvrf->tbl_mgr && vrf_is_backend_netns()
+ && (zvrf->tbl_mgr->start || zvrf->tbl_mgr->end))
+ vty_out(vty, " ip table range %u %u\n",
+ zvrf->tbl_mgr->start,
+ zvrf->tbl_mgr->end);
}
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index f32f09850b..27342908c4 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -177,6 +177,8 @@ struct zebra_vrf {
uint64_t lsp_installs;
uint64_t lsp_removals;
+ struct table_manager *tbl_mgr;
+
#if defined(HAVE_RTADV)
struct rtadv rtadv;
#endif /* HAVE_RTADV */
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 4b06e84788..c6b3eb48a0 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -59,6 +59,7 @@
#include "northbound_cli.h"
#include "zebra/zebra_nb.h"
#include "zebra/kernel_netlink.h"
+#include "zebra/table_manager.h"
extern int allow_delete;
@@ -4291,6 +4292,31 @@ DEFUN_HIDDEN(no_zebra_kernel_netlink_batch_tx_buf,
#endif /* HAVE_NETLINK */
+DEFUN(ip_table_range, ip_table_range_cmd,
+ "[no] ip table range (1-4294967295) (1-4294967295)",
+ NO_STR IP_STR
+ "table configuration\n"
+ "Configure table range\n"
+ "Start Routing Table\n"
+ "End Routing Table\n")
+{
+ ZEBRA_DECLVAR_CONTEXT(vrf, zvrf);
+
+ if (!zvrf)
+ return CMD_WARNING;
+
+ if (zvrf_id(zvrf) != VRF_DEFAULT && !vrf_is_backend_netns()) {
+ vty_out(vty,
+ "VRF subcommand does not make any sense in l3mdev based vrf's\n");
+ return CMD_WARNING;
+ }
+
+ if (strmatch(argv[0]->text, "no"))
+ return table_manager_range(vty, false, zvrf, NULL, NULL);
+
+ return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg);
+}
+
/* IP node for static routes. */
static int zebra_ip_config(struct vty *vty);
static struct cmd_node ip_node = {
@@ -4439,6 +4465,9 @@ void zebra_vty_init(void)
install_element(CONFIG_NODE, &zebra_dplane_queue_limit_cmd);
install_element(CONFIG_NODE, &no_zebra_dplane_queue_limit_cmd);
+ install_element(CONFIG_NODE, &ip_table_range_cmd);
+ install_element(VRF_NODE, &ip_table_range_cmd);
+
#ifdef HAVE_NETLINK
install_element(CONFIG_NODE, &zebra_kernel_netlink_batch_tx_buf_cmd);
install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd);