]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib, bgp: add initial support for asdot format
authorPhilippe Guibert <philippe.guibert@6wind.com>
Wed, 2 Nov 2022 17:17:21 +0000 (18:17 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 10 Feb 2023 09:27:17 +0000 (10:27 +0100)
AS number can be defined as an unsigned long number, or
two uint16 values separated by a period (.). The possible
valus are:
- usual 32 bit values : [1;2^32 -1]
- <1.65535>.<0.65535> for dot notation
- <0.65535>.<0.65535> for dot+ notation.

The 0.0 value is forbidden when configuring BGP instances
or peer configurations.

A new ASN type is added for parsing in the vty.
The following commands use that new identifier:
- router bgp ..
- bgp confederation ..
- neighbor <> remote-as <>
- neighbor <> local-as <>
- clear ip bgp <>
- route-map / set as-path <>

An asn library is available in lib/ and provides some
services:
- convert an as string into an as number.
- parse an as path list string and extract a number.
- convert an as number into a string.

Also, the bgp tests forge an as_zero_path, and to do that,
an API to relax the possibility to have a 0 as value is
specifically called from the tests.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
20 files changed:
bgpd/bgp_aspath.c
bgpd/bgp_routemap.c
bgpd/bgp_vty.c
bgpd/bgpd.c
bgpd/bgpd.h
doc/developer/cli.rst
lib/asn.c [new file with mode: 0644]
lib/asn.h [new file with mode: 0644]
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_lex.l
lib/command_match.c
lib/command_parse.y
lib/command_py.c
lib/subdir.am
python/clidef.py
tests/bgpd/test_aspath.c
vtysh/vtysh.c

index 2ae693cd306824c9d19f280b37521f595a81b4ba..9f74aa76d40d8de382edf41965439f9e31f477e1 100644 (file)
@@ -1940,6 +1940,8 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
                                   unsigned long *asno)
 {
        const char *p = buf;
+       as_t asval;
+       bool found = false;
 
        /* Skip separators (space for sequences, ',' for sets). */
        while (isspace((unsigned char)*p) || *p == ',')
@@ -1976,26 +1978,13 @@ static const char *aspath_gettoken(const char *buf, enum as_token *token,
                return p;
        }
 
-       /* Check actual AS value. */
-       if (isdigit((unsigned char)*p)) {
-               as_t asval;
-
-               *token = as_token_asval;
-               asval = (*p - '0');
-               p++;
-
-               while (isdigit((unsigned char)*p)) {
-                       asval *= 10;
-                       asval += (*p - '0');
-                       p++;
-               }
+       asval = 0;
+       p = asn_str2asn_parse(p, &asval, &found);
+       if (found) {
                *asno = asval;
-               return p;
-       }
-
-       /* There is no match then return unknown token. */
-       *token = as_token_unknown;
-       p++;
+               *token = as_token_asval;
+       } else
+               *token = as_token_unknown;
        return p;
 }
 
