diff options
55 files changed, 2330 insertions, 452 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 0135acec8f..d91c717f37 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -1515,6 +1515,19 @@ static int bgp_attr_aspath(struct bgp_attr_parser_args *args) 0); } + /* Conformant BGP speakers SHOULD NOT send BGP + * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of + * such messages, conformant BGP speakers SHOULD use the "Treat-as- + * withdraw" error handling behavior as per [RFC7606]. + */ + if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) { + flog_err(EC_BGP_ATTR_MAL_AS_PATH, + "AS_SET and AS_CONFED_SET are deprecated from %pBP", + peer); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, + 0); + } + /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS_PATH); @@ -1595,6 +1608,19 @@ static int bgp_attr_as4_path(struct bgp_attr_parser_args *args, 0); } + /* Conformant BGP speakers SHOULD NOT send BGP + * UPDATE messages containing AS_SET or AS_CONFED_SET. Upon receipt of + * such messages, conformant BGP speakers SHOULD use the "Treat-as- + * withdraw" error handling behavior as per [RFC7606]. + */ + if (peer->bgp->reject_as_sets && aspath_check_as_sets(attr->aspath)) { + flog_err(EC_BGP_ATTR_MAL_AS_PATH, + "AS_SET and AS_CONFED_SET are deprecated from %pBP", + peer); + return bgp_attr_malformed(args, BGP_NOTIFY_UPDATE_MAL_AS_PATH, + 0); + } + /* Set aspath attribute flag. */ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AS4_PATH); diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c index 9c2826fa13..fc44e86cbc 100644 --- a/bgpd/bgp_conditional_adv.c +++ b/bgpd/bgp_conditional_adv.c @@ -258,6 +258,25 @@ static void bgp_conditional_adv_timer(struct thread *t) ? UPDATE_TYPE_WITHDRAW : UPDATE_TYPE_ADVERTISE; + /* + * Update condadv update type so + * subgroup_announce_check() can properly apply + * outbound policy according to advertisement state + */ + paf = peer_af_find(peer, afi, safi); + if (paf && (SUBGRP_PEER(PAF_SUBGRP(paf)) + ->filter[afi][safi] + .advmap.update_type != + filter->advmap.update_type)) { + /* Handle change to peer advmap */ + if (BGP_DEBUG(update, UPDATE_OUT)) + zlog_debug( + "%s: advmap.update_type changed for peer %s, adjusting update_group.", + __func__, peer->host); + + update_group_adjust_peer(paf); + } + /* Send regular update as per the existing policy. * There is a change in route-map, match-rule, ACLs, * or route-map filter configuration on the same peer. @@ -270,11 +289,10 @@ static void bgp_conditional_adv_timer(struct thread *t) __func__, peer->host, get_afi_safi_str(afi, safi, false)); - - paf = peer_af_find(peer, afi, safi); if (paf) { update_subgroup_split_peer(paf, NULL); subgrp = paf->subgroup; + if (subgrp && subgrp->update_group) subgroup_announce_table( paf->subgroup, NULL); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 797075563b..6ba516c39c 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -4036,6 +4036,9 @@ DEFUN (no_bgp_evpn_advertise_type5, afi_t afi = 0; safi_t safi = 0; + if (!bgp_vrf) + return CMD_WARNING; + argv_find_and_parse_afi(argv, argc, &idx_afi, &afi); argv_find_and_parse_safi(argv, argc, &idx_safi, &safi); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 2e7dbaaf66..04f955f97a 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -2212,6 +2212,32 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, bgp_peer_remove_private_as(bgp, afi, safi, peer, attr); bgp_peer_as_override(bgp, afi, safi, peer, attr); + if (filter->advmap.update_type == UPDATE_TYPE_WITHDRAW && + filter->advmap.aname && + route_map_lookup_by_name(filter->advmap.aname)) { + struct bgp_path_info rmap_path = {0}; + struct bgp_path_info_extra dummy_rmap_path_extra = {0}; + struct attr dummy_attr = *attr; + + /* Fill temp path_info */ + prep_for_rmap_apply(&rmap_path, &dummy_rmap_path_extra, dest, + pi, peer, &dummy_attr); + + struct route_map *amap = + route_map_lookup_by_name(filter->advmap.aname); + + ret = route_map_apply(amap, p, &rmap_path); + + bgp_attr_flush(&dummy_attr); + + /* + * The conditional advertisement mode is Withdraw and this + * prefix is a conditional prefix. Don't advertise it + */ + if (ret == RMAP_PERMITMATCH) + return false; + } + /* Route map & unsuppress-map apply. */ if (!post_attr && (ROUTE_MAP_OUT_NAME(filter) || bgp_path_suppressed(pi))) { @@ -12438,8 +12464,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, list = community_list_lookup(bgp_clist, clist_number_or_name, 0, COMMUNITY_LIST_MASTER); if (list == NULL) { - vty_out(vty, - "%% %s is not a valid community-list name\n", + vty_out(vty, "%% %s community-list not found\n", clist_number_or_name); return CMD_WARNING; } @@ -12457,8 +12482,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, as_list = as_list_lookup(filter); if (as_list == NULL) { - vty_out(vty, - "%% %s is not a valid AS-path access-list name\n", + vty_out(vty, "%% %s AS-path access-list not found\n", filter); return CMD_WARNING; } @@ -12473,7 +12497,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, plist = prefix_list_lookup(afi, prefix_list_str); if (plist == NULL) { - vty_out(vty, "%% %s is not a valid prefix-list name\n", + vty_out(vty, "%% %s prefix-list not found\n", prefix_list_str); return CMD_WARNING; } @@ -12488,7 +12512,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, alist = access_list_lookup(afi, access_list_str); if (!alist) { - vty_out(vty, "%% %s is not a valid access-list name\n", + vty_out(vty, "%% %s access-list not found\n", access_list_str); return CMD_WARNING; } @@ -12503,8 +12527,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, rmap = route_map_lookup_by_name(rmap_str); if (!rmap) { - vty_out(vty, "%% %s is not a valid route-map name\n", - rmap_str); + vty_out(vty, "%% %s route-map not found\n", rmap_str); return CMD_WARNING; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 13d5ec6b86..f1173941a0 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -218,6 +218,8 @@ static void conf_copy(struct peer *dst, struct peer *src, afi_t afi, MTYPE_BGP_FILTER_NAME, CONDITION_MAP_NAME(srcfilter)); CONDITION_MAP(dstfilter) = CONDITION_MAP(srcfilter); } + + dstfilter->advmap.update_type = srcfilter->advmap.update_type; } /** @@ -389,6 +391,9 @@ static unsigned int updgrp_hash_key_make(const void *p) strlen(filter->advmap.aname), SEED1), key); + if (filter->advmap.update_type) + key = jhash_1word(filter->advmap.update_type, key); + if (peer->default_rmap[afi][safi].name) key = jhash_1word( jhash(peer->default_rmap[afi][safi].name, @@ -588,6 +593,9 @@ static bool updgrp_hash_cmp(const void *p1, const void *p2) && strcmp(fl1->advmap.aname, fl2->advmap.aname))) return false; + if (fl1->advmap.update_type != fl2->advmap.update_type) + return false; + if ((pe1->default_rmap[afi][safi].name && !pe2->default_rmap[afi][safi].name) || (!pe1->default_rmap[afi][safi].name diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 219dee4693..c17bd76ad7 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -482,14 +482,14 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) } /* BGP's cluster-id control. */ -int bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) +void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) { struct peer *peer; struct listnode *node, *nnode; if (bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID) && IPV4_ADDR_SAME(&bgp->cluster_id, cluster_id)) - return 0; + return; IPV4_ADDR_COPY(&bgp->cluster_id, cluster_id); bgp_config_set(bgp, BGP_CONFIG_CLUSTER_ID); @@ -505,16 +505,15 @@ int bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } - return 0; } -int bgp_cluster_id_unset(struct bgp *bgp) +void bgp_cluster_id_unset(struct bgp *bgp) { struct peer *peer; struct listnode *node, *nnode; if (!bgp_config_check(bgp, BGP_CONFIG_CLUSTER_ID)) - return 0; + return; bgp->cluster_id.s_addr = 0; bgp_config_unset(bgp, BGP_CONFIG_CLUSTER_ID); @@ -530,7 +529,6 @@ int bgp_cluster_id_unset(struct bgp *bgp) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } - return 0; } /* time_t value that is monotonicly increasing @@ -623,7 +621,7 @@ void bgp_confederation_id_set(struct bgp *bgp, as_t as) return; } -int bgp_confederation_id_unset(struct bgp *bgp) +void bgp_confederation_id_unset(struct bgp *bgp) { struct peer *peer; struct listnode *node, *nnode; @@ -645,7 +643,6 @@ int bgp_confederation_id_unset(struct bgp *bgp) bgp_session_reset_safe(peer, &nnode); } } - return 0; } /* Is an AS part of the confed or not? */ @@ -664,16 +661,16 @@ bool bgp_confederation_peers_check(struct bgp *bgp, as_t as) } /* Add an AS to the confederation set. */ -int bgp_confederation_peers_add(struct bgp *bgp, as_t as) +void bgp_confederation_peers_add(struct bgp *bgp, as_t as) { struct peer *peer; struct listnode *node, *nnode; if (bgp->as == as) - return BGP_ERR_INVALID_AS; + return; if (bgp_confederation_peers_check(bgp, as)) - return -1; + return; bgp->confed_peers = XREALLOC(MTYPE_BGP_CONFED_LIST, bgp->confed_peers, @@ -699,11 +696,10 @@ int bgp_confederation_peers_add(struct bgp *bgp, as_t as) } } } - return 0; } /* Delete an AS from the confederation set. */ -int bgp_confederation_peers_remove(struct bgp *bgp, as_t as) +void bgp_confederation_peers_remove(struct bgp *bgp, as_t as) { int i; int j; @@ -711,10 +707,10 @@ int bgp_confederation_peers_remove(struct bgp *bgp, as_t as) struct listnode *node, *nnode; if (!bgp) - return -1; + return; if (!bgp_confederation_peers_check(bgp, as)) - return -1; + return; for (i = 0; i < bgp->confed_peers_cnt; i++) if (bgp->confed_peers[i] == as) @@ -751,71 +747,58 @@ int bgp_confederation_peers_remove(struct bgp *bgp, as_t as) } } } - - return 0; } /* Local preference configuration. */ -int bgp_default_local_preference_set(struct bgp *bgp, uint32_t local_pref) +void bgp_default_local_preference_set(struct bgp *bgp, uint32_t local_pref) { if (!bgp) - return -1; + return; bgp->default_local_pref = local_pref; - - return 0; } -int bgp_default_local_preference_unset(struct bgp *bgp) +void bgp_default_local_preference_unset(struct bgp *bgp) { if (!bgp) - return -1; + return; bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF; - - return 0; } /* Local preference configuration. */ -int bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, uint32_t queue_size) +void bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, + uint32_t queue_size) { if (!bgp) - return -1; + return; bgp->default_subgroup_pkt_queue_max = queue_size; - - return 0; } -int bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp) +void bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp) { if (!bgp) - return -1; + return; bgp->default_subgroup_pkt_queue_max = BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX; - - return 0; } /* Listen limit configuration. */ -int bgp_listen_limit_set(struct bgp *bgp, int listen_limit) +void bgp_listen_limit_set(struct bgp *bgp, int listen_limit) { if (!bgp) - return -1; + return; bgp->dynamic_neighbors_limit = listen_limit; - - return 0; } -int bgp_listen_limit_unset(struct bgp *bgp) +void bgp_listen_limit_unset(struct bgp *bgp) { if (!bgp) - return -1; + return; bgp->dynamic_neighbors_limit = BGP_DYNAMIC_NEIGHBORS_LIMIT_DEFAULT; - - return 0; } int bgp_map_afi_safi_iana2int(iana_afi_t pkt_afi, iana_safi_t pkt_safi, @@ -1828,7 +1811,7 @@ struct peer *peer_create_accept(struct bgp *bgp) /* * Return true if we have a peer configured to use this afi/safi */ -int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) +bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) { struct listnode *node; struct peer *peer; @@ -1838,10 +1821,10 @@ int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) continue; if (peer->afc[afi][safi]) - return 1; + return true; } - return 0; + return false; } /* Change peer's AS number. */ @@ -5127,7 +5110,7 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) return 0; } -int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) +void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) { struct peer *member; struct listnode *node, *nnode; @@ -5136,7 +5119,7 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) peer_flag_set(peer, PEER_FLAG_UPDATE_SOURCE); if (peer->update_source) { if (sockunion_cmp(peer->update_source, su) == 0) - return 0; + return; sockunion_free(peer->update_source); } peer->update_source = sockunion_dup(su); @@ -5157,7 +5140,7 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) bgp_peer_bfd_update_source(peer); /* Skip peer-group mechanics for regular peers. */ - return 0; + return; } /* @@ -5193,17 +5176,15 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) if (member->bfd_config) bgp_peer_bfd_update_source(member); } - - return 0; } -int peer_update_source_unset(struct peer *peer) +void peer_update_source_unset(struct peer *peer) { struct peer *member; struct listnode *node, *nnode; if (!CHECK_FLAG(peer->flags, PEER_FLAG_UPDATE_SOURCE)) - return 0; + return; /* Inherit configuration from peer-group if peer is member. */ if (peer_group_active(peer)) { @@ -5234,7 +5215,7 @@ int peer_update_source_unset(struct peer *peer) bgp_peer_bfd_update_source(peer); /* Skip peer-group mechanics for regular peers. */ - return 0; + return; } /* @@ -5269,8 +5250,6 @@ int peer_update_source_unset(struct peer *peer) if (member->bfd_config) bgp_peer_bfd_update_source(member); } - - return 0; } int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index bcb214873f..8348b37b8e 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -2128,32 +2128,34 @@ extern void bgp_router_id_static_set(struct bgp *, struct in_addr); extern void bm_wait_for_fib_set(bool set); extern void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set); -extern int bgp_cluster_id_set(struct bgp *, struct in_addr *); -extern int bgp_cluster_id_unset(struct bgp *); +extern void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id); +extern void bgp_cluster_id_unset(struct bgp *bgp); -extern void bgp_confederation_id_set(struct bgp *, as_t); -extern int bgp_confederation_id_unset(struct bgp *); +extern void bgp_confederation_id_set(struct bgp *bgp, as_t as); +extern void bgp_confederation_id_unset(struct bgp *bgp); extern bool bgp_confederation_peers_check(struct bgp *, as_t); -extern int bgp_confederation_peers_add(struct bgp *, as_t); -extern int bgp_confederation_peers_remove(struct bgp *, as_t); +extern void bgp_confederation_peers_add(struct bgp *bgp, as_t as); +extern void bgp_confederation_peers_remove(struct bgp *bgp, as_t as); extern void bgp_timers_set(struct bgp *, uint32_t keepalive, uint32_t holdtime, uint32_t connect_retry, uint32_t delayopen); extern void bgp_timers_unset(struct bgp *); -extern int bgp_default_local_preference_set(struct bgp *, uint32_t); -extern int bgp_default_local_preference_unset(struct bgp *); +extern void bgp_default_local_preference_set(struct bgp *bgp, + uint32_t local_pref); +extern void bgp_default_local_preference_unset(struct bgp *bgp); -extern int bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, uint32_t); -extern int bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp); +extern void bgp_default_subgroup_pkt_queue_max_set(struct bgp *bgp, + uint32_t queue_size); +extern void bgp_default_subgroup_pkt_queue_max_unset(struct bgp *bgp); -extern int bgp_listen_limit_set(struct bgp *, int); -extern int bgp_listen_limit_unset(struct bgp *); +extern void bgp_listen_limit_set(struct bgp *bgp, int listen_limit); +extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); -extern int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); +extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); extern void peer_as_change(struct peer *, as_t, int); extern int peer_remote_as(struct bgp *, union sockunion *, const char *, as_t *, int); @@ -2194,8 +2196,9 @@ extern void peer_description_set(struct peer *, const char *); extern void peer_description_unset(struct peer *); extern int peer_update_source_if_set(struct peer *, const char *); -extern int peer_update_source_addr_set(struct peer *, const union sockunion *); -extern int peer_update_source_unset(struct peer *); +extern void peer_update_source_addr_set(struct peer *peer, + const union sockunion *su); +extern void peer_update_source_unset(struct peer *peer); extern int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi, const char *rmap, diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index e7e13631cc..e31bfe7bfa 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1672,7 +1672,7 @@ Configuring Peers .. clicmd:: bgp fast-external-failover - This command causes bgp to not take down ebgp peers immediately + This command causes bgp to take down ebgp peers immediately when a link flaps. `bgp fast-external-failover` is the default and will not be displayed as part of a `show run`. The no form of the command turns off this ability. @@ -2334,11 +2334,8 @@ setting BGP communities attribute to the updates. exit-address-family ! bgp community-list 70 permit 7675:70 - bgp community-list 70 deny bgp community-list 80 permit 7675:80 - bgp community-list 80 deny bgp community-list 90 permit 7675:90 - bgp community-list 90 deny ! route-map RMAP permit 10 match community 70 diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index e6585d0bac..851e58b814 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -445,3 +445,11 @@ the config was written out. .. clicmd:: debug pimv6 zebra This gathers data about events from zebra that come up through the ZAPI. + +.. clicmd:: debug mroute6 + + This turns on debugging for PIMv6 interaction with kernel MFC cache. + +.. clicmd:: debug mroute6 detail + + This turns on detailed debugging for PIMv6 interaction with kernel MFC cache. diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h new file mode 100644 index 0000000000..7ea59cfe1f --- /dev/null +++ b/include/linux/pkt_cls.h @@ -0,0 +1,776 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef __LINUX_PKT_CLS_H +#define __LINUX_PKT_CLS_H + +#include <linux/types.h> +#include <linux/pkt_sched.h> + +#define TC_COOKIE_MAX_SIZE 16 + +/* Action attributes */ +enum { + TCA_ACT_UNSPEC, + TCA_ACT_KIND, + TCA_ACT_OPTIONS, + TCA_ACT_INDEX, + TCA_ACT_STATS, + TCA_ACT_PAD, + TCA_ACT_COOKIE, + TCA_ACT_FLAGS, + TCA_ACT_HW_STATS, + TCA_ACT_USED_HW_STATS, + __TCA_ACT_MAX +}; + +#define TCA_ACT_FLAGS_NO_PERCPU_STATS 1 /* Don't use percpu allocator for + * actions stats. + */ + +/* tca HW stats type + * When user does not pass the attribute, he does not care. + * It is the same as if he would pass the attribute with + * all supported bits set. + * In case no bits are set, user is not interested in getting any HW statistics. + */ +#define TCA_ACT_HW_STATS_IMMEDIATE (1 << 0) /* Means that in dump, user + * gets the current HW stats + * state from the device + * queried at the dump time. + */ +#define TCA_ACT_HW_STATS_DELAYED (1 << 1) /* Means that in dump, user gets + * HW stats that might be out of date + * for some time, maybe couple of + * seconds. This is the case when + * driver polls stats updates + * periodically or when it gets async + * stats update from the device. + */ + +#define TCA_ACT_MAX __TCA_ACT_MAX +#define TCA_OLD_COMPAT (TCA_ACT_MAX+1) +#define TCA_ACT_MAX_PRIO 32 +#define TCA_ACT_BIND 1 +#define TCA_ACT_NOBIND 0 +#define TCA_ACT_UNBIND 1 +#define TCA_ACT_NOUNBIND 0 +#define TCA_ACT_REPLACE 1 +#define TCA_ACT_NOREPLACE 0 + +#define TC_ACT_UNSPEC (-1) +#define TC_ACT_OK 0 +#define TC_ACT_RECLASSIFY 1 +#define TC_ACT_SHOT 2 +#define TC_ACT_PIPE 3 +#define TC_ACT_STOLEN 4 +#define TC_ACT_QUEUED 5 +#define TC_ACT_REPEAT 6 +#define TC_ACT_REDIRECT 7 +#define TC_ACT_TRAP 8 /* For hw path, this means "trap to cpu" + * and don't further process the frame + * in hardware. For sw path, this is + * equivalent of TC_ACT_STOLEN - drop + * the skb and act like everything + * is alright. + */ +#define TC_ACT_VALUE_MAX TC_ACT_TRAP + +/* There is a special kind of actions called "extended actions", + * which need a value parameter. These have a local opcode located in + * the highest nibble, starting from 1. The rest of the bits + * are used to carry the value. These two parts together make + * a combined opcode. + */ +#define __TC_ACT_EXT_SHIFT 28 +#define __TC_ACT_EXT(local) ((local) << __TC_ACT_EXT_SHIFT) +#define TC_ACT_EXT_VAL_MASK ((1 << __TC_ACT_EXT_SHIFT) - 1) +#define TC_ACT_EXT_OPCODE(combined) ((combined) & (~TC_ACT_EXT_VAL_MASK)) +#define TC_ACT_EXT_CMP(combined, opcode) (TC_ACT_EXT_OPCODE(combined) == opcode) + +#define TC_ACT_JUMP __TC_ACT_EXT(1) +#define TC_ACT_GOTO_CHAIN __TC_ACT_EXT(2) +#define TC_ACT_EXT_OPCODE_MAX TC_ACT_GOTO_CHAIN + +/* These macros are put here for binary compatibility with userspace apps that + * make use of them. For kernel code and new userspace apps, use the TCA_ID_* + * versions. + */ +#define TCA_ACT_GACT 5 +#define TCA_ACT_IPT 6 +#define TCA_ACT_PEDIT 7 +#define TCA_ACT_MIRRED 8 +#define TCA_ACT_NAT 9 +#define TCA_ACT_XT 10 +#define TCA_ACT_SKBEDIT 11 +#define TCA_ACT_VLAN 12 +#define TCA_ACT_BPF 13 +#define TCA_ACT_CONNMARK 14 +#define TCA_ACT_SKBMOD 15 +#define TCA_ACT_CSUM 16 +#define TCA_ACT_TUNNEL_KEY 17 +#define TCA_ACT_SIMP 22 +#define TCA_ACT_IFE 25 +#define TCA_ACT_SAMPLE 26 + +/* Action type identifiers*/ +enum tca_id { + TCA_ID_UNSPEC = 0, + TCA_ID_POLICE = 1, + TCA_ID_GACT = TCA_ACT_GACT, + TCA_ID_IPT = TCA_ACT_IPT, + TCA_ID_PEDIT = TCA_ACT_PEDIT, + TCA_ID_MIRRED = TCA_ACT_MIRRED, + TCA_ID_NAT = TCA_ACT_NAT, + TCA_ID_XT = TCA_ACT_XT, + TCA_ID_SKBEDIT = TCA_ACT_SKBEDIT, + TCA_ID_VLAN = TCA_ACT_VLAN, + TCA_ID_BPF = TCA_ACT_BPF, + TCA_ID_CONNMARK = TCA_ACT_CONNMARK, + TCA_ID_SKBMOD = TCA_ACT_SKBMOD, + TCA_ID_CSUM = TCA_ACT_CSUM, + TCA_ID_TUNNEL_KEY = TCA_ACT_TUNNEL_KEY, + TCA_ID_SIMP = TCA_ACT_SIMP, + TCA_ID_IFE = TCA_ACT_IFE, + TCA_ID_SAMPLE = TCA_ACT_SAMPLE, + TCA_ID_CTINFO, + TCA_ID_MPLS, + TCA_ID_CT, + TCA_ID_GATE, + /* other actions go here */ + __TCA_ID_MAX = 255 +}; + +#define TCA_ID_MAX __TCA_ID_MAX + +struct tc_police { + __u32 index; + int action; +#define TC_POLICE_UNSPEC TC_ACT_UNSPEC +#define TC_POLICE_OK TC_ACT_OK +#define TC_POLICE_RECLASSIFY TC_ACT_RECLASSIFY +#define TC_POLICE_SHOT TC_ACT_SHOT +#define TC_POLICE_PIPE TC_ACT_PIPE + + __u32 limit; + __u32 burst; + __u32 mtu; + struct tc_ratespec rate; + struct tc_ratespec peakrate; + int refcnt; + int bindcnt; + __u32 capab; +}; + +struct tcf_t { + __u64 install; + __u64 lastuse; + __u64 expires; + __u64 firstuse; +}; + +struct tc_cnt { + int refcnt; + int bindcnt; +}; + +#define tc_gen \ + __u32 index; \ + __u32 capab; \ + int action; \ + int refcnt; \ + int bindcnt + +enum { + TCA_POLICE_UNSPEC, + TCA_POLICE_TBF, + TCA_POLICE_RATE, + TCA_POLICE_PEAKRATE, + TCA_POLICE_AVRATE, + TCA_POLICE_RESULT, + TCA_POLICE_TM, + TCA_POLICE_PAD, + TCA_POLICE_RATE64, + TCA_POLICE_PEAKRATE64, + __TCA_POLICE_MAX +#define TCA_POLICE_RESULT TCA_POLICE_RESULT +}; + +#define TCA_POLICE_MAX (__TCA_POLICE_MAX - 1) + +/* tca flags definitions */ +#define TCA_CLS_FLAGS_SKIP_HW (1 << 0) /* don't offload filter to HW */ +#define TCA_CLS_FLAGS_SKIP_SW (1 << 1) /* don't use filter in SW */ +#define TCA_CLS_FLAGS_IN_HW (1 << 2) /* filter is offloaded to HW */ +#define TCA_CLS_FLAGS_NOT_IN_HW (1 << 3) /* filter isn't offloaded to HW */ +#define TCA_CLS_FLAGS_VERBOSE (1 << 4) /* verbose logging */ + +/* U32 filters */ + +#define TC_U32_HTID(h) ((h)&0xFFF00000) +#define TC_U32_USERHTID(h) (TC_U32_HTID(h)>>20) +#define TC_U32_HASH(h) (((h)>>12)&0xFF) +#define TC_U32_NODE(h) ((h)&0xFFF) +#define TC_U32_KEY(h) ((h)&0xFFFFF) +#define TC_U32_UNSPEC 0 +#define TC_U32_ROOT (0xFFF00000) + +enum { + TCA_U32_UNSPEC, + TCA_U32_CLASSID, + TCA_U32_HASH, + TCA_U32_LINK, + TCA_U32_DIVISOR, + TCA_U32_SEL, + TCA_U32_POLICE, + TCA_U32_ACT, + TCA_U32_INDEV, + TCA_U32_PCNT, + TCA_U32_MARK, + TCA_U32_FLAGS, + TCA_U32_PAD, + __TCA_U32_MAX +}; + +#define TCA_U32_MAX (__TCA_U32_MAX - 1) + +struct tc_u32_key { + __be32 mask; + __be32 val; + int off; + int offmask; +}; + +struct tc_u32_sel { + unsigned char flags; + unsigned char offshift; + unsigned char nkeys; + + __be16 offmask; + __u16 off; + short offoff; + + short hoff; + __be32 hmask; + struct tc_u32_key keys[0]; +}; + +struct tc_u32_mark { + __u32 val; + __u32 mask; + __u32 success; +}; + +struct tc_u32_pcnt { + __u64 rcnt; + __u64 rhit; + __u64 kcnts[0]; +}; + +/* Flags */ + +#define TC_U32_TERMINAL 1 +#define TC_U32_OFFSET 2 +#define TC_U32_VAROFFSET 4 +#define TC_U32_EAT 8 + +#define TC_U32_MAXDEPTH 8 + + +/* RSVP filter */ + +enum { + TCA_RSVP_UNSPEC, + TCA_RSVP_CLASSID, + TCA_RSVP_DST, + TCA_RSVP_SRC, + TCA_RSVP_PINFO, + TCA_RSVP_POLICE, + TCA_RSVP_ACT, + __TCA_RSVP_MAX +}; + +#define TCA_RSVP_MAX (__TCA_RSVP_MAX - 1 ) + +struct tc_rsvp_gpi { + __u32 key; + __u32 mask; + int offset; +}; + +struct tc_rsvp_pinfo { + struct tc_rsvp_gpi dpi; + struct tc_rsvp_gpi spi; + __u8 protocol; + __u8 tunnelid; + __u8 tunnelhdr; + __u8 pad; +}; + +/* ROUTE filter */ + +enum { + TCA_ROUTE4_UNSPEC, + TCA_ROUTE4_CLASSID, + TCA_ROUTE4_TO, + TCA_ROUTE4_FROM, + TCA_ROUTE4_IIF, + TCA_ROUTE4_POLICE, + TCA_ROUTE4_ACT, + __TCA_ROUTE4_MAX +}; + +#define TCA_ROUTE4_MAX (__TCA_ROUTE4_MAX - 1) + + +/* FW filter */ + +enum { + TCA_FW_UNSPEC, + TCA_FW_CLASSID, + TCA_FW_POLICE, + TCA_FW_INDEV, + TCA_FW_ACT, /* used by CONFIG_NET_CLS_ACT */ + TCA_FW_MASK, + __TCA_FW_MAX +}; + +#define TCA_FW_MAX (__TCA_FW_MAX - 1) + +/* TC index filter */ + +enum { + TCA_TCINDEX_UNSPEC, + TCA_TCINDEX_HASH, + TCA_TCINDEX_MASK, + TCA_TCINDEX_SHIFT, + TCA_TCINDEX_FALL_THROUGH, + TCA_TCINDEX_CLASSID, + TCA_TCINDEX_POLICE, + TCA_TCINDEX_ACT, + __TCA_TCINDEX_MAX +}; + +#define TCA_TCINDEX_MAX (__TCA_TCINDEX_MAX - 1) + +/* Flow filter */ + +enum { + FLOW_KEY_SRC, + FLOW_KEY_DST, + FLOW_KEY_PROTO, + FLOW_KEY_PROTO_SRC, + FLOW_KEY_PROTO_DST, + FLOW_KEY_IIF, + FLOW_KEY_PRIORITY, + FLOW_KEY_MARK, + FLOW_KEY_NFCT, + FLOW_KEY_NFCT_SRC, + FLOW_KEY_NFCT_DST, + FLOW_KEY_NFCT_PROTO_SRC, + FLOW_KEY_NFCT_PROTO_DST, + FLOW_KEY_RTCLASSID, + FLOW_KEY_SKUID, + FLOW_KEY_SKGID, + FLOW_KEY_VLAN_TAG, + FLOW_KEY_RXHASH, + __FLOW_KEY_MAX, +}; + +#define FLOW_KEY_MAX (__FLOW_KEY_MAX - 1) + +enum { + FLOW_MODE_MAP, + FLOW_MODE_HASH, +}; + +enum { + TCA_FLOW_UNSPEC, + TCA_FLOW_KEYS, + TCA_FLOW_MODE, + TCA_FLOW_BASECLASS, + TCA_FLOW_RSHIFT, + TCA_FLOW_ADDEND, + TCA_FLOW_MASK, + TCA_FLOW_XOR, + TCA_FLOW_DIVISOR, + TCA_FLOW_ACT, + TCA_FLOW_POLICE, + TCA_FLOW_EMATCHES, + TCA_FLOW_PERTURB, + __TCA_FLOW_MAX +}; + +#define TCA_FLOW_MAX (__TCA_FLOW_MAX - 1) + +/* Basic filter */ + +struct tc_basic_pcnt { + __u64 rcnt; + __u64 rhit; +}; + +enum { + TCA_BASIC_UNSPEC, + TCA_BASIC_CLASSID, + TCA_BASIC_EMATCHES, + TCA_BASIC_ACT, + TCA_BASIC_POLICE, + TCA_BASIC_PCNT, + TCA_BASIC_PAD, + __TCA_BASIC_MAX +}; + +#define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) + + +/* Cgroup classifier */ + +enum { + TCA_CGROUP_UNSPEC, + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, + TCA_CGROUP_EMATCHES, + __TCA_CGROUP_MAX, +}; + +#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) + +/* BPF classifier */ + +#define TCA_BPF_FLAG_ACT_DIRECT (1 << 0) + +enum { + TCA_BPF_UNSPEC, + TCA_BPF_ACT, + TCA_BPF_POLICE, + TCA_BPF_CLASSID, + TCA_BPF_OPS_LEN, + TCA_BPF_OPS, + TCA_BPF_FD, + TCA_BPF_NAME, + TCA_BPF_FLAGS, + TCA_BPF_FLAGS_GEN, + TCA_BPF_TAG, + TCA_BPF_ID, + __TCA_BPF_MAX, +}; + +#define TCA_BPF_MAX (__TCA_BPF_MAX - 1) + +/* Flower classifier */ + +enum { + TCA_FLOWER_UNSPEC, + TCA_FLOWER_CLASSID, + TCA_FLOWER_INDEV, + TCA_FLOWER_ACT, + TCA_FLOWER_KEY_ETH_DST, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_DST_MASK, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_SRC, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_SRC_MASK, /* ETH_ALEN */ + TCA_FLOWER_KEY_ETH_TYPE, /* be16 */ + TCA_FLOWER_KEY_IP_PROTO, /* u8 */ + TCA_FLOWER_KEY_IPV4_SRC, /* be32 */ + TCA_FLOWER_KEY_IPV4_SRC_MASK, /* be32 */ + TCA_FLOWER_KEY_IPV4_DST, /* be32 */ + TCA_FLOWER_KEY_IPV4_DST_MASK, /* be32 */ + TCA_FLOWER_KEY_IPV6_SRC, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_SRC_MASK, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_DST, /* struct in6_addr */ + TCA_FLOWER_KEY_IPV6_DST_MASK, /* struct in6_addr */ + TCA_FLOWER_KEY_TCP_SRC, /* be16 */ + TCA_FLOWER_KEY_TCP_DST, /* be16 */ + TCA_FLOWER_KEY_UDP_SRC, /* be16 */ + TCA_FLOWER_KEY_UDP_DST, /* be16 */ + + TCA_FLOWER_FLAGS, + TCA_FLOWER_KEY_VLAN_ID, /* be16 */ + TCA_FLOWER_KEY_VLAN_PRIO, /* u8 */ + TCA_FLOWER_KEY_VLAN_ETH_TYPE, /* be16 */ + + TCA_FLOWER_KEY_ENC_KEY_ID, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_SRC, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_SRC_MASK,/* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_DST, /* be32 */ + TCA_FLOWER_KEY_ENC_IPV4_DST_MASK,/* be32 */ + TCA_FLOWER_KEY_ENC_IPV6_SRC, /* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_SRC_MASK,/* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_DST, /* struct in6_addr */ + TCA_FLOWER_KEY_ENC_IPV6_DST_MASK,/* struct in6_addr */ + + TCA_FLOWER_KEY_TCP_SRC_MASK, /* be16 */ + TCA_FLOWER_KEY_TCP_DST_MASK, /* be16 */ + TCA_FLOWER_KEY_UDP_SRC_MASK, /* be16 */ + TCA_FLOWER_KEY_UDP_DST_MASK, /* be16 */ + TCA_FLOWER_KEY_SCTP_SRC_MASK, /* be16 */ + TCA_FLOWER_KEY_SCTP_DST_MASK, /* be16 */ + + TCA_FLOWER_KEY_SCTP_SRC, /* be16 */ + TCA_FLOWER_KEY_SCTP_DST, /* be16 */ + + TCA_FLOWER_KEY_ENC_UDP_SRC_PORT, /* be16 */ + TCA_FLOWER_KEY_ENC_UDP_SRC_PORT_MASK, /* be16 */ + TCA_FLOWER_KEY_ENC_UDP_DST_PORT, /* be16 */ + TCA_FLOWER_KEY_ENC_UDP_DST_PORT_MASK, /* be16 */ + + TCA_FLOWER_KEY_FLAGS, /* be32 */ + TCA_FLOWER_KEY_FLAGS_MASK, /* be32 */ + + TCA_FLOWER_KEY_ICMPV4_CODE, /* u8 */ + TCA_FLOWER_KEY_ICMPV4_CODE_MASK,/* u8 */ + TCA_FLOWER_KEY_ICMPV4_TYPE, /* u8 */ + TCA_FLOWER_KEY_ICMPV4_TYPE_MASK,/* u8 */ + TCA_FLOWER_KEY_ICMPV6_CODE, /* u8 */ + TCA_FLOWER_KEY_ICMPV6_CODE_MASK,/* u8 */ + TCA_FLOWER_KEY_ICMPV6_TYPE, /* u8 */ + TCA_FLOWER_KEY_ICMPV6_TYPE_MASK,/* u8 */ + + TCA_FLOWER_KEY_ARP_SIP, /* be32 */ + TCA_FLOWER_KEY_ARP_SIP_MASK, /* be32 */ + TCA_FLOWER_KEY_ARP_TIP, /* be32 */ + TCA_FLOWER_KEY_ARP_TIP_MASK, /* be32 */ + TCA_FLOWER_KEY_ARP_OP, /* u8 */ + TCA_FLOWER_KEY_ARP_OP_MASK, /* u8 */ + TCA_FLOWER_KEY_ARP_SHA, /* ETH_ALEN */ + TCA_FLOWER_KEY_ARP_SHA_MASK, /* ETH_ALEN */ + TCA_FLOWER_KEY_ARP_THA, /* ETH_ALEN */ + TCA_FLOWER_KEY_ARP_THA_MASK, /* ETH_ALEN */ + + TCA_FLOWER_KEY_MPLS_TTL, /* u8 - 8 bits */ + TCA_FLOWER_KEY_MPLS_BOS, /* u8 - 1 bit */ + TCA_FLOWER_KEY_MPLS_TC, /* u8 - 3 bits */ + TCA_FLOWER_KEY_MPLS_LABEL, /* be32 - 20 bits */ + + TCA_FLOWER_KEY_TCP_FLAGS, /* be16 */ + TCA_FLOWER_KEY_TCP_FLAGS_MASK, /* be16 */ + + TCA_FLOWER_KEY_IP_TOS, /* u8 */ + TCA_FLOWER_KEY_IP_TOS_MASK, /* u8 */ + TCA_FLOWER_KEY_IP_TTL, /* u8 */ + TCA_FLOWER_KEY_IP_TTL_MASK, /* u8 */ + + TCA_FLOWER_KEY_CVLAN_ID, /* be16 */ + TCA_FLOWER_KEY_CVLAN_PRIO, /* u8 */ + TCA_FLOWER_KEY_CVLAN_ETH_TYPE, /* be16 */ + + TCA_FLOWER_KEY_ENC_IP_TOS, /* u8 */ + TCA_FLOWER_KEY_ENC_IP_TOS_MASK, /* u8 */ + TCA_FLOWER_KEY_ENC_IP_TTL, /* u8 */ + TCA_FLOWER_KEY_ENC_IP_TTL_MASK, /* u8 */ + + TCA_FLOWER_KEY_ENC_OPTS, + TCA_FLOWER_KEY_ENC_OPTS_MASK, + + TCA_FLOWER_IN_HW_COUNT, + + TCA_FLOWER_KEY_PORT_SRC_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_SRC_MAX, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MIN, /* be16 */ + TCA_FLOWER_KEY_PORT_DST_MAX, /* be16 */ + + TCA_FLOWER_KEY_CT_STATE, /* u16 */ + TCA_FLOWER_KEY_CT_STATE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE, /* u16 */ + TCA_FLOWER_KEY_CT_ZONE_MASK, /* u16 */ + TCA_FLOWER_KEY_CT_MARK, /* u32 */ + TCA_FLOWER_KEY_CT_MARK_MASK, /* u32 */ + TCA_FLOWER_KEY_CT_LABELS, /* u128 */ + TCA_FLOWER_KEY_CT_LABELS_MASK, /* u128 */ + + TCA_FLOWER_KEY_MPLS_OPTS, + + TCA_FLOWER_KEY_HASH, /* u32 */ + TCA_FLOWER_KEY_HASH_MASK, /* u32 */ + + __TCA_FLOWER_MAX, +}; + +#define TCA_FLOWER_MAX (__TCA_FLOWER_MAX - 1) + +enum { + TCA_FLOWER_KEY_CT_FLAGS_NEW = 1 << 0, /* Beginning of a new connection. */ + TCA_FLOWER_KEY_CT_FLAGS_ESTABLISHED = 1 << 1, /* Part of an existing connection. */ + TCA_FLOWER_KEY_CT_FLAGS_RELATED = 1 << 2, /* Related to an established connection. */ + TCA_FLOWER_KEY_CT_FLAGS_TRACKED = 1 << 3, /* Conntrack has occurred. */ + TCA_FLOWER_KEY_CT_FLAGS_INVALID = 1 << 4, /* Conntrack is invalid. */ + TCA_FLOWER_KEY_CT_FLAGS_REPLY = 1 << 5, /* Packet is in the reply direction. */ + __TCA_FLOWER_KEY_CT_FLAGS_MAX, +}; + +enum { + TCA_FLOWER_KEY_ENC_OPTS_UNSPEC, + TCA_FLOWER_KEY_ENC_OPTS_GENEVE, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_GENEVE_ + * attributes + */ + TCA_FLOWER_KEY_ENC_OPTS_VXLAN, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_VXLAN_ + * attributes + */ + TCA_FLOWER_KEY_ENC_OPTS_ERSPAN, /* Nested + * TCA_FLOWER_KEY_ENC_OPT_ERSPAN_ + * attributes + */ + __TCA_FLOWER_KEY_ENC_OPTS_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPTS_MAX (__TCA_FLOWER_KEY_ENC_OPTS_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_GENEVE_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_GENEVE_CLASS, /* u16 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_TYPE, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_GENEVE_DATA, /* 4 to 128 bytes */ + + __TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_GENEVE_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_VXLAN_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_VXLAN_GBP, /* u32 */ + __TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_VXLAN_MAX - 1) + +enum { + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_UNSPEC, + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_VER, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_INDEX, /* be32 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_DIR, /* u8 */ + TCA_FLOWER_KEY_ENC_OPT_ERSPAN_HWID, /* u8 */ + __TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX, +}; + +#define TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX \ + (__TCA_FLOWER_KEY_ENC_OPT_ERSPAN_MAX - 1) + +enum { + TCA_FLOWER_KEY_MPLS_OPTS_UNSPEC, + TCA_FLOWER_KEY_MPLS_OPTS_LSE, + __TCA_FLOWER_KEY_MPLS_OPTS_MAX, +}; + +#define TCA_FLOWER_KEY_MPLS_OPTS_MAX (__TCA_FLOWER_KEY_MPLS_OPTS_MAX - 1) + +enum { + TCA_FLOWER_KEY_MPLS_OPT_LSE_UNSPEC, + TCA_FLOWER_KEY_MPLS_OPT_LSE_DEPTH, + TCA_FLOWER_KEY_MPLS_OPT_LSE_TTL, + TCA_FLOWER_KEY_MPLS_OPT_LSE_BOS, + TCA_FLOWER_KEY_MPLS_OPT_LSE_TC, + TCA_FLOWER_KEY_MPLS_OPT_LSE_LABEL, + __TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX, +}; + +#define TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX \ + (__TCA_FLOWER_KEY_MPLS_OPT_LSE_MAX - 1) + +enum { + TCA_FLOWER_KEY_FLAGS_IS_FRAGMENT = (1 << 0), + TCA_FLOWER_KEY_FLAGS_FRAG_IS_FIRST = (1 << 1), +}; + +#define TCA_FLOWER_MASK_FLAGS_RANGE (1 << 0) /* Range-based match */ + +/* Match-all classifier */ + +struct tc_matchall_pcnt { + __u64 rhit; +}; + +enum { + TCA_MATCHALL_UNSPEC, + TCA_MATCHALL_CLASSID, + TCA_MATCHALL_ACT, + TCA_MATCHALL_FLAGS, + TCA_MATCHALL_PCNT, + TCA_MATCHALL_PAD, + __TCA_MATCHALL_MAX, +}; + +#define TCA_MATCHALL_MAX (__TCA_MATCHALL_MAX - 1) + +/* Extended Matches */ + +struct tcf_ematch_tree_hdr { + __u16 nmatches; + __u16 progid; +}; + +enum { + TCA_EMATCH_TREE_UNSPEC, + TCA_EMATCH_TREE_HDR, + TCA_EMATCH_TREE_LIST, + __TCA_EMATCH_TREE_MAX +}; +#define TCA_EMATCH_TREE_MAX (__TCA_EMATCH_TREE_MAX - 1) + +struct tcf_ematch_hdr { + __u16 matchid; + __u16 kind; + __u16 flags; + __u16 pad; /* currently unused */ +}; + +/* 0 1 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 + * +-----------------------+-+-+---+ + * | Unused |S|I| R | + * +-----------------------+-+-+---+ + * + * R(2) ::= relation to next ematch + * where: 0 0 END (last ematch) + * 0 1 AND + * 1 0 OR + * 1 1 Unused (invalid) + * I(1) ::= invert result + * S(1) ::= simple payload + */ +#define TCF_EM_REL_END 0 +#define TCF_EM_REL_AND (1<<0) +#define TCF_EM_REL_OR (1<<1) +#define TCF_EM_INVERT (1<<2) +#define TCF_EM_SIMPLE (1<<3) + +#define TCF_EM_REL_MASK 3 +#define TCF_EM_REL_VALID(v) (((v) & TCF_EM_REL_MASK) != TCF_EM_REL_MASK) + +enum { + TCF_LAYER_LINK, + TCF_LAYER_NETWORK, + TCF_LAYER_TRANSPORT, + __TCF_LAYER_MAX +}; +#define TCF_LAYER_MAX (__TCF_LAYER_MAX - 1) + +/* Ematch type assignments + * 1..32767 Reserved for ematches inside kernel tree + * 32768..65535 Free to use, not reliable + */ +#define TCF_EM_CONTAINER 0 +#define TCF_EM_CMP 1 +#define TCF_EM_NBYTE 2 +#define TCF_EM_U32 3 +#define TCF_EM_META 4 +#define TCF_EM_TEXT 5 +#define TCF_EM_VLAN 6 +#define TCF_EM_CANID 7 +#define TCF_EM_IPSET 8 +#define TCF_EM_IPT 9 +#define TCF_EM_MAX 9 + +enum { + TCF_EM_PROG_TC +}; + +enum { + TCF_EM_OPND_EQ, + TCF_EM_OPND_GT, + TCF_EM_OPND_LT +}; + +#endif diff --git a/lib/link_state.c b/lib/link_state.c index 0ef87b7a51..ab5a8515b5 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -1791,9 +1791,10 @@ struct ls_edge *ls_msg2edge(struct ls_ted *ted, struct ls_message *msg, case LS_MSG_EVENT_DELETE: edge = ls_find_edge_by_source(ted, attr); if (edge) { - if (delete) + if (delete) { ls_edge_del_all(ted, edge); - else + edge = NULL; + } else edge->status = DELETE; } break; diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 4b03032566..e7f2eaf5a7 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -17,6 +17,7 @@ #include "memory.h" #include "thread.h" #include "hash.h" +#include "network.h" #include "nhrpd.h" #include "nhrp_protocol.h" @@ -334,7 +335,7 @@ int nhrp_peer_check(struct nhrp_peer *p, int establish) &p->t_fallback); } else { /* Maximum timeout is 1 second */ - int r_time_ms = rand() % 1000; + int r_time_ms = frr_weak_random() % 1000; debugf(NHRP_DEBUG_COMMON, "Initiating IPsec connection request to %pSU after %d ms:", diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index efa5d2b7ab..155374d3f0 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -966,10 +966,6 @@ static const char *ospf6_iftype_str(uint8_t iftype) return "UNKNOWN"; } -#if CONFDATE > 20220709 -CPP_NOTICE("Time to remove ospf6Enabled from JSON output") -#endif - /* show specified interface structure */ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, json_object *json_obj, bool use_json) @@ -996,11 +992,8 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, ospf6_iftype_str(default_iftype)); json_object_int_add(json_obj, "interfaceId", ifp->ifindex); - if (ifp->info == NULL) { - json_object_boolean_false_add(json_obj, "ospf6Enabled"); + if (ifp->info == NULL) return 0; - } - json_object_boolean_true_add(json_obj, "ospf6Enabled"); oi = (struct ospf6_interface *)ifp->info; @@ -1719,8 +1712,11 @@ void ospf6_interface_start(struct ospf6_interface *oi) if (oi->area_id_format == OSPF6_AREA_FMT_UNSET) return; - if (oi->area) + if (oi->area) { + /* Recompute cost */ + ospf6_interface_recalculate_cost(oi); return; + } ospf6 = oi->interface->vrf->info; if (!ospf6) diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 93a062b215..360a9db0d6 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -2086,7 +2086,6 @@ static void ospf6_write(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); struct ospf6_interface *oi; - struct ospf6_interface *last_serviced_oi = NULL; struct ospf6_header *oh; struct ospf6_packet *op; struct listnode *node; @@ -2106,9 +2105,7 @@ static void ospf6_write(struct thread *thread) assert(node); oi = listgetdata(node); - while ((pkt_count < ospf6->write_oi_count) && oi - && (last_serviced_oi != oi)) { - + while ((pkt_count < ospf6->write_oi_count) && oi) { op = ospf6_fifo_head(oi->obuf); assert(op); assert(op->length >= OSPF6_HEADER_SIZE); @@ -2221,7 +2218,6 @@ static void ospf6_write(struct thread *thread) list_delete_node(ospf6->oi_write_q, node); if (ospf6_fifo_head(oi->obuf) == NULL) { oi->on_write_q = 0; - last_serviced_oi = NULL; oi = NULL; } else { listnode_add(ospf6->oi_write_q, oi); diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 13243a55af..b7db1a6a83 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -1067,7 +1067,7 @@ static void ospf_abr_process_network_rt(struct ospf *ospf, && !OSPF_IS_AREA_ID_BACKBONE(or->u.std.area_id)) { if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "ospf_abr_process_network_rt(): this is route is not backbone one, skipping"); + "ospf_abr_process_network_rt(): this route is not backbone one, skipping"); continue; } diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index 848f340750..fb3fb21e08 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -638,13 +638,15 @@ int ospf_flood_through_interface(struct ospf_interface *oi, if (oi->type == OSPF_IFTYPE_NBMA) { struct ospf_neighbor *nbr; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) - if ((nbr = rn->info) != NULL) - if (nbr != oi->nbr_self - && nbr->state >= NSM_Exchange) - ospf_ls_upd_send_lsa( - nbr, lsa, - OSPF_SEND_PACKET_DIRECT); + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + + if (!nbr) + continue; + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + ospf_ls_upd_send_lsa(nbr, lsa, + OSPF_SEND_PACKET_DIRECT); + } } else ospf_ls_upd_send_lsa(oi->nbr_self, lsa, OSPF_SEND_PACKET_INDIRECT); @@ -991,18 +993,20 @@ static void ospf_ls_retransmit_delete_nbr_if(struct ospf_interface *oi, struct ospf_lsa *lsr; if (ospf_if_is_enable(oi)) - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { /* If LSA find in LS-retransmit list, then remove it. */ - if ((nbr = rn->info) != NULL) { - lsr = ospf_ls_retransmit_lookup(nbr, lsa); + nbr = rn->info; - /* If LSA find in ls-retransmit list, remove it. - */ - if (lsr != NULL - && lsr->data->ls_seqnum - == lsa->data->ls_seqnum) - ospf_ls_retransmit_delete(nbr, lsr); - } + if (!nbr) + continue; + + lsr = ospf_ls_retransmit_lookup(nbr, lsa); + + /* If LSA find in ls-retransmit list, remove it. */ + if (lsr != NULL && + lsr->data->ls_seqnum == lsa->data->ls_seqnum) + ospf_ls_retransmit_delete(nbr, lsr); + } } void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *area, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 633ab05131..2a758d5583 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -66,15 +66,16 @@ int ospf_interface_neighbor_count(struct ospf_interface *oi) for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { nbr = rn->info; - if (nbr) { - /* Do not show myself. */ - if (nbr == oi->nbr_self) - continue; - /* Down state is not shown. */ - if (nbr->state == NSM_Down) - continue; - count++; - } + if (!nbr) + continue; + + /* Do not show myself. */ + if (nbr == oi->nbr_self) + continue; + /* Down state is not shown. */ + if (nbr->state == NSM_Down) + continue; + count++; } return count; @@ -315,10 +316,11 @@ void ospf_if_cleanup(struct ospf_interface *oi) } /* send Neighbor event KillNbr to all associated neighbors. */ - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { if ((nbr = rn->info) != NULL) if (nbr != oi->nbr_self) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); + } /* Cleanup Link State Acknowlegdment list. */ for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) @@ -492,6 +494,20 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf, return match; } +void ospf_interface_fifo_flush(struct ospf_interface *oi) +{ + struct ospf *ospf = oi->ospf; + + ospf_fifo_flush(oi->obuf); + + if (oi->on_write_q) { + listnode_delete(ospf->oi_write_q, oi); + if (list_isempty(ospf->oi_write_q)) + THREAD_OFF(ospf->t_write); + oi->on_write_q = 0; + } +} + static void ospf_if_reset_stats(struct ospf_interface *oi) { oi->hello_in = oi->hello_out = 0; @@ -503,19 +519,10 @@ static void ospf_if_reset_stats(struct ospf_interface *oi) void ospf_if_stream_unset(struct ospf_interface *oi) { - struct ospf *ospf = oi->ospf; - /* flush the interface packet queue */ - ospf_fifo_flush(oi->obuf); + ospf_interface_fifo_flush(oi); /*reset protocol stats */ ospf_if_reset_stats(oi); - - if (oi->on_write_q) { - listnode_delete(ospf->oi_write_q, oi); - if (list_isempty(ospf->oi_write_q)) - THREAD_OFF(ospf->t_write); - oi->on_write_q = 0; - } } diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index e441016406..51fc1bf3c3 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -351,6 +351,8 @@ extern void ospf_if_interface(struct interface *ifp); extern uint32_t ospf_if_count_area_params(struct interface *ifp); extern void ospf_reset_hello_timer(struct interface *ifp, struct in_addr addr, bool is_addr); + +extern void ospf_interface_fifo_flush(struct ospf_interface *oi); DECLARE_HOOK(ospf_vl_add, (struct ospf_vl_data * vd), (vd)); DECLARE_HOOK(ospf_vl_delete, (struct ospf_vl_data * vd), (vd)); diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 333389596b..a27550853b 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -382,6 +382,10 @@ static void nsm_clear_adj(struct ospf_neighbor *nbr) static int nsm_kill_nbr(struct ospf_neighbor *nbr) { + struct ospf_interface *oi = nbr->oi; + struct ospf_neighbor *on; + struct route_node *rn; + /* killing nbr_self is invalid */ if (nbr == nbr->oi->nbr_self) { assert(nbr != nbr->oi->nbr_self); @@ -407,6 +411,35 @@ static int nsm_kill_nbr(struct ospf_neighbor *nbr) ospf_get_name(nbr->oi->ospf)); } + /* + * Do we have any neighbors that are also operating + * on this interface? + */ + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + on = rn->info; + + if (!on) + continue; + + if (on == nbr || on == oi->nbr_self) + continue; + + /* + * on is in some state where we might be + * sending packets on this interface + */ + if (on->state > NSM_Down) { + route_unlock_node(rn); + return 0; + } + } + /* + * If we get here we know that this interface + * has no neighbors in a state where we could + * be sending packets. Let's flush anything + * we got. + */ + ospf_interface_fifo_flush(oi); return 0; } diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 4b3f30a3f1..c5e26fa371 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -623,7 +623,6 @@ static void ospf_write(struct thread *thread) { struct ospf *ospf = THREAD_ARG(thread); struct ospf_interface *oi; - struct ospf_interface *last_serviced_oi = NULL; struct ospf_packet *op; struct sockaddr_in sa_dst; struct ip iph; @@ -664,13 +663,7 @@ static void ospf_write(struct thread *thread) ipid = (time(NULL) & 0xffff); #endif /* WANT_OSPF_WRITE_FRAGMENT */ - while ((pkt_count < ospf->write_oi_count) && oi - && (last_serviced_oi != oi)) { - /* If there is only packet in the queue, the oi is removed from - write-q, so fix up the last interface that was serviced */ - if (last_serviced_oi == NULL) { - last_serviced_oi = oi; - } + while ((pkt_count < ospf->write_oi_count) && oi) { pkt_count++; #ifdef WANT_OSPF_WRITE_FRAGMENT /* convenience - max OSPF data per packet */ @@ -853,11 +846,9 @@ static void ospf_write(struct thread *thread) list_delete_node(ospf->oi_write_q, node); if (ospf_fifo_head(oi->obuf) == NULL) { oi->on_write_q = 0; - last_serviced_oi = NULL; oi = NULL; - } else { + } else listnode_add(ospf->oi_write_q, oi); - } /* Setup to service from the head of the queue again */ if (!list_isempty(ospf->oi_write_q)) { @@ -3358,49 +3349,44 @@ static int ospf_make_hello(struct ospf_interface *oi, struct stream *s) stream_put_ipv4(s, BDR(oi).s_addr); /* Add neighbor seen. */ - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) - if ((nbr = rn->info)) - if (nbr->router_id.s_addr - != INADDR_ANY) /* Ignore 0.0.0.0 node. */ - if (nbr->state - != NSM_Attempt) /* Ignore Down neighbor. */ - if (nbr->state - != NSM_Down) /* This is myself for - DR election. */ - if (!IPV4_ADDR_SAME( - &nbr->router_id, - &oi->ospf->router_id)) { - /* Check neighbor is - * sane? */ - if (nbr->d_router.s_addr - != INADDR_ANY - && IPV4_ADDR_SAME( - &nbr->d_router, - &oi->address - ->u - .prefix4) - && IPV4_ADDR_SAME( - &nbr->bd_router, - &oi->address - ->u - .prefix4)) - flag = 1; - - /* Hello packet overflows interface MTU. */ - if (length + sizeof(uint32_t) - > ospf_packet_max(oi)) { - flog_err( - EC_OSPF_LARGE_HELLO, - "Oversized Hello packet! Larger than MTU. Not sending it out"); - return 0; - } - - stream_put_ipv4( - s, - nbr->router_id - .s_addr); - length += 4; - } + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + + if (!nbr) + continue; + + /* Ignore the 0.0.0.0 node */ + if (nbr->router_id.s_addr == INADDR_ANY) + continue; + + /* Ignore Down neighbor */ + if (nbr->state == NSM_Attempt) + continue; + + /* This is myself for DR election */ + if (nbr->state == NSM_Down) + continue; + + if (IPV4_ADDR_SAME(&nbr->router_id, &oi->ospf->router_id)) + continue; + /* Check neighbor is sane? */ + if (nbr->d_router.s_addr != INADDR_ANY && + IPV4_ADDR_SAME(&nbr->d_router, &oi->address->u.prefix4) && + IPV4_ADDR_SAME(&nbr->bd_router, &oi->address->u.prefix4)) + flag = 1; + + /* Hello packet overflows interface MTU. + */ + if (length + sizeof(uint32_t) > ospf_packet_max(oi)) { + flog_err( + EC_OSPF_LARGE_HELLO, + "Oversized Hello packet! Larger than MTU. Not sending it out"); + return 0; + } + + stream_put_ipv4(s, nbr->router_id.s_addr); + length += 4; + } /* Let neighbor generate BackupSeen. */ if (flag == 1) @@ -3781,54 +3767,44 @@ void ospf_hello_send(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) - if ((nbr = rn->info)) - if (nbr != oi->nbr_self) - if (nbr->state != NSM_Down) { - /* RFC 2328 Section 9.5.1 - If the router is not - eligible to become Designated - Router, - it must periodically send - Hello Packets to both the - Designated Router and the - Backup Designated Router (if - they - exist). */ - if (PRIORITY(oi) == 0 - && IPV4_ADDR_CMP( - &DR(oi), - &nbr->address.u - .prefix4) - && IPV4_ADDR_CMP( - &BDR(oi), - &nbr->address.u - .prefix4)) - continue; - - /* If the router is eligible to - become Designated Router, it - must periodically send Hello - Packets to all neighbors that - are also eligible. In - addition, if the router is - itself the - Designated Router or Backup - Designated Router, it must - also - send periodic Hello Packets - to all other neighbors. */ - - if (nbr->priority == 0 - && oi->state == ISM_DROther) - continue; - /* if oi->state == Waiting, send - * hello to all neighbors */ - ospf_hello_send_sub( - oi, - nbr->address.u.prefix4 - .s_addr); - } + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + if (!nbr) + continue; + + if (nbr == oi->nbr_self) + continue; + + if (nbr->state == NSM_Down) + continue; + + /* + * RFC 2328 Section 9.5.1 + * If the router is not eligible to become Designated + * Router, it must periodically send Hello Packets to + * both the Designated Router and the Backup + * Designated Router (if they exist). + */ + if (PRIORITY(oi) == 0 && + IPV4_ADDR_CMP(&DR(oi), &nbr->address.u.prefix4) && + IPV4_ADDR_CMP(&BDR(oi), &nbr->address.u.prefix4)) + continue; + + /* + * If the router is eligible to become Designated + * Router, it must periodically send Hello Packets to + * all neighbors that are also eligible. In addition, + * if the router is itself the Designated Router or + * Backup Designated Router, it must also send periodic + * Hello Packets to all other neighbors. + */ + if (nbr->priority == 0 && oi->state == ISM_DROther) + continue; + + /* if oi->state == Waiting, send + * hello to all neighbors */ + ospf_hello_send_sub(oi, nbr->address.u.prefix4.s_addr); + } } else { /* Decide destination address. */ if (oi->type == OSPF_IFTYPE_VIRTUALLINK) @@ -4300,14 +4276,18 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) - if ((nbr = rn->info) != NULL) - if (nbr != oi->nbr_self - && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + + if (!nbr) + continue; + + if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) + while (listcount(oi->ls_ack)) + ospf_ls_ack_send_list( + oi, oi->ls_ack, + nbr->address.u.prefix4); + } return; } if (oi->type == OSPF_IFTYPE_VIRTUALLINK) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 2c7c80686c..3a71e55710 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -756,13 +756,14 @@ static struct ospf_neighbor *get_neighbor_by_addr(struct ospf *top, for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi)) for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { nbr = rn->info; - if (nbr) - if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, - &addr) - || IPV4_ADDR_SAME(&nbr->router_id, &addr)) { - route_unlock_node(rn); - return nbr; - } + if (!nbr) + continue; + + if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &addr) || + IPV4_ADDR_SAME(&nbr->router_id, &addr)) { + route_unlock_node(rn); + return nbr; + } } return NULL; } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 1c22fad669..a6572794aa 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -4008,13 +4008,15 @@ static void show_ip_ospf_interface_traffic_sub(struct vty *vty, oi->ls_ack_in); json_object_int_add(json_interface_sub, "lsAckOut", oi->ls_ack_out); + json_object_int_add(json_interface_sub, "packetsQueued", + listcount(oi->obuf)); } else { vty_out(vty, - "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u\n", + "%-10s %8u/%-8u %7u/%-7u %7u/%-7u %7u/%-7u %7u/%-7u %12lu\n", oi->ifp->name, oi->hello_in, oi->hello_out, oi->db_desc_in, oi->db_desc_out, oi->ls_req_in, oi->ls_req_out, oi->ls_upd_in, oi->ls_upd_out, - oi->ls_ack_in, oi->ls_ack_out); + oi->ls_ack_in, oi->ls_ack_out, listcount(oi->obuf)); } } @@ -4030,14 +4032,14 @@ static int show_ip_ospf_interface_traffic_common( if (!use_json && !display_once) { vty_out(vty, "\n"); - vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", "Interface", - " HELLO", " DB-Desc", " LS-Req", " LS-Update", - " LS-Ack"); - vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s\n", "", + vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s%-17s\n", + "Interface", " HELLO", " DB-Desc", " LS-Req", + " LS-Update", " LS-Ack", " Packets"); + vty_out(vty, "%-10s%-18s%-18s%-17s%-17s%-17s%-17s\n", "", " Rx/Tx", " Rx/Tx", " Rx/Tx", " Rx/Tx", - " Rx/Tx"); + " Rx/Tx", " Queued"); vty_out(vty, - "--------------------------------------------------------------------------------------------\n"); + "-------------------------------------------------------------------------------------------------------------\n"); } else if (use_json) { if (use_vrf) json_vrf = json_object_new_object(); @@ -4476,19 +4478,22 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, struct ospf_neighbor *nbr, *prev_nbr = NULL; for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - if ((nbr = rn->info)) { - /* Do not show myself. */ - if (nbr == oi->nbr_self) - continue; - /* Down state is not shown. */ - if (nbr->state == NSM_Down) - continue; + nbr = rn->info; - prev_nbr = nbr; + if (!nbr) + continue; - show_ip_ospf_neighbour_brief(vty, nbr, prev_nbr, json, - use_json); - } + /* Do not show myself. */ + if (nbr == oi->nbr_self) + continue; + /* Down state is not shown. */ + if (nbr->state == NSM_Down) + continue; + + prev_nbr = nbr; + + show_ip_ospf_neighbour_brief(vty, nbr, prev_nbr, json, + use_json); } } @@ -5402,14 +5407,17 @@ static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json, use_vrf); for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { - if ((nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, router_id))) { - if (is_detail) - show_ip_ospf_neighbor_detail_sub( - vty, oi, nbr, NULL, json, use_json); - else - show_ip_ospf_neighbour_brief(vty, nbr, NULL, - json, use_json); - } + nbr = ospf_nbr_lookup_by_routerid(oi->nbrs, router_id); + + if (!nbr) + continue; + + if (is_detail) + show_ip_ospf_neighbor_detail_sub(vty, oi, nbr, NULL, + json, use_json); + else + show_ip_ospf_neighbour_brief(vty, nbr, NULL, json, + use_json); } if (use_json) @@ -5498,16 +5506,19 @@ static int show_ip_ospf_neighbor_detail_common(struct vty *vty, struct ospf_neighbor *nbr, *prev_nbr = NULL; for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - if ((nbr = rn->info)) { - if (nbr != oi->nbr_self) { - if (nbr->state != NSM_Down) { - show_ip_ospf_neighbor_detail_sub( - vty, oi, nbr, prev_nbr, - json_nbr_sub, use_json); - } + nbr = rn->info; + + if (!nbr) + continue; + + if (nbr != oi->nbr_self) { + if (nbr->state != NSM_Down) { + show_ip_ospf_neighbor_detail_sub( + vty, oi, nbr, prev_nbr, + json_nbr_sub, use_json); } - prev_nbr = nbr; } + prev_nbr = nbr; } } @@ -5668,27 +5679,29 @@ static int show_ip_ospf_neighbor_detail_all_common(struct vty *vty, struct ospf_nbr_nbma *nbr_nbma; for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - if ((nbr = rn->info)) { - if (nbr != oi->nbr_self) - if (nbr->state != NSM_Down) - show_ip_ospf_neighbor_detail_sub( - vty, oi, rn->info, - prev_nbr, - json_vrf, use_json); - prev_nbr = nbr; - } + nbr = rn->info; + + if (!nbr) + continue; + + if (nbr != oi->nbr_self) + if (nbr->state != NSM_Down) + show_ip_ospf_neighbor_detail_sub( + vty, oi, rn->info, prev_nbr, + json_vrf, use_json); + prev_nbr = nbr; } - if (oi->type == OSPF_IFTYPE_NBMA) { - struct listnode *nd; + if (oi->type != OSPF_IFTYPE_NBMA) + continue; - for (ALL_LIST_ELEMENTS_RO(oi->nbr_nbma, nd, nbr_nbma)) { - if (nbr_nbma->nbr == NULL - || nbr_nbma->nbr->state == NSM_Down) - show_ip_ospf_nbr_nbma_detail_sub( - vty, oi, nbr_nbma, use_json, - json_vrf); - } + struct listnode *nd; + + for (ALL_LIST_ELEMENTS_RO(oi->nbr_nbma, nd, nbr_nbma)) { + if (nbr_nbma->nbr == NULL || + nbr_nbma->nbr->state == NSM_Down) + show_ip_ospf_nbr_nbma_detail_sub( + vty, oi, nbr_nbma, use_json, json_vrf); } } @@ -5853,19 +5866,25 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty, } for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { - if ((oi = rn->info)) { - for (nrn = route_top(oi->nbrs); nrn; - nrn = route_next(nrn)) { - if ((nbr = nrn->info)) { - if (nbr != oi->nbr_self) { - if (nbr->state != NSM_Down) - show_ip_ospf_neighbor_detail_sub( - vty, oi, nbr, - NULL, - json, use_json); - } - } - } + oi = rn->info; + + if (!oi) + continue; + + for (nrn = route_top(oi->nbrs); nrn; nrn = route_next(nrn)) { + nbr = nrn->info; + + if (!nbr) + continue; + + if (nbr == oi->nbr_self) + continue; + + if (nbr->state == NSM_Down) + continue; + + show_ip_ospf_neighbor_detail_sub(vty, oi, nbr, NULL, + json, use_json); } } @@ -8019,13 +8038,17 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) struct route_node *rn; struct ospf_neighbor *nbr; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) - if ((nbr = rn->info)) { - nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); - nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); - } + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + + if (!nbr) + continue; + + nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); + nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + } } static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str, diff --git a/pathd/path_pcep_pcc.c b/pathd/path_pcep_pcc.c index b72a536ef4..a1c56f93ad 100644 --- a/pathd/path_pcep_pcc.c +++ b/pathd/path_pcep_pcc.c @@ -1326,9 +1326,9 @@ void handle_pcep_lsp_initiate(struct ctrl_state *ctrl_state, * possibly disconnect and blacklist */ flog_warn(EC_PATH_PCEP_UNSUPPORTED_PCEP_FEATURE, "Unsupported PCEP protocol feature: %s", err); - pcep_free_path(path); send_pcep_error(pcc_state, PCEP_ERRT_INVALID_OPERATION, PCEP_ERRV_LSP_NOT_PCE_INITIATED, path); + pcep_free_path(path); } } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index d68bcfa160..a2b3431b94 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -137,6 +137,9 @@ DEFPY(pbr_map_match_src, pbr_map_match_src_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (pbrms->dst && pbrms->family && prefix->family != pbrms->family) { vty_out(vty, "Cannot mismatch families within match src/dst\n"); return CMD_WARNING_CONFIG_FAILED; @@ -170,6 +173,9 @@ DEFPY(pbr_map_match_dst, pbr_map_match_dst_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (pbrms->src && pbrms->family && prefix->family != pbrms->family) { vty_out(vty, "Cannot mismatch families within match src/dst\n"); return CMD_WARNING_CONFIG_FAILED; @@ -204,6 +210,9 @@ DEFPY(pbr_map_match_ip_proto, pbr_map_match_ip_proto_cmd, struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); struct protoent *p; + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) { p = getprotobyname(ip_proto); if (!p) { @@ -228,6 +237,9 @@ DEFPY(pbr_map_match_src_port, pbr_map_match_src_port_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) { if (pbrms->src_prt == port) return CMD_SUCCESS; @@ -250,6 +262,9 @@ DEFPY(pbr_map_match_dst_port, pbr_map_match_dst_port_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) { if (pbrms->dst_prt == port) return CMD_SUCCESS; @@ -274,6 +289,9 @@ DEFPY(pbr_map_match_dscp, pbr_map_match_dscp_cmd, char dscpname[100]; uint8_t rawDscp; + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + /* Discriminate dscp enums (cs0, cs1 etc.) and numbers */ bool isANumber = true; for (int i = 0; i < (int)strlen(dscp); i++) { @@ -333,6 +351,9 @@ DEFPY(pbr_map_match_ecn, pbr_map_match_ecn_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) { if ((pbrms->dsfield & PBR_DSFIELD_ECN) == ecn) return CMD_SUCCESS; @@ -357,6 +378,9 @@ DEFPY(pbr_map_match_mark, pbr_map_match_mark_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + #ifndef GNU_LINUX vty_out(vty, "pbr marks are not supported on this platform\n"); return CMD_WARNING_CONFIG_FAILED; @@ -417,6 +441,9 @@ DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) pbrms->action_queue_id = queue_id; else if ((uint32_t)queue_id == pbrms->action_queue_id) @@ -435,6 +462,9 @@ DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[no] set pcp <(0-7)$pcp>", { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) pbrms->action_pcp = pcp; else if (pcp == pbrms->action_pcp) @@ -454,6 +484,9 @@ DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) pbrms->action_vlan_id = vlan_id; else if (pbrms->action_vlan_id == vlan_id) @@ -472,6 +505,9 @@ DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (!no) pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY; else @@ -492,6 +528,9 @@ DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); struct nexthop_group_cmd *nhgc; + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + nhgc = nhgc_find(name); if (!nhgc) { vty_out(vty, "Specified nexthop-group %s does not exist\n", @@ -522,6 +561,9 @@ DEFPY(no_pbr_map_nexthop_group, no_pbr_map_nexthop_group_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + pbrms_clear_set_config(pbrms); return CMD_SUCCESS; @@ -548,6 +590,9 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, struct nexthop nhop; struct nexthop *nh = NULL; + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + if (vrf_name) vrf = vrf_lookup_by_name(vrf_name); else @@ -670,6 +715,9 @@ DEFPY(no_pbr_map_nexthop, no_pbr_map_nexthop_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + pbrms_clear_set_config(pbrms); return CMD_SUCCESS; @@ -684,6 +732,9 @@ DEFPY(pbr_map_vrf, pbr_map_vrf_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + /* * If an equivalent set vrf * exists, just return success. */ @@ -722,6 +773,9 @@ DEFPY(no_pbr_map_vrf, no_pbr_map_vrf_cmd, { struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + if (!pbrms) + return CMD_WARNING_CONFIG_FAILED; + pbrms_clear_set_config(pbrms); return CMD_SUCCESS; diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index 01c5745426..dc84de6bfd 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -1516,6 +1516,37 @@ DEFPY (debug_pimv6_zebra, return CMD_SUCCESS; } +DEFPY (debug_mroute6, + debug_mroute6_cmd, + "[no] debug mroute6", + NO_STR + DEBUG_STR + DEBUG_MROUTE6_STR) +{ + if (!no) + PIM_DO_DEBUG_MROUTE; + else + PIM_DONT_DEBUG_MROUTE; + + return CMD_SUCCESS; +} + +DEFPY (debug_mroute6_detail, + debug_mroute6_detail_cmd, + "[no] debug mroute6 detail", + NO_STR + DEBUG_STR + DEBUG_MROUTE6_STR + "detailed\n") +{ + if (!no) + PIM_DO_DEBUG_MROUTE_DETAIL; + else + PIM_DONT_DEBUG_MROUTE_DETAIL; + + return CMD_SUCCESS; +} + DEFUN_NOSH (show_debugging_pimv6, show_debugging_pimv6_cmd, "show debugging [pimv6]", @@ -1660,6 +1691,8 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &debug_pimv6_trace_cmd); install_element(ENABLE_NODE, &debug_pimv6_trace_detail_cmd); install_element(ENABLE_NODE, &debug_pimv6_zebra_cmd); + install_element(ENABLE_NODE, &debug_mroute6_cmd); + install_element(ENABLE_NODE, &debug_mroute6_detail_cmd); install_element(CONFIG_NODE, &debug_pimv6_cmd); install_element(CONFIG_NODE, &debug_pimv6_nht_cmd); @@ -1671,4 +1704,6 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &debug_pimv6_trace_cmd); install_element(CONFIG_NODE, &debug_pimv6_trace_detail_cmd); install_element(CONFIG_NODE, &debug_pimv6_zebra_cmd); + install_element(CONFIG_NODE, &debug_mroute6_cmd); + install_element(CONFIG_NODE, &debug_mroute6_detail_cmd); } diff --git a/pimd/pim6_cmd.h b/pimd/pim6_cmd.h index 8fb82d9f26..c45c998453 100644 --- a/pimd/pim6_cmd.h +++ b/pimd/pim6_cmd.h @@ -57,6 +57,7 @@ #define DEBUG_PIMV6_PACKETDUMP_RECV_STR "Dump received packets\n" #define DEBUG_PIMV6_TRACE_STR "PIMv6 internal daemon activity\n" #define DEBUG_PIMV6_ZEBRA_STR "ZEBRA protocol activity\n" +#define DEBUG_MROUTE6_STR "PIMv6 interaction with kernel MFC cache\n" void pim_cmd_init(void); diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index 2f0743b570..2f2ff24675 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -36,6 +36,7 @@ typedef struct in_addr pim_addr; #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" #define PIM_AF_DBG "pim" +#define PIM_MROUTE_DBG "mroute" #define PIMREG "pimreg" #define PIM_ADDR_FUNCNAME(name) ipv4_##name @@ -61,6 +62,7 @@ typedef struct in6_addr pim_addr; #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" #define PIM_AF_DBG "pimv6" +#define PIM_MROUTE_DBG "mroute6" #define PIMREG "pim6reg" #define PIM_ADDR_FUNCNAME(name) ipv6_##name diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a3188128fa..c2453efa06 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -5526,12 +5526,13 @@ DEFUN (show_ip_msdp_mesh_group, int idx = 2; struct pim_msdp_mg *mg; struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); - struct pim_instance *pim = vrf->info; + struct pim_instance *pim; struct json_object *json = NULL; if (!vrf) return CMD_WARNING; + pim = vrf->info; /* Quick case: list is empty. */ if (SLIST_EMPTY(&pim->msdp.mglist)) { if (uj) diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 1d3f5f430a..009936cdb7 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -888,6 +888,8 @@ void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json) { struct pim_upstream *up; time_t now = pim_time_monotonic_sec(); + struct ttable *tt = NULL; + char *table = NULL; json_object *json_group = NULL; json_object *json_row = NULL; @@ -895,8 +897,15 @@ void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json) if (!json) { vty_out(vty, "\n"); - vty_out(vty, - "Source Group RpfIface RpfAddress RibNextHop Metric Pref\n"); + + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "Source|Group|RpfIface|RpfAddress|RibNextHop|Metric|Pref"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); } frr_each (rb_pim_upstream, &pim->upstream_head, up) { @@ -944,8 +953,8 @@ void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json) json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, - "%-15pPAs %-15pPAs %-16s %-15pPA %-15pPAs %6d %4d\n", + ttable_add_row( + tt, "%pPAs|%pPAs|%s|%pPA|%pPAs|%d|%d", &up->sg.src, &up->sg.grp, rpf_ifname, &rpf->rpf_addr, &rpf->source_nexthop.mrib_nexthop_addr, @@ -953,14 +962,27 @@ void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json) rpf->source_nexthop.mrib_metric_preference); } } + /* Dump the generated table. */ + if (!json) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } } void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty) { struct interface *ifp; + struct ttable *tt = NULL; + char *table = NULL; - vty_out(vty, - "Interface Address Neighbor Secondary \n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Interface|Address|Neighbor|Secondary"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; @@ -988,12 +1010,16 @@ void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty) for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, prefix_node, p)) - vty_out(vty, - "%-16s %-15pPAs %-15pPAs %-15pFX\n", - ifp->name, &ifaddr, &neigh->source_addr, - p); + ttable_add_row(tt, "%s|%pPAs|%pPAs|%pFX", + ifp->name, &ifaddr, + &neigh->source_addr, p); } } + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); } void pim_show_state(struct pim_instance *pim, struct vty *vty, @@ -1317,15 +1343,24 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty, pim_sgaddr *sg, json_object *json) { struct pim_upstream *up; + struct ttable *tt = NULL; + char *table = NULL; time_t now; json_object *json_group = NULL; json_object *json_row = NULL; now = pim_time_monotonic_sec(); - if (!json) - vty_out(vty, - "Iif Source Group State Uptime JoinTimer RSTimer KATimer RefCnt\n"); + if (!json) { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "Iif|Source|Group|State|Uptime|JoinTimer|RSTimer|KATimer|RefCnt"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } frr_each (rb_pim_upstream, &pim->upstream_head, up) { char uptime[10]; @@ -1446,8 +1481,8 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty, json_object_int_add(json_row, "sptBit", up->sptbit); json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, - "%-16s%-15pPAs %-15pPAs %-11s %-8s %-9s %-9s %-9s %6d\n", + ttable_add_row(tt, + "%s|%pPAs|%pPAs|%s|%s|%s|%s|%s|%d", up->rpf.source_nexthop.interface ? up->rpf.source_nexthop.interface->name : "Unknown", @@ -1455,12 +1490,20 @@ void pim_show_upstream(struct pim_instance *pim, struct vty *vty, join_timer, rs_timer, ka_timer, up->ref_count); } } + /* Dump the generated table. */ + if (!json) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } } static void pim_show_join_desired_helper(struct pim_instance *pim, struct vty *vty, struct pim_upstream *up, - json_object *json, bool uj) + json_object *json, bool uj, + struct ttable *tt) { json_object *json_group = NULL; json_object *json_row = NULL; @@ -1491,45 +1534,68 @@ static void pim_show_join_desired_helper(struct pim_instance *pim, json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, "%-15pPAs %-15pPAs %-6s\n", &up->sg.src, - &up->sg.grp, - pim_upstream_evaluate_join_desired(pim, up) ? "yes" - : "no"); + ttable_add_row(tt, "%pPAs|%pPAs|%s", &up->sg.src, &up->sg.grp, + pim_upstream_evaluate_join_desired(pim, up) + ? "yes" + : "no"); } } void pim_show_join_desired(struct pim_instance *pim, struct vty *vty, bool uj) { struct pim_upstream *up; + struct ttable *tt = NULL; + char *table = NULL; json_object *json = NULL; if (uj) json = json_object_new_object(); - else - vty_out(vty, "Source Group EvalJD\n"); + else { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Source|Group|EvalJD"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } frr_each (rb_pim_upstream, &pim->upstream_head, up) { /* scan all interfaces */ - pim_show_join_desired_helper(pim, vty, up, json, uj); + pim_show_join_desired_helper(pim, vty, up, json, uj, tt); } if (uj) vty_json(vty, json); + else { + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } } void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj) { struct pim_upstream *up; + struct ttable *tt = NULL; + char *table = NULL; json_object *json = NULL; json_object *json_group = NULL; json_object *json_row = NULL; if (uj) json = json_object_new_object(); - else - vty_out(vty, - "Source Group RpfIface RibNextHop RpfAddress \n"); + else { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, + "Source|Group|RpfIface|RibNextHop|RpfAddress"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } frr_each (rb_pim_upstream, &pim->upstream_head, up) { struct pim_rpf *rpf; @@ -1571,16 +1637,22 @@ void pim_show_upstream_rpf(struct pim_instance *pim, struct vty *vty, bool uj) &rpf->rpf_addr); json_object_object_add(json_group, src_str, json_row); } else { - vty_out(vty, - "%-15pPAs %-15pPAs %-16s %-15pPA %-15pPA\n", - &up->sg.src, &up->sg.grp, rpf_ifname, - &rpf->source_nexthop.mrib_nexthop_addr, - &rpf->rpf_addr); + ttable_add_row(tt, "%pPAs|%pPAs|%s|%pPA|%pPA", + &up->sg.src, &up->sg.grp, rpf_ifname, + &rpf->source_nexthop.mrib_nexthop_addr, + &rpf->rpf_addr); } } if (uj) vty_json(vty, json); + else { + /* Dump the generated table. */ + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } } static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index ac2eee0a30..ce252366ce 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -539,10 +539,7 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, if (up_flags == PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) PIM_IF_FLAG_SET_PROTO_IGMP(ch->flags); - if (ch->upstream) - ch->upstream->flags |= up_flags; - else if (PIM_DEBUG_EVENTS) - zlog_debug("%s:%pSG No Upstream found", __func__, sg); + ch->upstream->flags |= up_flags; return ch; } @@ -637,8 +634,7 @@ static void ifjoin_to_noinfo(struct pim_ifchannel *ch) pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO); pim_forward_stop(ch); - if (ch->upstream) - PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags); + PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags); PIM_IF_FLAG_UNSET_PROTO_PIM(ch->flags); @@ -696,31 +692,29 @@ static void on_ifjoin_prune_pending_timer(struct thread *t) * message on RP path upon prune timer expiry. */ ch->ifjoin_state = PIM_IFJOIN_PRUNE; - if (ch->upstream) { - struct pim_upstream *parent = - ch->upstream->parent; + struct pim_upstream *parent = + ch->upstream->parent; - pim_upstream_update_join_desired(pim_ifp->pim, - ch->upstream); + pim_upstream_update_join_desired(pim_ifp->pim, + ch->upstream); - pim_jp_agg_single_upstream_send(&parent->rpf, - parent, true); - /* - * SGRpt prune pending expiry has to install - * SG entry with empty olist to drop the SG - * traffic incase no other intf exists. - * On that scenario, SG entry wouldn't have - * got installed until Prune pending timer - * expired. So install now. - */ - pim_channel_del_oif( - ch->upstream->channel_oil, ifp, - PIM_OIF_FLAG_PROTO_STAR, __func__); - if (!ch->upstream->channel_oil->installed) - pim_upstream_mroute_add( - ch->upstream->channel_oil, - __func__); - } + pim_jp_agg_single_upstream_send(&parent->rpf, + parent, true); + /* + * SGRpt prune pending expiry has to install + * SG entry with empty olist to drop the SG + * traffic incase no other intf exists. + * On that scenario, SG entry wouldn't have + * got installed until Prune pending timer + * expired. So install now. + */ + pim_channel_del_oif( + ch->upstream->channel_oil, ifp, + PIM_OIF_FLAG_PROTO_STAR, __func__); + if (!ch->upstream->channel_oil->installed) + pim_upstream_mroute_add( + ch->upstream->channel_oil, + __func__); } /* from here ch may have been deleted */ } diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 783c9b97e7..1dce6b3562 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -51,6 +51,7 @@ #include "pim_bsm.h" #include "pim_util.h" #include "pim_ssm.h" +#include "termtable.h" /* Cleanup pim->rpf_hash each node data */ void pim_rp_list_hash_clean(void *data) @@ -1166,14 +1167,25 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range, struct rp_info *rp_info; struct rp_info *prev_rp_info = NULL; struct listnode *node; + struct ttable *tt = NULL; + char *table = NULL; char source[7]; + char grp[INET6_ADDRSTRLEN]; json_object *json_rp_rows = NULL; json_object *json_row = NULL; - if (!json) - vty_out(vty, - "RP address group/prefix-list OIF I am RP Source Group-Type\n"); + if (!json) { + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row( + tt, + "RP address|group/prefix-list|OIF|I am RP|Source|Group-Type"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + } + for (ALL_LIST_ELEMENTS_RO(pim->rp_list, node, rp_info)) { if (pim_rpf_addr_is_inaddr_any(&rp_info->rp)) continue; @@ -1243,32 +1255,31 @@ void pim_rp_show_information(struct pim_instance *pim, struct prefix *range, json_object_array_add(json_rp_rows, json_row); } else { - vty_out(vty, "%-15pPA ", &rp_info->rp.rpf_addr); - - if (rp_info->plist) - vty_out(vty, "%-18s ", rp_info->plist); - else - vty_out(vty, "%-18pFX ", &rp_info->group); - - if (rp_info->rp.source_nexthop.interface) - vty_out(vty, "%-16s ", - rp_info->rp.source_nexthop - .interface->name); - else - vty_out(vty, "%-16s ", "(Unknown)"); - - if (rp_info->i_am_rp) - vty_out(vty, "yes"); - else - vty_out(vty, "no"); - - vty_out(vty, "%14s", source); - vty_out(vty, "%6s\n", group_type); + prefix2str(&rp_info->group, grp, sizeof(grp)); + ttable_add_row(tt, "%pPA|%s|%s|%s|%s|%s", + &rp_info->rp.rpf_addr, + rp_info->plist + ? rp_info->plist + : grp, + rp_info->rp.source_nexthop.interface + ? rp_info->rp.source_nexthop + .interface->name + : "Unknown", + rp_info->i_am_rp + ? "yes" + : "no", + source, group_type); } prev_rp_info = rp_info; } - if (json) { + /* Dump the generated table. */ + if (!json) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + ttable_del(tt); + } else { if (prev_rp_info && json_rp_rows) json_object_object_addf(json, json_rp_rows, "%pPA", &prev_rp_info->rp.rpf_addr); diff --git a/pimd/pim_sock.c b/pimd/pim_sock.c index 73184d5c63..b5a055c6aa 100644 --- a/pimd/pim_sock.c +++ b/pimd/pim_sock.c @@ -185,7 +185,7 @@ int pim_reg_sock(void) long flags; frr_with_privs (&pimd_privs) { - fd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + fd = socket(PIM_AF, SOCK_RAW, IPPROTO_RAW); } if (fd < 0) { diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index 25e7e52705..0742daa4de 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -1061,15 +1061,13 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg, } if (PIM_DEBUG_PIM_TRACE) { - if (up) - zlog_debug("%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d", - __func__, name, - up->sg_str, &up->rpf.rpf_addr, up->rpf.source_nexthop.interface ? - up->rpf.source_nexthop.interface->name : "Unknown" , - found, up->ref_count); - else - zlog_debug("%s(%s): (%pSG) failure to create", __func__, - name, sg); + zlog_debug( + "%s(%s): %s, iif %pPA (%s) found: %d: ref_count: %d", + __func__, name, up->sg_str, &up->rpf.rpf_addr, + up->rpf.source_nexthop.interface ? up->rpf.source_nexthop + .interface->name + : "Unknown", + found, up->ref_count); } return up; diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index f9642b2133..3d5d68b1f4 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -78,11 +78,11 @@ int pim_debug_config_write(struct vty *vty) /* PIM_DEBUG_MROUTE catches _DETAIL too */ if (router->debugs & PIM_MASK_MROUTE) { - vty_out(vty, "debug mroute\n"); + vty_out(vty, "debug " PIM_MROUTE_DBG "\n"); ++writes; } if (PIM_DEBUG_MROUTE_DETAIL) { - vty_out(vty, "debug mroute detail\n"); + vty_out(vty, "debug " PIM_MROUTE_DBG " detail\n"); ++writes; } diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index c94785ec01..962541405f 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -409,9 +409,6 @@ routing state through standard SNMP MIBs. --disable-bgp-vnc \ %endif --enable-isisd \ -%if "%{initsystem}" == "systemd" - --enable-systemd \ -%endif --enable-rpki \ %if %{with_bfdd} --enable-bfdd \ diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py index c9824e79c5..d318ec0906 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -183,7 +183,7 @@ def test_ospfv3_p2p_tc3_p0(request): step("Verify that interface is enabled in ospf.") step("Verify that config is successful.") dut = "r0" - input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}} + input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}} result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -339,7 +339,7 @@ def test_ospfv3_p2p_tc3_p0(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) step("Verify that interface is enabled in ospf.") dut = "r0" - input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}} + input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}} result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -374,7 +374,7 @@ def test_ospfv3_p2p_tc3_p0(request): step("Verify that interface is enabled in ospf.") dut = "r0" - input_dict = {"r0": {"links": {"r3": {"ospf6": {"ospf6Enabled": True}}}}} + input_dict = {"r0": {"links": {"r3": {"ospf6": {}}}}} result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) @@ -1172,7 +1172,6 @@ def test_ospfv3_show_p1(request): "ospf6": { "status": "up", "type": "BROADCAST", - "ospf6Enabled": True, "attachedToArea": True, "instanceId": 0, "interfaceMtu": 1500, diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index fc285c748a..423f25faa2 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -1429,7 +1429,7 @@ int main(int argc, char **argv) if ((sscanf(optarg, "%ld%1s", &gs.operational_timeout, garbage) != 1) || - (gs.max_restart_interval < 0)) { + (gs.operational_timeout < 0)) { fprintf(stderr, "Invalid Operational_timeout argument: %s\n", optarg); diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index a16d442521..afefab6674 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -1536,6 +1536,24 @@ next_rta: goto next_rta; } +static const char *tcm_nltype2str(int nltype) +{ + switch (nltype) { + case RTM_NEWQDISC: + case RTM_DELQDISC: + return "qdisc"; + case RTM_NEWTCLASS: + case RTM_DELTCLASS: + return "tclass"; + case RTM_NEWTFILTER: + case RTM_DELTFILTER: + return "tfilter"; + default: + /* should never hit */ + return "unknown"; + } +} + static void nlncm_dump(const struct netconfmsg *ncm, size_t msglen) { const struct rtattr *rta; @@ -1595,6 +1613,8 @@ void nl_dump(void *msg, size_t msglen) struct ifinfomsg *ifi; struct tunnel_msg *tnlm; struct fib_rule_hdr *frh; + struct tcmsg *tcm; + char fbuf[128]; char ibuf[128]; @@ -1730,6 +1750,21 @@ next_header: nlncm_dump(ncm, nlmsg->nlmsg_len - NLMSG_LENGTH(sizeof(*ncm))); break; + case RTM_NEWQDISC: + case RTM_DELQDISC: + case RTM_NEWTCLASS: + case RTM_DELTCLASS: + case RTM_NEWTFILTER: + case RTM_DELTFILTER: + tcm = NLMSG_DATA(nlmsg); + zlog_debug( + " tcm [type=%s family=%s (%d) ifindex=%d handle=%04x:%04x]", + tcm_nltype2str(nlmsg->nlmsg_type), + af_type2str(tcm->tcm_family), tcm->tcm_family, + tcm->tcm_ifindex, tcm->tcm_handle >> 16, + tcm->tcm_handle & 0xffff); + break; + default: break; } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index ec4ea372f1..d07c4c6332 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -815,6 +815,9 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: case DPLANE_OP_NONE: break; diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 7a4e1304bd..c7e7443a1b 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -423,7 +423,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) ecmd.cmd = ETHTOOL_GSET; /* ETHTOOL_GLINK */ ifdata.ifr_data = (caddr_t)&ecmd; - /* use ioctl to get IP address of an interface */ + /* use ioctl to get speed of an interface */ frr_with_privs(&zserv_privs) { sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP, interface->vrf->vrf_id, NULL); @@ -436,7 +436,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) *error = -1; return 0; } - /* Get the current link state for the interface */ + /* Get the current link state for the interface */ rc = vrf_ioctl(interface->vrf->vrf_id, sd, SIOCETHTOOL, (char *)&ifdata); } diff --git a/zebra/interface.c b/zebra/interface.c index 205fa88293..c674b499ac 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1573,6 +1573,9 @@ void zebra_if_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: break; /* should never hit here */ } } diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index 396ccb34bd..45a372f88c 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -47,6 +47,7 @@ #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" #include "zebra/rule_netlink.h" +#include "zebra/tc_netlink.h" #include "zebra/netconf_netlink.h" #include "zebra/zebra_errors.h" @@ -114,6 +115,15 @@ static const struct message nlmsg_str[] = {{RTM_NEWROUTE, "RTM_NEWROUTE"}, {RTM_NEWTUNNEL, "RTM_NEWTUNNEL"}, {RTM_DELTUNNEL, "RTM_DELTUNNEL"}, {RTM_GETTUNNEL, "RTM_GETTUNNEL"}, + {RTM_NEWQDISC, "RTM_NEWQDISC"}, + {RTM_DELQDISC, "RTM_DELQDISC"}, + {RTM_GETQDISC, "RTM_GETQDISC"}, + {RTM_NEWTCLASS, "RTM_NEWTCLASS"}, + {RTM_DELTCLASS, "RTM_DELTCLASS"}, + {RTM_GETTCLASS, "RTM_GETTCLASS"}, + {RTM_NEWTFILTER, "RTM_NEWTFILTER"}, + {RTM_DELTFILTER, "RTM_DELTFILTER"}, + {RTM_GETTFILTER, "RTM_GETTFILTER"}, {0}}; static const struct message rtproto_str[] = { @@ -1623,6 +1633,11 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: return netlink_put_intf_update_msg(bth, ctx); + + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + return netlink_put_tc_update_msg(bth, ctx); } return FRR_NETLINK_ERROR; diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 076e9c4dfa..cb549339af 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -1603,6 +1603,12 @@ void kernel_update_multi(struct dplane_ctx_q *ctx_list) res = kernel_intf_update(ctx); break; + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + res = kernel_tc_update(ctx); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/rt.h b/zebra/rt.h index 0a86a2897c..d8a22d2cfc 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -71,6 +71,7 @@ kernel_intf_update(struct zebra_dplane_ctx *ctx); extern enum zebra_dplane_result kernel_intf_netconf_update(struct zebra_dplane_ctx *ctx); +extern enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx); #endif /* !HAVE_NETLINK */ diff --git a/zebra/subdir.am b/zebra/subdir.am index a926c14adf..298b71598c 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -82,6 +82,8 @@ zebra_zebra_SOURCES = \ zebra/rule_netlink.c \ zebra/rule_socket.c \ zebra/table_manager.c \ + zebra/tc_netlink.c \ + zebra/tc_socket.c \ zebra/zapi_msg.c \ zebra/zebra_dplane.c \ zebra/zebra_errors.c \ @@ -163,6 +165,7 @@ noinst_HEADERS += \ zebra/rtadv.h \ zebra/rule_netlink.h \ zebra/table_manager.h \ + zebra/tc_netlink.h \ zebra/zapi_msg.h \ zebra/zebra_dplane.h \ zebra/zebra_errors.h \ diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c new file mode 100644 index 0000000000..4fb0241d1d --- /dev/null +++ b/zebra/tc_netlink.c @@ -0,0 +1,468 @@ +/* + * Zebra Traffic Control (TC) interaction with the kernel using netlink. + * + * Copyright (C) 2022 Shichu Yang + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#ifdef HAVE_NETLINK + +#include <linux/if_ether.h> +#include <sys/socket.h> + +#include "if.h" +#include "prefix.h" +#include "vrf.h" + +#include <linux/fib_rules.h> +#include <linux/pkt_cls.h> +#include <linux/pkt_sched.h> +#include "zebra/zserv.h" +#include "zebra/zebra_ns.h" +#include "zebra/zebra_vrf.h" +#include "zebra/rt.h" +#include "zebra/interface.h" +#include "zebra/debug.h" +#include "zebra/rtadv.h" +#include "zebra/kernel_netlink.h" +#include "zebra/tc_netlink.h" +#include "zebra/zebra_errors.h" +#include "zebra/zebra_dplane.h" +#include "zebra/zebra_trace.h" + +/* TODO: move these bitflags to zebra_tc.h */ +#define TC_FILTER_SRC_IP (1 << 0) +#define TC_FILTER_DST_IP (1 << 1) +#define TC_FILTER_IP_PROTOCOL (1 << 9) + +#define TC_FREQ_DEFAULT (100) + +#define TC_MAJOR_BASE (0x1000u) +#define TC_MINOR_NOCLASS (0xffffu) + +#define TC_FILTER_MASK (0x8000u) + +#define TIME_UNITS_PER_SEC (1000000) +#define xmittime(r, s) (TIME_UNITS_PER_SEC * ((double)(s) / (double)(r))) + +static uint32_t tc_get_freq(void) +{ + int freq = 0; + FILE *fp = fopen("/proc/net/psched", "r"); + + if (fp) { + uint32_t nom, denom; + + if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) { + if (nom == 1000000) + freq = denom; + } + fclose(fp); + } + + return freq == 0 ? TC_FREQ_DEFAULT : freq; +} + +static inline uint32_t tc_make_handle(uint16_t major, uint16_t minor) +{ + return (major) << 16 | (minor); +} + +static inline uint32_t tc_get_handle(struct zebra_dplane_ctx *ctx, + uint16_t minor) +{ + uint16_t major = TC_MAJOR_BASE + (uint16_t)dplane_ctx_get_ifindex(ctx); + + return tc_make_handle(major, minor); +} + +static void tc_calc_rate_table(struct tc_ratespec *ratespec, uint32_t *table, + uint32_t mtu) +{ + if (mtu == 0) + mtu = 2047; + + int cell_log = -1; + + if (cell_log < 0) { + cell_log = 0; + while ((mtu >> cell_log) > 255) + cell_log++; + } + + for (int i = 0; i < 256; i++) + table[i] = xmittime(ratespec->rate, (i + 1) << cell_log); + + ratespec->cell_align = -1; + ratespec->cell_log = cell_log; + ratespec->linklayer = TC_LINKLAYER_ETHERNET; +} + +static int tc_flower_get_inet_prefix(const struct prefix *prefix, + struct inet_prefix *addr) +{ + addr->family = prefix->family; + + if (addr->family == AF_INET) { + addr->bytelen = 4; + addr->bitlen = prefix->prefixlen; + addr->flags = 0; + addr->flags |= PREFIXLEN_SPECIFIED; + addr->flags |= ADDRTYPE_INET; + memcpy(addr->data, prefix->u.val32, sizeof(prefix->u.val32)); + } else if (addr->family == AF_INET6) { + addr->bytelen = 16; + addr->bitlen = prefix->prefixlen; + addr->flags = 0; + addr->flags |= PREFIXLEN_SPECIFIED; + addr->flags |= ADDRTYPE_INET; + memcpy(addr->data, prefix->u.val, sizeof(prefix->u.val)); + } else { + return -1; + } + + return 0; +} + +static int tc_flower_get_inet_mask(const struct prefix *prefix, + struct inet_prefix *addr) +{ + addr->family = prefix->family; + + if (addr->family == AF_INET) { + addr->bytelen = 4; + addr->bitlen = prefix->prefixlen; + addr->flags = 0; + addr->flags |= PREFIXLEN_SPECIFIED; + addr->flags |= ADDRTYPE_INET; + } else if (addr->family == AF_INET6) { + addr->bytelen = 16; + addr->bitlen = prefix->prefixlen; + addr->flags = 0; + addr->flags |= PREFIXLEN_SPECIFIED; + addr->flags |= ADDRTYPE_INET; + } else { + return -1; + } + + memset(addr->data, 0xff, addr->bytelen); + + int rest = prefix->prefixlen; + + for (int i = 0; i < addr->bytelen / 4; i++) { + if (!rest) { + addr->data[i] = 0; + } else if (rest / 32 >= 1) { + rest -= 32; + } else { + addr->data[i] <<= 32 - rest; + addr->data[i] = htonl(addr->data[i]); + rest = 0; + } + } + + return 0; +} + +/* + * Traffic control queue discipline encoding (only "htb" supported) + */ +static ssize_t netlink_qdisc_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *data, size_t datalen) +{ + struct nlsock *nl; + + const char *kind = "htb"; + + struct tc_htb_glob htb_glob = { + .rate2quantum = 10, .version = 3, .defcls = TC_MINOR_NOCLASS}; + + struct rtattr *nest; + + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[0]; + } *req = (void *)data; + + if (datalen < sizeof(*req)) + return 0; + + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + + req->n.nlmsg_flags |= NLM_F_REPLACE; + + req->n.nlmsg_type = cmd; + + req->n.nlmsg_pid = nl->snl.nl_pid; + + req->t.tcm_family = AF_UNSPEC; + req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx); + req->t.tcm_handle = tc_get_handle(ctx, 0); + req->t.tcm_parent = TC_H_ROOT; + + nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1); + + nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS); + + nl_attr_put(&req->n, datalen, TCA_HTB_INIT, &htb_glob, + sizeof(htb_glob)); + nl_attr_nest_end(&req->n, nest); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +/* + * Traffic control class encoding + */ +static ssize_t netlink_tclass_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *data, size_t datalen) +{ + struct nlsock *nl; + struct tc_htb_opt htb_opt = {}; + + uint64_t rate, ceil; + uint64_t buffer, cbuffer; + + /* TODO: fetch mtu from interface */ + uint32_t mtu = 0; + + uint32_t rtab[256]; + uint32_t ctab[256]; + + struct rtattr *nest; + + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[0]; + } *req = (void *)data; + + if (datalen < sizeof(*req)) + return 0; + + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + + req->n.nlmsg_type = cmd; + + req->n.nlmsg_pid = nl->snl.nl_pid; + + req->t.tcm_family = AF_UNSPEC; + req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx); + req->t.tcm_handle = tc_get_handle(ctx, 1); + req->t.tcm_parent = tc_get_handle(ctx, 0); + + rate = dplane_ctx_tc_get_rate(ctx); + ceil = dplane_ctx_tc_get_ceil(ctx); + + ceil = ceil < rate ? rate : ceil; + + htb_opt.rate.rate = (rate >> 32 != 0) ? ~0U : rate; + htb_opt.ceil.rate = (ceil >> 32 != 0) ? ~0U : ceil; + + buffer = rate / tc_get_freq(), cbuffer = ceil / tc_get_freq(); + + htb_opt.buffer = buffer; + htb_opt.cbuffer = cbuffer; + + tc_calc_rate_table(&htb_opt.rate, rtab, mtu); + tc_calc_rate_table(&htb_opt.ceil, ctab, mtu); + + htb_opt.ceil.mpu = htb_opt.rate.mpu = 0; + htb_opt.ceil.overhead = htb_opt.rate.overhead = 0; + + nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS); + + if (rate >> 32 != 0) { + nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &rate, + sizeof(rate)); + } + + if (ceil >> 32 != 0) { + nl_attr_put(&req->n, datalen, TCA_HTB_CEIL64, &ceil, + sizeof(ceil)); + } + + nl_attr_put(&req->n, datalen, TCA_HTB_PARMS, &htb_opt, sizeof(htb_opt)); + + nl_attr_put(&req->n, datalen, TCA_HTB_RTAB, rtab, sizeof(rtab)); + nl_attr_put(&req->n, datalen, TCA_HTB_CTAB, ctab, sizeof(ctab)); + nl_attr_nest_end(&req->n, nest); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +/* + * Traffic control filter encoding (only "flower" supported) + */ +static ssize_t netlink_tfilter_msg_encode(int cmd, struct zebra_dplane_ctx *ctx, + void *data, size_t datalen) +{ + struct nlsock *nl; + struct rtattr *nest; + + const char *kind = "flower"; + + uint16_t priority; + uint16_t protocol; + uint32_t classid; + uint32_t filter_bm; + uint32_t flags = 0; + + struct inet_prefix addr; + + struct { + struct nlmsghdr n; + struct tcmsg t; + char buf[0]; + } *req = (void *)data; + + if (datalen < sizeof(*req)) + return 0; + + nl = kernel_netlink_nlsock_lookup(dplane_ctx_get_ns_sock(ctx)); + + memset(req, 0, sizeof(*req)); + + req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg)); + req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST; + + req->n.nlmsg_flags |= NLM_F_EXCL; + + req->n.nlmsg_type = cmd; + + req->n.nlmsg_pid = nl->snl.nl_pid; + + req->t.tcm_family = AF_UNSPEC; + req->t.tcm_ifindex = dplane_ctx_get_ifindex(ctx); + + /* TODO: priority and layer-3 protocol support */ + priority = 0; + protocol = htons(ETH_P_IP); + classid = tc_get_handle(ctx, 1); + filter_bm = dplane_ctx_tc_get_filter_bm(ctx); + + req->t.tcm_info = tc_make_handle(priority, protocol); + + req->t.tcm_handle = 1; + req->t.tcm_parent = tc_get_handle(ctx, 0); + + nl_attr_put(&req->n, datalen, TCA_KIND, kind, strlen(kind) + 1); + nest = nl_attr_nest(&req->n, datalen, TCA_OPTIONS); + + nl_attr_put(&req->n, datalen, TCA_FLOWER_CLASSID, &classid, + sizeof(classid)); + + if (filter_bm & TC_FILTER_SRC_IP) { + const struct prefix *src_p = dplane_ctx_tc_get_src_ip(ctx); + + if (tc_flower_get_inet_prefix(src_p, &addr) != 0) + return 0; + + nl_attr_put(&req->n, datalen, + (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_SRC + : TCA_FLOWER_KEY_IPV6_SRC, + addr.data, addr.bytelen); + + if (tc_flower_get_inet_mask(src_p, &addr) != 0) + return 0; + + nl_attr_put(&req->n, datalen, + (addr.family == AF_INET) + ? TCA_FLOWER_KEY_IPV4_SRC_MASK + : TCA_FLOWER_KEY_IPV6_SRC_MASK, + addr.data, addr.bytelen); + } + + if (filter_bm & TC_FILTER_DST_IP) { + const struct prefix *dst_p = dplane_ctx_tc_get_dst_ip(ctx); + + if (tc_flower_get_inet_prefix(dst_p, &addr) != 0) + return 0; + + nl_attr_put(&req->n, datalen, + (addr.family == AF_INET) ? TCA_FLOWER_KEY_IPV4_DST + : TCA_FLOWER_KEY_IPV6_DST, + addr.data, addr.bytelen); + + if (tc_flower_get_inet_mask(dst_p, &addr) != 0) + return 0; + + nl_attr_put(&req->n, datalen, + (addr.family == AF_INET) + ? TCA_FLOWER_KEY_IPV4_DST_MASK + : TCA_FLOWER_KEY_IPV6_DST_MASK, + addr.data, addr.bytelen); + } + + if (filter_bm & TC_FILTER_IP_PROTOCOL) { + nl_attr_put8(&req->n, datalen, TCA_FLOWER_KEY_IP_PROTO, + dplane_ctx_tc_get_ip_proto(ctx)); + } + + nl_attr_put32(&req->n, datalen, TCA_FLOWER_FLAGS, flags); + + nl_attr_put16(&req->n, datalen, TCA_FLOWER_KEY_ETH_TYPE, protocol); + nl_attr_nest_end(&req->n, nest); + + return NLMSG_ALIGN(req->n.nlmsg_len); +} + +static ssize_t netlink_newqdisc_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_qdisc_msg_encode(RTM_NEWQDISC, ctx, buf, buflen); +} + +static ssize_t netlink_newtclass_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_tclass_msg_encode(RTM_NEWTCLASS, ctx, buf, buflen); +} + +static ssize_t netlink_newtfilter_msg_encoder(struct zebra_dplane_ctx *ctx, + void *buf, size_t buflen) +{ + return netlink_tfilter_msg_encode(RTM_NEWTFILTER, ctx, buf, buflen); +} + +enum netlink_msg_status netlink_put_tc_update_msg(struct nl_batch *bth, + struct zebra_dplane_ctx *ctx) +{ + /* TODO: error handling and other actions (delete, replace, ...) */ + + netlink_batch_add_msg(bth, ctx, netlink_newqdisc_msg_encoder, false); + netlink_batch_add_msg(bth, ctx, netlink_newtclass_msg_encoder, false); + return netlink_batch_add_msg(bth, ctx, netlink_newtfilter_msg_encoder, + false); +} + +#endif /* HAVE_NETLINK */ diff --git a/zebra/tc_netlink.h b/zebra/tc_netlink.h new file mode 100644 index 0000000000..2190bca4f9 --- /dev/null +++ b/zebra/tc_netlink.h @@ -0,0 +1,62 @@ +/* + * Zebra Traffic Control (TC) interaction with the kernel using netlink. + * + * Copyright (C) 2022 Shichu Yang + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef _ZEBRA_TC_NETLINK_H +#define _ZEBRA_TC_NETLINK_H + +#ifdef HAVE_NETLINK + +#ifdef __cplusplus +extern "C" { +#endif + +/* Represent a prefixed address in flower filter */ + +struct inet_prefix { + uint16_t flags; + uint16_t bytelen; + uint16_t bitlen; + uint16_t family; + uint32_t data[64]; +}; + +enum { + PREFIXLEN_SPECIFIED = (1 << 0), + ADDRTYPE_INET = (1 << 1), + ADDRTYPE_UNSPEC = (1 << 2), + ADDRTYPE_MULTI = (1 << 3), + + ADDRTYPE_INET_UNSPEC = ADDRTYPE_INET | ADDRTYPE_UNSPEC, + ADDRTYPE_INET_MULTI = ADDRTYPE_INET | ADDRTYPE_MULTI +}; + +extern enum netlink_msg_status +netlink_put_tc_update_msg(struct nl_batch *bth, struct zebra_dplane_ctx *ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* HAVE_NETLINK */ + +#endif /* _ZEBRA_TC_NETLINK_H */ diff --git a/zebra/tc_socket.c b/zebra/tc_socket.c new file mode 100644 index 0000000000..0bf9e487b0 --- /dev/null +++ b/zebra/tc_socket.c @@ -0,0 +1,41 @@ +/* + * Zebra Traffic Control (TC) interaction with the kernel using socket. + * + * Copyright (C) 2022 Shichu Yang + * + * This file is part of FRR. + * + * FRR is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any + * later version. + * + * FRR is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with FRR; see the file COPYING. If not, write to the Free + * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <zebra.h> + +#ifndef HAVE_NETLINK + +#include "lib_errors.h" + +#include "zebra/rt.h" +#include "zebra/zebra_dplane.h" +#include "zebra/zebra_errors.h" + +enum zebra_dplane_result kernel_tc_update(struct zebra_dplane_ctx *ctx) +{ + flog_err(EC_LIB_UNAVAILABLE, "%s not Implemented for this platform", + __func__); + return ZEBRA_DPLANE_REQUEST_FAILURE; +} + +#endif /* !HAVE_NETLINK */ diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 4c7838198e..5a816a4c19 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -314,6 +314,25 @@ struct dplane_netconf_info { }; /* + * Traffic control contexts for the dplane + */ +struct dplane_tc_info { + /* Rate spec (unit: Bytes/s) */ + uint64_t rate; + uint64_t ceil; + + /* TODO: custom burst */ + + /* Filter components for "tfilter" */ + uint32_t filter_bm; + struct prefix src_ip; + struct prefix dst_ip; + uint8_t ip_proto; + + /* TODO: more filter components */ +}; + +/* * The context block used to exchange info about route updates across * the boundary between the zebra main context (and pthread) and the * dataplane layer (and pthread). @@ -362,6 +381,7 @@ struct zebra_dplane_ctx { struct dplane_mac_info macinfo; struct dplane_neigh_info neigh; struct dplane_rule_info rule; + struct dplane_tc_info tc; struct zebra_pbr_iptable iptable; struct zebra_pbr_ipset ipset; struct { @@ -540,6 +560,9 @@ static struct zebra_dplane_globals { _Atomic uint32_t dg_intfs_in; _Atomic uint32_t dg_intf_errors; + _Atomic uint32_t dg_tcs_in; + _Atomic uint32_t dg_tcs_errors; + /* Dataplane pthread */ struct frr_pthread *dg_pthread; @@ -777,6 +800,9 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: break; case DPLANE_OP_IPSET_ENTRY_ADD: @@ -1100,6 +1126,16 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_INTF_DELETE: ret = "INTF_DELETE"; break; + + case DPLANE_OP_TC_INSTALL: + ret = "TC_INSTALL"; + break; + case DPLANE_OP_TC_UPDATE: + ret = "TC_UPDATE"; + break; + case DPLANE_OP_TC_DELETE: + ret = "TC_DELETE"; + break; } return ret; @@ -1419,6 +1455,50 @@ uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx) return ctx->u.rinfo.zd_old_distance; } +uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.tc.rate; +} + +uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.tc.ceil; +} + +uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.tc.filter_bm; +} + +const struct prefix * +dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.tc.src_ip); +} + +const struct prefix * +dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return &(ctx->u.tc.dst_ip); +} + +uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->u.tc.ip_proto; +} + /* * Set the nexthops associated with a context: note that processing code * may well expect that nexthops are in canonical (sorted) order, so we @@ -2691,6 +2771,25 @@ done: return ret; } +int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op) +{ + int ret = EINVAL; + + struct zebra_ns *zns = NULL; + + ctx->zd_op = op; + ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; + + /* TODO: init traffic control qdisc */ + zns = zebra_ns_lookup(NS_DEFAULT); + + dplane_ctx_ns_init(ctx, zns, true); + + ret = AOK; + + return ret; +} + /** * dplane_ctx_nexthop_init() - Initialize a context block for a nexthop update * @@ -3410,6 +3509,47 @@ dplane_route_update_internal(struct route_node *rn, return result; } +static enum zebra_dplane_result dplane_tc_update_internal(enum dplane_op_e op) +{ + enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; + int ret = EINVAL; + struct zebra_dplane_ctx *ctx = NULL; + + /* Obtain context block */ + ctx = dplane_ctx_alloc(); + + if (!ctx) { + ret = ENOMEM; + goto done; + } + + /* Init context with info from zebra data structs */ + ret = dplane_ctx_tc_init(ctx, op); + + if (ret == AOK) + ret = dplane_update_enqueue(ctx); + +done: + /* Update counter */ + atomic_fetch_add_explicit(&zdplane_info.dg_tcs_in, 1, + memory_order_relaxed); + if (ret == AOK) { + result = ZEBRA_DPLANE_REQUEST_QUEUED; + } else { + atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, 1, + memory_order_relaxed); + if (ctx) + dplane_ctx_free(&ctx); + } + + return result; +} + +enum zebra_dplane_result dplane_tc_update(void) +{ + return dplane_tc_update_internal(DPLANE_OP_TC_UPDATE); +} + /** * dplane_nexthop_update_internal() - Helper for enqueuing nexthop changes * @@ -3422,7 +3562,7 @@ static enum zebra_dplane_result dplane_nexthop_update_internal(struct nhg_hash_entry *nhe, enum dplane_op_e op) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; - int ret = EINVAL; + int ret; struct zebra_dplane_ctx *ctx = NULL; /* Obtain context block */ @@ -3700,7 +3840,7 @@ dplane_lsp_notif_update(struct zebra_lsp *lsp, enum dplane_op_e op, struct zebra_dplane_ctx *notif_ctx) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; - int ret = EINVAL; + int ret; struct zebra_dplane_ctx *ctx = NULL; struct nhlfe_list_head *head; struct zebra_nhlfe *nhlfe, *new_nhlfe; @@ -4075,7 +4215,7 @@ static enum zebra_dplane_result dplane_intf_update_internal(const struct interface *ifp, enum dplane_op_e op) { enum zebra_dplane_result result = ZEBRA_DPLANE_REQUEST_FAILURE; - int ret = EINVAL; + int ret; struct zebra_dplane_ctx *ctx = NULL; /* Obtain context block */ @@ -5591,6 +5731,13 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifindex(ctx), dplane_ctx_intf_is_protodown(ctx)); break; + + /* TODO: more detailed log */ + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + zlog_debug("Dplane tc ifidx %u", dplane_ctx_get_ifindex(ctx)); + break; } } @@ -5734,6 +5881,14 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) 1, memory_order_relaxed); break; + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) + atomic_fetch_add_explicit(&zdplane_info.dg_tcs_errors, + 1, memory_order_relaxed); + break; + /* Ignore 'notifications' - no-op */ case DPLANE_OP_SYS_ROUTE_ADD: case DPLANE_OP_SYS_ROUTE_DELETE: diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index c96ea40094..8b239a9ba1 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -193,6 +193,11 @@ enum dplane_op_e { DPLANE_OP_INTF_INSTALL, DPLANE_OP_INTF_UPDATE, DPLANE_OP_INTF_DELETE, + + /* Traffic control */ + DPLANE_OP_TC_INSTALL, + DPLANE_OP_TC_UPDATE, + DPLANE_OP_TC_DELETE, }; /* @@ -378,6 +383,16 @@ uint8_t dplane_ctx_get_distance(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_distance(struct zebra_dplane_ctx *ctx, uint8_t distance); uint8_t dplane_ctx_get_old_distance(const struct zebra_dplane_ctx *ctx); +/* Accessors for traffic control context */ +uint64_t dplane_ctx_tc_get_rate(const struct zebra_dplane_ctx *ctx); +uint64_t dplane_ctx_tc_get_ceil(const struct zebra_dplane_ctx *ctx); +uint32_t dplane_ctx_tc_get_filter_bm(const struct zebra_dplane_ctx *ctx); +const struct prefix * +dplane_ctx_tc_get_src_ip(const struct zebra_dplane_ctx *ctx); +const struct prefix * +dplane_ctx_tc_get_dst_ip(const struct zebra_dplane_ctx *ctx); +uint8_t dplane_ctx_tc_get_ip_proto(const struct zebra_dplane_ctx *ctx); + void dplane_ctx_set_nexthops(struct zebra_dplane_ctx *ctx, struct nexthop *nh); void dplane_ctx_set_backup_nhg(struct zebra_dplane_ctx *ctx, const struct nexthop_group *nhg); @@ -708,6 +723,13 @@ enum zebra_dplane_result dplane_intf_update(const struct interface *ifp); enum zebra_dplane_result dplane_intf_delete(const struct interface *ifp); /* + * Enqueue interface link changes for the dataplane. + */ +enum zebra_dplane_result dplane_tc_add(void); +enum zebra_dplane_result dplane_tc_update(void); +enum zebra_dplane_result dplane_tc_delete(void); + +/* * Link layer operations for the dataplane. */ enum zebra_dplane_result dplane_neigh_ip_update(enum dplane_op_e op, @@ -849,6 +871,9 @@ int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, int dplane_ctx_intf_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, const struct interface *ifp); +/* Encode traffic control information into data plane context. */ +int dplane_ctx_tc_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op); + /* Retrieve the limit on the number of pending, unprocessed updates. */ uint32_t dplane_get_in_queue_limit(void); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index c5b533fc22..1964c763c5 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -3125,6 +3125,9 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_INTF_INSTALL: case DPLANE_OP_INTF_UPDATE: case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: break; } } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 6dde513f40..be089fc759 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -101,13 +101,15 @@ void zebra_pw_del(struct zebra_vrf *zvrf, struct zebra_pw *pw) if (pw->status == PW_FORWARDING) { hook_call(pw_uninstall, pw); dplane_pw_uninstall(pw); - } else if (pw->install_retry_timer) - THREAD_OFF(pw->install_retry_timer); + } + + THREAD_OFF(pw->install_retry_timer); /* unlink and release memory */ RB_REMOVE(zebra_pw_head, &zvrf->pseudowires, pw); if (pw->protocol == ZEBRA_ROUTE_STATIC) RB_REMOVE(zebra_static_pw_head, &zvrf->static_pseudowires, pw); + XFREE(MTYPE_PW, pw); } @@ -230,7 +232,6 @@ static void zebra_pw_install_retry(struct thread *thread) { struct zebra_pw *pw = THREAD_ARG(thread); - pw->install_retry_timer = NULL; zebra_pw_install(pw); } diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 79eb99ddf9..03bda8cc33 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4391,6 +4391,11 @@ static void rib_process_dplane_results(struct thread *thread) zebra_if_dplane_result(ctx); break; + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + break; + /* Some op codes not handled here */ case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c index d247f87708..2e2f4159cd 100644 --- a/zebra/zebra_script.c +++ b/zebra/zebra_script.c @@ -329,14 +329,6 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) lua_setfield(L, -2, "ipset"); break; } - case DPLANE_OP_ADDR_INSTALL: - case DPLANE_OP_ADDR_UNINSTALL: - case DPLANE_OP_INTF_ADDR_ADD: - case DPLANE_OP_INTF_ADDR_DEL: - case DPLANE_OP_INTF_INSTALL: - case DPLANE_OP_INTF_UPDATE: - case DPLANE_OP_INTF_DELETE: - break; case DPLANE_OP_NEIGH_INSTALL: case DPLANE_OP_NEIGH_UPDATE: case DPLANE_OP_NEIGH_DELETE: @@ -418,6 +410,17 @@ void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) } lua_setfield(L, -2, "gre"); + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + case DPLANE_OP_INTF_INSTALL: + case DPLANE_OP_INTF_UPDATE: + case DPLANE_OP_INTF_DELETE: + case DPLANE_OP_TC_INSTALL: + case DPLANE_OP_TC_UPDATE: + case DPLANE_OP_TC_DELETE: + /* Not currently handled */ case DPLANE_OP_INTF_NETCONFIG: /*NYI*/ case DPLANE_OP_NONE: break; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 49689c6ac4..5a6321ae7e 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -4062,7 +4062,7 @@ int zebra_vxlan_dp_network_mac_add(struct interface *ifp, } /* If local MAC on a down local ES translate the network-mac-add - * to a local-inactive-mac-add + * to a local-active-mac-add */ if (IS_ZEBRA_DEBUG_VXLAN || IS_ZEBRA_DEBUG_EVPN_MH_MAC) zlog_debug("dpAdd local-nw-MAC %pEA VID %u", macaddr, vid); |
