]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #12386 from opensourcerouting/bfd-ipv4-source-bind
authorRuss White <russ@riw.us>
Tue, 29 Nov 2022 15:03:44 +0000 (10:03 -0500)
committerGitHub <noreply@github.com>
Tue, 29 Nov 2022 15:03:44 +0000 (10:03 -0500)
bfdd: fix IPv4 socket source selection

50 files changed:
.github/workflows/size-label.yml [new file with mode: 0644]
bgpd/bgp_mpath.c
bgpd/bgp_route.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
doc/developer/workflow.rst
doc/user/bgp.rst
doc/user/setup.rst
doc/user/zebra.rst
lib/libospf.h
lib/vty.c
ospf6d/ospf6_abr.c
ospf6d/ospf6_route.c
ospf6d/ospf6_route.h
ospfd/ospf_ism.c
ospfd/ospf_lsa.c
ospfd/ospf_network.c
pimd/pim_cmd_common.c
staticd/static_nb_config.c
staticd/static_vty.c
tests/topotests/bgp_peer_graceful_shutdown/__init__.py [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
tests/topotests/lib/topotest.py
tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py
tests/topotests/ospf6_topo2/test_ospf6_topo2.py
tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py
tests/topotests/pim_basic/test_pim.py
tests/topotests/pim_basic_topo2/test_pim_basic_topo2.py
tests/topotests/srv6_locator/test_srv6_locator.py
tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
tests/topotests/srv6_locator_usid/r1/zebra.conf
tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
tools/etc/frr/daemons
tools/frrcommon.sh.in
zebra/interface.c
zebra/zebra_rnh.c
zebra/zebra_rnh.h
zebra/zebra_srv6_vty.c
zebra/zebra_trace.h
zebra/zebra_vty.c

diff --git a/.github/workflows/size-label.yml b/.github/workflows/size-label.yml
new file mode 100644 (file)
index 0000000..a377003
--- /dev/null
@@ -0,0 +1,25 @@
+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"
+            }
index 64af8a541161ddc7988bb25929f910fa88cc69b2..52f6b64c2c96fec54a85ea094a4c00765ae3dc6d 100644 (file)
@@ -278,8 +278,10 @@ void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo)
 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;
 }
 
@@ -313,8 +315,6 @@ bgp_path_info_mpath_get(struct bgp_path_info *path)
 
        if (!path->mpath) {
                mpath = bgp_path_info_mpath_new();
-               if (!mpath)
-                       return NULL;
                path->mpath = mpath;
                mpath->mp_info = path;
        }
index d6e6fc952f568ba391b141de00843fe619b9ab24..867c701172ec88b1e201d0e3ab80c25eb3af88d8 100644 (file)
@@ -4237,9 +4237,11 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
                        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);
        }
 
index 9422469bca1f884004cbaf2da7ca39c777814f8a..03f6eb03165a877500c594fee008dc37547aa2b5 100644 (file)
@@ -6852,9 +6852,9 @@ DEFUN_YANG (no_set_vpn_nexthop,
 }
 #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"
@@ -6870,6 +6870,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
 
        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']";
 