index d00bdd2571a2c835845596fe1b3f2fccbac0fce6..c9da71c6de249f57ea5306113b6c07c03aa77e0e 100644 (file)
@@ -5608,15 +5608,16 @@ DEFUN_YANG (no_set_label_index,
 
 DEFUN_YANG (set_aspath_prepend_asn,
            set_aspath_prepend_asn_cmd,
-           "set as-path prepend (1-4294967295)...",
+           "set as-path prepend ASNUM...",
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Prepend to the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        int idx_asn = 3;
        int ret;
        char *str;
+       struct aspath *aspath;
 
        str = argv_concat(argv, argc, idx_asn);
 
@@ -5624,6 +5625,12 @@ DEFUN_YANG (set_aspath_prepend_asn,
                "./set-action[action='frr-bgp-route-map:as-path-prepend']";
        char xpath_value[XPATH_MAXLEN];
 
+       aspath = route_aspath_compile(str);
+       if (!aspath) {
+               vty_out(vty, "%% Invalid AS path value %s\n", str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       route_aspath_free(aspath);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
                 "%s/rmap-set-action/frr-bgp-route-map:prepend-as-path", xpath);
@@ -5658,16 +5665,22 @@ DEFUN_YANG (set_aspath_prepend_lastas,
 
 DEFPY_YANG (set_aspath_replace_asn,
            set_aspath_replace_asn_cmd,
-           "set as-path replace <any|(1-4294967295)>$replace",
+           "set as-path replace <any|ASNUM>$replace",
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Replace AS number to local AS number\n"
            "Replace any AS number to local AS number\n"
-           "Replace a specific AS number to local AS number\n")
+           "Replace a specific AS number in plain or dotted format to local AS number\n")
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-replace']";
        char xpath_value[XPATH_MAXLEN];
+       as_t as_value;
+
+       if (!strmatch(replace, "any") && !asn_str2asn(replace, &as_value)) {
+               vty_out(vty, "%% Invalid AS value %s\n", replace);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
@@ -5678,13 +5691,13 @@ DEFPY_YANG (set_aspath_replace_asn,
 
 DEFPY_YANG (no_set_aspath_replace_asn,
            no_set_aspath_replace_asn_cmd,
-           "no set as-path replace [<any|(1-4294967295)>]",
+           "no set as-path replace [<any|ASNUM>]",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Replace AS number to local AS number\n"
            "Replace any AS number to local AS number\n"
-           "Replace a specific AS number to local AS number\n")
+           "Replace a specific AS number in plain or dotted format to local AS number\n")
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-replace']";
@@ -5695,12 +5708,12 @@ DEFPY_YANG (no_set_aspath_replace_asn,
 
 DEFUN_YANG (no_set_aspath_prepend,
            no_set_aspath_prepend_cmd,
-           "no set as-path prepend [(1-4294967295)]",
+           "no set as-path prepend [ASNUM]",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
            "Prepend to the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:as-path-prepend']";
@@ -5728,15 +5741,16 @@ DEFUN_YANG (no_set_aspath_prepend_lastas,
 
 DEFUN_YANG (set_aspath_exclude,
            set_aspath_exclude_cmd,
-           "set as-path exclude (1-4294967295)...",
+           "set as-path exclude ASNUM...",
            SET_STR
            "Transform BGP AS-path attribute\n"
            "Exclude from the as-path\n"
-           "AS number\n")
+           AS_STR)
 {
        int idx_asn = 3;
        int ret;
        char *str;
+       struct aspath *aspath;
 
        str = argv_concat(argv, argc, idx_asn);
 
@@ -5744,6 +5758,12 @@ DEFUN_YANG (set_aspath_exclude,
                "./set-action[action='frr-bgp-route-map:as-path-exclude']";
        char xpath_value[XPATH_MAXLEN];
 
+       aspath = route_aspath_compile(str);
+       if (!aspath) {
+               vty_out(vty, "%% Invalid AS path value %s\n", str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+       route_aspath_free(aspath);
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
        snprintf(xpath_value, sizeof(xpath_value),
                 "%s/rmap-set-action/frr-bgp-route-map:exclude-as-path", xpath);
@@ -5755,7 +5775,7 @@ DEFUN_YANG (set_aspath_exclude,
 
 DEFUN_YANG (no_set_aspath_exclude,
            no_set_aspath_exclude_cmd,
-           "no set as-path exclude (1-4294967295)...",
+           "no set as-path exclude ASNUM...",
            NO_STR
            SET_STR
            "Transform BGP AS_PATH attribute\n"
@@ -6441,11 +6461,11 @@ DEFPY_YANG (no_set_aigp_metric,
 
 DEFUN_YANG (set_aggregator_as,
            set_aggregator_as_cmd,
-           "set aggregator as (1-4294967295) A.B.C.D",
+           "set aggregator as ASNUM A.B.C.D",
            SET_STR
            "BGP aggregator attribute\n"
            "AS number of aggregator\n"
-           "AS number\n"
+           AS_STR
            "IP address of aggregator\n")
 {
        int idx_number = 3;
@@ -6454,6 +6474,12 @@ DEFUN_YANG (set_aggregator_as,
        char xpath_addr[XPATH_MAXLEN];
        const char *xpath =
                "./set-action[action='frr-bgp-route-map:aggregator']";
+       as_t as_value;
+
+       if (!asn_str2asn(argv[idx_number]->arg, &as_value)) {
+               vty_out(vty, "%% Invalid AS value %s\n", argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
 
        nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
 
@@ -6476,12 +6502,12 @@ DEFUN_YANG (set_aggregator_as,
 
 DEFUN_YANG (no_set_aggregator_as,
            no_set_aggregator_as_cmd,
-           "no set aggregator as [(1-4294967295) A.B.C.D]",
+           "no set aggregator as [ASNUM A.B.C.D]",
            NO_STR
            SET_STR
            "BGP aggregator attribute\n"
            "AS number of aggregator\n"
-           "AS number\n"
+           AS_STR
            "IP address of aggregator\n")
 {
        const char *xpath =
index 6023d9811d49c99ce38565e71a054d042187a4c5..8af3f65f45f2ebd359ae1da64e75d0e15c58f6a4 100644 (file)
@@ -39,6 +39,7 @@
 #include "queue.h"
 #include "filter.h"
 #include "frrstr.h"
+#include "asn.h"
 
 #include "bgpd/bgpd.h"
 #include "bgpd/bgp_attr_evpn.h"
@@ -1237,7 +1238,12 @@ static int bgp_clear(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
 
        /* Clear all neighbors belonging to a specific AS. */
        if (sort == clear_as) {
-               as_t as = strtoul(arg, NULL, 10);
+               as_t as;
+
+               if (!asn_str2asn(arg, &as)) {
+                       vty_out(vty, "%% BGP: No such AS %s\n", arg);
+                       return CMD_WARNING;
+               }
 
                for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) {
                        if (peer->as != as)
@@ -1475,7 +1481,7 @@ DEFUN (no_auto_summary,
 /* "router bgp" commands. */
 DEFUN_NOSH (router_bgp,
        router_bgp_cmd,
-       "router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
+       "router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME]]",
        ROUTER_STR
        BGP_STR
        AS_STR
@@ -1509,7 +1515,11 @@ DEFUN_NOSH (router_bgp,
 
        // "router bgp X"
        else {
-               as = strtoul(argv[idx_asn]->arg, NULL, 10);
+               if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
+                       vty_out(vty, "%% BGP: No such AS %s\n",
+                               argv[idx_asn]->arg);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
 
                if (as == BGP_PRIVATE_AS_MAX || as == BGP_AS4_MAX)
                        vty_out(vty, "Reserved AS used (%u|%u); AS is %u\n",
@@ -1571,7 +1581,7 @@ DEFUN_NOSH (router_bgp,
 /* "no router bgp" commands. */
 DEFUN (no_router_bgp,
        no_router_bgp_cmd,
-       "no router bgp [(1-4294967295)$instasn [<view|vrf> VIEWVRFNAME]]",
+       "no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME]]",
        NO_STR
        ROUTER_STR
        BGP_STR
@@ -1605,8 +1615,11 @@ DEFUN (no_router_bgp,
                        return CMD_WARNING_CONFIG_FAILED;
                }
        } else {
-               as = strtoul(argv[idx_asn]->arg, NULL, 10);
-
+               if (!asn_str2asn(argv[idx_asn]->arg, &as)) {
+                       vty_out(vty, "%% BGP: No such AS %s\n",
+                               argv[idx_asn]->arg);
+                       return CMD_WARNING_CONFIG_FAILED;
+               }
                if (argc > 4) {
                        name = argv[idx_vrf]->arg;
                        if (strmatch(argv[idx_vrf - 1]->text, "vrf")
@@ -1934,17 +1947,20 @@ DEFPY (no_bgp_send_extra_data,
 
 DEFUN (bgp_confederation_identifier,
        bgp_confederation_identifier_cmd,
-       "bgp confederation identifier (1-4294967295)",
+       "bgp confederation identifier ASNUM",
        BGP_STR
        "AS confederation parameters\n"
-       "AS number\n"
+       AS_STR
        "Set routing domain confederation AS\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
        int idx_number = 3;
        as_t as;
 
-       as = strtoul(argv[idx_number]->arg, NULL, 10);
+       if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+               vty_out(vty, "%% BGP: No such AS %s\n", argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
 
        bgp_confederation_id_set(bgp, as);
 
@@ -1953,11 +1969,11 @@ DEFUN (bgp_confederation_identifier,
 
 DEFUN (no_bgp_confederation_identifier,
        no_bgp_confederation_identifier_cmd,
-       "no bgp confederation identifier [(1-4294967295)]",
+       "no bgp confederation identifier [ASNUM]",
        NO_STR
        BGP_STR
        "AS confederation parameters\n"
-       "AS number\n"
+       AS_STR
        "Set routing domain confederation AS\n")
 {
        VTY_DECLVAR_CONTEXT(bgp, bgp);
@@ -1968,7 +1984,7 @@ DEFUN (no_bgp_confederation_identifier,
 
 DEFUN (bgp_confederation_peers,
        bgp_confederation_peers_cmd,
-       "bgp confederation peers (1-4294967295)...",
+       "bgp confederation peers ASNUM...",
        BGP_STR
        "AS confederation parameters\n"
        "Peer ASs in BGP confederation\n"
@@ -1980,7 +1996,12 @@ DEFUN (bgp_confederation_peers,
        int i;
 
        for (i = idx_asn; i < argc; i++) {
-               as = strtoul(argv[i]->arg, NULL, 10);
+               if (!asn_str2asn(argv[i]->arg, &as)) {
+                       vty_out(vty, "%% Invalid confed peer AS value: %s\n",
+                               argv[i]->arg);
+                       continue;
+               }
+
                bgp_confederation_peers_add(bgp, as);
        }
        return CMD_SUCCESS;
@@ -1988,7 +2009,7 @@ DEFUN (bgp_confederation_peers,
 
 DEFUN (no_bgp_confederation_peers,
        no_bgp_confederation_peers_cmd,
-       "no bgp confederation peers (1-4294967295)...",
+       "no bgp confederation peers ASNUM...",
        NO_STR
        BGP_STR
        "AS confederation parameters\n"
@@ -2001,8 +2022,11 @@ DEFUN (no_bgp_confederation_peers,
        int i;
 
        for (i = idx_asn; i < argc; i++) {
-               as = strtoul(argv[i]->arg, NULL, 10);
-
+               if (!asn_str2asn(argv[i]->arg, &as)) {
+                       vty_out(vty, "%% Invalid confed peer AS value: %s\n",
+                               argv[i]->arg);
+                       continue;
+               }
                bgp_confederation_peers_remove(bgp, as);
        }
        return CMD_SUCCESS;
@@ -4506,11 +4530,13 @@ static int peer_remote_as_vty(struct vty *vty, const char *peer_str,
        } else if (as_str[0] == 'e') {
                as = 0;
                as_type = AS_EXTERNAL;
-       } else {
-               /* Get AS number.  */
-               as = strtoul(as_str, NULL, 10);
-       }
+       } else if (!asn_str2asn(as_str, &as))
+               as_type = AS_UNSPECIFIED;
 
+       if (as_type == AS_UNSPECIFIED) {
+               vty_out(vty, "%% Invalid peer AS: %s\n", as_str);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
        /* If peer is peer group or interface peer, call proper function. */
        ret = str2sockunion(peer_str, &su);
        if (ret < 0) {
@@ -4608,7 +4634,7 @@ ALIAS(no_bgp_shutdown, no_bgp_shutdown_msg_cmd,
 
 DEFUN (neighbor_remote_as,
        neighbor_remote_as_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <(1-4294967295)|internal|external>",
+       "neighbor <A.B.C.D|X:X::X:X|WORD> remote-as <ASNUM|internal|external>",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Specify a BGP neighbor\n"
@@ -4688,8 +4714,8 @@ static int peer_conf_interface_get(struct vty *vty, const char *conf_if,
                        as_type = AS_EXTERNAL;
                } else {
                        /* Get AS number.  */
-                       as = strtoul(as_str, NULL, 10);
-                       as_type = AS_SPECIFIED;
+                       if (asn_str2asn(as_str, &as))
+                               as_type = AS_SPECIFIED;
                }
        }
 
@@ -4801,7 +4827,7 @@ DEFUN (neighbor_interface_config_v6only,
 
 DEFUN (neighbor_interface_config_remote_as,
        neighbor_interface_config_remote_as_cmd,
-       "neighbor WORD interface remote-as <(1-4294967295)|internal|external>",
+       "neighbor WORD interface remote-as <ASNUM|internal|external>",
        NEIGHBOR_STR
        "Interface name or neighbor tag\n"
        "Enable BGP on interface\n"
@@ -4818,7 +4844,7 @@ DEFUN (neighbor_interface_config_remote_as,
 
 DEFUN (neighbor_interface_v6only_config_remote_as,
        neighbor_interface_v6only_config_remote_as_cmd,
-       "neighbor WORD interface v6only remote-as <(1-4294967295)|internal|external>",
+       "neighbor WORD interface v6only remote-as <ASNUM|internal|external>",
        NEIGHBOR_STR
        "Interface name or neighbor tag\n"
        "Enable BGP with v6 link-local only\n"
@@ -4987,7 +5013,7 @@ DEFUN (no_neighbor_peer_group,
 
 DEFUN (no_neighbor_interface_peer_group_remote_as,
        no_neighbor_interface_peer_group_remote_as_cmd,
-       "no neighbor WORD remote-as <(1-4294967295)|internal|external>",
+       "no neighbor WORD remote-as <ASNUM|internal|external>",
        NO_STR
        NEIGHBOR_STR
        "Interface name or neighbor tag\n"
@@ -5020,11 +5046,11 @@ DEFUN (no_neighbor_interface_peer_group_remote_as,
 
 DEFUN (neighbor_local_as,
        neighbor_local_as_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295)",
+       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Specify a local-as number\n"
-       "AS number used as local AS\n")
+       "AS number expressed in dotted or plain format used as local AS\n")
 {
        int idx_peer = 1;
        int idx_number = 3;
@@ -5036,18 +5062,23 @@ DEFUN (neighbor_local_as,
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       as = strtoul(argv[idx_number]->arg, NULL, 10);
+       if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+               vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+                       argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        ret = peer_local_as_set(peer, as, 0, 0);
        return bgp_vty_return(vty, ret);
 }
 
 DEFUN (neighbor_local_as_no_prepend,
        neighbor_local_as_no_prepend_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend",
+       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Specify a local-as number\n"
-       "AS number used as local AS\n"
+       "AS number expressed in dotted or plain format used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n")
 {
        int idx_peer = 1;
@@ -5060,18 +5091,23 @@ DEFUN (neighbor_local_as_no_prepend,
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       as = strtoul(argv[idx_number]->arg, NULL, 10);
+       if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+               vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+                       argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        ret = peer_local_as_set(peer, as, 1, 0);
        return bgp_vty_return(vty, ret);
 }
 
 DEFUN (neighbor_local_as_no_prepend_replace_as,
        neighbor_local_as_no_prepend_replace_as_cmd,
-       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as (1-4294967295) no-prepend replace-as",
+       "neighbor <A.B.C.D|X:X::X:X|WORD> local-as ASNUM no-prepend replace-as",
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Specify a local-as number\n"
-       "AS number used as local AS\n"
+       "AS number expressed in dotted or plain format used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n"
        "Do not prepend local-as to updates from ibgp peers\n")
 {
@@ -5085,19 +5121,24 @@ DEFUN (neighbor_local_as_no_prepend_replace_as,
        if (!peer)
                return CMD_WARNING_CONFIG_FAILED;
 
-       as = strtoul(argv[idx_number]->arg, NULL, 10);
+       if (!asn_str2asn(argv[idx_number]->arg, &as)) {
+               vty_out(vty, "%% Invalid neighbor local-as value: %s\n",
+                       argv[idx_number]->arg);
+               return CMD_WARNING_CONFIG_FAILED;
+       }
+
        ret = peer_local_as_set(peer, as, 1, 1);
        return bgp_vty_return(vty, ret);
 }
 
 DEFUN (no_neighbor_local_as,
        no_neighbor_local_as_cmd,
-       "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [(1-4294967295) [no-prepend [replace-as]]]",
+       "no neighbor <A.B.C.D|X:X::X:X|WORD> local-as [ASNUM [no-prepend [replace-as]]]",
        NO_STR
        NEIGHBOR_STR
        NEIGHBOR_ADDR_STR2
        "Specify a local-as number\n"
-       "AS number used as local AS\n"
+       "AS number expressed in dotted or plain format used as local AS\n"
        "Do not prepend local-as to updates from ebgp peers\n"
        "Do not prepend local-as to updates from ibgp peers\n")
 {
@@ -10084,7 +10125,7 @@ static int bgp_clear_prefix(struct vty *vty, const char *view_name,
 /* one clear bgp command to rule them all */
 DEFUN (clear_ip_bgp_all,
        clear_ip_bgp_all_cmd,
-       "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|(1-4294967295)|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
+       "clear [ip] bgp [<view|vrf> VIEWVRFNAME] [<ipv4|ipv6|l2vpn> [<unicast|multicast|vpn|labeled-unicast|flowspec|evpn>]] <*|A.B.C.D$neighbor|X:X::X:X$neighbor|WORD$neighbor|ASNUM|external|peer-group PGNAME> [<soft [<in|out>]|in [prefix-filter]|out|message-stats>]",
        CLEAR_STR
        IP_STR
        BGP_STR
@@ -10097,7 +10138,7 @@ DEFUN (clear_ip_bgp_all,
        "BGP IPv4 neighbor to clear\n"
        "BGP IPv6 neighbor to clear\n"
        "BGP neighbor on interface to clear\n"
-       "Clear peers with the AS number\n"
+       "Clear peers with the AS number in plain or dotted format\n"
        "Clear all external peers\n"
        "Clear all members of peer-group\n"
        "BGP peer-group name\n"
@@ -10138,7 +10179,7 @@ DEFUN (clear_ip_bgp_all,
        if (argv_find_and_parse_afi(argv, argc, &idx, &afi))
                argv_find_and_parse_safi(argv, argc, &idx, &safi);
 
-       /* <*|A.B.C.D|X:X::X:X|WORD|(1-4294967295)|external|peer-group PGNAME> */
+       /* <*|A.B.C.D|X:X::X:X|WORD|ASNUM|external|peer-group PGNAME> */
        if (argv_find(argv, argc, "*", &idx)) {
                clr_sort = clear_all;
        } else if (argv_find(argv, argc, "A.B.C.D", &idx)) {
@@ -10157,7 +10198,7 @@ DEFUN (clear_ip_bgp_all,
        } else if (argv_find(argv, argc, "WORD", &idx)) {
                clr_sort = clear_peer;
                clr_arg = argv[idx]->arg;
-       } else if (argv_find(argv, argc, "(1-4294967295)", &idx)) {
+       } else if (argv_find(argv, argc, "ASNUM", &idx)) {
                clr_sort = clear_as;
                clr_arg = argv[idx]->arg;
        } else if (argv_find(argv, argc, "external", &idx)) {
@@ -11827,7 +11868,7 @@ int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
 DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
       "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR
       " [" BGP_SAFI_WITH_LABEL_CMD_STR
-      "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <(1-4294967295)|internal|external>>] [terse] [wide] [json$uj]",
+      "]] [all$all] summary [established|failed] [<neighbor <A.B.C.D|X:X::X:X|WORD>|remote-as <ASNUM|internal|external>>] [terse] [wide] [json$uj]",
       SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
              BGP_SAFI_WITH_LABEL_HELP_STR
       "Display the entries for all address families\n"
@@ -11838,8 +11879,7 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
       "Neighbor to display information about\n"
       "Neighbor to display information about\n"
       "Neighbor on BGP configured interface\n"
-      "Show only the specified remote AS sessions\n"
-      "AS number\n"
+      "Show only the specified remote AS sessions\n" AS_STR
       "Internal (iBGP) AS sessions\n"
       "External (eBGP) AS sessions\n"
       "Shorten the information on BGP instances\n"
@@ -11881,8 +11921,12 @@ DEFPY(show_ip_bgp_summary, show_ip_bgp_summary_cmd,
                        as_type = AS_INTERNAL;
                else if (argv[idx + 1]->arg[0] == 'e')
                        as_type = AS_EXTERNAL;
-               else
-                       as = (as_t)atoi(argv[idx + 1]->arg);
+               else if (!asn_str2asn(argv[idx + 1]->arg, &as)) {
+                       vty_out(vty,
+                               "%% Invalid neighbor remote-as value: %s\n",
+                               argv[idx + 1]->arg);
+                       return CMD_SUCCESS;
+               }
        }
 
        if (argv_find(argv, argc, "terse", &idx))
index 9fca97521204053a4591d7653672460c17461e69..32f169e3427a63213069f6d5b2ee1b1c358a32ba 100644 (file)
@@ -3200,6 +3200,9 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        bgp->as = *as;
        if (as_pretty)
                bgp->as_pretty = XSTRDUP(MTYPE_BGP, as_pretty);
+       else
+               bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as));
+
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        zlog_debug("Creating Default VRF, AS %s",
index a0627af75192f70db1c8d1d003d93920316f9427..4efeb0e9efe64a4416642356c07505180965efbe 100644 (file)
@@ -31,6 +31,7 @@
 #include "vty.h"
 #include "srv6.h"
 #include "iana_afi.h"
+#include "asn.h"
 
 /* For union sockunion.  */
 #include "queue.h"
@@ -77,7 +78,6 @@ enum zebra_gr_mode {
 };
 
 /* Typedef BGP specific types.  */
-typedef uint32_t as_t;
 typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */
 typedef uint16_t bgp_size_t;
 
index 5d1dda06dfcea1a9f5546910991ee250d884ba58..2a08531bd742c3ea3499056f5df600cc8e37d748 100644 (file)
@@ -151,6 +151,7 @@ by the parser.
                          : RANGE
                          : MAC
                          : MAC_PREFIX
+                         : ASNUM
    selector: "<" `selector_seq_seq` ">" `varname_token`
            : "{" `selector_seq_seq` "}" `varname_token`
            : "[" `selector_seq_seq` "]" `varname_token`
@@ -176,27 +177,29 @@ parser, but this is merely a dumb copy job.
 
 Here is a brief summary of the various token types along with examples.
 
-+-----------------+-------------------+-------------------------------------------------------------+
-| Token type      | Syntax            | Description                                                 |
-+=================+===================+=============================================================+
-| ``WORD``        | ``show ip bgp``   | Matches itself. In the given example every token is a WORD. |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV4``        | ``A.B.C.D``       | Matches an IPv4 address.                                    |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV6``        | ``X:X::X:X``      | Matches an IPv6 address.                                    |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV4_PREFIX`` | ``A.B.C.D/M``     | Matches an IPv4 prefix in CIDR notation.                    |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``IPV6_PREFIX`` | ``X:X::X:X/M``    | Matches an IPv6 prefix in CIDR notation.                    |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``MAC``         | ``X:X:X:X:X:X``   | Matches a 48-bit mac address.                               |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``MAC_PREFIX``  | ``X:X:X:X:X:X/M`` | Matches a 48-bit mac address with a mask.                   |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``VARIABLE``    | ``FOOBAR``        | Matches anything.                                           |
-+-----------------+-------------------+-------------------------------------------------------------+
-| ``RANGE``       | ``(X-Y)``         | Matches numbers in the range X..Y inclusive.                |
-+-----------------+-------------------+-------------------------------------------------------------+
++-----------------+-------------------------+-------------------------------------------------------+
+| Token type      | Syntax                  | Description                                           |
++=================+=========================+=======================================================+
+| ``WORD``        | ``show ip bgp``         | Matches itself. In the example every token is a WORD. |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV4``        | ``A.B.C.D``             | Matches an IPv4 address.                              |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV6``        | ``X:X::X:X``            | Matches an IPv6 address.                              |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV4_PREFIX`` | ``A.B.C.D/M``           | Matches an IPv4 prefix in CIDR notation.              |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``IPV6_PREFIX`` | ``X:X::X:X/M``          | Matches an IPv6 prefix in CIDR notation.              |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``MAC``         | ``X:X:X:X:X:X``         | Matches a 48-bit mac address.                         |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``MAC_PREFIX``  | ``X:X:X:X:X:X/M``       | Matches a 48-bit mac address with a mask.             |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``VARIABLE``    | ``FOOBAR``              | Matches anything.                                     |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``RANGE``       | ``(X-Y)``               | Matches numbers in the range X..Y inclusive.          |
++-----------------+-------------------------+-------------------------------------------------------+
+| ``ASNUM``       | ``<A.B|(1-4294967295>`` | Matches an AS in plain or dot format.                 |
++-----------------+-------------------------+-------------------------------------------------------+
 
 When presented with user input, the parser will search over all defined
 commands in the current context to find a match. It is aware of the various
diff --git a/lib/asn.c b/lib/asn.c
new file mode 100644 (file)
index 0000000..7a78686
--- /dev/null
+++ b/lib/asn.c
@@ -0,0 +1,150 @@
+/*
+ * ASN functions
+ *
+ * Copyright 2022 6WIND
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <zebra.h>
+#include "log.h"
+#include "asn.h"
+
+static bool relax_as_zero;
+
+/* converts a string into an Autonomous system number
+ * "1.1" => 65536
+ * "65500" => 65500
+ */
+static bool asn_str2asn_internal(const char *asstring, as_t *asn,
+                                const char **next, bool *partial)
+{
+       uint32_t high = 0, low = 0;
+       uint64_t temp_val;
+       const char *p = asstring;
+       bool ret = false;
+       uint32_t digit;
+
+       if (!asstring)
+               goto end;
+
+       if  (!isdigit((unsigned char)*p))
+               goto end;
+
+       temp_val = 0;
+       while (isdigit((unsigned char)*p)) {
+               digit = (*p) - '0';
+               temp_val *= 10;
+               temp_val += digit;
+               if (temp_val > UINT32_MAX)
+                       /* overflow */
+                       goto end;
+               p++;
+       }
+       high = (uint32_t)temp_val;
+       if (*p == '.') { /* dot format */
+               p++;
+               temp_val = 0;
+               if (*p == '\0' && partial) {
+                       *partial = true;
+                       goto end;
+               }
+               while (isdigit((unsigned char)*p)) {
+                       digit = (*p) - '0';
+                       temp_val *= 10;
+                       temp_val += digit;
+                       if (temp_val > UINT16_MAX)
+                               /* overflow */
+                               goto end;
+                       p++;
+               }
+               low = (uint32_t)temp_val;
+
+               if (!next && *p != '\0' && !isdigit((unsigned char)*p))
+                       goto end;
+               /* AS <AS4B>.<AS4B> is forbidden */
+               if (high > UINT16_MAX)
+                       goto end;
+               /* AS 0.0 is authorised for some case only */
+               if (!relax_as_zero && high == 0 && low == 0) {
+                       if (partial)
+                               *partial = true;
+                       goto end;
+               }
+               if (!asn) {
+                       ret = true;
+                       goto end;
+               }
+               *asn = (high << 16) + low;
+               ret = true;
+               goto end;
+       }
+       /* AS 0 is forbidden */
+       if (!relax_as_zero && high == 0)
+               goto end;
+       if (!asn) {
+               ret = true;
+               goto end;
+       }
+       *asn = high;
+       ret = true;
+ end:
+       if (next)
+               *next = p;
+       return ret;
+}
+
+bool asn_str2asn(const char *asstring, as_t *asn)
+{
+       return asn_str2asn_internal(asstring, asn, NULL, NULL);
+}
+
+const char *asn_asn2asplain(as_t asn)
+{
+       static char buf[ASN_STRING_MAX_SIZE];
+
+       snprintf(buf, sizeof(buf), "%u", asn);
+       return buf;
+}
+
+const char *asn_str2asn_parse(const char *asstring, as_t *asn, bool *found_ptr)
+{
+       const char *p = NULL;
+       const char **next = &p;
+       bool found;
+
+       found = asn_str2asn_internal(asstring, asn, next, NULL);
+       if (found_ptr)
+               *found_ptr = found;
+       return *next;
+}
+
+void asn_relax_as_zero(bool relax)
+{
+       relax_as_zero = relax;
+}
+
+enum match_type asn_str2asn_match(const char *str)
+{
+       bool found, partial = false;
+
+       found = asn_str2asn_internal(str, NULL, NULL, &partial);
+       if (found && !partial)
+               return exact_match;
+
+       if (partial)
+               return partly_match;
+
+       return no_match;
+}
diff --git a/lib/asn.h b/lib/asn.h
new file mode 100644 (file)
index 0000000..baaaf4d
--- /dev/null
+++ b/lib/asn.h
@@ -0,0 +1,48 @@
+/*
+ * AS number structure
+ * Copyright 2022 6WIND
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_ASN_H
+#define _FRR_ASN_H
+
+#include "zebra.h"
+#include "command_match.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ASN_STRING_MAX_SIZE    12
+
+typedef uint32_t as_t;
+
+extern bool asn_str2asn(const char *asstring, as_t *asn);
+extern const char *asn_asn2asplain(as_t asn);
+extern const char *asn_str2asn_parse(const char *asstring, as_t *asn,
+                                    bool *found_ptr);
+extern enum match_type asn_str2asn_match(const char *str);
+/* for test */
+extern void asn_relax_as_zero(bool relax);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ASN_H */
index 4e8194bbc6e854bc30efd3ab60dcd8fca9333125..3cab6a1e7ac1c0921fed99ff4bc478c4e3ae1037 100644 (file)
@@ -71,6 +71,7 @@ const struct message tokennames[] = {
        item(IPV6_PREFIX_TKN),
        item(MAC_TKN),
        item(MAC_PREFIX_TKN),
+       item(ASNUM_TKN),
        item(FORK_TKN),
        item(JOIN_TKN),
        item(START_TKN),
index 8f5d96053cb10fdf1df07222516d8071225d8292..0ee45cee55fa9d86be56759331bc482ae4a5a475 100644 (file)
@@ -403,7 +403,8 @@ struct cmd_node {
 #define DEBUG_STR "Debugging functions\n"
 #define UNDEBUG_STR "Disable debugging functions (see also 'debug')\n"
 #define ROUTER_STR "Enable a routing process\n"
-#define AS_STR "AS number\n"
+#define AS_STR                                                                 \
+       "AS number in plain  <1-4294967295> or dotted <0-65535>.<0-65535> format\n"
 #define MAC_STR "MAC address\n"
 #define MBGP_STR "MBGP information\n"
 #define MATCH_STR "Match values from routing table\n"
index 766d7e937197b051c907e36a412bdaf449f5f913..ee03ff85d4ed678340522b6b6b8527a5514d254d 100644 (file)
@@ -279,6 +279,7 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb)
        case END_TKN:
        case NEG_ONLY_TKN:
        case WORD_TKN:
+       case ASNUM_TKN:
                return true;
        }
 
@@ -548,6 +549,7 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
        case MAC_PREFIX_TKN:
        case END_TKN:
        case VARIABLE_TKN:
+       case ASNUM_TKN:
                color = "#ffffff";
                break;
        }
index b8c7a9c72cc7f260f392f7ac863417940afb420d..2ead2798e00dd0489bbdee85b0263008955b227a 100644 (file)
@@ -58,6 +58,7 @@ enum cmd_token_type {
        IPV6_PREFIX_TKN, // IPV6 network prefixes
        MAC_TKN,         // Ethernet address
        MAC_PREFIX_TKN,  // Ethernet address w/ CIDR mask
+       ASNUM_TKN,       // AS dot format
 
        /* plumbing types */
        FORK_TKN,  // marks subgraph beginning
index ec366ce7e178919eb91441144f078323b89e4ab6..60661b986df074cbd2b1e09a7c7a64418dce9fcb 100644 (file)
@@ -54,6 +54,7 @@ VARIABLE        [A-Z][-_A-Z:0-9]+
 WORD            (\-|\+)?[a-zA-Z0-9\*][-+_a-zA-Z0-9\*]*
 NUMBER          (\-|\+)?[0-9]{1,20}
 RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
+ASNUM           ASNUM
 
 /* yytext shall be a pointer */
 %pointer
@@ -73,6 +74,7 @@ RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
 %}
 
 [ \t]+          LOC_STEP /* ignore whitespace */;
+{ASNUM}         {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return ASNUM;}
 {IPV4}          {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4;}
 {IPV4_PREFIX}   {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4_PREFIX;}
 {IPV6}          {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV6;}
index 6c1d05d92657bdac6994d6838375f8e64c5284f1..3318e2c7e621a20c0d872955904365274c05cd17 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "command_match.h"
 #include "memory.h"
+#include "asn.h"
 
 DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack");
 
@@ -556,6 +557,7 @@ static enum match_type min_match_level(enum cmd_token_type type)
        case END_TKN:
        case NEG_ONLY_TKN:
        case VARIABLE_TKN:
+       case ASNUM_TKN:
                return exact_match;
        }
 
@@ -579,6 +581,7 @@ static int score_precedence(enum cmd_token_type type)
        case IPV6_PREFIX_TKN:
        case MAC_TKN:
        case MAC_PREFIX_TKN:
+       case ASNUM_TKN:
        case RANGE_TKN:
                return 2;
        case WORD_TKN:
@@ -713,6 +716,8 @@ static enum match_type match_token(struct cmd_token *token, char *input_token)
                return match_mac(input_token, false);
        case MAC_PREFIX_TKN:
                return match_mac(input_token, true);
+       case ASNUM_TKN:
+               return asn_str2asn_match(input_token);
        case END_TKN:
        case FORK_TKN:
        case JOIN_TKN:
@@ -855,7 +860,6 @@ static enum match_type match_ipv4_prefix(const char *str)
        return exact_match;
 }
 
-
 #define IPV6_ADDR_STR   "0123456789abcdefABCDEF:."
 #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./"
 #define STATE_START     1
index 35c119691bbbb2afd02af04c71bd4afd64d0f846..6de14d621fd975bb4450cf2d97eefd009f1d5784 100644 (file)
 %token <string> RANGE
 %token <string> MAC
 %token <string> MAC_PREFIX
+%token <string> ASNUM
 
 /* special syntax, value is irrelevant */
 %token <string> EXCL_BRACKET
@@ -293,6 +294,11 @@ placeholder_token_real:
   $$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
   XFREE (MTYPE_LEX, $1);
 }
+| ASNUM
+{
+  $$ = new_token_node (ctx, ASNUM_TKN, $1, doc_next(ctx));
+  XFREE (MTYPE_LEX, $1);
+}
 
 placeholder_token:
   placeholder_token_real varname_token
index cce9542e303cce766ac5d589fd4c8889df8360a3..a560453e6a8494d4d5eecadd75faaf494579c28e 100644 (file)
@@ -214,6 +214,7 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
                        item(IPV6_PREFIX_TKN); // IPV6 network prefixes
                        item(MAC_TKN);         // MAC address
                        item(MAC_PREFIX_TKN);  // MAC address with mask
+                       item(ASNUM_TKN);       // ASNUM
 
                        /* plumbing types */
                        item(FORK_TKN);
index 18e9825a7a302fa5cc6a59977c6747504f6e79f1..9a00cd01b1692ce683267d66440ff06f0aac01bb 100644 (file)
@@ -9,6 +9,7 @@ lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST
 lib_libfrr_la_SOURCES = \
        lib/agg_table.c \
        lib/atomlist.c \
+       lib/asn.c \
        lib/base64.c \
        lib/bfd.c \
        lib/buffer.c \
@@ -160,6 +161,7 @@ clippy_scan += \
 
 pkginclude_HEADERS += \
        lib/agg_table.h \
+       lib/asn.h \
        lib/atomlist.h \
        lib/base64.h \
        lib/bfd.h \
index 101c9a5ae376d0aea64c3ad196f7e19ff1de417e..cd399e93b5dc513e9a81ab7e458752a5ec6b5147 100644 (file)
@@ -64,6 +64,12 @@ _fail = (_end == argv[_i]->arg) || (*_end != '\\0');"""
     )
 
 
+class AsDotHandler(RenderHandler):
+    argtype = "as_t"
+    decl = Template("as_t $varname = 0;")
+    code = Template("_fail = !asn_str2asn(argv[_i]->arg, &$varname);")
+
+
 # A.B.C.D/M (prefix_ipv4) and
 # X:X::X:X/M (prefix_ipv6) are "compatible" and can merge into a
 # struct prefix:
@@ -165,6 +171,7 @@ handlers = {
     "IPV6_PREFIX_TKN": Prefix6Handler,
     "MAC_TKN": PrefixEthHandler,
     "MAC_PREFIX_TKN": PrefixEthHandler,
+    "ASNUM_TKN": AsDotHandler,
 }
 
 # core template invoked for each occurence of DEFPY.
index ef1fcf5cec1bd9c4a69ca4a5f73b7dfef002a8ab..0f6d5b023de4eeb7530f3b6aebb1415c4894ce4d 100644 (file)
@@ -924,7 +924,9 @@ static int validate(struct aspath *as, const struct test_spec *sp)
        bytes4 = aspath_put(s, as, 1);
        as4 = make_aspath(STREAM_DATA(s), bytes4, 1);
 
+       asn_relax_as_zero(true);
        asstr = aspath_str2aspath(sp->shouldbe);
+       asn_relax_as_zero(false);
 
        asconfeddel = aspath_delete_confed_seq(aspath_dup(asinout));
 
index acc984ced70cd20f9524da8018fa3215b4025396..8a46dfc10860909aa8512770a24f3381c36f4f98 100644 (file)
@@ -1688,7 +1688,7 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd,
 
 #ifdef HAVE_BGPD
 DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
-       "router bgp [(1-4294967295) [<view|vrf> VIEWVRFNAME]]",
+       "router bgp [ASNUM [<view|vrf> VIEWVRFNAME]]",
        ROUTER_STR BGP_STR AS_STR
        "BGP view\nBGP VRF\n"
        "View/VRF name\n")