--- /dev/null
+name: Add PRs size label
+
+on: pull_request_target
+
+jobs:
+ size-label:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: size-label
+ uses: "pascalgn/size-label-action@v0.4.2"
+ env:
+ GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+ with:
+ sizes: >
+ {
+ "0": "XS",
+ "20": "S",
+ "50": "M",
+ "200": "L",
+ "800": "XL",
+ "2000": "XXL"
+ }
static struct bgp_path_info_mpath *bgp_path_info_mpath_new(void)
{
struct bgp_path_info_mpath *new_mpath;
+
new_mpath = XCALLOC(MTYPE_BGP_MPATH_INFO,
sizeof(struct bgp_path_info_mpath));
+
return new_mpath;
}
if (!path->mpath) {
mpath = bgp_path_info_mpath_new();
- if (!mpath)
- return NULL;
path->mpath = mpath;
mpath->mp_info = path;
}
new_attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_LOCAL_PREF);
new_attr.local_pref = BGP_GSHUT_LOCAL_PREF;
- /* If graceful-shutdown is configured then add the GSHUT
- * community to all paths received from eBGP peers */
- } else if (bgp_in_graceful_shutdown(peer->bgp))
+ /* If graceful-shutdown is configured globally or
+ * per neighbor, then add the GSHUT community to
+ * all paths received from eBGP peers. */
+ } else if (bgp_in_graceful_shutdown(peer->bgp) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_SHUTDOWN))
bgp_attr_add_gshut_community(&new_attr);
}
}
#endif /* KEEP_OLD_VPN_COMMANDS */
-DEFUN_YANG (set_ipx_vpn_nexthop,
+DEFPY_YANG (set_ipx_vpn_nexthop,
set_ipx_vpn_nexthop_cmd,
- "set <ipv4|ipv6> vpn next-hop <A.B.C.D|X:X::X:X>",
+ "set <ipv4|ipv6> vpn next-hop <A.B.C.D$addrv4|X:X::X:X$addrv6>",
SET_STR
"IPv4 information\n"
"IPv6 information\n"
if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) {
if (afi == AFI_IP) {
+ if (addrv6_str) {
+ vty_out(vty, "%% IPv4 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv4-vpn-address']";
"%s/rmap-set-action/frr-bgp-route-map:ipv4-address",
xpath);
} else {
+ if (addrv4_str) {
+ vty_out(vty, "%% IPv6 next-hop expected\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
const char *xpath =
"./set-action[action='frr-bgp-route-map:ipv6-vpn-address']";
bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
}
+static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag, int set)
+{
+ int ret;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ /*
+ * If 'neighbor <interface>', then this is for directly connected peers,
+ * we should not accept disable-connected-check.
+ */
+ if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
+ vty_out(vty,
+ "%s is directly connected peer, cannot accept disable-connected-check\n",
+ ip_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!set && flag == PEER_FLAG_SHUTDOWN)
+ peer_tx_shutdown_message_unset(peer);
+
+ if (set)
+ ret = peer_flag_set(peer, flag);
+ else
+ ret = peer_flag_unset(peer, flag);
+
+ return bgp_vty_return(vty, ret);
+}
+
+static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 1);
+}
+
+static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
+ uint64_t flag)
+{
+ return peer_flag_modify_vty(vty, ip_str, flag, 0);
+}
+
#include "bgpd/bgp_vty_clippy.c"
DEFUN_HIDDEN (bgp_local_mac,
return bgp_vty_return(vty, ret);
}
+DEFPY (neighbor_graceful_shutdown,
+ neighbor_graceful_shutdown_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor graceful-shutdown",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Graceful shutdown\n")
+{
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ ret = peer_flag_unset_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+ else
+ ret = peer_flag_set_vty(vty, neighbor,
+ PEER_FLAG_GRACEFUL_SHUTDOWN);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_clear(vty, bgp, afi, safi, clear_peer, BGP_CLEAR_SOFT_IN,
+ neighbor);
+ }
+
+ return ret;
+}
+
DEFUN_HIDDEN (bgp_graceful_restart_disable_eor,
bgp_graceful_restart_disable_eor_cmd,
"bgp graceful-restart disable-eor",
"Member of the peer-group\n"
"Peer-group name\n")
-static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
- uint64_t flag, int set)
-{
- int ret;
- struct peer *peer;
-
- peer = peer_and_group_lookup_vty(vty, ip_str);
- if (!peer)
- return CMD_WARNING_CONFIG_FAILED;
-
- /*
- * If 'neighbor <interface>', then this is for directly connected peers,
- * we should not accept disable-connected-check.
- */
- if (peer->conf_if && (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK)) {
- vty_out(vty,
- "%s is directly connected peer, cannot accept disable-connected-check\n",
- ip_str);
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- if (!set && flag == PEER_FLAG_SHUTDOWN) {
- peer_tx_shutdown_message_unset(peer);
- UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
- }
-
- if (set)
- ret = peer_flag_set(peer, flag);
- else
- ret = peer_flag_unset(peer, flag);
-
- return bgp_vty_return(vty, ret);
-}
-
-static int peer_flag_set_vty(struct vty *vty, const char *ip_str, uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 1);
-}
-
-static int peer_flag_unset_vty(struct vty *vty, const char *ip_str,
- uint64_t flag)
-{
- return peer_flag_modify_vty(vty, ip_str, flag, 0);
-}
-
/* neighbor passive. */
DEFUN (neighbor_passive,
neighbor_passive_cmd,
if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
vty_out(vty, " neighbor %s aigp\n", addr);
+ /* graceful-shutdown */
+ if (peergroup_flag_check(peer, PEER_FLAG_GRACEFUL_SHUTDOWN))
+ vty_out(vty, " neighbor %s graceful-shutdown\n", addr);
+
/* role */
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
peer->local_role != ROLE_UNDEFINED)
/* "neighbor aigp" commands. */
install_element(BGP_NODE, &neighbor_aigp_cmd);
+ /* "neighbor graceful-shutdown" command */
+ install_element(BGP_NODE, &neighbor_graceful_shutdown_cmd);
+
/* bgp disable-ebgp-connected-nh-check */
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
{PEER_FLAG_ROLE, 0, peer_change_reset},
{PEER_FLAG_PORT, 0, peer_change_reset},
{PEER_FLAG_AIGP, 0, peer_change_none},
+ {PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
#define PEER_FLAG_ROLE (1ULL << 32)
#define PEER_FLAG_PORT (1ULL << 33)
#define PEER_FLAG_AIGP (1ULL << 34)
+#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
version. Once the release is done, whatever updates we make to changelog
files on the release branch need to be cherry-picked to the master branch.
+ Update essential dates in advance for reference table (below) when
+ the next freeze, dev/X.Y, RC, and release phases are scheduled. This should
+ go in the ``master`` branch.
+
- 2 weeks earlier, a ``frr-X.Y-rc`` release candidate is tagged.
.. code-block:: console
For reference, the expected release schedule according to the above is:
+---------+------------+------------+------------+------------+------------+
-| Release | 2022-07-05 | 2022-11-01 | 2023-03-07 | 2023-07-04 | 2023-10-31 |
+| Release | 2023-03-07 | 2023-07-04 | 2023-10-31 | 2024-02-27 | 2024-06-25 |
+---------+------------+------------+------------+------------+------------+
-| RC | 2022-06-21 | 2022-10-18 | 2023-02-21 | 2023-06-20 | 2023-10-17 |
+| RC | 2023-02-21 | 2023-06-20 | 2023-10-17 | 2024-02-13 | 2024-06-11 |
+---------+------------+------------+------------+------------+------------+
-| dev/X.Y | 2022-06-07 | 2022-10-04 | 2023-02-07 | 2023-06-06 | 2023-10-03 |
+| dev/X.Y | 2023-02-07 | 2023-06-06 | 2023-10-03 | 2024-01-30 | 2024-05-28 |
+---------+------------+------------+------------+------------+------------+
-| freeze | 2022-05-24 | 2022-09-20 | 2023-01-24 | 2023-05-23 | 2023-09-19 |
+| freeze | 2023-01-24 | 2023-05-23 | 2023-09-19 | 2024-01-16 | 2024-05-14 |
+---------+------------+------------+------------+------------+------------+
+Here is the hint on how to get the dates easily:
+
+ .. code-block:: console
+
+ ~$ # Last freeze date was 2023-09-19
+ ~$ date +%F --date='2023-09-19 +119 days' # Next freeze date
+ 2024-01-16
+ ~$ date +%F --date='2024-01-16 +14 days' # Next dev/X.Y date
+ 2024-01-30
+ ~$ date +%F --date='2024-01-30 +14 days' # Next RC date
+ 2024-02-13
+ ~$ date +%F --date='2024-02-13 +14 days' # Next Release date
+ 2024-02-27
+
Each release is managed by one or more volunteer release managers from the FRR
community. These release managers are expected to handle the branch for a period
of one year. To spread and distribute this workload, this should be rotated for
Default: disabled.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> graceful-shutdown
+
+ Mark all routes from this neighbor as less preferred by setting ``graceful-shutdown``
+ community, and local-preference to 0.
+
.. clicmd:: bgp fast-external-failover
This command causes bgp to take down ebgp peers immediately
several thousands of peers then this is where we would modify FRR to
allow this to happen.
+::
+
+ FRR_NO_ROOT="yes"
+
+This option allows you to run FRR as a non-root user. Use this option
+only when you know what you are doing since most of the daemons
+in FRR will not be able to run under a regular user. This option
+is useful for example when you run FRR in a container with a designated
+user instead of root.
+
::
zebra_options=" -s 90000000 --daemon -A 127.0.0.1"
indicates that the operator wants to see the multicast rib address resolution
table. An alternative form of the command is ``show ip import-check`` and this
form of the command is deprecated at this point in time.
- If the ``json`` option is specified, output is displayed in JSON format.
+ User can get that information as JSON string when ``json`` key word
+ at the end of cli is presented.
PBR dataplane programming
=========================
#define OSPF_DEFAULT_DESTINATION 0x00000000 /* 0.0.0.0 */
#define OSPF_INITIAL_SEQUENCE_NUMBER 0x80000001U
#define OSPF_MAX_SEQUENCE_NUMBER 0x7fffffffU
+#define OSPF_INVALID_SEQUENCE_NUMBER 0x80000000U
/* OSPF Interface Types */
#define OSPF_IFTYPE_NONE 0
/*
* Log non empty command lines
*/
- if (do_log_commands)
+ if (do_log_commands &&
+ strncmp(buf, "echo PING", strlen("echo PING")) != 0)
cp = buf;
if (cp != NULL) {
/* Skip white spaces. */
ospf6_copy_nexthops(tmp_route->nh_list,
o_path->nh_list);
- if (ospf6_route_cmp_nexthops(tmp_route, route) != 0) {
+ if (!ospf6_route_cmp_nexthops(tmp_route, route)) {
/* adv. router exists in the list, update nhs */
list_delete_all_node(o_path->nh_list);
ospf6_copy_nexthops(o_path->nh_list,
}
}
-int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
+/*
+ * If the nexthops are the same return true
+ */
+bool ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
{
struct listnode *anode, *bnode;
struct ospf6_nexthop *anh, *bnh;
/* Currnet List A element not found List B
* Non-Identical lists return */
if (identical == false)
- return 1;
+ return false;
}
- return 0;
+ return true;
} else
- return 1;
+ return false;
}
/* One of the routes doesn't exist ? */
- return (1);
+ return false;
}
int ospf6_num_nexthops(struct list *nh_list)
for (target = ospf6_route_lookup(&route->prefix, table); target;
target = target->next) {
- if (target->type == route->type
- && prefix_same(&target->prefix, &route->prefix)
- && target->path.type == route->path.type
- && target->path.cost == route->path.cost
- && target->path.u.cost_e2 == route->path.u.cost_e2
- && ospf6_route_cmp_nexthops(target, route) == 0)
+ if (ospf6_route_is_identical(target, route))
return target;
}
return NULL;
}
if (old) {
+ /* if route does not actually change, return unchanged */
+ if (ospf6_route_is_identical(old, route)) {
+ if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
+ zlog_debug(
+ "%s %p: route add %p: needless update of %p old cost %u",
+ ospf6_route_table_name(table),
+ (void *)table, (void *)route,
+ (void *)old, old->path.cost);
+ else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
+ zlog_debug("%s: route add: needless update",
+ ospf6_route_table_name(table));
+
+ ospf6_route_delete(route);
+ SET_FLAG(old->flag, OSPF6_ROUTE_ADD);
+ ospf6_route_table_assert(table);
+
+ /* to free the lookup lock */
+ route_unlock_node(node);
+ return old;
+ }
+
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
zlog_debug(
"%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u",
&& (ra)->path.origin.type == (rb)->path.origin.type \
&& (ra)->path.origin.id == (rb)->path.origin.id \
&& (ra)->path.origin.adv_router == (rb)->path.origin.adv_router)
+#define ospf6_route_is_identical(ra, rb) \
+ ((ra)->type == (rb)->type && \
+ prefix_same(&(ra)->prefix, &(rb)->prefix) && \
+ (ra)->path.type == (rb)->path.type && \
+ (ra)->path.cost == (rb)->path.cost && \
+ (ra)->path.u.cost_e2 == (rb)->path.u.cost_e2 && \
+ listcount(ra->paths) == listcount(rb->paths) && \
+ ospf6_route_cmp_nexthops(ra, rb))
#define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST))
struct in6_addr *addr);
extern void ospf6_add_route_nexthop_blackhole(struct ospf6_route *route);
extern int ospf6_num_nexthops(struct list *nh_list);
-extern int ospf6_route_cmp_nexthops(struct ospf6_route *a,
- struct ospf6_route *b);
+extern bool ospf6_route_cmp_nexthops(struct ospf6_route *a,
+ struct ospf6_route *b);
extern void ospf6_route_zebra_copy_nexthops(struct ospf6_route *route,
struct zapi_nexthop nexthops[],
int entries, vrf_id_t vrf_id);
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[1st]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[1st]: DR %pI4", &DR(oi));
+ }
if (new_state != old_state
&& !(new_state == ISM_DROther && old_state < ISM_DROther)) {
new_state = ospf_ism_state(oi);
- zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
- zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ if (IS_DEBUG_OSPF(ism, ISM_STATUS)) {
+ zlog_debug("DR-Election[2nd]: Backup %pI4", &BDR(oi));
+ zlog_debug("DR-Election[2nd]: DR %pI4", &DR(oi));
+ }
}
list_delete(&el_list);
struct ospf_interface *oi;
struct ospf_lsa *lsa;
struct route_node *rn;
+ struct ospf_if_params *oip;
int need_to_flush_ase = 0;
ospf->inst_shutdown = 1;
ospf_lsa_flush_area(oi->network_lsa_self, area);
ospf_lsa_unlock(&oi->network_lsa_self);
oi->network_lsa_self = NULL;
+
+ oip = ospf_lookup_if_params(
+ oi->ifp, oi->address->u.prefix4);
+ if (oip)
+ oip->network_lsa_seqnum = htonl(
+ OSPF_INVALID_SEQUENCE_NUMBER);
}
if (oi->type != OSPF_IFTYPE_VIRTUALLINK
"can't setsockopt IP_ADD_MEMBERSHIP (fd %d, addr %pI4, ifindex %u, AllDRouters): %s; perhaps a kernel limit on # of multicast group memberships has been exceeded?",
top->fd, &p->u.prefix4, ifindex,
safe_strerror(errno));
- else
- zlog_debug(
- "interface %pI4 [%u] join AllDRouters Multicast group.",
- &p->u.prefix4, ifindex);
-
+ else {
+ if (IS_DEBUG_OSPF_EVENT)
+ zlog_debug(
+ "interface %pI4 [%u] join AllDRouters Multicast group.",
+ &p->u.prefix4, ifindex);
+ }
return ret;
}
bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
/* unaligned, again */
- memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr.addr,
sizeof(rp_addr));
buf += sizeof(struct bsmmsg_rpinfo);
struct static_nexthop *nh;
uint32_t old_color;
- nh = nb_running_unset_entry(args->dnode);
+ nh = nb_running_get_entry(args->dnode, NULL, true);
old_color = nh->color;
nh->color = 0;
#define STATICD_STR "Static route daemon\n"
-static int static_route_leak(struct vty *vty, const char *svrf,
- const char *nh_svrf, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *label_str,
- const char *table_str, bool onlink,
- const char *color_str)
+/** All possible route parameters available in CLI. */
+struct static_route_args {
+ /** "no" command? */
+ bool delete;
+ /** Is VRF obtained from XPath? */
+ bool xpath_vrf;
+
+ bool onlink;
+ afi_t afi;
+ safi_t safi;
+
+ const char *vrf;
+ const char *nexthop_vrf;
+ const char *prefix;
+ const char *prefix_mask;
+ const char *source;
+ const char *gateway;
+ const char *interface_name;
+ const char *flag;
+ const char *tag;
+ const char *distance;
+ const char *label;
+ const char *table;
+ const char *color;
+};
+
+static int static_route_nb_run(struct vty *vty, struct static_route_args *args)
{
int ret;
struct prefix p, src;
char xpath_label[XPATH_MAXLEN];
char ab_xpath[XPATH_MAXLEN];
char buf_prefix[PREFIX_STRLEN];
- char buf_src_prefix[PREFIX_STRLEN];
- char buf_nh_type[PREFIX_STRLEN];
+ char buf_src_prefix[PREFIX_STRLEN] = {};
+ char buf_nh_type[PREFIX_STRLEN] = {};
char buf_tag[PREFIX_STRLEN];
uint8_t label_stack_id = 0;
const char *buf_gate_str;
route_tag_t tag = 0;
uint32_t table_id = 0;
const struct lyd_node *dnode;
+ const struct lyd_node *vrf_dnode;
- memset(buf_src_prefix, 0, PREFIX_STRLEN);
- memset(buf_nh_type, 0, PREFIX_STRLEN);
+ if (args->xpath_vrf) {
+ vrf_dnode = yang_dnode_get(vty->candidate_config->dnode,
+ VTY_CURR_XPATH);
+ if (vrf_dnode == NULL) {
+ vty_out(vty,
+ "%% Failed to get vrf dnode in candidate db\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ args->vrf = yang_dnode_get_string(vrf_dnode, "./name");
+ } else {
+ if (args->vrf == NULL)
+ args->vrf = VRF_DEFAULT_NAME;
+ }
+ if (args->nexthop_vrf == NULL)
+ args->nexthop_vrf = args->vrf;
- ret = str2prefix(dest_str, &p);
- if (ret <= 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
+ if (args->interface_name &&
+ !strcasecmp(args->interface_name, "Null0")) {
+ args->flag = "Null0";
+ args->interface_name = NULL;
}
- switch (afi) {
+ assert(!!str2prefix(args->prefix, &p));
+
+ switch (args->afi) {
case AFI_IP:
/* Cisco like mask notation. */
- if (mask_str) {
- ret = inet_aton(mask_str, &mask);
- if (ret == 0) {
- vty_out(vty, "%% Malformed address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (args->prefix_mask) {
+ assert(inet_pton(AF_INET, args->prefix_mask, &mask) ==
+ 1);
p.prefixlen = ip_masklen(mask);
}
break;
case AFI_IP6:
/* srcdest routing */
- if (src_str) {
- ret = str2prefix(src_str, &src);
- if (ret <= 0 || src.family != AF_INET6) {
- vty_out(vty, "%% Malformed source address\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- }
+ if (args->source)
+ assert(!!str2prefix(args->source, &src));
break;
default:
break;
/* Apply mask for given prefix. */
apply_mask(&p);
-
prefix2str(&p, buf_prefix, sizeof(buf_prefix));
- if (src_str)
+ if (args->source)
prefix2str(&src, buf_src_prefix, sizeof(buf_src_prefix));
- if (gate_str)
- buf_gate_str = gate_str;
+ if (args->gateway)
+ buf_gate_str = args->gateway;
else
buf_gate_str = "";
- if (gate_str == NULL && ifname == NULL)
+ if (args->gateway == NULL && args->interface_name == NULL)
type = STATIC_BLACKHOLE;
- else if (gate_str && ifname) {
- if (afi == AFI_IP)
+ else if (args->gateway && args->interface_name) {
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY_IFNAME;
else
type = STATIC_IPV6_GATEWAY_IFNAME;
- } else if (ifname)
+ } else if (args->interface_name)
type = STATIC_IFNAME;
else {
- if (afi == AFI_IP)
+ if (args->afi == AFI_IP)
type = STATIC_IPV4_GATEWAY;
else
type = STATIC_IPV6_GATEWAY;
}
/* Administrative distance. */
- if (distance_str)
- distance = atoi(distance_str);
+ if (args->distance)
+ distance = strtol(args->distance, NULL, 10);
/* tag */
- if (tag_str)
- tag = strtoul(tag_str, NULL, 10);
+ if (args->tag)
+ tag = strtoul(args->tag, NULL, 10);
/* TableID */
- if (table_str)
- table_id = atol(table_str);
+ if (args->table)
+ table_id = strtol(args->table, NULL, 10);
- static_get_nh_type(type, buf_nh_type, PREFIX_STRLEN);
- if (!negate) {
- if (src_str)
+ static_get_nh_type(type, buf_nh_type, sizeof(buf_nh_type));
+ if (!args->delete) {
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
/*
* If there's already the same nexthop but with a different
}
/* route + path procesing */
- if (src_str)
+ if (args->source)
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_S_ROUTE_SRC_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
buf_src_prefix, table_id, distance);
else
snprintf(xpath_prefix, sizeof(xpath_prefix),
FRR_STATIC_ROUTE_INFO_KEY_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
table_id, distance);
nb_cli_enqueue_change(vty, xpath_prefix, NB_OP_CREATE, NULL);
/* nexthop processing */
snprintf(ab_xpath, sizeof(ab_xpath),
- FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ FRR_STATIC_ROUTE_NH_KEY_XPATH, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str, args->interface_name);
strlcpy(xpath_nexthop, xpath_prefix, sizeof(xpath_nexthop));
strlcat(xpath_nexthop, ab_xpath, sizeof(xpath_nexthop));
nb_cli_enqueue_change(vty, xpath_nexthop, NB_OP_CREATE, NULL);
sizeof(ab_xpath));
/* Route flags */
- if (flag_str) {
- switch (flag_str[0]) {
+ if (args->flag) {
+ switch (args->flag[0]) {
case 'r':
bh_type = "reject";
break;
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_ONLINK_XPATH,
sizeof(ab_xpath));
- if (onlink)
+ if (args->onlink)
nb_cli_enqueue_change(vty, ab_xpath,
NB_OP_MODIFY, "true");
else
strlcpy(ab_xpath, xpath_nexthop, sizeof(ab_xpath));
strlcat(ab_xpath, FRR_STATIC_ROUTE_NH_COLOR_XPATH,
sizeof(ab_xpath));
- if (color_str)
+ if (args->color)
nb_cli_enqueue_change(vty, ab_xpath,
- NB_OP_MODIFY, color_str);
+ NB_OP_MODIFY,
+ args->color);
}
- if (label_str) {
+ if (args->label) {
/* copy of label string (start) */
char *ostr;
/* pointer to next segment */
nb_cli_enqueue_change(vty, xpath_mpls, NB_OP_DESTROY,
NULL);
- ostr = XSTRDUP(MTYPE_TMP, label_str);
+ ostr = XSTRDUP(MTYPE_TMP, args->label);
while ((nump = strsep(&ostr, "/")) != NULL) {
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_STATIC_ROUTE_NHLB_KEY_XPATH,
}
ret = nb_cli_apply_changes(vty, xpath_prefix);
} else {
- if (src_str)
+ if (args->source)
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_SRC_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- buf_src_prefix, table_id, buf_nh_type, nh_svrf,
- buf_gate_str, ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ buf_src_prefix, table_id, buf_nh_type,
+ args->nexthop_vrf, buf_gate_str,
+ args->interface_name);
else
snprintf(ab_xpath, sizeof(ab_xpath),
FRR_DEL_S_ROUTE_NH_KEY_NO_DISTANCE_XPATH,
- "frr-staticd:staticd", "staticd", svrf,
+ "frr-staticd:staticd", "staticd", args->vrf,
buf_prefix,
- yang_afi_safi_value2identity(afi, safi),
- table_id, buf_nh_type, nh_svrf, buf_gate_str,
- ifname);
+ yang_afi_safi_value2identity(args->afi,
+ args->safi),
+ table_id, buf_nh_type, args->nexthop_vrf,
+ buf_gate_str, args->interface_name);
dnode = yang_dnode_get(vty->candidate_config->dnode, ab_xpath);
if (!dnode) {
return ret;
}
-static int static_route(struct vty *vty, afi_t afi, safi_t safi,
- const char *negate, const char *dest_str,
- const char *mask_str, const char *src_str,
- const char *gate_str, const char *ifname,
- const char *flag_str, const char *tag_str,
- const char *distance_str, const char *vrf_name,
- const char *label_str, const char *table_str)
-{
- if (!vrf_name)
- vrf_name = VRF_DEFAULT_NAME;
-
- return static_route_leak(vty, vrf_name, vrf_name, afi, safi, negate,
- dest_str, mask_str, src_str, gate_str, ifname,
- flag_str, tag_str, distance_str, label_str,
- table_str, false, NULL);
-}
/* Static unicast routes for multicast RPF lookup. */
DEFPY_YANG (ip_mroute_dist,
"Nexthop interface name\n"
"Distance\n")
{
- return static_route(vty, AFI_IP, SAFI_MULTICAST, no, prefix_str,
- NULL, NULL, gate_str, ifname, NULL, NULL,
- distance_str, NULL, NULL, NULL);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_MULTICAST,
+ .prefix = prefix_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .distance = distance_str,
+ };
+
+ return static_route_nb_run(vty, &args);
}
/* Static route configuration. */
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP, SAFI_UNICAST, no, prefix,
- mask_str, NULL, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP, SAFI_UNICAST,
- no, prefix, mask_str, NULL, NULL, NULL, flag,
- tag_str, distance_str, label, table_str,
- false, NULL);
+ assert(args.prefix);
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ip_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
-
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP, SAFI_UNICAST, no,
- prefix, mask_str, NULL, gate_str, ifname, flag,
- tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix,
+ .prefix_mask = mask_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole,
"Table to configure\n"
"The table number to configure\n")
{
- return static_route(vty, AFI_IP6, SAFI_UNICAST, no, prefix_str,
- NULL, from_str, NULL, NULL, flag, tag_str,
- distance_str, vrf, label, table_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .vrf = vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_blackhole_vrf,
"Table to configure\n"
"The table number to configure\n")
{
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .flag = flag,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .xpath_vrf = true,
+ };
/*
* Coverity is complaining that prefix could
* be dereferenced, but we know that prefix will
* valid. Add an assert to make it happy
*/
- assert(prefix);
+ assert(args.prefix);
- return static_route_leak(vty, vrfname, vrfname, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, NULL, NULL,
- flag, tag_str, distance_str, label, table_str,
- false, NULL);
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_address_interface_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, !!onlink, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .onlink = !!onlink,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
-
- if (!vrf)
- vrf = VRF_DEFAULT_NAME;
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrf;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrf, nh_vrf, AFI_IP6, SAFI_UNICAST, no,
- prefix_str, NULL, from_str, gate_str, ifname,
- flag, tag_str, distance_str, label, table_str,
- false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .vrf = vrf,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
DEFPY_YANG(ipv6_route_vrf,
"SR-TE color\n"
"The SR-TE color to configure\n")
{
- const char *nh_vrf;
- const char *flag = NULL;
- const struct lyd_node *vrf_dnode;
- const char *vrfname;
-
- vrf_dnode =
- yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH);
- if (!vrf_dnode) {
- vty_out(vty, "%% Failed to get vrf dnode in candidate db\n");
- return CMD_WARNING_CONFIG_FAILED;
- }
- vrfname = yang_dnode_get_string(vrf_dnode, "./name");
-
- if (nexthop_vrf)
- nh_vrf = nexthop_vrf;
- else
- nh_vrf = vrfname;
-
- if (ifname && !strncasecmp(ifname, "Null0", 5)) {
- flag = "Null0";
- ifname = NULL;
- }
- return static_route_leak(vty, vrfname, nh_vrf, AFI_IP6, SAFI_UNICAST,
- no, prefix_str, NULL, from_str, gate_str,
- ifname, flag, tag_str, distance_str, label,
- table_str, false, color_str);
+ struct static_route_args args = {
+ .delete = !!no,
+ .afi = AFI_IP6,
+ .safi = SAFI_UNICAST,
+ .prefix = prefix_str,
+ .source = from_str,
+ .gateway = gate_str,
+ .interface_name = ifname,
+ .tag = tag_str,
+ .distance = distance_str,
+ .label = label,
+ .table = table_str,
+ .color = color_str,
+ .xpath_vrf = true,
+ .nexthop_vrf = nexthop_vrf,
+ };
+
+ return static_route_nb_run(vty, &args);
}
void static_cli_show(struct vty *vty, const struct lyd_node *dnode,
--- /dev/null
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
--- /dev/null
+!
+int lo
+ ip address 10.10.10.1/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
--- /dev/null
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.2.2 remote-as internal
+ address-family ipv4 unicast
+ neighbor 192.168.2.2 next-hop-self
+ exit-address-family
+!
--- /dev/null
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.1/24
+!
--- /dev/null
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as internal
+!
--- /dev/null
+!
+int r3-eth0
+ ip address 192.168.2.2/24
+!
--- /dev/null
+#!/usr/bin/env python
+
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Check if routes from R1 has local-preference set to 0 and graceful-shutdown
+community.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2"), "s2": ("r2", "r3")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_orf():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r2 = tgen.gears["r2"]
+ r3 = tgen.gears["r3"]
+
+ def _bgp_converge():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbor 192.168.2.2 advertised-routes json"
+ )
+ )
+ expected = {"advertisedRoutes": {"10.10.10.1/32": {"locPrf": 100}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge at R2"
+
+ step("Mark routes from R1 as graceful-shutdown")
+ r2.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ neighbor 192.168.1.1 graceful-shutdown
+ """
+ )
+
+ def _bgp_check_peer_graceful_shutdown():
+ output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.10.10.1/32 json"))
+ expected = {
+ "paths": [
+ {
+ "locPrf": 0,
+ "community": {"string": "graceful-shutdown"},
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_peer_graceful_shutdown)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert (
+ result is None
+ ), "local-preference is not 0 and/or graceful-shutdown community missing"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
rname,
"show ipv6 route isis json",
outputs[rname][15]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=5,
+ count=10,
)
rname,
"show ip route isis json",
outputs[rname][11]["show_ip_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show ipv6 route isis json",
outputs[rname][11]["show_ipv6_route.ref"],
- count=5,
+ count=10,
)
router_compare_json_output(
rname,
"show mpls table json",
outputs[rname][11]["show_mpls_table.ref"],
- count=5,
+ count=10,
)
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ wait_time = wait * count
+ if wait_time < 5:
+ assert (
+ wait_time >= 5
+ ), "Waiting time is too small (count={}, wait={}), adjust timer values".format(
+ count, wait
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum {} tries)".format(
func_name, wait, count
else:
func_name = func.__name__
+ # Just a safety-check to avoid running topotests with very
+ # small wait/count arguments.
+ wait_time = wait * count
+ if wait_time < 5:
+ assert (
+ wait_time >= 5
+ ), "Waiting time is too small (count={}, wait={}), adjust timer values".format(
+ count, wait
+ )
+
logger.info(
"'{}' polling started (interval {} secs, maximum wait {} secs)".format(
func_name, wait, int(wait * count)
if restarting != None:
tries = 40
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries
)
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname,
"show ipv6 ospf database json",
"show ipv6 route json",
{route: [{"metric": metric}]},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" convergence failure'.format(router)
assert result is None, assertmsg
if restarting != None:
tries = 60
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip route ospf json", "show_ip_route.json", tries
)
if initial_convergence == True or restarting == rname:
tries = 240
else:
- tries = 1
+ tries = 10
router_compare_json_output(
rname, "show ip ospf database json", "show_ip_ospf_database.json", tries
)
test_func = partial(
topotest.router_json_cmp, r1, "show ip pim upstream json", expected
)
- _, result = topotest.run_and_expect(test_func, None, count=5, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5)
assertmsg = '"{}" JSON output mismatches'.format(r1.name)
assert result is None, assertmsg
finally:
"show ip pim neighbor json",
{interface: {peer: None}},
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" PIM convergence failure'.format(router)
assert result is None, assertmsg
"show bfd peers json",
[settings],
)
- _, result = topotest.run_and_expect(test_func, None, count=4, wait=1)
+ _, result = topotest.run_and_expect(test_func, None, count=5, wait=1)
assertmsg = '"{}" BFD convergence failure'.format(router)
assert result is None, assertmsg
def check_srv6_locator(router, expected_file):
func = functools.partial(_check_srv6_locator, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
def check_sharpd_chunk(router, expected_file):
func = functools.partial(_check_sharpd_chunk, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
# FOR DEVELOPER:
def check_srv6_locator(router, expected_file):
func = functools.partial(_check_srv6_locator, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
def check_sharpd_chunk(router, expected_file):
func = functools.partial(_check_sharpd_chunk, router, expected_file)
- success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
assert result is None, "Failed"
# FOR DEVELOPER:
srv6
locators
locator loc3
- prefix 2001:db8:3::/48 func-bits 16 block-len 32 node-len 16
+ prefix 2001:db8:3::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators4.json")
srv6
locators
locator loc1
- prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
behavior usid
!
!
for rname, router in tgen.routers().items():
router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(
- CWD, "{}/zebra.conf".format(rname))
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
)
router.load_config(
- TopoRouter.RD_SHARP, os.path.join(
- CWD, "{}/sharpd.conf".format(rname))
+ TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
)
tgen.start_router()
def _check_srv6_locator(router, expected_locator_file):
logger.info("checking zebra locator status")
- output = json.loads(
- router.vtysh_cmd("show segment-routing srv6 locator json")
- )
+ output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json"))
expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
return topotest.json_cmp(output, expected)
def _check_sharpd_chunk(router, expected_chunk_file):
logger.info("checking sharpd locator chunk status")
- output = json.loads(
- router.vtysh_cmd("show sharp segment-routing srv6 json")
- )
+ output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json"))
expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
return topotest.json_cmp(output, expected)
srv6
locators
locator loc2
- prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ prefix fc00:0:2::/48 block-len 32 node-len 16 func-bits 16
"""
)
check_srv6_locator(router, "expected_locators_4.json")
# If you want to stop some specific line and start interactive shell,
# please use tgen.mininet_cli() to start it.
- logger.info(
- "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
- )
+ logger.info("Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator")
router.vtysh_cmd(
"""
configure terminal
#
#MAX_FDS=1024
+# Uncomment this option if you want to run FRR as a non-root user. Note that
+# you should know what you are doing since most of the daemons need root
+# to work. This could be useful if you want to run FRR in a container
+# for instance.
+# FRR_NO_ROOT="yes"
# For any daemon, you can specify a "wrap" command to start instead of starting
# the daemon directly. This will simply be prepended to the daemon invocation.
#
is_user_root () {
+ if [[ ! -z $FRR_NO_ROOT && "${FRR_NO_ROOT}" == "yes" ]]; then
+ return 0
+ fi
+
[ "${EUID:-$(id -u)}" -eq 0 ] || {
log_failure_msg "Only users having EUID=0 can start/stop daemons"
return 1
? ""
: "no ");
if (if_data->mpls == IF_ZEBRA_DATA_ON)
- vty_out(vty, " mpls\n");
+ vty_out(vty, " mpls enable\n");
}
hook_call(zebra_if_config_wr, vty, ifp);
static void copy_state(struct rnh *rnh, const struct route_entry *re,
struct route_node *rn);
static bool compare_state(struct route_entry *r1, struct route_entry *r2);
-static void print_rnh(struct route_node *rn, struct vty *vty);
+static void print_rnh(struct route_node *rn, struct vty *vty,
+ json_object *json);
static int zebra_client_cleanup_rnh(struct zserv *client);
void zebra_rnh_init(void)
}
void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p)
+ struct vty *vty, const struct prefix *p,
+ json_object *json)
{
struct route_table *table;
struct route_node *rn;
continue;
if (rn->info)
- print_rnh(rn, vty);
+ print_rnh(rn, vty, json);
}
}
return -1;
}
-static void print_nh(struct nexthop *nexthop, struct vty *vty)
+static void print_nh(struct nexthop *nexthop, struct vty *vty,
+ json_object *json)
{
- char buf[BUFSIZ];
struct zebra_ns *zns = zebra_ns_lookup(nexthop->vrf_id);
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
- if (nexthop->ifindex)
- vty_out(vty, ", %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI4",
+ &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " via %pI4", &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ vty_out(vty, ", %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- vty_out(vty, " %s",
- inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ));
- if (nexthop->ifindex)
- vty_out(vty, ", via %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_addf(json, "ip", "%pI6",
+ &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ } else {
+ vty_out(vty, " %pI6", &nexthop->gate.ipv6);
+ if (nexthop->ifindex)
+ vty_out(vty, ", via %s",
+ ifindex2ifname_per_ns(
+ zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_IFINDEX:
- vty_out(vty, " is directly connected, %s",
- ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ if (json) {
+ json_object_string_add(
+ json, "interface",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, %s",
+ ifindex2ifname_per_ns(zns, nexthop->ifindex));
+ }
break;
case NEXTHOP_TYPE_BLACKHOLE:
- vty_out(vty, " is directly connected, Null0");
+ if (json) {
+ json_object_string_add(json, "interface", "Null0");
+ json_object_boolean_true_add(json, "directlyConnected");
+ } else {
+ vty_out(vty, " is directly connected, Null0");
+ }
break;
default:
break;
}
- vty_out(vty, "\n");
+
+ if (!json)
+ vty_out(vty, "\n");
}
-static void print_rnh(struct route_node *rn, struct vty *vty)
+static void print_rnh(struct route_node *rn, struct vty *vty, json_object *json)
{
struct rnh *rnh;
struct nexthop *nexthop;
struct listnode *node;
struct zserv *client;
char buf[BUFSIZ];
+ json_object *json_nht = NULL;
+ json_object *json_client_array = NULL;
+ json_object *json_client = NULL;
+ json_object *json_nexthop_array = NULL;
+ json_object *json_nexthop = NULL;
rnh = rn->info;
- vty_out(vty, "%s%s\n",
- inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
- CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED) ? "(Connected)"
- : "");
- if (rnh->state) {
- vty_out(vty, " resolved via %s\n",
- zebra_route_string(rnh->state->type));
- for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
- nexthop = nexthop->next)
- print_nh(nexthop, vty);
- } else
- vty_out(vty, " unresolved%s\n",
+
+ if (json) {
+ json_nht = json_object_new_object();
+ json_nexthop_array = json_object_new_array();
+ json_client_array = json_object_new_array();
+
+ json_object_object_add(
+ json,
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
+ json_nht);
+ json_object_boolean_add(
+ json_nht, "nhtConnected",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ json_object_object_add(json_nht, "clientList",
+ json_client_array);
+ json_object_object_add(json_nht, "gates", json_nexthop_array);
+ } else {
+ vty_out(vty, "%s%s\n",
+ inet_ntop(rn->p.family, &rn->p.u.prefix, buf, BUFSIZ),
CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
? "(Connected)"
: "");
+ }
+
+ if (rnh->state) {
+ if (json)
+ json_object_string_add(
+ json_nht, "resolvedProtocol",
+ zebra_route_string(rnh->state->type));
+ else
+ vty_out(vty, " resolved via %s\n",
+ zebra_route_string(rnh->state->type));
+
+ for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop;
+ nexthop = nexthop->next) {
+ if (json) {
+ json_nexthop = json_object_new_object();
+ json_object_array_add(json_nexthop_array,
+ json_nexthop);
+ }
+ print_nh(nexthop, vty, json_nexthop);
+ }
+ } else {
+ if (json)
+ json_object_boolean_add(
+ json_nht, "unresolved",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED));
+ else
+ vty_out(vty, " unresolved%s\n",
+ CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)
+ ? "(Connected)"
+ : "");
+ }
+
+ if (!json)
+ vty_out(vty, " Client list:");
+
+ for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) {
+ if (json) {
+ json_client = json_object_new_object();
+ json_object_array_add(json_client_array, json_client);
+
+ json_object_string_add(
+ json_client, "protocol",
+ zebra_route_string(client->proto));
+ json_object_int_add(json_client, "socket",
+ client->sock);
+ json_object_string_add(json_client, "protocolFiltered",
+ (rnh->filtered[client->proto]
+ ? "(filtered)"
+ : "none"));
+ } else {
+ vty_out(vty, " %s(fd %d)%s",
+ zebra_route_string(client->proto), client->sock,
+ rnh->filtered[client->proto] ? "(filtered)"
+ : "");
+ }
+ }
+
+ if (!list_isempty(rnh->zebra_pseudowire_list)) {
+ if (json)
+ json_object_boolean_true_add(json_nht,
+ "zebraPseudowires");
+ else
+ vty_out(vty, " zebra[pseudowires]");
+ }
- vty_out(vty, " Client list:");
- for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client))
- vty_out(vty, " %s(fd %d)%s", zebra_route_string(client->proto),
- client->sock,
- rnh->filtered[client->proto] ? "(filtered)" : "");
- if (!list_isempty(rnh->zebra_pseudowire_list))
- vty_out(vty, " zebra[pseudowires]");
- vty_out(vty, "\n");
+ if (!json)
+ vty_out(vty, "\n");
}
static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, safi_t safi,
extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
const struct prefix *p, safi_t safi);
extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
- struct vty *vty, const struct prefix *p);
+ struct vty *vty, const struct prefix *p,
+ json_object *json);
extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
DEFPY (locator_prefix,
locator_prefix_cmd,
- "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len] \
- [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len]",
+ "prefix X:X::X:X/M$prefix [block-len (16-64)$block_bit_len] \
+ [node-len (16-64)$node_bit_len] [func-bits (0-64)$func_bit_len]",
"Configure SRv6 locator prefix\n"
"Specify SRv6 locator prefix\n"
- "Configure SRv6 locator function length in bits\n"
- "Specify SRv6 locator function length in bits\n"
"Configure SRv6 locator block length in bits\n"
"Specify SRv6 locator block length in bits\n"
"Configure SRv6 locator node length in bits\n"
- "Specify SRv6 locator node length in bits\n")
+ "Specify SRv6 locator node length in bits\n"
+ "Configure SRv6 locator function length in bits\n"
+ "Specify SRv6 locator function length in bits\n")
{
VTY_DECLVAR_CONTEXT(srv6_locator, locator);
struct srv6_locator_chunk *chunk = NULL;
)
)
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_qdisc_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_class_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
+
+TRACEPOINT_EVENT(
+ frr_zebra,
+ netlink_tc_filter_change,
+ TP_ARGS(
+ struct nlmsghdr *, header,
+ ns_id_t, ns_id,
+ int, startup),
+ TP_FIELDS(
+ ctf_integer_hex(intptr_t, header, header)
+ ctf_integer(uint32_t, ns_id, ns_id)
+ ctf_integer(uint32_t, startup, startup)
+ )
+ )
+
#include <lttng/tracepoint-event.h>
#endif /* HAVE_LTTNG */
DEFPY (show_ip_nht,
show_ip_nht_cmd,
- "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib]",
+ "show <ip$ipv4|ipv6$ipv6> <nht|import-check>$type [<A.B.C.D|X:X::X:X>$addr|vrf NAME$vrf_name [<A.B.C.D|X:X::X:X>$addr]|vrf all$vrf_all] [mrib$mrib] [json]",
SHOW_STR
IP_STR
IP6_STR
"IPv4 Address\n"
"IPv6 Address\n"
VRF_ALL_CMD_HELP_STR
- "Show Multicast (MRIB) NHT state\n")
+ "Show Multicast (MRIB) NHT state\n"
+ JSON_STR)
{
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL;
safi_t safi = mrib ? SAFI_MULTICAST : SAFI_UNICAST;
+ bool uj = use_json(argc, argv);
+ json_object *json = NULL;
+ json_object *json_vrf = NULL;
+ json_object *json_nexthop = NULL;
+
+ if (uj)
+ json = json_object_new_object();
if (vrf_all) {
struct vrf *vrf;
struct zebra_vrf *zvrf;
- RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name)
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
if ((zvrf = vrf->info) != NULL) {
- vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf));
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ json_object_object_add(json,
+ zvrf_name(zvrf),
+ json_vrf);
+ json_object_object_add(json_vrf,
+ "nexthops",
+ json_nexthop);
+ } else {
+ vty_out(vty, "\nVRF %s:\n",
+ zvrf_name(zvrf));
+ }
zebra_print_rnh_table(zvrf_id(zvrf), afi, safi,
- vty, NULL);
+ vty, NULL, json_nexthop);
}
+ }
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}
if (vrf_name)
memset(&prefix, 0, sizeof(prefix));
if (addr) {
p = sockunion2hostprefix(addr, &prefix);
- if (!p)
+ if (!p) {
+ if (uj)
+ json_object_free(json);
return CMD_WARNING;
+ }
}
- zebra_print_rnh_table(vrf_id, afi, safi, vty, p);
+ if (uj) {
+ json_vrf = json_object_new_object();
+ json_nexthop = json_object_new_object();
+ if (vrf_name)
+ json_object_object_add(json, vrf_name, json_vrf);
+ else
+ json_object_object_add(json, "default", json_vrf);
+
+ json_object_object_add(json_vrf, "nexthops", json_nexthop);
+ }
+
+ zebra_print_rnh_table(vrf_id, afi, safi, vty, p, json_nexthop);
+
+ if (uj)
+ vty_json(vty, json);
+
return CMD_SUCCESS;
}