@@ -6879,6 +6884,11 @@ DEFUN_YANG (set_ipx_vpn_nexthop,
                                "%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']";
 
index 4b17d289684c2ad146e770bda0f814f35b9b5403..70649c3b4aa1558604ce9b595e1c8183396999c0 100644 (file)
@@ -1308,6 +1308,49 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
        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,
@@ -3326,6 +3369,42 @@ DEFUN (no_bgp_neighbor_graceful_restart_disable,
        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",
@@ -5251,51 +5330,6 @@ ALIAS_HIDDEN(no_neighbor_set_peer_group, no_neighbor_set_peer_group_hidden_cmd,
             "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,
@@ -17220,6 +17254,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
        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)
@@ -18666,6 +18704,9 @@ void bgp_vty_init(void)
        /* "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);
index 6ad1cf2c06f150c05f88d672ce555ff8db90b378..12ee96ff4506b3bc96b081b4ccaf46a599ccaf8a 100644 (file)
@@ -4289,6 +4289,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
        {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[] = {
index 8a0ec5ad2d3f1003da844979dc3ebac7037f0301..b7a329fdcdeb3c82c9bdfca6f7a1ed8a5af70515 100644 (file)
@@ -1413,6 +1413,7 @@ struct peer {
 #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
index 688ce545fbe4050698ca55ca8c620f9988a9f8f3..b8e298dd3c866fb5746f469b730446ff19bad1df 100644 (file)
@@ -139,6 +139,10 @@ March/July/November.  Walking backwards from this date:
    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
@@ -163,15 +167,29 @@ as early as possible, i.e. the first 2-week window.
 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
index 4a812a75e9cec106178b00de929d395e8fdfbe86..98338ebf3205795c53e9b11fca27f5fb33f49176 100644 (file)
@@ -1704,6 +1704,11 @@ Configuring Peers
 
    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
index dcc7607e4841418faa816c62c1fdeaf38c03f115..372494fbce9bac91d73d2a9391ee58f0a1a88371 100644 (file)
@@ -114,6 +114,16 @@ most operating systems is 1024.  If the operator plans to run bgp with
 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"
index c44642a788af3509a1db2a6f3ce45982715d6a21..a78731ca942f4774a57f31c56dd2e8d6ef552bc6 100644 (file)
@@ -305,7 +305,8 @@ the default route.
    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
 =========================
index c8ada9d3c52fb69b66cd0a9ae2965860283c2413..161c7635d8816b2e3cbb8bd4352910906487ce2d 100644 (file)
@@ -52,6 +52,7 @@ extern "C" {
 #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
index 5fe8d82473b10a9bb18306fcde68e4d94738b4da..352080e580410d5951198d026c5712808f50af9a 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -447,7 +447,8 @@ static int vty_command(struct vty *vty, char *buf)
        /*
         * 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. */
index e9c42bb80c736f11586b545b8952a919d28fc755..e007709f995d90821bfe772d2ef4f89286a69d0c 100644 (file)
@@ -1322,7 +1322,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa)
                        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,
index db94b85b1b5bef5193c534ae69379d9af8079a45..9603c91a9ad78fd17cdd0e7a8c57adec6760a256 100644 (file)
@@ -246,7 +246,10 @@ void ospf6_merge_nexthops(struct list *dst, struct list *src)
        }
 }
 
