summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_advertise.c26
-rw-r--r--bgpd/bgp_advertise.h3
-rw-r--r--bgpd/bgp_fsm.c2
-rw-r--r--bgpd/bgp_io.c19
-rw-r--r--bgpd/bgp_packet.c5
-rw-r--r--bgpd/bgp_route.c8
-rw-r--r--bgpd/bgp_updgrp.c2
-rw-r--r--bgpd/bgp_updgrp.h6
-rw-r--r--bgpd/bgp_vty.c8
-rw-r--r--bgpd/bgp_zebra.c84
-rw-r--r--bgpd/bgpd.c34
-rw-r--r--bgpd/bgpd.h15
-rw-r--r--bgpd/rfapi/rfapi.c4
-rw-r--r--bgpd/rfapi/vnc_zebra.c4
-rw-r--r--doc/user/bfd.rst12
-rw-r--r--doc/user/isisd.rst5
-rw-r--r--isisd/isis_cli.c128
-rw-r--r--isisd/isis_nb.c46
-rw-r--r--isisd/isis_nb.h19
-rw-r--r--isisd/isis_nb_config.c93
-rw-r--r--isisd/isis_redist.c254
-rw-r--r--isisd/isis_redist.h24
-rw-r--r--isisd/isis_zebra.c16
-rw-r--r--isisd/isis_zebra.h6
-rw-r--r--isisd/isisd.c102
-rw-r--r--isisd/isisd.h4
-rw-r--r--lib/elf_py.c2
-rw-r--r--lib/nexthop.c2
-rw-r--r--lib/pbr.h17
-rw-r--r--lib/zclient.c129
-rw-r--r--ospfd/ospf_asbr.c18
-rw-r--r--ospfd/ospf_asbr.h4
-rw-r--r--ospfd/ospf_vty.c6
-rw-r--r--ospfd/ospfd.c2
-rw-r--r--ospfd/ospfd.h4
-rw-r--r--pbrd/pbr_vty.c3
-rw-r--r--pbrd/pbr_zebra.c159
-rw-r--r--tests/lib/test_nexthop_iter.c5
-rw-r--r--tests/topotests/isis_topo1/r3/r3_route.json15
-rw-r--r--tests/topotests/isis_topo1/r4/r4_route.json15
-rw-r--r--tests/topotests/isis_topo1/r5/isisd.conf1
-rw-r--r--tests/topotests/isis_topo1/r5/r5_route.json16
-rw-r--r--tests/topotests/isis_topo1/r5/zebra.conf2
-rw-r--r--tests/topotests/pbr_topo1/test_pbr_topo1.py38
-rw-r--r--yang/frr-isisd.yang51
-rw-r--r--zebra/redistribute.c2
-rw-r--r--zebra/zapi_msg.c64
-rw-r--r--zebra/zebra_nhg.c9
-rw-r--r--zebra/zebra_rib.c8
-rw-r--r--zebra/zebra_vty.c6
-rw-r--r--zebra/zebra_vxlan.c12
51 files changed, 999 insertions, 520 deletions
diff --git a/bgpd/bgp_advertise.c b/bgpd/bgp_advertise.c
index 9686b08a98..da7b496d65 100644
--- a/bgpd/bgp_advertise.c
+++ b/bgpd/bgp_advertise.c
@@ -219,29 +219,3 @@ bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
return true;
}
-
-void bgp_sync_init(struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
- struct bgp_synchronize *sync;
-
- FOREACH_AFI_SAFI (afi, safi) {
- sync = XCALLOC(MTYPE_BGP_SYNCHRONISE,
- sizeof(struct bgp_synchronize));
- bgp_adv_fifo_init(&sync->update);
- bgp_adv_fifo_init(&sync->withdraw);
- bgp_adv_fifo_init(&sync->withdraw_low);
- peer->sync[afi][safi] = sync;
- }
-}
-
-void bgp_sync_delete(struct peer *peer)
-{
- afi_t afi;
- safi_t safi;
-
- FOREACH_AFI_SAFI (afi, safi) {
- XFREE(MTYPE_BGP_SYNCHRONISE, peer->sync[afi][safi]);
- }
-}
diff --git a/bgpd/bgp_advertise.h b/bgpd/bgp_advertise.h
index c5e2a5f216..a063208b6d 100644
--- a/bgpd/bgp_advertise.h
+++ b/bgpd/bgp_advertise.h
@@ -100,7 +100,6 @@ struct bgp_adj_in {
struct bgp_synchronize {
struct bgp_adv_fifo_head update;
struct bgp_adv_fifo_head withdraw;
- struct bgp_adv_fifo_head withdraw_low;
};
/* BGP adjacency linked list. */
@@ -135,8 +134,6 @@ extern bool bgp_adj_in_unset(struct bgp_dest *dest, struct peer *peer,
uint32_t addpath_id);
extern void bgp_adj_in_remove(struct bgp_dest *dest, struct bgp_adj_in *bai);
-extern void bgp_sync_init(struct peer *peer);
-extern void bgp_sync_delete(struct peer *peer);
extern unsigned int bgp_advertise_attr_hash_key(const void *p);
extern bool bgp_advertise_attr_hash_cmp(const void *p1, const void *p2);
extern void bgp_advertise_add(struct bgp_advertise_attr *baa,
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 2cea9971e6..269f5c2948 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -1517,8 +1517,6 @@ enum bgp_fsm_state_progress bgp_stop(struct peer *peer)
if (peer->ibuf_work)
ringbuf_wipe(peer->ibuf_work);
- if (peer->obuf_work)
- stream_reset(peer->obuf_work);
if (peer->curr) {
stream_free(peer->curr);
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index e9178fd8fc..a375bd6005 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -218,7 +218,6 @@ static void bgp_process_reads(struct event *thread)
bool fatal = false; /* whether fatal error occurred */
bool added_pkt = false; /* whether we pushed onto ->ibuf */
int code = 0; /* FSM code if error occurred */
- bool ibuf_full = false; /* Is peer fifo IN Buffer full */
static bool ibuf_full_logged; /* Have we logged full already */
int ret = 1;
/* clang-format on */
@@ -265,7 +264,6 @@ static void bgp_process_reads(struct event *thread)
fatal = true;
break;
case -ENOMEM:
- ibuf_full = true;
if (!ibuf_full_logged) {
if (bgp_debug_neighbor_events(peer))
zlog_debug(
@@ -288,10 +286,6 @@ done:
return;
}
- /* ringbuf should be fully drained unless ibuf is full */
- if (!ibuf_full)
- assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size);
-
event_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
&peer->t_read);
if (added_pkt)
@@ -480,6 +474,7 @@ done : {
return status;
}
+uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX];
/*
* Reads a chunk of data from peer->fd into peer->ibuf_work.
*
@@ -487,6 +482,10 @@ done : {
* Pointer to location to store FSM event code in case of fatal error.
*
* @return status flag (see top-of-file)
+ *
+ * PLEASE NOTE: If we ever transform the bgp_read to be a pthread
+ * per peer then we need to rethink the global ibuf_scratch
+ * data structure above.
*/
static uint16_t bgp_read(struct peer *peer, int *code_p)
{
@@ -502,9 +501,9 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
return status;
}
- readsize = MIN(ibuf_work_space, sizeof(peer->ibuf_scratch));
+ readsize = MIN(ibuf_work_space, sizeof(ibuf_scratch));
- nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
+ nbytes = read(peer->fd, ibuf_scratch, readsize);
/* EAGAIN or EWOULDBLOCK; come back later */
if (nbytes < 0 && ERRNO_IO_RETRY(errno)) {
@@ -533,8 +532,8 @@ static uint16_t bgp_read(struct peer *peer, int *code_p)
SET_FLAG(status, BGP_IO_FATAL_ERR);
} else {
- assert(ringbuf_put(peer->ibuf_work, peer->ibuf_scratch, nbytes)
- == (size_t)nbytes);
+ assert(ringbuf_put(peer->ibuf_work, ibuf_scratch, nbytes) ==
+ (size_t)nbytes);
}
return status;
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ab9e940997..2d1fc103bc 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -956,8 +956,9 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
if (use_curr && peer->curr) {
size_t packetsize = stream_get_endp(peer->curr);
assert(packetsize <= peer->max_packet_size);
- memcpy(peer->last_reset_cause, peer->curr->data, packetsize);
- peer->last_reset_cause_size = packetsize;
+ if (peer->last_reset_cause)
+ stream_free(peer->last_reset_cause);
+ peer->last_reset_cause = stream_dup(peer->curr);
}
/* For debug */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 4e83b36fe0..5f923c598f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -14639,8 +14639,12 @@ CPP_NOTICE("Drop `bgpOriginCodes` from JSON outputs")
json_object_free(json_ocode);
}
- vty_json(vty, json);
- } else if (output_count > 0) {
+ /*
+ * This is an extremely expensive operation at scale
+ * and non-pretty reduces memory footprint significantly.
+ */
+ vty_json_no_pretty(vty, json);
+ } else if (output_count > 0) {
if (!match && filtered_count > 0)
vty_out(vty,
"\nTotal number of prefixes %ld (%ld filtered)\n",
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 849f669932..a55e48d8ed 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -74,7 +74,7 @@ static void sync_init(struct update_subgroup *subgrp,
XCALLOC(MTYPE_BGP_SYNCHRONISE, sizeof(struct bgp_synchronize));
bgp_adv_fifo_init(&subgrp->sync->update);
bgp_adv_fifo_init(&subgrp->sync->withdraw);
- bgp_adv_fifo_init(&subgrp->sync->withdraw_low);
+
subgrp->hash =
hash_create(bgp_advertise_attr_hash_key,
bgp_advertise_attr_hash_cmp, "BGP SubGroup Hash");
diff --git a/bgpd/bgp_updgrp.h b/bgpd/bgp_updgrp.h
index 70e7ac30b5..0d866f3be7 100644
--- a/bgpd/bgp_updgrp.h
+++ b/bgpd/bgp_updgrp.h
@@ -584,11 +584,9 @@ static inline void bgp_announce_peer(struct peer *peer)
*/
static inline int advertise_list_is_empty(struct update_subgroup *subgrp)
{
- if (bgp_adv_fifo_count(&subgrp->sync->update)
- || bgp_adv_fifo_count(&subgrp->sync->withdraw)
- || bgp_adv_fifo_count(&subgrp->sync->withdraw_low)) {
+ if (bgp_adv_fifo_count(&subgrp->sync->update) ||
+ bgp_adv_fifo_count(&subgrp->sync->withdraw))
return 0;
- }
return 1;
}
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 02ee5320e9..4f773f21a5 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -14862,15 +14862,15 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
BGP_UPTIME_LEN, 0, NULL));
bgp_show_peer_reset(vty, p, NULL, false);
- if (p->last_reset_cause_size) {
- msg = p->last_reset_cause;
+ if (p->last_reset_cause) {
+ msg = p->last_reset_cause->data;
vty_out(vty,
" Message received that caused BGP to send a NOTIFICATION:\n ");
- for (i = 1; i <= p->last_reset_cause_size;
+ for (i = 1; i <= p->last_reset_cause->size;
i++) {
vty_out(vty, "%02X", *msg++);
- if (i != p->last_reset_cause_size) {
+ if (i != p->last_reset_cause->size) {
if (i % 16 == 0) {
vty_out(vty, "\n ");
} else if (i % 4 == 0) {
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 07428bd01f..becd99167f 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2712,17 +2712,20 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
struct bgp_pbr_action *pbra,
struct bgp_pbr_rule *pbr)
{
- struct prefix pfx;
uint8_t fam = AF_INET;
- char ifname[INTERFACE_NAMSIZ];
+ struct pbr_rule r;
if (pbra->nh.type == NEXTHOP_TYPE_IPV6)
fam = AF_INET6;
- stream_putl(s, 0); /* seqno unused */
+
+ /*
+ * Convert to canonical form
+ */
+ memset(&r, 0, sizeof(r));
+ /* r.seq unused */
if (pbr)
- stream_putl(s, pbr->priority);
- else
- stream_putl(s, 0);
+ r.priority = pbr->priority;
+
/* ruleno unused - priority change
* ruleno permits distinguishing various FS PBR entries
* - FS PBR entries based on ipset/iptables
@@ -2730,56 +2733,37 @@ static void bgp_encode_pbr_rule_action(struct stream *s,
* the latter may contain default routing information injected by FS
*/
if (pbr)
- stream_putl(s, pbr->unique);
+ r.unique = pbr->unique;
else
- stream_putl(s, pbra->unique);
+ r.unique = pbra->unique;
- stream_putl(s, 0); /* filter_bm placeholder */
- stream_putc(s, 0); /* ip protocol being used */
- if (pbr && pbr->flags & MATCH_IP_SRC_SET)
- memcpy(&pfx, &(pbr->src), sizeof(struct prefix));
- else {
- memset(&pfx, 0, sizeof(pfx));
- pfx.family = fam;
- }
- stream_putc(s, pfx.family);
- stream_putc(s, pfx.prefixlen);
- stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
-
- stream_putw(s, 0); /* src port */
+ /* filter */
- if (pbr && pbr->flags & MATCH_IP_DST_SET)
- memcpy(&pfx, &(pbr->dst), sizeof(struct prefix));
- else {
- memset(&pfx, 0, sizeof(pfx));
- pfx.family = fam;
+ if (pbr && pbr->flags & MATCH_IP_SRC_SET) {
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP);
+ r.filter.src_ip = pbr->src;
+ } else {
+ /* ??? */
+ r.filter.src_ip.family = fam;
+ }
+ if (pbr && pbr->flags & MATCH_IP_DST_SET) {
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP);
+ r.filter.dst_ip = pbr->dst;
+ } else {
+ /* ??? */
+ r.filter.dst_ip.family = fam;
+ }
+ /* src_port, dst_port, pcp, dsfield not used */
+ if (!pbr) {
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK);
+ r.filter.fwmark = pbra->fwmark;
}
- stream_putc(s, pfx.family);
- stream_putc(s, pfx.prefixlen);
- stream_put(s, &pfx.u.prefix, prefix_blen(&pfx));
-
- stream_putw(s, 0); /* dst port */
-
- stream_putc(s, 0); /* filter dsfield */
- /* if pbr present, fwmark is not used */
- if (pbr)
- stream_putl(s, 0);
- else
- stream_putl(s, pbra->fwmark); /* filter fwmark */
-
- stream_putc(s, 0); /* pcp filter */
- stream_putw(s, 0); /* pcp action */
- stream_putw(s, 0); /* vlan_id filter */
- stream_putw(s, 0); /* vlan_flags filter */
- stream_putw(s, 0); /* vlan_id action */
- stream_putw(s, 0); /* vlan_flags action */
- stream_putl(s, 0); /* queue id action */
- stream_putl(s, pbra->table_id); /* table action */
+ SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */
+ r.action.table = pbra->table_id;
- memset(ifname, 0, sizeof(ifname));
- stream_put(s, ifname, INTERFACE_NAMSIZ); /* ifname unused */
+ zapi_pbr_rule_encode(s, &r);
}
static void bgp_encode_pbr_ipset_match(struct stream *s,
@@ -3545,11 +3529,9 @@ void bgp_send_pbr_rule_action(struct bgp_pbr_action *pbra,
zclient_create_header(s,
install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
VRF_DEFAULT);
- stream_putl(s, 1); /* send one pbr action */
bgp_encode_pbr_rule_action(s, pbra, pbr);
- stream_putw_at(s, 0, stream_get_endp(s));
if ((zclient_send_message(zclient) != ZCLIENT_SEND_FAILURE)
&& install) {
if (!pbr)
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 00a5e190cb..28c1a9da6b 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1171,8 +1171,6 @@ static void peer_free(struct peer *peer)
if (peer->clear_node_queue)
work_queue_free_and_null(&peer->clear_node_queue);
- bgp_sync_delete(peer);
-
XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
@@ -1191,6 +1189,8 @@ static void peer_free(struct peer *peer)
bgp_unlock(peer->bgp);
+ stream_free(peer->last_reset_cause);
+
memset(peer, 0, sizeof(struct peer));
XFREE(MTYPE_BGP_PEER, peer);
@@ -1415,26 +1415,8 @@ struct peer *peer_new(struct bgp *bgp)
peer->obuf = stream_fifo_new();
pthread_mutex_init(&peer->io_mtx, NULL);
- /* We use a larger buffer for peer->obuf_work in the event that:
- * - We RX a BGP_UPDATE where the attributes alone are just
- * under BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE.
- * - The user configures an outbound route-map that does many as-path
- * prepends or adds many communities. At most they can have
- * CMD_ARGC_MAX args in a route-map so there is a finite limit on how
- * large they can make the attributes.
- *
- * Having a buffer with BGP_MAX_PACKET_SIZE_OVERFLOW allows us to avoid
- * bounds checking for every single attribute as we construct an
- * UPDATE.
- */
- peer->obuf_work =
- stream_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE_OVERFLOW);
peer->ibuf_work =
- ringbuf_new(BGP_MAX_PACKET_SIZE * BGP_READ_PACKET_MAX);
-
- peer->scratch = stream_new(BGP_MAX_PACKET_SIZE);
-
- bgp_sync_init(peer);
+ ringbuf_new(BGP_MAX_PACKET_SIZE + BGP_MAX_PACKET_SIZE/2);
/* Get service port number. */
sp = getservbyname("bgp", "tcp");
@@ -2624,16 +2606,6 @@ int peer_delete(struct peer *peer)
peer->ibuf_work = NULL;
}
- if (peer->obuf_work) {
- stream_free(peer->obuf_work);
- peer->obuf_work = NULL;
- }
-
- if (peer->scratch) {
- stream_free(peer->scratch);
- peer->scratch = NULL;
- }
-
/* Local and remote addresses. */
if (peer->su_local) {
sockunion_free(peer->su_local);
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index cddb896615..5e467bb873 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1163,20 +1163,10 @@ struct peer {
struct stream_fifo *ibuf; // packets waiting to be processed
struct stream_fifo *obuf; // packets waiting to be written
- /* used as a block to deposit raw wire data to */
- uint8_t ibuf_scratch[BGP_EXTENDED_MESSAGE_MAX_PACKET_SIZE
- * BGP_READ_PACKET_MAX];
struct ringbuf *ibuf_work; // WiP buffer used by bgp_read() only
- struct stream *obuf_work; // WiP buffer used to construct packets
struct stream *curr; // the current packet being parsed
- /* We use a separate stream to encode MP_REACH_NLRI for efficient
- * NLRI packing. peer->obuf_work stores all the other attributes. The
- * actual packet is then constructed by concatenating the two.
- */
- struct stream *scratch;
-
/* the doppelganger peer structure, due to dual TCP conn setup */
struct peer *doppelganger;
@@ -1612,8 +1602,6 @@ struct peer {
uint8_t update_delay_over; /* When this is set, BGP is no more waiting
for EOR */
- /* Syncronization list and time. */
- struct bgp_synchronize *sync[AFI_MAX][SAFI_MAX];
time_t synctime;
/* timestamp when the last UPDATE msg was written */
_Atomic time_t last_write;
@@ -1728,8 +1716,7 @@ struct peer {
* a new value to the last_reset reason
*/
- uint16_t last_reset_cause_size;
- uint8_t last_reset_cause[BGP_MAX_PACKET_SIZE];
+ struct stream *last_reset_cause;
/* The kind of route-map Flags.*/
uint16_t rmap_type;
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index 67c70431bd..985094d323 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -1237,7 +1237,6 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
*/
rfd->peer = peer_new(bgp);
rfd->peer->status = Established; /* keep bgp core happy */
- bgp_sync_delete(rfd->peer); /* don't need these */
/*
* since this peer is not on the I/O thread, this lock is not strictly
@@ -1252,12 +1251,9 @@ static int rfapi_open_inner(struct rfapi_descriptor *rfd, struct bgp *bgp,
if (rfd->peer->ibuf_work)
ringbuf_del(rfd->peer->ibuf_work);
- if (rfd->peer->obuf_work)
- stream_free(rfd->peer->obuf_work);
rfd->peer->ibuf = NULL;
rfd->peer->obuf = NULL;
- rfd->peer->obuf_work = NULL;
rfd->peer->ibuf_work = NULL;
}
diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c
index 9c971272e4..c17b17a335 100644
--- a/bgpd/rfapi/vnc_zebra.c
+++ b/bgpd/rfapi/vnc_zebra.c
@@ -173,7 +173,6 @@ static void vnc_redistribute_add(struct prefix *p, uint32_t metric,
vncHD1VR.peer = peer_new(bgp);
vncHD1VR.peer->status =
Established; /* keep bgp core happy */
- bgp_sync_delete(vncHD1VR.peer); /* don't need these */
/*
* since this peer is not on the I/O thread, this lock
@@ -189,12 +188,9 @@ static void vnc_redistribute_add(struct prefix *p, uint32_t metric,
if (vncHD1VR.peer->ibuf_work)
ringbuf_del(vncHD1VR.peer->ibuf_work);
- if (vncHD1VR.peer->obuf_work)
- stream_free(vncHD1VR.peer->obuf_work);
vncHD1VR.peer->ibuf = NULL;
vncHD1VR.peer->obuf = NULL;
- vncHD1VR.peer->obuf_work = NULL;
vncHD1VR.peer->ibuf_work = NULL;
}
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 776726f193..6c57822510 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -225,12 +225,6 @@ BFD peers and profiles share the same BFD session configuration commands.
BFD Peer Specific Commands
--------------------------
-.. clicmd:: label WORD
-
- Labels a peer with the provided word. This word can be referenced
- later on other daemons to refer to a specific peer.
-
-
.. clicmd:: profile BFDPROF
Configure peer to use the profile configurations.
@@ -443,7 +437,6 @@ Here is an example of BFD configuration:
bfd
peer 192.168.0.1
- label home-peer
no shutdown
!
!
@@ -457,7 +450,7 @@ Here is an example of BFD configuration:
!
Peers can be identified by its address (use ``multihop`` when you need
-to specify a multi hop peer) or can be specified manually by a label.
+to specify a multi hop peer).
Here are the available peer configurations:
@@ -500,7 +493,6 @@ Here are the available peer configurations:
! configure a peer with every option possible
peer 192.168.0.4
- label peer-label
detect-multiplier 50
receive-interval 60000
transmit-interval 3000
@@ -548,7 +540,6 @@ You can inspect the current BFD peer status with the following commands:
Echo receive interval: 50ms
peer 192.168.1.1
- label: router3-peer
ID: 2
Remote ID: 2
Status: up
@@ -571,7 +562,6 @@ You can inspect the current BFD peer status with the following commands:
frr# show bfd peer 192.168.1.1
BFD Peer:
peer 192.168.1.1
- label: router3-peer
ID: 2
Remote ID: 2
Status: up
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 570b8bd182..83fc2e0281 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -166,6 +166,11 @@ flavors (local LFA, Remote LFA and TI-LFA).
Configure a prefix-list to select eligible PQ nodes for remote LFA
backups (valid for all protected interfaces).
+.. clicmd:: redistribute <ipv4 | ipv6> table (1-65535) <level-1 | level-2> [metric (0-16777215)|route-map WORD]
+
+ Redistribute routes from a given routing table into the given ISIS
+ level database.
+
.. _isis-region:
ISIS region
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index 7c7a8d2389..6f53ab479f 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1430,20 +1430,99 @@ DEFPY_YANG(isis_redistribute, isis_redistribute_cmd,
level);
}
-static void vty_print_redistribute(struct vty *vty,
- const struct lyd_node *dnode,
- bool show_defaults, const char *family)
-{
- const char *level = yang_dnode_get_string(dnode, "./level");
- const char *protocol = yang_dnode_get_string(dnode, "./protocol");
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/table
+ */
+DEFPY_YANG(isis_redistribute_table, isis_redistribute_table_cmd,
+ "[no] redistribute <ipv4|ipv6>$ip table (1-65535)$table"
+ "<level-1|level-2>$level [{metric (0-16777215)|route-map WORD}]",
+ NO_STR REDIST_STR "Redistribute IPv4 routes\n"
+ "Redistribute IPv6 routes\n"
+ "Non-main Kernel Routing Table\n"
+ "Table Id\n"
+ "Redistribute into level-1\n"
+ "Redistribute into level-2\n"
+ "Metric for redistributed routes\n"
+ "IS-IS default metric\n"
+ "Route map reference\n"
+ "Pointer to route-map entries\n")
+{
+ struct isis_redist_table_present_args rtda = {};
+ char xpath[XPATH_MAXLEN];
+ char xpath_entry[XPATH_MAXLEN + 128];
+ int rv;
+
+ rtda.rtda_table = table_str;
+ rtda.rtda_ip = ip;
+ rtda.rtda_level = level;
- vty_out(vty, " redistribute %s %s %s", family, protocol, level);
+ if (no) {
+ if (!isis_redist_table_is_present(vty, &rtda))
+ return CMD_WARNING_CONFIG_FAILED;
+
+ snprintf(xpath, sizeof(xpath), "./table[table='%s']", table_str);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ rv = nb_cli_apply_changes(vty,
+ "./redistribute/%s[protocol='table'][level='%s']",
+ ip, level);
+ if (rv == CMD_SUCCESS) {
+ if (isis_redist_table_get_first(vty, &rtda) > 0)
+ return CMD_SUCCESS;
+ nb_cli_enqueue_change(vty, "./table", NB_OP_DESTROY,
+ NULL);
+ nb_cli_apply_changes(vty,
+ "./redistribute/%s[protocol='table'][level='%s']",
+ ip, level);
+ }
+ return CMD_SUCCESS;
+ }
+ if (isis_redist_table_is_present(vty, &rtda))
+ return CMD_SUCCESS;
+
+ snprintf(xpath, sizeof(xpath), "./table[table='%s']", table_str);
+ nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_entry, sizeof(xpath_entry), "%s/route-map", xpath);
+ nb_cli_enqueue_change(vty, xpath_entry,
+ route_map ? NB_OP_MODIFY : NB_OP_DESTROY,
+ route_map ? route_map : NULL);
+ snprintf(xpath_entry, sizeof(xpath_entry), "%s/metric", xpath);
+ nb_cli_enqueue_change(vty, xpath_entry, NB_OP_MODIFY,
+ metric_str ? metric_str : NULL);
+ return nb_cli_apply_changes(vty,
+ "./redistribute/%s[protocol='table'][level='%s']",
+ ip, level);
+}
+
+static void vty_print_redistribute(struct vty *vty, const struct lyd_node *dnode,
+ bool show_defaults, const char *family,
+ bool table)
+{
+ const char *level;
+ const char *protocol = NULL;
+ const char *routemap = NULL;
+ uint16_t tableid;
+
+ if (table) {
+ level = yang_dnode_get_string(dnode, "../level");
+ tableid = yang_dnode_get_uint16(dnode, "./table");
+ vty_out(vty, " redistribute %s table %d ", family, tableid);
+ } else {
+ protocol = yang_dnode_get_string(dnode, "./protocol");
+ if (!table && strmatch(protocol, "table"))
+ return;
+ level = yang_dnode_get_string(dnode, "./level");
+ vty_out(vty, " redistribute %s %s ", family, protocol);
+ }
+ vty_out(vty, "%s", level);
if (show_defaults || !yang_dnode_is_default(dnode, "./metric"))
vty_out(vty, " metric %s",
- yang_dnode_get_string(dnode, "./metric"));
+ yang_dnode_get_string(dnode, "%s", "./metric"));
+
if (yang_dnode_exists(dnode, "./route-map"))
- vty_out(vty, " route-map %s",
- yang_dnode_get_string(dnode, "./route-map"));
+ routemap = yang_dnode_get_string(dnode, "./route-map");
+ if (routemap)
+ vty_out(vty, " route-map %s", routemap);
vty_out(vty, "\n");
}
@@ -1451,13 +1530,37 @@ void cli_show_isis_redistribute_ipv4(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
- vty_print_redistribute(vty, dnode, show_defaults, "ipv4");
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv4", false);
}
+
void cli_show_isis_redistribute_ipv6(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults)
{
- vty_print_redistribute(vty, dnode, show_defaults, "ipv6");
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv6", false);
+}
+
+void cli_show_isis_redistribute_ipv4_table(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv4", true);
+}
+
+void cli_show_isis_redistribute_ipv6_table(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_print_redistribute(vty, dnode, show_defaults, "ipv6", true);
+}
+
+int cli_cmp_isis_redistribute_table(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2)
+{
+ uint16_t table1 = yang_dnode_get_uint16(dnode1, "./table");
+ uint16_t table2 = yang_dnode_get_uint16(dnode2, "./table");
+
+ return table1 - table2;
}
/*
@@ -3681,6 +3784,7 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &isis_default_originate_cmd);
install_element(ISIS_NODE, &isis_redistribute_cmd);
+ install_element(ISIS_NODE, &isis_redistribute_table_cmd);
install_element(ISIS_NODE, &isis_topology_cmd);
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index 6da8fa2d28..c81412d24a 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -382,6 +382,29 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv4/metric",
.cbs = {
+ .destroy = isis_instance_redistribute_ipv4_metric_destroy,
+ .modify = isis_instance_redistribute_ipv4_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table",
+ .cbs = {
+ .cli_show = cli_show_isis_redistribute_ipv4_table,
+ .cli_cmp = cli_cmp_isis_redistribute_table,
+ .create = isis_instance_redistribute_ipv4_table_create,
+ .destroy = isis_instance_redistribute_ipv4_table_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table/route-map",
+ .cbs = {
+ .destroy = isis_instance_redistribute_ipv4_route_map_destroy,
+ .modify = isis_instance_redistribute_ipv4_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv4/table/metric",
+ .cbs = {
.modify = isis_instance_redistribute_ipv4_metric_modify,
},
},
@@ -404,6 +427,29 @@ const struct frr_yang_module_info frr_isisd_info = {
{
.xpath = "/frr-isisd:isis/instance/redistribute/ipv6/metric",
.cbs = {
+ .destroy = isis_instance_redistribute_ipv6_metric_destroy,
+ .modify = isis_instance_redistribute_ipv6_metric_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table",
+ .cbs = {
+ .cli_show = cli_show_isis_redistribute_ipv6_table,
+ .cli_cmp = cli_cmp_isis_redistribute_table,
+ .create = isis_instance_redistribute_ipv6_table_create,
+ .destroy = isis_instance_redistribute_ipv6_table_destroy,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table/route-map",
+ .cbs = {
+ .destroy = isis_instance_redistribute_ipv6_route_map_destroy,
+ .modify = isis_instance_redistribute_ipv6_route_map_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/redistribute/ipv6/table/metric",
+ .cbs = {
.modify = isis_instance_redistribute_ipv6_metric_modify,
},
},
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 13efa36d78..3b8ddca4f8 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -121,6 +121,11 @@ int isis_instance_redistribute_ipv4_route_map_destroy(
struct nb_cb_destroy_args *args);
int isis_instance_redistribute_ipv4_metric_modify(
struct nb_cb_modify_args *args);
+int isis_instance_redistribute_ipv4_metric_destroy(
+ struct nb_cb_destroy_args *args);
+int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args);
+int isis_instance_redistribute_ipv4_table_destroy(
+ struct nb_cb_destroy_args *args);
int isis_instance_redistribute_ipv6_create(struct nb_cb_create_args *args);
int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args);
int isis_instance_redistribute_ipv6_route_map_modify(
@@ -129,6 +134,11 @@ int isis_instance_redistribute_ipv6_route_map_destroy(
struct nb_cb_destroy_args *args);
int isis_instance_redistribute_ipv6_metric_modify(
struct nb_cb_modify_args *args);
+int isis_instance_redistribute_ipv6_metric_destroy(
+ struct nb_cb_destroy_args *args);
+int isis_instance_redistribute_ipv6_table_create(struct nb_cb_create_args *args);
+int isis_instance_redistribute_ipv6_table_destroy(
+ struct nb_cb_destroy_args *args);
int isis_instance_multi_topology_ipv4_multicast_create(
struct nb_cb_create_args *args);
int isis_instance_multi_topology_ipv4_multicast_destroy(
@@ -587,6 +597,12 @@ void cli_show_isis_redistribute_ipv6(struct vty *vty,
void cli_show_isis_mt_ipv4_multicast(struct vty *vty,
const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_redistribute_ipv4_table(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_redistribute_ipv6_table(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mt_ipv6_unicast(struct vty *vty,
@@ -742,6 +758,9 @@ void isis_notif_seqno_skipped(const struct isis_circuit *circuit,
const uint8_t *lsp_id);
void isis_notif_own_lsp_purge(const struct isis_circuit *circuit,
const uint8_t *lsp_id);
+/* cmp */
+int cli_cmp_isis_redistribute_table(const struct lyd_node *dnode1,
+ const struct lyd_node *dnode2);
/* We also declare hook for every notification */
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 8a111b301d..a3d8896e4f 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -1088,7 +1088,7 @@ void default_info_origin_apply_finish(const struct lyd_node *dnode, int family)
routemap = yang_dnode_get_string(dnode, "./route-map");
isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
- originate_type);
+ originate_type, 0);
}
void default_info_origin_ipv4_apply_finish(struct nb_cb_apply_finish_args *args)
@@ -1119,7 +1119,7 @@ int isis_instance_default_information_originate_ipv4_destroy(
area = nb_running_get_entry(args->dnode, NULL, true);
level = yang_dnode_get_enum(args->dnode, "./level");
- isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE);
+ isis_redist_unset(area, level, AF_INET, DEFAULT_ROUTE, 0);
return NB_OK;
}
@@ -1182,7 +1182,7 @@ int isis_instance_default_information_originate_ipv6_destroy(
area = nb_running_get_entry(args->dnode, NULL, true);
level = yang_dnode_get_enum(args->dnode, "./level");
- isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE);
+ isis_redist_unset(area, level, AF_INET6, DEFAULT_ROUTE, 0);
return NB_OK;
}
@@ -1244,7 +1244,7 @@ void redistribute_apply_finish(const struct lyd_node *dnode, int family)
if (yang_dnode_exists(dnode, "./route-map"))
routemap = yang_dnode_get_string(dnode, "./route-map");
- isis_redist_set(area, level, family, type, metric, routemap, 0);
+ isis_redist_set(area, level, family, type, metric, routemap, 0, 0);
}
void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args)
@@ -1274,13 +1274,14 @@ int isis_instance_redistribute_ipv4_destroy(struct nb_cb_destroy_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
level = yang_dnode_get_enum(args->dnode, "./level");
type = yang_dnode_get_enum(args->dnode, "./protocol");
- isis_redist_unset(area, level, AF_INET, type);
+ isis_redist_unset(area, level, AF_INET, type, 0);
return NB_OK;
}
/*
* XPath: /frr-isisd:isis/instance/redistribute/ipv4/route-map
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/route-map
*/
int isis_instance_redistribute_ipv4_route_map_modify(
struct nb_cb_modify_args *args)
@@ -1298,6 +1299,7 @@ int isis_instance_redistribute_ipv4_route_map_destroy(
/*
* XPath: /frr-isisd:isis/instance/redistribute/ipv4/metric
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table/metric
*/
int isis_instance_redistribute_ipv4_metric_modify(
struct nb_cb_modify_args *args)
@@ -1306,6 +1308,58 @@ int isis_instance_redistribute_ipv4_metric_modify(
return NB_OK;
}
+int isis_instance_redistribute_ipv4_metric_destroy(struct nb_cb_destroy_args *args)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv4/table
+ */
+int isis_instance_redistribute_ipv4_table_create(struct nb_cb_create_args *args)
+{
+ uint16_t table;
+ int type, level;
+ unsigned long metric = 0;
+ const char *routemap = NULL;
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ type = yang_dnode_get_enum(args->dnode, "../protocol");
+ level = yang_dnode_get_enum(args->dnode, "../level");
+ area = nb_running_get_entry(args->dnode, "../.", true);
+
+ if (yang_dnode_exists(args->dnode, "./metric"))
+ metric = yang_dnode_get_uint32(args->dnode, "./metric");
+ if (yang_dnode_exists(args->dnode, "./route-map"))
+ routemap = yang_dnode_get_string(args->dnode, "./route-map");
+
+ table = yang_dnode_get_uint16(args->dnode, "./table");
+ isis_redist_set(area, level, AF_INET, type, metric, routemap, 0, table);
+
+ return NB_OK;
+}
+int isis_instance_redistribute_ipv4_table_destroy(struct nb_cb_destroy_args *args)
+{
+ struct isis_area *area;
+ int level, type;
+ uint16_t table;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, "../.", true);
+ level = yang_dnode_get_enum(args->dnode, "../level");
+ type = yang_dnode_get_enum(args->dnode, "../protocol");
+ table = yang_dnode_get_uint16(args->dnode, "./table");
+ isis_redist_unset(area, level, AF_INET, type, table);
+
+ return NB_OK;
+}
+
/*
* XPath: /frr-isisd:isis/instance/redistribute/ipv6
*/
@@ -1326,7 +1380,7 @@ int isis_instance_redistribute_ipv6_destroy(struct nb_cb_destroy_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
level = yang_dnode_get_enum(args->dnode, "./level");
type = yang_dnode_get_enum(args->dnode, "./protocol");
- isis_redist_unset(area, level, AF_INET6, type);
+ isis_redist_unset(area, level, AF_INET6, type, 0);
return NB_OK;
}
@@ -1358,6 +1412,33 @@ int isis_instance_redistribute_ipv6_metric_modify(
return NB_OK;
}
+int isis_instance_redistribute_ipv6_metric_destroy(struct nb_cb_destroy_args *args)
+{
+ /* It's all done by redistribute_apply_finish */
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/redistribute/ipv6/table
+ */
+int isis_instance_redistribute_ipv6_table_create(struct nb_cb_create_args *args)
+{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* TODO */
+ return NB_OK;
+}
+
+int isis_instance_redistribute_ipv6_table_destroy(struct nb_cb_destroy_args *args)
+{
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ /* TODO */
+ return NB_OK;
+}
+
/*
* XPath: /frr-isisd:isis/instance/multi-topology/ipv4-multicast
*/
diff --git a/isisd/isis_redist.c b/isisd/isis_redist.c
index 6a822f02fe..2cb08db27b 100644
--- a/isisd/isis_redist.c
+++ b/isisd/isis_redist.c
@@ -31,6 +31,7 @@
DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_ROUTE, "ISIS redistributed route");
DEFINE_MTYPE_STATIC(ISISD, ISIS_EXT_INFO, "ISIS redistributed route info");
DEFINE_MTYPE_STATIC(ISISD, ISIS_RMAP_NAME, "ISIS redistribute route-map name");
+DEFINE_MTYPE_STATIC(ISISD, ISIS_REDISTRIBUTE, "ISIS redistribute");
static int redist_protocol(int family)
{
@@ -61,12 +62,43 @@ static struct route_table *get_ext_info(struct isis *i, int family)
return i->ext_info[protocol];
}
-static struct isis_redist *get_redist_settings(struct isis_area *area,
- int family, int type, int level)
+static struct isis_redist *isis_redist_lookup(struct isis_area *area,
+ int family, int type, int level,
+ uint16_t table)
{
int protocol = redist_protocol(family);
+ struct listnode *node;
+ struct isis_redist *red;
+
+ if (area->redist_settings[protocol][type][level - 1]) {
+ for (ALL_LIST_ELEMENTS_RO(area->redist_settings[protocol][type]
+ [level - 1],
+ node, red))
+ if (red->table == table)
+ return red;
+ }
+ return NULL;
+}
+
+static struct isis_redist *isis_redist_get(struct isis_area *area, int family,
+ int type, int level, uint16_t table)
+{
+ struct isis_redist *red;
+ int protocol;
+
+ red = isis_redist_lookup(area, family, type, level, table);
+ if (red)
+ return red;
- return &area->redist_settings[protocol][type][level - 1];
+ protocol = redist_protocol(family);
+ if (area->redist_settings[protocol][type][level - 1] == NULL)
+ area->redist_settings[protocol][type][level - 1] = list_new();
+
+ red = XCALLOC(MTYPE_ISIS_REDISTRIBUTE, sizeof(struct isis_redist));
+ red->table = table;
+
+ listnode_add(area->redist_settings[protocol][type][level - 1], red);
+ return red;
}
struct route_table *get_ext_reach(struct isis_area *area, int family, int level)
@@ -206,10 +238,57 @@ static void isis_redist_ensure_default(struct isis *isis, int family)
info->metric = MAX_WIDE_PATH_METRIC;
}
+static int _isis_redist_table_is_present(const struct lyd_node *dnode, void *arg)
+{
+ struct isis_redist_table_present_args *rtda = arg;
+
+ /* This entry is the caller, so skip it. */
+ if (yang_dnode_get_uint16(dnode, "table") !=
+ (uint16_t)atoi(rtda->rtda_table))
+ return YANG_ITER_CONTINUE;
+
+ /* found */
+ rtda->rtda_found = true;
+ return YANG_ITER_CONTINUE;
+}
+
+static int _isis_redist_table_get_first_cb(const struct lyd_node *dnode,
+ void *arg)
+{
+ uint16_t *table = arg;
+
+ *table = yang_dnode_get_uint16(dnode, "table");
+ return YANG_ITER_STOP;
+}
+
+uint16_t isis_redist_table_get_first(const struct vty *vty,
+ struct isis_redist_table_present_args *rtda)
+{
+ uint16_t table = 0;
+
+ yang_dnode_iterate(_isis_redist_table_get_first_cb, &table,
+ vty->candidate_config->dnode,
+ "%s/redistribute/%s[protocol='table'][level='%s']/table",
+ VTY_CURR_XPATH, rtda->rtda_ip, rtda->rtda_level);
+ return table;
+}
+
+bool isis_redist_table_is_present(const struct vty *vty,
+ struct isis_redist_table_present_args *rtda)
+{
+ rtda->rtda_found = false;
+ yang_dnode_iterate(_isis_redist_table_is_present, rtda,
+ vty->candidate_config->dnode,
+ "%s/redistribute/%s[protocol='table'][level='%s']/table",
+ VTY_CURR_XPATH, rtda->rtda_ip, rtda->rtda_level);
+
+ return rtda->rtda_found;
+}
+
/* Handle notification about route being added */
void isis_redist_add(struct isis *isis, int type, struct prefix *p,
struct prefix_ipv6 *src_p, uint8_t distance,
- uint32_t metric, const route_tag_t tag)
+ uint32_t metric, const route_tag_t tag, uint16_t table)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -249,8 +328,9 @@ void isis_redist_add(struct isis *isis, int type, struct prefix *p,
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
for (level = 1; level <= ISIS_LEVELS; level++) {
- redist = get_redist_settings(area, family, type, level);
- if (!redist->redist)
+ redist = isis_redist_lookup(area, family, type, level,
+ table);
+ if (!redist || !redist->redist)
continue;
isis_redist_update_ext_reach(area, level, redist, p,
@@ -259,7 +339,7 @@ void isis_redist_add(struct isis *isis, int type, struct prefix *p,
}
void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
- struct prefix_ipv6 *src_p)
+ struct prefix_ipv6 *src_p, uint16_t table)
{
int family = p->family;
struct route_table *ei_table = get_ext_info(isis, family);
@@ -279,7 +359,7 @@ void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
* "always" setting will ignore routes with origin
* DEFAULT_ROUTE. */
isis_redist_add(isis, DEFAULT_ROUTE, p, NULL, 254,
- MAX_WIDE_PATH_METRIC, 0);
+ MAX_WIDE_PATH_METRIC, 0, table);
return;
}
@@ -302,8 +382,9 @@ void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
for (level = ISIS_LEVEL1; level <= ISIS_LEVEL2; level++) {
- redist = get_redist_settings(area, family, type, level);
- if (!redist->redist)
+ redist = isis_redist_lookup(area, family, type, level,
+ table);
+ if (!redist || !redist->redist)
continue;
isis_redist_uninstall(area, level, p, src_p);
@@ -329,53 +410,6 @@ static void isis_redist_routemap_set(struct isis_redist *redist,
}
}
-static void isis_redist_update_zebra_subscriptions(struct isis *isis)
-{
- struct listnode *node;
- struct isis_area *area;
- int type;
- int level;
- int protocol;
-
- if (isis->vrf_id == VRF_UNKNOWN)
- return;
-
- char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1];
-
- memset(do_subscribe, 0, sizeof(do_subscribe));
-
- for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
- for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
- for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
- for (level = 0; level < ISIS_LEVELS; level++)
- if (area->redist_settings[protocol]
- [type][level]
- .redist
- == 1)
- do_subscribe[protocol][type] =
- 1;
-
- for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
- for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) {
- /* This field is actually controlling transmission of
- * the IS-IS
- * routes to Zebra and has nothing to do with
- * redistribution,
- * so skip it. */
- if (type == PROTO_TYPE)
- continue;
-
- afi_t afi = afi_for_redist_protocol(protocol);
-
- if (do_subscribe[protocol][type])
- isis_zebra_redistribute_set(afi, type,
- isis->vrf_id);
- else
- isis_zebra_redistribute_unset(afi, type,
- isis->vrf_id);
- }
-}
-
void isis_redist_free(struct isis *isis)
{
struct route_node *rn;
@@ -397,11 +431,12 @@ void isis_redist_free(struct isis *isis)
}
void isis_redist_set(struct isis_area *area, int level, int family, int type,
- uint32_t metric, const char *routemap, int originate_type)
+ uint32_t metric, const char *routemap, int originate_type,
+ uint16_t table)
{
int protocol = redist_protocol(family);
- struct isis_redist *redist =
- get_redist_settings(area, family, type, level);
+ struct isis_redist *redist = isis_redist_get(area, family, type, level,
+ table);
int i;
struct route_table *ei_table;
struct route_node *rn;
@@ -421,7 +456,8 @@ void isis_redist_set(struct isis_area *area, int level, int family, int type,
}
}
- isis_redist_update_zebra_subscriptions(area->isis);
+ isis_zebra_redistribute_set(afi_for_redist_protocol(protocol), type,
+ area->isis->vrf_id, redist->table);
if (type == DEFAULT_ROUTE && originate_type == DEFAULT_ORIGINATE_ALWAYS)
isis_redist_ensure_default(area->isis, family);
@@ -452,18 +488,26 @@ void isis_redist_set(struct isis_area *area, int level, int family, int type,
}
}
-void isis_redist_unset(struct isis_area *area, int level, int family, int type)
+void isis_redist_unset(struct isis_area *area, int level, int family, int type,
+ uint16_t table)
{
- struct isis_redist *redist =
- get_redist_settings(area, family, type, level);
+ struct isis_redist *redist = isis_redist_lookup(area, family, type,
+ level, table);
struct route_table *er_table = get_ext_reach(area, family, level);
struct route_node *rn;
struct isis_ext_info *info;
+ struct list *redist_list;
+ int protocol = redist_protocol(family);
- if (!redist->redist)
+ if (!redist || !redist->redist)
return;
redist->redist = 0;
+
+ redist_list = area->redist_settings[protocol][type][level - 1];
+ listnode_delete(redist_list, redist);
+ XFREE(MTYPE_ISIS_REDISTRIBUTE, redist);
+
if (!er_table) {
zlog_warn("%s: External reachability table uninitialized.",
__func__);
@@ -493,7 +537,8 @@ void isis_redist_unset(struct isis_area *area, int level, int family, int type)
}
lsp_regenerate_schedule(area, level, 0);
- isis_redist_update_zebra_subscriptions(area->isis);
+ isis_zebra_redistribute_unset(afi_for_redist_protocol(protocol), type,
+ area->isis->vrf_id, table);
}
void isis_redist_area_finish(struct isis_area *area)
@@ -502,16 +547,30 @@ void isis_redist_area_finish(struct isis_area *area)
int protocol;
int level;
int type;
+ struct isis_redist *redist;
+ struct listnode *node, *nnode;
+ struct list *redist_list;
for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
for (level = 0; level < ISIS_LEVELS; level++) {
for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) {
- struct isis_redist *redist;
-
- redist = &area->redist_settings[protocol][type]
- [level];
- redist->redist = 0;
- XFREE(MTYPE_ISIS_RMAP_NAME, redist->map_name);
+ redist_list = area->redist_settings[protocol]
+ [type][level];
+ if (!redist_list)
+ continue;
+ for (ALL_LIST_ELEMENTS(redist_list, node, nnode,
+ redist)) {
+ redist->redist = 0;
+ XFREE(MTYPE_ISIS_RMAP_NAME,
+ redist->map_name);
+ isis_zebra_redistribute_unset(
+ afi_for_redist_protocol(protocol),
+ type, area->isis->vrf_id,
+ redist->table);
+ listnode_delete(redist_list, redist);
+ XFREE(MTYPE_ISIS_REDISTRIBUTE, redist);
+ }
+ list_delete(&redist_list);
}
if (!area->ext_reach[protocol][level])
continue;
@@ -523,8 +582,6 @@ void isis_redist_area_finish(struct isis_area *area)
route_table_finish(area->ext_reach[protocol][level]);
area->ext_reach[protocol][level] = NULL;
}
-
- isis_redist_update_zebra_subscriptions(area->isis);
}
#ifdef FABRICD
@@ -581,7 +638,7 @@ DEFUN (isis_redistribute,
routemap = argv[idx_metric_rmap + 1]->arg;
}
- isis_redist_set(area, level, family, type, metric, routemap, 0);
+ isis_redist_set(area, level, family, type, metric, routemap, 0, 0);
return 0;
}
@@ -617,7 +674,7 @@ DEFUN (no_isis_redistribute,
level = 2;
- isis_redist_unset(area, level, family, type);
+ isis_redist_unset(area, level, family, type, 0);
return 0;
}
@@ -677,7 +734,7 @@ DEFUN (isis_default_originate,
}
isis_redist_set(area, level, family, DEFAULT_ROUTE, metric, routemap,
- originate_type);
+ originate_type, 0);
return 0;
}
@@ -701,7 +758,7 @@ DEFUN (no_isis_default_originate,
level = 2;
- isis_redist_unset(area, level, family, DEFAULT_ROUTE);
+ isis_redist_unset(area, level, family, DEFAULT_ROUTE, 0);
return 0;
}
#endif /* ifdef FABRICD */
@@ -713,7 +770,9 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area,
int level;
int write = 0;
struct isis_redist *redist;
+ struct list *redist_list;
const char *family_str;
+ struct listnode *node;
if (family == AF_INET)
family_str = "ipv4";
@@ -727,25 +786,36 @@ int isis_redist_config_write(struct vty *vty, struct isis_area *area,
continue;
for (level = 1; level <= ISIS_LEVELS; level++) {
- redist = get_redist_settings(area, family, type, level);
- if (!redist->redist)
+ redist_list = area->redist_settings[redist_protocol(
+ family)][type][level - 1];
+ if (!redist_list)
continue;
- vty_out(vty, " redistribute %s %s", family_str,
- zebra_route_string(type));
- if (!fabricd)
- vty_out(vty, " level-%d", level);
- if (redist->metric)
- vty_out(vty, " metric %u", redist->metric);
- if (redist->map_name)
- vty_out(vty, " route-map %s", redist->map_name);
- vty_out(vty, "\n");
- write++;
+ for (ALL_LIST_ELEMENTS_RO(redist_list, node, redist)) {
+ if (!redist->redist)
+ continue;
+ vty_out(vty, " redistribute %s %s", family_str,
+ zebra_route_string(type));
+ if (type == ZEBRA_ROUTE_TABLE)
+ vty_out(vty, " %u", redist->table);
+ if (!fabricd)
+ vty_out(vty, " level-%d", level);
+ if (redist->metric)
+ vty_out(vty, " metric %u",
+ redist->metric);
+ if (redist->map_name)
+ vty_out(vty, " route-map %s",
+ redist->map_name);
+ vty_out(vty, "\n");
+ write++;
+ }
}
}
for (level = 1; level <= ISIS_LEVELS; level++) {
- redist =
- get_redist_settings(area, family, DEFAULT_ROUTE, level);
+ redist = isis_redist_lookup(area, family, DEFAULT_ROUTE, level,
+ 0);
+ if (!redist)
+ continue;
if (!redist->redist)
continue;
vty_out(vty, " default-information originate %s",
diff --git a/isisd/isis_redist.h b/isisd/isis_redist.h
index ae5ec2b3b3..688f27e62d 100644
--- a/isisd/isis_redist.h
+++ b/isisd/isis_redist.h
@@ -26,6 +26,15 @@ struct isis_redist {
uint32_t metric;
char *map_name;
struct route_map *map;
+ uint16_t table;
+};
+
+struct isis_redist_table_present_args {
+ /* from filter.h, struct acl_dup_args */
+ const char *rtda_ip;
+ const char *rtda_level;
+ const char *rtda_table;
+ bool rtda_found;
};
struct isis;
@@ -40,17 +49,24 @@ struct route_table *get_ext_reach(struct isis_area *area, int family,
int level);
void isis_redist_add(struct isis *isis, int type, struct prefix *p,
struct prefix_ipv6 *src_p, uint8_t distance,
- uint32_t metric, route_tag_t tag);
+ uint32_t metric, route_tag_t tag, uint16_t instance);
void isis_redist_delete(struct isis *isis, int type, struct prefix *p,
- struct prefix_ipv6 *src_p);
+ struct prefix_ipv6 *src_p, uint16_t tableid);
int isis_redist_config_write(struct vty *vty, struct isis_area *area,
int family);
void isis_redist_init(void);
void isis_redist_area_finish(struct isis_area *area);
void isis_redist_set(struct isis_area *area, int level, int family, int type,
- uint32_t metric, const char *routemap, int originate_type);
-void isis_redist_unset(struct isis_area *area, int level, int family, int type);
+ uint32_t metric, const char *routemap, int originate_type,
+ uint16_t table);
+void isis_redist_unset(struct isis_area *area, int level, int family, int type,
+ uint16_t table);
void isis_redist_free(struct isis *isis);
+
+bool isis_redist_table_is_present(const struct vty *vty,
+ struct isis_redist_table_present_args *rtda);
+uint16_t isis_redist_table_get_first(const struct vty *vty,
+ struct isis_redist_table_present_args *rtda);
#endif
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 95bd37812f..43e9865fce 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -498,10 +498,10 @@ static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
if (cmd == ZEBRA_REDISTRIBUTE_ROUTE_ADD)
isis_redist_add(isis, api.type, &api.prefix, &api.src_prefix,
- api.distance, api.metric, api.tag);
+ api.distance, api.metric, api.tag, api.instance);
else
- isis_redist_delete(isis, api.type, &api.prefix,
- &api.src_prefix);
+ isis_redist_delete(isis, api.type, &api.prefix, &api.src_prefix,
+ api.instance);
return 0;
}
@@ -511,24 +511,26 @@ int isis_distribute_list_update(int routetype)
return 0;
}
-void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id)
+void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id,
+ uint16_t tableid)
{
if (type == DEFAULT_ROUTE)
zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_ADD,
zclient, afi, vrf_id);
else
zclient_redistribute(ZEBRA_REDISTRIBUTE_ADD, zclient, afi, type,
- 0, vrf_id);
+ tableid, vrf_id);
}
-void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id)
+void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id,
+ uint16_t tableid)
{
if (type == DEFAULT_ROUTE)
zclient_redistribute_default(ZEBRA_REDISTRIBUTE_DEFAULT_DELETE,
zclient, afi, vrf_id);
else
zclient_redistribute(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi,
- type, 0, vrf_id);
+ type, tableid, vrf_id);
}
/**
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index 045c75874a..1dcd896d0b 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -43,8 +43,10 @@ void isis_zebra_prefix_sid_uninstall(struct isis_area *area,
struct isis_sr_psid_info *psid);
void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
int isis_distribute_list_update(int routetype);
-void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id);
-void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id);
+void isis_zebra_redistribute_set(afi_t afi, int type, vrf_id_t vrf_id,
+ uint16_t tableid);
+void isis_zebra_redistribute_unset(afi_t afi, int type, vrf_id_t vrf_id,
+ uint16_t tableid);
int isis_zebra_rlfa_register(struct isis_spftree *spftree, struct rlfa *rlfa);
void isis_zebra_rlfa_unregister_all(struct isis_spftree *spftree);
bool isis_zebra_label_manager_ready(void);
diff --git a/isisd/isisd.c b/isisd/isisd.c
index c6a7e803c1..942073b70c 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -599,64 +599,66 @@ static int isis_vrf_delete(struct vrf *vrf)
static void isis_set_redist_vrf_bitmaps(struct isis *isis, bool set)
{
- struct listnode *node;
+ struct listnode *node, *lnode;
struct isis_area *area;
int type;
int level;
int protocol;
-
- char do_subscribe[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1];
-
- memset(do_subscribe, 0, sizeof(do_subscribe));
+ struct isis_redist *redist;
for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area))
for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++)
- for (level = 0; level < ISIS_LEVELS; level++)
- if (area->redist_settings[protocol]
- [type][level]
- .redist
- == 1)
- do_subscribe[protocol][type] =
- 1;
-
- for (protocol = 0; protocol < REDIST_PROTOCOL_COUNT; protocol++)
- for (type = 0; type < ZEBRA_ROUTE_MAX + 1; type++) {
- /* This field is actually controlling transmission of
- * the IS-IS
- * routes to Zebra and has nothing to do with
- * redistribution,
- * so skip it. */
- if (type == PROTO_TYPE)
- continue;
-
- if (!do_subscribe[protocol][type])
- continue;
-
- afi_t afi = afi_for_redist_protocol(protocol);
-
- if (type == DEFAULT_ROUTE) {
- if (set)
- vrf_bitmap_set(
- &zclient->default_information
- [afi],
- isis->vrf_id);
- else
- vrf_bitmap_unset(
- &zclient->default_information
- [afi],
- isis->vrf_id);
- } else {
- if (set)
- vrf_bitmap_set(
- &zclient->redist[afi][type],
- isis->vrf_id);
- else
- vrf_bitmap_unset(
- &zclient->redist[afi][type],
- isis->vrf_id);
- }
- }
+ for (level = 0; level < ISIS_LEVELS; level++) {
+ if (area->redist_settings[protocol][type]
+ [level] == NULL)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(area->redist_settings
+ [protocol]
+ [type]
+ [level],
+ lnode,
+ redist)) {
+ if (redist->redist == 0)
+ continue;
+ /* This field is actually
+ * controlling transmission of
+ * the IS-IS
+ * routes to Zebra and has
+ * nothing to do with
+ * redistribution,
+ * so skip it. */
+ afi_t afi =
+ afi_for_redist_protocol(
+ protocol);
+
+ if (type == DEFAULT_ROUTE) {
+ if (set)
+ vrf_bitmap_set(
+ &zclient->default_information
+ [afi],
+ isis->vrf_id);
+ else
+ vrf_bitmap_unset(
+ &zclient->default_information
+ [afi],
+ isis->vrf_id);
+ } else {
+ if (set)
+ vrf_bitmap_set(
+ &zclient->redist
+ [afi]
+ [type],
+ isis->vrf_id);
+ else
+ vrf_bitmap_unset(
+ &zclient->redist
+ [afi]
+ [type],
+ isis->vrf_id);
+ }
+ }
+ }
}
static int isis_vrf_enable(struct vrf *vrf)
diff --git a/isisd/isisd.h b/isisd/isisd.h
index f0d236b643..cd2a694453 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -230,8 +230,8 @@ struct isis_area {
#endif /* ifndef FABRICD */
/* Counters */
uint32_t circuit_state_changes;
- struct isis_redist redist_settings[REDIST_PROTOCOL_COUNT]
- [ZEBRA_ROUTE_MAX + 1][ISIS_LEVELS];
+ struct list *redist_settings[REDIST_PROTOCOL_COUNT][ZEBRA_ROUTE_MAX + 1]
+ [ISIS_LEVELS];
struct route_table *ext_reach[REDIST_PROTOCOL_COUNT][ISIS_LEVELS];
struct spf_backoff *spf_delay_ietf[ISIS_LEVELS]; /*Structure with IETF
diff --git a/lib/elf_py.c b/lib/elf_py.c
index d473dc10cb..81ca668e70 100644
--- a/lib/elf_py.c
+++ b/lib/elf_py.c
@@ -1140,7 +1140,7 @@ static PyObject *elffile_load(PyTypeObject *type, PyObject *args,
fd = open(filename, O_RDONLY | O_NOCTTY);
if (fd < 0 || fstat(fd, &st)) {
PyErr_SetFromErrnoWithFilename(PyExc_OSError, filename);
- if (fd > 0)
+ if (fd >= 0)
close(fd);
goto out;
}
diff --git a/lib/nexthop.c b/lib/nexthop.c
index dcbb76b68e..6b6b0a79c1 100644
--- a/lib/nexthop.c
+++ b/lib/nexthop.c
@@ -932,6 +932,8 @@ ssize_t printfrr_nhs(struct fbuf *buf, const struct nexthop *nexthop)
ret += bputs(buf, "blackhole");
break;
}
+
+ ret += bprintfrr(buf, " vrfid %u", nexthop->vrf_id);
return ret;
}
diff --git a/lib/pbr.h b/lib/pbr.h
index f4b6633812..1a3d562ed9 100644
--- a/lib/pbr.h
+++ b/lib/pbr.h
@@ -85,14 +85,23 @@ struct pbr_filter {
* the user criteria may directly point to a table too.
*/
struct pbr_action {
+ uint32_t flags;
+
+#define PBR_ACTION_TABLE (1 << 0)
+#define PBR_ACTION_QUEUE_ID (1 << 1)
+#define PBR_ACTION_PCP (1 << 2)
+#define PBR_ACTION_VLAN_ID (1 << 3)
+#define PBR_ACTION_VLAN_FLAGS (1 << 4)
+
+ uint32_t table;
+ uint32_t queue_id;
+
/* VLAN */
uint8_t pcp;
uint16_t vlan_id;
uint16_t vlan_flags;
- uint32_t queue_id;
- uint32_t table;
};
/*
@@ -146,8 +155,8 @@ struct pbr_rule {
#define MATCH_FLOW_LABEL_SET (1 << 12)
#define MATCH_FLOW_LABEL_INVERSE_SET (1 << 13)
-extern int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s,
- struct pbr_rule *zrule);
+extern int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r);
+extern bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r);
#ifdef __cplusplus
}
diff --git a/lib/zclient.c b/lib/zclient.c
index 929a18a953..c36bcc6e2e 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1611,30 +1611,105 @@ static void zapi_encode_prefix(struct stream *s, struct prefix *p,
stream_put(s, &p->u.prefix, prefix_blen(p));
}
-int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
+static bool zapi_decode_prefix(struct stream *s, struct prefix *p)
{
- stream_reset(s);
- zclient_create_header(s, cmd, zrule->vrf_id);
+ STREAM_GETC(s, p->family);
+ STREAM_GETC(s, p->prefixlen);
+ STREAM_GET(&(p->u.prefix), s, prefix_blen(p));
+ return true;
+
+stream_failure:
+ return false;
+}
+
+/*
+ * Encode filter subsection of pbr_rule
+ */
+static void zapi_pbr_rule_filter_encode(struct stream *s, struct pbr_filter *f)
+{
+ assert(f->src_ip.family == f->dst_ip.family);
+ assert((f->src_ip.family == AF_INET) || (f->src_ip.family == AF_INET6));
+
+ stream_putl(s, f->filter_bm);
+ stream_putc(s, f->ip_proto);
+ /* addresses */
+ zapi_encode_prefix(s, &f->src_ip, f->src_ip.family);
+ zapi_encode_prefix(s, &f->dst_ip, f->dst_ip.family);
+
+ /* port numbers */
+ stream_putw(s, f->src_port);
+ stream_putw(s, f->dst_port);
+
+ /* vlan */
+ stream_putc(s, f->pcp);
+ stream_putw(s, f->vlan_id);
+ stream_putw(s, f->vlan_flags);
+
+ stream_putc(s, f->dsfield);
+ stream_putl(s, f->fwmark);
+}
+
+static bool zapi_pbr_rule_filter_decode(struct stream *s, struct pbr_filter *f)
+{
+ STREAM_GETL(s, f->filter_bm);
+ STREAM_GETC(s, f->ip_proto);
+ if (!zapi_decode_prefix(s, &(f->src_ip)))
+ goto stream_failure;
+ if (!zapi_decode_prefix(s, &(f->dst_ip)))
+ goto stream_failure;
+ STREAM_GETW(s, f->src_port);
+ STREAM_GETW(s, f->dst_port);
+ STREAM_GETC(s, f->pcp);
+ STREAM_GETW(s, f->vlan_id);
+ STREAM_GETW(s, f->vlan_flags);
+ STREAM_GETC(s, f->dsfield);
+ STREAM_GETL(s, f->fwmark);
+ return true;
+
+stream_failure:
+ return false;
+}
+
+static void zapi_pbr_rule_action_encode(struct stream *s, struct pbr_action *a)
+{
+ stream_putl(s, a->flags);
+ stream_putl(s, a->table);
+ stream_putl(s, a->queue_id);
+ stream_putc(s, a->pcp);
+ stream_putw(s, a->vlan_id);
+ stream_putw(s, a->vlan_flags);
+}
+
+static bool zapi_pbr_rule_action_decode(struct stream *s, struct pbr_action *a)
+{
+ STREAM_GETL(s, a->flags);
+ STREAM_GETL(s, a->table);
+ STREAM_GETL(s, a->queue_id);
+ STREAM_GETC(s, a->pcp);
+ STREAM_GETW(s, a->vlan_id);
+ STREAM_GETW(s, a->vlan_flags);
+ return true;
+
+stream_failure:
+ return false;
+}
+
+int zapi_pbr_rule_encode(struct stream *s, struct pbr_rule *r)
+{
/*
- * We are sending one item at a time at the moment
+ * PBR record count is always 1
*/
stream_putl(s, 1);
- stream_putl(s, zrule->seq);
- stream_putl(s, zrule->priority);
- stream_putl(s, zrule->unique);
+ stream_putl(s, r->seq);
+ stream_putl(s, r->priority);
+ stream_putl(s, r->unique);
- zapi_encode_prefix(s, &(zrule->filter.src_ip),
- zrule->filter.src_ip.family);
- stream_putw(s, zrule->filter.src_port); /* src port */
- zapi_encode_prefix(s, &(zrule->filter.dst_ip),
- zrule->filter.src_ip.family);
- stream_putw(s, zrule->filter.dst_port); /* dst port */
- stream_putw(s, zrule->filter.fwmark); /* fwmark */
+ zapi_pbr_rule_filter_encode(s, &(r->filter));
+ zapi_pbr_rule_action_encode(s, &(r->action));
- stream_putl(s, zrule->action.table);
- stream_put(s, zrule->ifname, INTERFACE_NAMSIZ);
+ stream_put(s, r->ifname, INTERFACE_NAMSIZ);
/* Put length at the first point of the stream. */
stream_putw_at(s, 0, stream_get_endp(s));
@@ -1642,6 +1717,28 @@ int zapi_pbr_rule_encode(uint8_t cmd, struct stream *s, struct pbr_rule *zrule)
return 0;
}
+bool zapi_pbr_rule_decode(struct stream *s, struct pbr_rule *r)
+{
+ /* NB caller has already read 4-byte rule count */
+
+ memset(r, 0, sizeof(*r));
+
+ STREAM_GETL(s, r->seq);
+ STREAM_GETL(s, r->priority);
+ STREAM_GETL(s, r->unique);
+
+ if (!zapi_pbr_rule_filter_decode(s, &(r->filter)))
+ goto stream_failure;
+ if (!zapi_pbr_rule_action_decode(s, &(r->action)))
+ goto stream_failure;
+
+ STREAM_GET(r->ifname, s, INTERFACE_NAMSIZ);
+ return true;
+
+stream_failure:
+ return false;
+}
+
int zapi_tc_qdisc_encode(uint8_t cmd, struct stream *s, struct tc_qdisc *qdisc)
{
stream_reset(s);
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 1b68f6e022..bf6f0b1614 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -265,17 +265,17 @@ void ospf_asbr_status_update(struct ospf *ospf, uint8_t status)
}
/* If there's redistribution configured, we need to refresh external
- * LSAs in order to install Type-7 and flood to all NSSA Areas
+ * LSAs (e.g. when default-metric changes or NSSA settings change).
*/
-static void ospf_asbr_nssa_redist_update_timer(struct event *thread)
+static void ospf_asbr_redist_update_timer(struct event *thread)
{
struct ospf *ospf = EVENT_ARG(thread);
int type;
- ospf->t_asbr_nssa_redist_update = NULL;
+ ospf->t_asbr_redist_update = NULL;
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("Running ASBR NSSA redistribution update on timer");
+ zlog_debug("Running ASBR redistribution update on timer");
for (type = 0; type < ZEBRA_ROUTE_MAX; type++) {
struct list *red_list;
@@ -295,14 +295,14 @@ static void ospf_asbr_nssa_redist_update_timer(struct event *thread)
ospf_external_lsa_refresh_default(ospf);
}
-void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf)
+void ospf_schedule_asbr_redist_update(struct ospf *ospf)
{
if (IS_DEBUG_OSPF_EVENT)
- zlog_debug("Scheduling ASBR NSSA redistribution update");
+ zlog_debug("Scheduling ASBR redistribution update");
- event_add_timer(master, ospf_asbr_nssa_redist_update_timer, ospf,
- OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY,
- &ospf->t_asbr_nssa_redist_update);
+ event_add_timer(master, ospf_asbr_redist_update_timer, ospf,
+ OSPF_ASBR_REDIST_UPDATE_DELAY,
+ &ospf->t_asbr_redist_update);
}
void ospf_redistribute_withdraw(struct ospf *ospf, uint8_t type,
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
index dfb9d965c5..6158d65f22 100644
--- a/ospfd/ospf_asbr.h
+++ b/ospfd/ospf_asbr.h
@@ -95,7 +95,7 @@ struct ospf_external_aggr_rt {
};
#define OSPF_ASBR_CHECK_DELAY 30
-#define OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY 9
+#define OSPF_ASBR_REDIST_UPDATE_DELAY 9
extern void ospf_external_route_remove(struct ospf *, struct prefix_ipv4 *);
extern struct external_info *ospf_external_info_new(struct ospf *, uint8_t,
@@ -113,7 +113,7 @@ extern struct external_info *ospf_external_info_lookup(struct ospf *, uint8_t,
unsigned short,
struct prefix_ipv4 *);
extern void ospf_asbr_status_update(struct ospf *, uint8_t);
-extern void ospf_schedule_asbr_nssa_redist_update(struct ospf *ospf);
+extern void ospf_schedule_asbr_redist_update(struct ospf *ospf);
extern void ospf_redistribute_withdraw(struct ospf *, uint8_t, unsigned short);
extern void ospf_asbr_check(void);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index d3dbd4821f..1500d61b48 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -1529,7 +1529,7 @@ DEFPY (ospf_area_nssa,
/* Flush the external LSA for the specified area */
ospf_flush_lsa_from_area(ospf, area_id, OSPF_AS_EXTERNAL_LSA);
ospf_schedule_abr_task(ospf);
- ospf_schedule_asbr_nssa_redist_update(ospf);
+ ospf_schedule_asbr_redist_update(ospf);
return CMD_SUCCESS;
}
@@ -9633,6 +9633,8 @@ DEFUN (ospf_default_metric,
ospf->default_metric = metric;
+ ospf_schedule_asbr_redist_update(ospf);
+
return CMD_SUCCESS;
}
@@ -9647,6 +9649,8 @@ DEFUN (no_ospf_default_metric,
ospf->default_metric = -1;
+ ospf_schedule_asbr_redist_update(ospf);
+
return CMD_SUCCESS;
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index 3bafc313f6..172356895a 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -816,7 +816,7 @@ static void ospf_finish_final(struct ospf *ospf)
EVENT_OFF(ospf->t_abr_task);
EVENT_OFF(ospf->t_abr_fr);
EVENT_OFF(ospf->t_asbr_check);
- EVENT_OFF(ospf->t_asbr_nssa_redist_update);
+ EVENT_OFF(ospf->t_asbr_redist_update);
EVENT_OFF(ospf->t_distribute_update);
EVENT_OFF(ospf->t_lsa_refresher);
EVENT_OFF(ospf->t_opaque_lsa_self);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 860140cb76..2ab7db119e 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -268,8 +268,8 @@ struct ospf {
struct event *t_abr_task; /* ABR task timer. */
struct event *t_abr_fr; /* ABR FR timer. */
struct event *t_asbr_check; /* ASBR check timer. */
- struct event *t_asbr_nssa_redist_update; /* ASBR NSSA redistribution
- update timer. */
+ struct event *t_asbr_redist_update; /* ASBR redistribution update
+ timer. */
struct event *t_distribute_update; /* Distirbute list update timer. */
struct event *t_spf_calc; /* SPF calculation timer. */
struct event *t_ase_calc; /* ASE calculation timer. */
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index bc83c2d61c..8e9673482e 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -73,7 +73,7 @@ DEFPY(pbr_map_match_vlan_id, pbr_map_match_vlan_id_cmd,
/* clang-format off */
DEFPY(pbr_map_match_vlan_tag, pbr_map_match_vlan_tag_cmd,
- "[no] match vlan [<tagged|untagged|untagged-or-zero>$tag_type]",
+ "[no] match vlan ![<tagged|untagged|untagged-or-zero>$tag_type]",
NO_STR
"Match the rest of the command\n"
"Match based on VLAN tagging\n"
@@ -88,6 +88,7 @@ DEFPY(pbr_map_match_vlan_tag, pbr_map_match_vlan_tag_cmd,
return CMD_WARNING;
if (!no) {
+ assert(tag_type);
if (strmatch(tag_type, "tagged")) {
pbr_set_match_clause_for_vlan(pbrms, 0,
PBR_VLAN_FLAGS_TAGGED);
diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c
index 28d89b0b5c..030c4c1114 100644
--- a/pbrd/pbr_zebra.c
+++ b/pbrd/pbr_zebra.c
@@ -483,27 +483,9 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg)
}
}
-static void pbr_encode_pbr_map_sequence_prefix(struct stream *s,
- struct prefix *p,
- unsigned char family)
-{
- struct prefix any;
-
- if (!p) {
- memset(&any, 0, sizeof(any));
- any.family = family;
- p = &any;
- }
-
- stream_putc(s, p->family);
- stream_putc(s, p->prefixlen);
- stream_put(s, &p->u.prefix, prefix_blen(p));
-}
-static void
-pbr_encode_pbr_map_sequence_vrf(struct stream *s,
- const struct pbr_map_sequence *pbrms,
- const struct interface *ifp)
+static uint32_t pbr_map_sequence_vrf(const struct pbr_map_sequence *pbrms,
+ const struct interface *ifp)
{
struct pbr_vrf *pbr_vrf;
@@ -514,66 +496,130 @@ pbr_encode_pbr_map_sequence_vrf(struct stream *s,
if (!pbr_vrf) {
DEBUGD(&pbr_dbg_zebra, "%s: VRF not found", __func__);
- return;
+ return 0;
}
- stream_putl(s, pbr_vrf->vrf->data.l.table_id);
+ return pbr_vrf->vrf->data.l.table_id;
+
}
+/*
+ * 230716 gpz note: it would be worthwhile for pbrd to represent
+ * its rules internally using the lib/pbr.h structures to help
+ * move toward a more common structure across pbrd, bgpd, and zebra.
+ */
static bool pbr_encode_pbr_map_sequence(struct stream *s,
struct pbr_map_sequence *pbrms,
struct interface *ifp)
{
- unsigned char family;
+ struct pbr_rule r;
+ uint8_t family;
+
+ /*
+ * There seems to be some effort in pbr_vty.c to keep the three
+ * copies of "family" equal. Not sure if the reason goes beyond
+ * ensuring consistency in ZAPI encoding. In any case, it might
+ * be handled better as an internal matter for the encoder (TBD).
+ */
family = AF_INET;
if (pbrms->family)
family = pbrms->family;
- stream_putl(s, pbrms->seqno);
- stream_putl(s, pbrms->ruleno);
- stream_putl(s, pbrms->unique);
-
- stream_putl(s, pbrms->filter_bm);
-
- stream_putc(s, pbrms->ip_proto); /* The ip_proto */
- pbr_encode_pbr_map_sequence_prefix(s, pbrms->src, family);
- stream_putw(s, pbrms->src_prt);
- pbr_encode_pbr_map_sequence_prefix(s, pbrms->dst, family);
- stream_putw(s, pbrms->dst_prt);
- stream_putc(s, pbrms->dsfield);
- stream_putl(s, pbrms->mark);
- /* PCP */
- if (CHECK_FLAG(pbrms->filter_bm, PBR_FILTER_PCP))
- stream_putc(s, pbrms->match_pcp);
+ if (pbrms->src)
+ assert(family == pbrms->src->family);
+ if (pbrms->dst)
+ assert(family == pbrms->dst->family);
+
+ /*
+ * Convert struct pbr_map_sequence to canonical form
+ */
+ memset(&r, 0, sizeof(r));
+ r.seq = pbrms->seqno;
+ r.priority = pbrms->ruleno;
+ r.unique = pbrms->unique;
+
+ /* filter */
+ r.filter.filter_bm = pbrms->filter_bm;
+ if (pbrms->src)
+ r.filter.src_ip = *pbrms->src;
+ else
+ r.filter.src_ip.family = family;
+ if (pbrms->dst)
+ r.filter.dst_ip = *pbrms->dst;
else
- stream_putc(s, 0);
- stream_putw(s, pbrms->action_pcp);
- /* VLAN */
- stream_putw(s, pbrms->match_vlan_id);
- stream_putw(s, pbrms->match_vlan_flags);
+ r.filter.dst_ip.family = family;
+ r.filter.src_port = pbrms->src_prt;
+ r.filter.dst_port = pbrms->dst_prt;
+ r.filter.pcp = pbrms->match_pcp;
+ r.filter.vlan_id = pbrms->match_vlan_id;
+ r.filter.vlan_flags = pbrms->match_vlan_flags;
+ r.filter.dsfield = pbrms->dsfield;
+ r.filter.fwmark = pbrms->mark;
+ r.filter.ip_proto = pbrms->ip_proto;
- stream_putw(s, pbrms->action_vlan_id);
- stream_putw(s, pbrms->action_vlan_flags);
- stream_putl(s, pbrms->action_queue_id);
+ /*
+ * Fix up filter flags for now, since PBRD doesn't maintain
+ * them yet (aside from PBR_FILTER_PCP)
+ */
+ if (!is_default_prefix(&r.filter.src_ip))
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_IP);
+ if (!is_default_prefix(&r.filter.dst_ip))
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_IP);
+ if (r.filter.src_port)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_SRC_PORT);
+ if (r.filter.dst_port)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_DST_PORT);
+ if (r.filter.vlan_id)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_ID);
+ if (r.filter.vlan_flags)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_VLAN_FLAGS);
+ if (r.filter.dsfield)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_DSFIELD);
+ if (r.filter.fwmark)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_FWMARK);
+ if (r.filter.ip_proto)
+ SET_FLAG(r.filter.filter_bm, PBR_FILTER_IP_PROTOCOL);
+
+ /* actions */
- /* if the user does not use the command "set vrf name |unchanged"
- * then pbr_encode_pbr_map_sequence_vrf will not be called
+ /*
+ * PBR should maintain its own set of action flags that we
+ * can copy here instead of trying to infer from magic values.
*/
+ SET_FLAG(r.action.flags, PBR_ACTION_TABLE); /* always valid */
+ if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID)
+ SET_FLAG(r.action.flags, PBR_ACTION_QUEUE_ID);
+ if (pbrms->action_pcp != 0)
+ SET_FLAG(r.action.flags, PBR_ACTION_PCP);
+ if (pbrms->action_vlan_id != 0)
+ SET_FLAG(r.action.flags, PBR_ACTION_VLAN_ID);
+ if (pbrms->action_vlan_flags != 0)
+ SET_FLAG(r.action.flags, PBR_ACTION_VLAN_FLAGS);
- /* these statement get a table id */
+ /*
+ * if the user does not use the command "set vrf name unchanged"
+ * then pbr_encode_pbr_map_sequence_vrf will not be called
+ */
if (pbrms->vrf_unchanged || pbrms->vrf_lookup)
- pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp);
+ r.action.table = pbr_map_sequence_vrf(pbrms, ifp);
else if (pbrms->nhgrp_name)
- stream_putl(s, pbr_nht_get_table(pbrms->nhgrp_name));
+ r.action.table = pbr_nht_get_table(pbrms->nhgrp_name);
else if (pbrms->nhg)
- stream_putl(s, pbr_nht_get_table(pbrms->internal_nhg_name));
+ r.action.table = pbr_nht_get_table(pbrms->internal_nhg_name);
else {
/* Not valid for install without table */
return false;
}
- stream_put(s, ifp->name, INTERFACE_NAMSIZ);
+ r.action.queue_id = pbrms->action_queue_id;
+ r.action.pcp = pbrms->action_pcp;
+ r.action.vlan_id = pbrms->action_vlan_id;
+ r.action.vlan_flags = pbrms->action_vlan_flags;
+
+ strlcpy(r.ifname, ifp->name, sizeof(r.ifname));
+
+ zapi_pbr_rule_encode(s, &r);
return true;
}
@@ -607,11 +653,6 @@ bool pbr_send_pbr_map(struct pbr_map_sequence *pbrms,
install ? ZEBRA_RULE_ADD : ZEBRA_RULE_DELETE,
VRF_DEFAULT);
- /*
- * We are sending one item at a time at the moment
- */
- stream_putl(s, 1);
-
DEBUGD(&pbr_dbg_zebra, "%s: %s %s seq %u %d %s %u", __func__,
install ? "Installing" : "Deleting", pbrm->name, pbrms->seqno,
install, pmi->ifp->name, pmi->delete);
diff --git a/tests/lib/test_nexthop_iter.c b/tests/lib/test_nexthop_iter.c
index 91380f1111..33ff116890 100644
--- a/tests/lib/test_nexthop_iter.c
+++ b/tests/lib/test_nexthop_iter.c
@@ -19,9 +19,10 @@ static int verbose;
static void str_append(char **buf, const char *repr)
{
if (*buf) {
- *buf = realloc(*buf, strlen(*buf) + strlen(repr) + 1);
+ size_t new_size = strlen(*buf) + strlen(repr) + 1;
+ *buf = realloc(*buf, new_size);
assert(*buf);
- strncpy((*buf) + strlen(*buf), repr, strlen(repr) + 1);
+ (void)strlcat(*buf, repr, new_size);
} else {
*buf = strdup(repr);
assert(*buf);
diff --git a/tests/topotests/isis_topo1/r3/r3_route.json b/tests/topotests/isis_topo1/r3/r3_route.json
index 61d05e80bb..c3b6e3b0a6 100644
--- a/tests/topotests/isis_topo1/r3/r3_route.json
+++ b/tests/topotests/isis_topo1/r3/r3_route.json
@@ -146,5 +146,20 @@
"protocol": "isis",
"selected": true
}
+ ],
+ "192.0.2.6/32": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "fib": true,
+ "ip": "10.0.10.1",
+ "interfaceName": "r3-eth1"
+ }
+ ],
+ "prefix": "192.0.2.6/32",
+ "protocol": "isis",
+ "selected": true
+ }
]
}
diff --git a/tests/topotests/isis_topo1/r4/r4_route.json b/tests/topotests/isis_topo1/r4/r4_route.json
index 79361af4b5..8fd46add33 100644
--- a/tests/topotests/isis_topo1/r4/r4_route.json
+++ b/tests/topotests/isis_topo1/r4/r4_route.json
@@ -61,5 +61,20 @@
"protocol": "connected",
"selected": true
}
+ ],
+ "192.0.2.6/32": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "fib": true,
+ "ip": "10.0.11.1",
+ "interfaceName": "r4-eth1"
+ }
+ ],
+ "prefix": "192.0.2.6/32",
+ "protocol": "isis",
+ "selected": true
+ }
]
}
diff --git a/tests/topotests/isis_topo1/r5/isisd.conf b/tests/topotests/isis_topo1/r5/isisd.conf
index e0e9200d62..81686e0525 100644
--- a/tests/topotests/isis_topo1/r5/isisd.conf
+++ b/tests/topotests/isis_topo1/r5/isisd.conf
@@ -20,4 +20,5 @@ router isis 1
is-type level-1
redistribute ipv4 connected level-1
redistribute ipv6 connected level-1
+ redistribute ipv4 table 20 level-1
!
diff --git a/tests/topotests/isis_topo1/r5/r5_route.json b/tests/topotests/isis_topo1/r5/r5_route.json
index cca844b27c..ec544b8e85 100644
--- a/tests/topotests/isis_topo1/r5/r5_route.json
+++ b/tests/topotests/isis_topo1/r5/r5_route.json
@@ -141,5 +141,21 @@
"protocol": "connected",
"selected": true
}
+ ],
+ "192.0.2.6/32": [
+ {
+ "nexthops": [
+ {
+ "active": true,
+ "fib": true,
+ "ip": "10.0.10.6",
+ "interfaceName": "r5-eth0"
+ }
+ ],
+ "prefix": "192.0.2.6/32",
+ "protocol": "table",
+ "instance": 20,
+ "selected": true
+ }
]
}
diff --git a/tests/topotests/isis_topo1/r5/zebra.conf b/tests/topotests/isis_topo1/r5/zebra.conf
index 48fed69662..7c400f797b 100644
--- a/tests/topotests/isis_topo1/r5/zebra.conf
+++ b/tests/topotests/isis_topo1/r5/zebra.conf
@@ -1,4 +1,6 @@
hostname r5
+ip route 192.0.2.6/32 10.0.10.6 table 20
+ip import 20
interface r5-eth0
ip address 10.0.10.1/24
ipv6 address 2001:db8:2:1::1/64
diff --git a/tests/topotests/pbr_topo1/test_pbr_topo1.py b/tests/topotests/pbr_topo1/test_pbr_topo1.py
index 699e4489a3..ad096fa14e 100644
--- a/tests/topotests/pbr_topo1/test_pbr_topo1.py
+++ b/tests/topotests/pbr_topo1/test_pbr_topo1.py
@@ -181,8 +181,10 @@ def test_pbr_data():
#
#
-# tm: must-match pattern
-# tN: must Not match pattern
+# c: command
+# cDN: omit default destination IP address (special case)
+# tm: must-match pattern
+# tN: must Not match pattern
#
# Note we are searching amid a bunch of other rules, so these elements
# should be unique.
@@ -199,6 +201,27 @@ ftest = [
{"c": "match vlan untagged", "tm": r"VLAN Flags Match: untagged$"},
{"c": "match vlan untagged-or-zero", "tm": r"VLAN Flags Match: untagged-or-zero$"},
{"c": "no match vlan tagged", "tN": r"VLAN Flags Match:"},
+
+ {"c": "match src-ip 37.49.22.0/24", "tm": r"SRC IP Match: 37.49.22.0/24$"},
+ {"c": "no match src-ip 37.49.22.0/24", "tN": r"SRC IP Match: 37.49.22.0/24$"},
+
+ {"c": "match dst-ip 38.41.29.0/25", "cDN": "foo", "tm": r"DST IP Match: 38.41.29.0/25$"},
+ {"c": "no match dst-ip 38.41.29.0/25", "tN": r"DST IP Match: 38.41.29.0/25$"},
+
+ {"c": "match src-port 117", "tm": r"SRC Port Match: 117$"},
+ {"c": "no match src-port 117", "tN": r"SRC Port Match: 117$"},
+
+ {"c": "match dst-port 119", "tm": r"DST Port Match: 119$"},
+ {"c": "no match dst-port 119", "tN": r"DST Port Match: 119$"},
+
+ {"c": "match dscp cs3", "tm": r"DSCP Match: 24$"},
+ {"c": "no match dscp cs3", "tN": r"DSCP Match: 24$"},
+
+ {"c": "match ecn 2", "tm": r"ECN Match: 2$"},
+ {"c": "no match ecn 2", "tN": r"ECN Match: 2$"},
+
+ {"c": "match mark 337", "tm": r"MARK Match: 337$"},
+ {"c": "no match mark 337", "tN": r"MARK Match: 337$"},
]
@@ -233,6 +256,9 @@ def test_pbr_fields():
logger.info("Verifying PBR rule fields")
+ # uncomment for manual interaction
+ # tgen.cli()
+
tag = "field"
router_list = tgen.routers().values()
@@ -240,8 +266,12 @@ def test_pbr_fields():
for t in ftest:
# send field-setting command
# always have a match dst-ip to satisfy rule non-empty check
- vcmd = "c t\npbr-map ASAKUSA seq 100\n{}\nmatch dst-ip 9.9.9.9/32\nset nexthop-group A\nend\nend".format(
- t["c"]
+ if "cDN" in t:
+ match_dstip = ""
+ else:
+ match_dstip = "match dst-ip 9.9.9.9/32\n"
+ vcmd = "c t\npbr-map ASAKUSA seq 100\n{}\n{}set nexthop-group A\nend\nend".format(
+ t["c"], match_dstip
)
router.vtysh_multicmd(vcmd)
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index ae69d53ccc..478d058c19 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1495,9 +1495,32 @@ module frr-isisd {
"IS-IS level into which the routes should be redistributed.";
}
- uses redistribute-attributes;
- }
+ choice protocol-type {
+ case protocol-table {
+ when "./protocol = \"table\"";
+ list table {
+ key "table";
+ when "../protocol = \"table\"";
+ description
+ "Routing table number";
+
+ leaf table {
+ type uint16 {
+ range "1..65535";
+ }
+ description
+ "Routing table number.";
+ }
+
+ uses redistribute-attributes;
+ }
+ }
+ case protocol-other {
+ uses redistribute-attributes;
+ }
+ }
+ }
list ipv6 {
key "protocol level";
description
@@ -1516,7 +1539,29 @@ module frr-isisd {
"IS-IS level into which the routes should be redistributed.";
}
- uses redistribute-attributes;
+ choice protocol-type {
+ case protocol-table {
+ when "./protocol = \"table\"";
+ list table {
+ key "table";
+ when "../protocol = \"table\"";
+
+ leaf table {
+ type uint16 {
+ range "1..65535";
+ }
+ description
+ "Routing table number.";
+ }
+
+ uses redistribute-attributes;
+ }
+ }
+ case protocol-other {
+ uses redistribute-attributes;
+ }
+ }
+
}
}
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 11b7b7cf82..9ca9c7a55a 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -675,6 +675,8 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn,
zebra_del_import_table_entry(zvrf, rn, same);
}
+ UNSET_FLAG(re->flags, ZEBRA_FLAG_RR_USE_DISTANCE);
+
newre = zebra_rib_route_entry_new(
0, ZEBRA_ROUTE_TABLE, re->table, re->flags, re->nhe_id,
zvrf->table_id, re->metric, re->mtu,
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 928cb3f9b7..a136fcf8ae 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -3184,7 +3184,6 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
struct zebra_pbr_rule zpr;
struct stream *s;
uint32_t total, i;
- char ifname[INTERFACE_NAMSIZ + 1] = {};
s = msg;
STREAM_GETL(s, total);
@@ -3194,68 +3193,11 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS)
zpr.sock = client->sock;
zpr.rule.vrf_id = hdr->vrf_id;
- STREAM_GETL(s, zpr.rule.seq);
- STREAM_GETL(s, zpr.rule.priority);
- STREAM_GETL(s, zpr.rule.unique);
- STREAM_GETL(s, zpr.rule.filter.filter_bm);
-
- STREAM_GETC(s, zpr.rule.filter.ip_proto);
- STREAM_GETC(s, zpr.rule.filter.src_ip.family);
- STREAM_GETC(s, zpr.rule.filter.src_ip.prefixlen);
- STREAM_GET(&zpr.rule.filter.src_ip.u.prefix, s,
- prefix_blen(&zpr.rule.filter.src_ip));
- STREAM_GETW(s, zpr.rule.filter.src_port);
- STREAM_GETC(s, zpr.rule.filter.dst_ip.family);
- STREAM_GETC(s, zpr.rule.filter.dst_ip.prefixlen);
- STREAM_GET(&zpr.rule.filter.dst_ip.u.prefix, s,
- prefix_blen(&zpr.rule.filter.dst_ip));
- STREAM_GETW(s, zpr.rule.filter.dst_port);
- STREAM_GETC(s, zpr.rule.filter.dsfield);
- STREAM_GETL(s, zpr.rule.filter.fwmark);
-
- STREAM_GETC(s, zpr.rule.filter.pcp);
- STREAM_GETW(s, zpr.rule.action.pcp);
- STREAM_GETW(s, zpr.rule.filter.vlan_id);
- STREAM_GETW(s, zpr.rule.filter.vlan_flags);
- STREAM_GETW(s, zpr.rule.action.vlan_id);
- STREAM_GETW(s, zpr.rule.action.vlan_flags);
- STREAM_GETL(s, zpr.rule.action.queue_id);
-
- STREAM_GETL(s, zpr.rule.action.table);
- STREAM_GET(ifname, s, INTERFACE_NAMSIZ);
-
- strlcpy(zpr.ifname, ifname, sizeof(zpr.ifname));
- strlcpy(zpr.rule.ifname, ifname, sizeof(zpr.rule.ifname));
-
- if (!is_default_prefix(&zpr.rule.filter.src_ip))
- zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_IP;
-
- if (!is_default_prefix(&zpr.rule.filter.dst_ip))
- zpr.rule.filter.filter_bm |= PBR_FILTER_DST_IP;
-
- if (zpr.rule.filter.src_port)
- zpr.rule.filter.filter_bm |= PBR_FILTER_SRC_PORT;
-
- if (zpr.rule.filter.dst_port)
- zpr.rule.filter.filter_bm |= PBR_FILTER_DST_PORT;
-
- if (zpr.rule.filter.dsfield)
- zpr.rule.filter.filter_bm |= PBR_FILTER_DSFIELD;
-
- if (zpr.rule.filter.ip_proto)
- zpr.rule.filter.filter_bm |= PBR_FILTER_IP_PROTOCOL;
-
- if (zpr.rule.filter.fwmark)
- zpr.rule.filter.filter_bm |= PBR_FILTER_FWMARK;
-
- /* NB PBR_FILTER_PCP should already be set by sender */
-
- if (zpr.rule.filter.vlan_flags)
- zpr.rule.filter.filter_bm |= PBR_FILTER_VLAN_FLAGS;
+ if (!zapi_pbr_rule_decode(s, &zpr.rule))
+ goto stream_failure;
- if (zpr.rule.filter.vlan_id)
- zpr.rule.filter.filter_bm |= PBR_FILTER_VLAN_ID;
+ strlcpy(zpr.ifname, zpr.rule.ifname, sizeof(zpr.ifname));
if (!(zpr.rule.filter.src_ip.family == AF_INET
|| zpr.rule.filter.src_ip.family == AF_INET6)) {
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 977ea425d5..2104e477be 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2401,10 +2401,13 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
nexthop->ifindex);
newhop = match->nhe->nhg.nexthop;
- if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
- nexthop->type == NEXTHOP_TYPE_IPV6)
+ if (nexthop->type == NEXTHOP_TYPE_IPV4) {
nexthop->ifindex = newhop->ifindex;
- else if (nexthop->ifindex != newhop->ifindex) {
+ nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ } else if (nexthop->type == NEXTHOP_TYPE_IPV6) {
+ nexthop->ifindex = newhop->ifindex;
+ nexthop->type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ } else if (nexthop->ifindex != newhop->ifindex) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
"%s: %pNHv given ifindex does not match nexthops ifindex found: %pNHv",
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index a5e036fe48..c61b37a697 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -4170,10 +4170,10 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data)
mq->size++;
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- "Route %pFX(%u) queued for processing into sub-queue %s",
- &ere->p, ere->re->vrf_id,
- subqueue2str(META_QUEUE_EARLY_ROUTE));
+ zlog_debug("Route %pFX(%u) (%s) queued for processing into sub-queue %s",
+ &ere->p, ere->re->vrf_id,
+ ere->deletion ? "delete" : "add",
+ subqueue2str(META_QUEUE_EARLY_ROUTE));
return 0;
}
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 19366eb2c1..291c2eb7e0 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -962,8 +962,12 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf,
}
}
+ /*
+ * This is an extremely expensive operation at scale
+ * and non-pretty reduces memory footprint significantly.
+ */
if (use_json)
- vty_json(vty, json);
+ vty_json_no_pretty(vty, json);
}
static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf,
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index 5178448ebc..50a7462d89 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -3229,7 +3229,11 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf,
if (use_json) {
json_object_object_add(json, "macs", json_mac);
- vty_json(vty, json);
+ /*
+ * This is an extremely expensive operation at scale
+ * and non-pretty reduces memory footprint significantly.
+ */
+ vty_json_no_pretty(vty, json);
}
}
@@ -4014,8 +4018,12 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf,
void *))zl3vni_print_hash_detail,
&zes);
+ /*
+ * This is an extremely expensive operation at scale
+ * and non-pretty reduces memory footprint significantly.
+ */
if (use_json)
- vty_json(vty, json_array);
+ vty_json_no_pretty(vty, json_array);
}
/*