diff options
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; } @@ -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); } /* |