-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;
@@ -264,14 +267,14 @@ int ospf6_route_cmp_nexthops(struct ospf6_route *a, struct ospf6_route *b)
                                /* 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)
@@ -577,12 +580,7 @@ ospf6_route_lookup_identical(struct ospf6_route *route,
 
        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;
@@ -702,6 +700,27 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
        }
 
        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",
index bb5827a1766fbc5760141df6478f106faccecf8e..71a84a5c5dc890b3a027af9817bfe3953892016e 100644 (file)
@@ -297,6 +297,14 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX];
         && (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))
 
@@ -322,8 +330,8 @@ extern void ospf6_add_nexthop(struct list *nh_list, int ifindex,
                              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);
index ab75ab9a1a336fae98a389f349b145f75921780b..d4565b6651601fe2c935e1fcf934538f75dd652a 100644 (file)
@@ -223,8 +223,10 @@ int ospf_dr_election(struct ospf_interface *oi)
 
        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)) {
@@ -233,8 +235,10 @@ int ospf_dr_election(struct ospf_interface *oi)
 
                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);
index a67b6c6c19586e352174f3686ea85513878df42b..92558e3c51ab51420016d019821e5120f0b424d0 100644 (file)
@@ -3648,6 +3648,7 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
        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;
@@ -3680,6 +3681,12 @@ void ospf_flush_self_originated_lsas_now(struct ospf *ospf)
                                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
index be06afe532620e162dbde3d4bc82809ce34df9ae..a8c9493ec8e4d910933c534242f5ca6df50b0d44 100644 (file)
@@ -104,11 +104,12 @@ int ospf_if_add_alldrouters(struct ospf *top, struct prefix *p,
                        "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;
 }
 
index b39f688cdb9d828a063c1b9f30b7f6517d2bcc51..0d60b17f04ceabc5673303b14e757260529e3286 100644 (file)
@@ -5610,7 +5610,7 @@ static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
 
                                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);
index 5a7044e9f9feadebc508fb275c539d4d9697d428..4a3d9e17a4433fcbfb72152244353b4f724330f7 100644 (file)
@@ -370,7 +370,7 @@ static int static_nexthop_color_destroy(struct nb_cb_destroy_args *args)
        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;
 
index 94a3493477f1b7fda32d2f508a05389e60bf5a7e..efae3c53da6b0befc29ede1ff930121fdbbb53aa 100644 (file)
 
 #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;
@@ -62,8 +80,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
        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;
@@ -71,37 +89,46 @@ static int static_route_leak(struct vty *vty, const char *svrf,
        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;
@@ -109,62 +136,64 @@ static int static_route_leak(struct vty *vty, const char *svrf,
 
        /* 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
@@ -181,19 +210,21 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                }
 
                /* 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);
@@ -208,8 +239,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                /* 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);
@@ -220,8 +251,8 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                                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;
@@ -248,7 +279,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                        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
@@ -262,11 +293,12 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                        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 */
@@ -279,7 +311,7 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                        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,
@@ -302,22 +334,25 @@ static int static_route_leak(struct vty *vty, const char *svrf,
                }
                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) {
@@ -336,22 +371,6 @@ static int static_route_leak(struct vty *vty, const char *svrf,
 
        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,
@@ -365,9 +384,17 @@ 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.  */
@@ -398,9 +425,21 @@ DEFPY_YANG(ip_route_blackhole,
       "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,
@@ -428,26 +467,28 @@ 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,
@@ -486,25 +527,25 @@ 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,
@@ -541,32 +582,25 @@ 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,
@@ -602,26 +636,24 @@ 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,
@@ -655,33 +687,24 @@ 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,
@@ -711,9 +734,21 @@ 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,
@@ -741,28 +776,28 @@ 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,
@@ -801,26 +836,25 @@ 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,
@@ -857,32 +891,25 @@ 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,
@@ -918,25 +945,24 @@ 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,
@@ -970,32 +996,24 @@ 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,
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/__init__.py b/tests/topotests/bgp_peer_graceful_shutdown/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..8e59098
--- /dev/null
@@ -0,0 +1,8 @@
+!
+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
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r1/zebra.conf
new file mode 100644 (file)
index 0000000..376a19a
--- /dev/null
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 10.10.10.1/32
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/bgpd.conf
new file mode 100644 (file)
index 0000000..0ee1821
--- /dev/null
@@ -0,0 +1,8 @@
+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
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r2/zebra.conf
new file mode 100644 (file)
index 0000000..67ca02f
--- /dev/null
@@ -0,0 +1,7 @@
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
+int r2-eth1
+ ip address 192.168.2.1/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/bgpd.conf
new file mode 100644 (file)
index 0000000..5945a02
--- /dev/null
@@ -0,0 +1,5 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as internal
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf b/tests/topotests/bgp_peer_graceful_shutdown/r3/zebra.conf
new file mode 100644 (file)
index 0000000..e5a37c9
--- /dev/null
@@ -0,0 +1,4 @@
+!
+int r3-eth0
+ ip address 192.168.2.2/24
+!
diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py
new file mode 100644 (file)
index 0000000..de62889
--- /dev/null
@@ -0,0 +1,120 @@
+#!/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))
index 61caf257ebcbe12d7f68705f1ffe5277fd5f6c26..012814919d79749edd4b600a5cbe0ba175312a8c 100755 (executable)
@@ -1054,7 +1054,7 @@ def test_rib_ipv6_step24():
         rname,
         "show ipv6 route isis json",
         outputs[rname][15]["show_ipv6_route.ref"],
-        count=5,
+        count=10,
     )
 
 
index fa76072b4a8a8a8fec325b71aac6ae0428283537..213439d3f5558ab226923434e49c577f7706e027 100755 (executable)
@@ -831,19 +831,19 @@ def test_rt6_step11():
         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,
     )
 
 
@@ -1028,19 +1028,19 @@ def test_rt6_step14():
         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,
     )
 
 
index 5a3f586f824245a225a4f58a2446fed8f6536cee..61cf16944ff52e2a64be2bfa52eed588ca7baab3 100644 (file)
@@ -355,6 +355,16 @@ def run_and_expect(func, what, count=20, wait=3):
     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
@@ -402,6 +412,16 @@ def run_and_expect_type(func, etype, count=20, wait=3, avalue=None):
     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)
index e59333ebd2a9c69bf268007b74384d3af362147c..1876dabed736a72cbdba0c6811ed236e8a6ed39a 100755 (executable)
@@ -224,7 +224,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
             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
         )
@@ -246,7 +246,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
             if initial_convergence == True or restarting == rname:
                 tries = 240
             else:
-                tries = 1
+                tries = 10
             router_compare_json_output(
                 rname,
                 "show ipv6 ospf database json",
index d17aeda3eae43ba2c29ba22f882a49f9e2fac5e7..f16e8f396e02c8962a0fcdc6603b749f029b1fad 100644 (file)
@@ -243,7 +243,7 @@ def test_ospf6_default_route():
             "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
 
index debf7ad766596512059a2d6e3f51c5708d905b8c..429b7dc96d4f2c0928a40b1738bb042392304802 100755 (executable)
@@ -233,7 +233,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
             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
         )
@@ -252,7 +252,7 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None):
             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
             )
index 6cea521aa9a354a9074f8be3ffab26154014997b..2c1bc52d09fafa91bf59aa521e19b7afc1b32572 100644 (file)
@@ -225,7 +225,7 @@ def test_pim_igmp_report():
         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:
index 9506c3c6d11800c2b55021b497ce73e30ac7bde6..5aa313137fd9b63371d8319324a81f873c1904ae 100644 (file)
@@ -175,7 +175,7 @@ def test_pim_reconvergence():
             "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
 
@@ -201,7 +201,7 @@ def test_pim_bfd_profile():
             "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
 
index bc5fa409d2f3680bcd248060d7a549a3bf858bca..b918da065567732721e0b3a2d42d8475fab5c0e3 100755 (executable)
@@ -94,12 +94,12 @@ def test_srv6():
 
     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:
index ecc0856371a370c8ec87ac6eb77a661df293c581..4bd0682bde4720737c846993e2a0137a8e4052d3 100755 (executable)
@@ -90,12 +90,12 @@ def test_srv6():
 
     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:
@@ -124,7 +124,7 @@ def test_srv6():
           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")
index 78ef1e9d407aa2df5faeb284b8261e59fb3fc3f1..190e831ac1e83518852e7791b61396fbc36d2702 100644 (file)
@@ -12,7 +12,7 @@ segment-routing
  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
    !
   !
index 37fd736d2be5072fff6b48ef72396786df511b5c..40235555247b132c592c65ac77735d6b8e072139 100755 (executable)
@@ -54,12 +54,10 @@ def setup_module(mod):
     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()
 
@@ -71,18 +69,14 @@ def teardown_module(mod):
 
 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)
 
@@ -164,7 +158,7 @@ def test_srv6_usid_locator_create_locator():
           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")
@@ -181,9 +175,7 @@ def test_srv6_usid_locator_set_behavior_usid():
     # 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
index 8aa08871e351306b685b78078d7757fd5ec479c1..2427bfff7771fc343f242998f5006e215f5c0084 100644 (file)
@@ -91,6 +91,11 @@ pathd_options="  -A 127.0.0.1"
 #
 #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.
index 3c16c27c6dfa135b54f3ab7e25969b32726edc5d..4f095a176e4c6a1af1dc9f9f016484260e91b51d 100755 (executable)
@@ -43,6 +43,10 @@ RELOAD_SCRIPT="$D_PATH/frr-reload.py"
 #
 
 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
index d61d3620f17d537d7103e2876d9066de06e80918..81ee995dd7cf2eb7feac0c95ca327179d487fbdc 100644 (file)
@@ -4646,7 +4646,7 @@ static int if_config_write(struct vty *vty)
                                                        ? ""
                                                        : "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);
index 7934a9d2066e34b7875413399eb78f430da85e15..599c679864e908221afbfdd31b4634f4f21f8f60 100644 (file)
@@ -62,7 +62,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
 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)
@@ -803,7 +804,8 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
 }
 
 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;
@@ -820,7 +822,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, safi_t safi,
                        continue;
 
                if (rn->info)
-                       print_rnh(rn, vty);
+                       print_rnh(rn, vty, json);
        }
 }
 
@@ -1268,73 +1270,178 @@ failure:
        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,
index 70eda725c4a71d46d47aab9e876a2fa7939dc885..44ce65b4b650a31a839c47f5e1ff5ce99ca17702 100644 (file)
@@ -46,7 +46,8 @@ extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client);
 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);
 
index 1221365d4d5e5e826c3afa2afda9ca7cc97bf8cd..13ad9d71bbdae1f5f0af7ad795e16772b5fbde32 100644 (file)
@@ -276,16 +276,16 @@ DEFUN (no_srv6_locator,
 
 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;
index 49a0c8e7930eb4069cc27661b9c4012a023ab2a5..374305fcda5f2f0327399bdc440e741854a691ed 100644 (file)
@@ -123,6 +123,49 @@ TRACEPOINT_EVENT(
                )
        )
 
+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 */
index 6561ac95fa3d81808f41eeb0a997010bedeae59c..91a0c1dd31b8d062c1e8385079bb763146cafbf9 100644 (file)
@@ -1370,7 +1370,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi,
 
 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
@@ -1382,23 +1382,48 @@ DEFPY (show_ip_nht,
        "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)
@@ -1407,11 +1432,29 @@ DEFPY (show_ip_nht,
        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;
 }