]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: add as-notation keyword to 'router bgp' vty command
authorPhilippe Guibert <philippe.guibert@6wind.com>
Thu, 3 Nov 2022 20:17:57 +0000 (21:17 +0100)
committerPhilippe Guibert <philippe.guibert@6wind.com>
Fri, 10 Feb 2023 09:27:23 +0000 (10:27 +0100)
A new keyword permits changing the BGP as-notation output:
- [no] router bgp <> [vrf BLABLA] [as-notation [<dot|plain|dot+>]]

At the BGP instance creation, the output will inherit the way the
BGP instance is declared. For instance, the 'router bgp 1.1'
command will configure the output in the dot format. However, if
the client wants to choose an alternate output, he will have to
add the extra command: 'router bgp 1.1 as-notation dot+'.

Also, if the user wants to have plain format, even if the BGP
instance is declared in dot format, the keyword can also be used
for that.

The as-notation output is only taken into account at the BGP
instance creation. In the case where VPN instances are used,
a separate instance may be dynamically created. In that case,
the real as-notation format will be taken into acccount at the
first configuration.

Linking the as-notation format with the BGP instance makes sense,
as the operators want to keep consistency of what they configure.

One technical reason why to link the as-notation output with the
BGP instance creation is that the as-path segment lists stored
in the BGP updates use a string representation to handle aspath
operations (by using regexp for instance). Changing on the fly
the output needs to regenerate this string representation to the
correct format. Linking the configuration to the BGP instance
creation avoids refreshing the BGP updates. A similar mechanism
is put in place in junos too.

Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
12 files changed:
bgpd/bgp_evpn.c
bgpd/bgp_vty.c
bgpd/bgp_vty.h
bgpd/bgpd.c
bgpd/bgpd.h
doc/user/bgp.rst
lib/asn.c
lib/asn.h
tests/bgpd/test_capability.c
tests/bgpd/test_mp_attr.c
tests/bgpd/test_packet.c
vtysh/vtysh.c

index 6ccd64dba4670c7221c63522364e9dc8e3112ec4..323256816b6de68db36a80c2b3134efd0476af1a 100644 (file)
@@ -6254,7 +6254,7 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
                                  vrf_id == VRF_DEFAULT
                                          ? BGP_INSTANCE_TYPE_DEFAULT
                                          : BGP_INSTANCE_TYPE_VRF,
-                                 NULL);
+                                 NULL, ASNOTATION_UNDEFINED);
                switch (ret) {
                case BGP_ERR_AS_MISMATCH:
                        flog_err(EC_BGP_EVPN_AS_MISMATCH,
index 8af3f65f45f2ebd359ae1da64e75d0e15c58f6a4..a1fda80ad9bbce46a332bb976e67f91035599b1b 100644 (file)
@@ -595,9 +595,10 @@ static const char *get_bgp_default_af_flag(afi_t afi, safi_t safi)
 }
 
 int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
-               enum bgp_instance_type inst_type, const char *as_pretty)
+               enum bgp_instance_type inst_type, const char *as_pretty,
+               enum asnotation_mode asnotation)
 {
-       int ret = bgp_get(bgp, as, name, inst_type, as_pretty);
+       int ret = bgp_get(bgp, as, name, inst_type, as_pretty, asnotation);
 
        if (ret == BGP_CREATED) {
                bgp_timers_set(*bgp, DFLT_BGP_KEEPALIVE, DFLT_BGP_HOLDTIME,
@@ -1481,16 +1482,23 @@ DEFUN (no_auto_summary,
 /* "router bgp" commands. */
 DEFUN_NOSH (router_bgp,
        router_bgp_cmd,
-       "router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME]]",
+       "router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
        ROUTER_STR
        BGP_STR
        AS_STR
-       BGP_INSTANCE_HELP_STR)
+       BGP_INSTANCE_HELP_STR
+       "Force the AS notation output\n"
+       "use 'AA.BB' format for AS 4 byte values\n"
+       "use 'AA.BB' format for all AS values\n"
+       "use plain format for all AS values\n")
 {
        int idx_asn = 2;
        int idx_view_vrf = 3;
        int idx_vrf = 4;
        int is_new_bgp = 0;
+       int idx_asnotation = 3;
+       int idx_asnotation_kind = 4;
+       enum asnotation_mode asnotation = ASNOTATION_UNDEFINED;
        int ret;
        as_t as;
        struct bgp *bgp;
@@ -1526,23 +1534,40 @@ DEFUN_NOSH (router_bgp,
                                BGP_PRIVATE_AS_MAX, BGP_AS4_MAX, as);
 
                inst_type = BGP_INSTANCE_TYPE_DEFAULT;
-               if (argc > 3) {
-                       name = argv[idx_vrf]->arg;
 
-                       if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
-                               if (strmatch(name, VRF_DEFAULT_NAME))
-                                       name = NULL;
-                               else
-                                       inst_type = BGP_INSTANCE_TYPE_VRF;
-                       } else if (!strcmp(argv[idx_view_vrf]->text, "view"))
-                               inst_type = BGP_INSTANCE_TYPE_VIEW;
+               if (argv_find(argv, argc, "VIEWVRFNAME", &idx_vrf)) {
+                       idx_view_vrf = idx_vrf - 1;
+                       if (argv[idx_view_vrf]->text) {
+                               name = argv[idx_vrf]->arg;
+
+                               if (!strcmp(argv[idx_view_vrf]->text, "vrf")) {
+                                       if (strmatch(name, VRF_DEFAULT_NAME))
+                                               name = NULL;
+                                       else
+                                               inst_type =
+                                                       BGP_INSTANCE_TYPE_VRF;
+                               } else if (!strcmp(argv[idx_view_vrf]->text,
+                                                  "view"))
+                                       inst_type = BGP_INSTANCE_TYPE_VIEW;
+                       }
+               }
+               if (argv_find(argv, argc, "as-notation", &idx_asnotation)) {
+                       idx_asnotation_kind = idx_asnotation + 1;
+                       if (strmatch(argv[idx_asnotation_kind]->text, "dot+"))
+                               asnotation = ASNOTATION_DOTPLUS;
+                       else if (strmatch(argv[idx_asnotation_kind]->text,
+                                         "dot"))
+                               asnotation = ASNOTATION_DOT;
+                       else if (strmatch(argv[idx_asnotation_kind]->text,
+                                         "plain"))
+                               asnotation = ASNOTATION_PLAIN;
                }
 
                if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        is_new_bgp = (bgp_lookup(as, name) == NULL);
 
                ret = bgp_get_vty(&bgp, &as, name, inst_type,
-                                 argv[idx_asn]->arg);
+                                 argv[idx_asn]->arg, asnotation);
                switch (ret) {
                case BGP_ERR_AS_MISMATCH:
                        vty_out(vty, "BGP is already running; AS is %s\n",
@@ -1569,6 +1594,19 @@ DEFUN_NOSH (router_bgp,
                        bgp_vpn_leak_export(bgp);
                /* Pending: handle when user tries to change a view to vrf n vv.
                 */
+               /* for pre-existing bgp instance,
+                * - update as_pretty
+                * - update asnotation if explicitly mentioned
+                */
+               if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
+                       XFREE(MTYPE_BGP, bgp->as_pretty);
+                       bgp->as_pretty = XSTRDUP(MTYPE_BGP, argv[idx_asn]->arg);
+                       if (!CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION) &&
+                           asnotation != ASNOTATION_UNDEFINED) {
+                               SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+                               bgp->asnotation = asnotation;
+                       }
+               }
        }
 
        /* unset the auto created flag as the user config is now present */
@@ -1581,12 +1619,16 @@ DEFUN_NOSH (router_bgp,
 /* "no router bgp" commands. */
 DEFUN (no_router_bgp,
        no_router_bgp_cmd,
-       "no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME]]",
+       "no router bgp [ASNUM$instasn [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
        NO_STR
        ROUTER_STR
        BGP_STR
        AS_STR
-       BGP_INSTANCE_HELP_STR)
+       BGP_INSTANCE_HELP_STR
+       "Force the AS notation output\n"
+       "use 'AA.BB' format for AS 4 byte values\n"
+       "use 'AA.BB' format for all AS values\n"
+       "use plain format for all AS values\n")
 {
        int idx_asn = 3;
        int idx_vrf = 5;
@@ -1851,7 +1893,6 @@ DEFPY (bgp_suppress_fib_pending,
        return CMD_SUCCESS;
 }
 
-
 /* BGP Cluster ID.  */
 DEFUN (bgp_cluster_id,
        bgp_cluster_id_cmd,
@@ -9529,7 +9570,8 @@ DEFPY(af_import_vrf_route_map, af_import_vrf_route_map_cmd,
 
                /* Auto-create assuming the same AS */
                ret = bgp_get_vty(&bgp_default, &as, NULL,
-                                 BGP_INSTANCE_TYPE_DEFAULT, NULL);
+                                 BGP_INSTANCE_TYPE_DEFAULT, NULL,
+                                 ASNOTATION_UNDEFINED);
 
                if (ret) {
                        vty_out(vty,
@@ -9641,7 +9683,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
        if (!bgp_default) {
                /* Auto-create assuming the same AS */
                ret = bgp_get_vty(&bgp_default, &as, NULL,
-                                 BGP_INSTANCE_TYPE_DEFAULT, NULL);
+                                 BGP_INSTANCE_TYPE_DEFAULT, NULL,
+                                 ASNOTATION_UNDEFINED);
 
                if (ret) {
                        vty_out(vty,
@@ -9656,8 +9699,8 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
                        vrf_bgp = bgp_default;
                else
                        /* Auto-create assuming the same AS */
-                       ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type, NULL);
-
+                       ret = bgp_get_vty(&vrf_bgp, &as, import_name, bgp_type,
+                                         NULL, ASNOTATION_UNDEFINED);
                if (ret) {
                        vty_out(vty,
                                "VRF %s is not configured as a bgp instance\n",
@@ -17996,6 +18039,10 @@ int bgp_config_write(struct vty *vty)
                        vty_out(vty, " %s %s",
                                (bgp->inst_type  == BGP_INSTANCE_TYPE_VIEW)
                                ? "view" : "vrf", bgp->name);
+               if (CHECK_FLAG(bgp->config, BGP_CONFIG_ASNOTATION))
+                       vty_out(vty, " as-notation %s",
+                               asn_mode2str(bgp->asnotation));
+
                vty_out(vty, "\n");
 
                /* BGP fast-external-failover. */
index 8ed7c965e4f5be9d7450a4a983bebd63db86e8e3..d75eed2ddabbe826a3ea79f3bb693484d4ee2af4 100644 (file)
@@ -150,7 +150,8 @@ extern void bgp_vty_init(void);
 extern void community_alias_vty(void);
 extern const char *get_afi_safi_str(afi_t afi, safi_t safi, bool for_json);
 extern int bgp_get_vty(struct bgp **bgp, as_t *as, const char *name,
-                      enum bgp_instance_type inst_type, const char *as_pretty);
+                      enum bgp_instance_type inst_type, const char *as_pretty,
+                      enum asnotation_mode asnotation);
 extern void bgp_config_write_update_delay(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_wpkt_quanta(struct vty *vty, struct bgp *bgp);
 extern void bgp_config_write_rpkt_quanta(struct vty *vty, struct bgp *bgp);
index 32f169e3427a63213069f6d5b2ee1b1c358a32ba..565cbccee4a820d1194d24717541673d1bffe032 100644 (file)
@@ -3190,7 +3190,8 @@ static void bgp_vrf_string_name_delete(void *data)
 /* BGP instance creation by `router bgp' commands. */
 static struct bgp *bgp_create(as_t *as, const char *name,
                              enum bgp_instance_type inst_type,
-                             const char *as_pretty)
+                             const char *as_pretty,
+                             enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        afi_t afi;
@@ -3203,6 +3204,12 @@ static struct bgp *bgp_create(as_t *as, const char *name,
        else
                bgp->as_pretty = XSTRDUP(MTYPE_BGP, asn_asn2asplain(*as));
 
+       if (asnotation != ASNOTATION_UNDEFINED) {
+               bgp->asnotation = asnotation;
+               SET_FLAG(bgp->config, BGP_CONFIG_ASNOTATION);
+       } else
+               asn_str2asn_notation(bgp->as_pretty, NULL, &bgp->asnotation);
+
        if (BGP_DEBUG(zebra, ZEBRA)) {
                if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
                        zlog_debug("Creating Default VRF, AS %s",
@@ -3525,7 +3532,8 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *name,
 
 /* Called from VTY commands. */
 int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
-           enum bgp_instance_type inst_type, const char *as_pretty)
+           enum bgp_instance_type inst_type, const char *as_pretty,
+           enum asnotation_mode asnotation)
 {
        struct bgp *bgp;
        struct vrf *vrf = NULL;
@@ -3535,7 +3543,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
        if (ret || *bgp_val)
                return ret;
 
-       bgp = bgp_create(as, name, inst_type, as_pretty);
+       bgp = bgp_create(as, name, inst_type, as_pretty, asnotation);
 
        /*
         * view instances will never work inside of a vrf
index 4efeb0e9efe64a4416642356c07505180965efbe..634c4cf1d1d96bd2d359ba958d25279abe17a52a 100644 (file)
@@ -399,6 +399,7 @@ struct bgp {
        uint16_t config;
 #define BGP_CONFIG_CLUSTER_ID             (1 << 0)
 #define BGP_CONFIG_CONFEDERATION          (1 << 1)
+#define BGP_CONFIG_ASNOTATION             (1 << 2)
 
        /* BGP router identifier.  */
        struct in_addr router_id;
@@ -798,6 +799,8 @@ struct bgp {
 
        bool allow_martian;
 
+       enum asnotation_mode asnotation;
+
        QOBJ_FIELDS;
 };
 DECLARE_QOBJ_TYPE(bgp);
@@ -2163,7 +2166,8 @@ extern void bgp_option_norib_set_runtime(void);
 extern void bgp_option_norib_unset_runtime(void);
 
 extern int bgp_get(struct bgp **bgp, as_t *as, const char *name,
-                  enum bgp_instance_type kind, const char *as_pretty);
+                  enum bgp_instance_type kind, const char *as_pretty,
+                  enum asnotation_mode asnotation);
 extern void bgp_instance_up(struct bgp *);
 extern void bgp_instance_down(struct bgp *);
 extern int bgp_delete(struct bgp *);
index b17442f64160c65747a68f1ac0499314d36003a0..4e887eecf005e6acbf41f72e0efa42c342e7d637 100644 (file)
@@ -254,8 +254,9 @@ ASN and Router ID
 -----------------
 
 First of all you must configure BGP router with the :clicmd:`router bgp ASN`
-command. The AS number is an identifier for the autonomous system. The BGP
-protocol uses the AS number for detecting whether the BGP connection is
+command. The AS number is an identifier for the autonomous system. The AS
+identifier can either be a number or two numbers separated by a period. The
+BGP protocol uses the AS identifier for detecting whether the BGP connection is
 internal or external.
 
 .. clicmd:: router bgp ASN
@@ -4289,6 +4290,26 @@ Segment-Routing IPv6
      vpn_policy[AFI_IP].tovpn_sid: none
      vpn_policy[AFI_IP6].tovpn_sid: 2001:db8:1:1::200
 
+AS-notation support
+-------------------
+
+By default, the ASN value output follows how the BGP ASN instance is
+expressed in the configuration. Three as-notation outputs are available:
+
+- plain output: both AS4B and AS2B use a single number.
+  ` router bgp 65536`.
+
+- dot output: AS4B values are using two numbers separated by a period.
+  `router bgp 1.1` means that the AS number is 65536.
+
+- dot+ output: AS2B and AS4B values are using two numbers separated by a
+  period. `router bgp 0.5` means that the AS number is 5.
+
+The below option permits forcing the as-notation output:
+
+.. clicmd:: router bgp ASN as-notation dot|dot+|plain
+
+   The chosen as-notation format will override the BGP ASN output.
 
 .. _bgp-route-reflector:
 
index 7a786866cb9b31f9f87ff1dfdcd2837c952ca673..502854ec95fb31a6a70ed43c65bec83fd0761017 100644 (file)
--- a/lib/asn.c
+++ b/lib/asn.c
 
 static bool relax_as_zero;
 
+static const struct message asnotation_mode_msg[] = {
+       {ASNOTATION_PLAIN, "plain"},
+       {ASNOTATION_DOT, "dot"},
+       {ASNOTATION_DOTPLUS, "dot+"},
+       {ASNOTATION_UNDEFINED, "undefined"},
+       {0}
+};
+
 /* 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)
+                                const char **next, bool *partial,
+                                enum asnotation_mode *mode)
 {
        uint32_t high = 0, low = 0;
        uint64_t temp_val;
        const char *p = asstring;
        bool ret = false;
        uint32_t digit;
+       enum asnotation_mode val = ASNOTATION_PLAIN;
 
        if (!asstring)
                goto end;
@@ -82,12 +92,13 @@ static bool asn_str2asn_internal(const char *asstring, as_t *asn,
                                *partial = true;
                        goto end;
                }
-               if (!asn) {
-                       ret = true;
-                       goto end;
-               }
-               *asn = (high << 16) + low;
+               if (asn)
+                       *asn = (high << 16) + low;
                ret = true;
+               if (high == 0)
+                       val = ASNOTATION_DOTPLUS;
+               else
+                       val = ASNOTATION_DOT;
                goto end;
        }
        /* AS 0 is forbidden */
@@ -102,12 +113,14 @@ static bool asn_str2asn_internal(const char *asstring, as_t *asn,
  end:
        if (next)
                *next = p;
+       if (mode)
+               *mode = val;
        return ret;
 }
 
 bool asn_str2asn(const char *asstring, as_t *asn)
 {
-       return asn_str2asn_internal(asstring, asn, NULL, NULL);
+       return asn_str2asn_internal(asstring, asn, NULL, NULL, NULL);
 }
 
 const char *asn_asn2asplain(as_t asn)
@@ -124,7 +137,7 @@ const char *asn_str2asn_parse(const char *asstring, as_t *asn, bool *found_ptr)
        const char **next = &p;
        bool found;
 
-       found = asn_str2asn_internal(asstring, asn, next, NULL);
+       found = asn_str2asn_internal(asstring, asn, next, NULL, NULL);
        if (found_ptr)
                *found_ptr = found;
        return *next;
@@ -139,7 +152,7 @@ enum match_type asn_str2asn_match(const char *str)
 {
        bool found, partial = false;
 
-       found = asn_str2asn_internal(str, NULL, NULL, &partial);
+       found = asn_str2asn_internal(str, NULL, NULL, &partial, NULL);
        if (found && !partial)
                return exact_match;
 
@@ -148,3 +161,15 @@ enum match_type asn_str2asn_match(const char *str)
 
        return no_match;
 }
+
+bool asn_str2asn_notation(const char *asstring, as_t *asn,
+                         enum asnotation_mode *asnotation)
+{
+       return asn_str2asn_internal(asstring, asn, NULL, NULL, asnotation);
+}
+
+const char *asn_mode2str(enum asnotation_mode asnotation)
+{
+       return lookup_msg(asnotation_mode_msg, asnotation,
+                         "Unrecognized AS notation mode");
+}
index baaaf4d8075336ab0c404050f7324e452003eda1..2884aafd542b9d92795b4aae56d295c7e614385a 100644 (file)
--- a/lib/asn.h
+++ b/lib/asn.h
@@ -31,6 +31,13 @@ extern "C" {
 
 #define ASN_STRING_MAX_SIZE    12
 
+enum asnotation_mode {
+       ASNOTATION_PLAIN = 0,
+       ASNOTATION_DOT,
+       ASNOTATION_DOTPLUS,
+       ASNOTATION_UNDEFINED,
+};
+
 typedef uint32_t as_t;
 
 extern bool asn_str2asn(const char *asstring, as_t *asn);
@@ -38,6 +45,9 @@ 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);
+extern bool asn_str2asn_notation(const char *asstring, as_t *asn,
+                                enum asnotation_mode *asnotation);
+extern const char *asn_mode2str(enum asnotation_mode asnotation);
 /* for test */
 extern void asn_relax_as_zero(bool relax);
 
index 5a63758d060e758a9ffaf810e6127af9d047ff0f..6257d2517a3126e5cf8e4c8f262ec788d21670a0 100644 (file)
@@ -952,8 +952,8 @@ int main(void)
        if (fileno(stdout) >= 0)
                tty = isatty(fileno(stdout));
 
-       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT,
-                   NULL) < 0)
+       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+                   ASNOTATION_PLAIN) < 0)
                return -1;
 
        peer = peer_create_accept(bgp);
index 3f6401a2a3d60d13f1f36f1145240b2dc1a963d8..0b2c182e60b4004236c0415c9c0d2cbc6fb6f3ee 100644 (file)
@@ -1094,8 +1094,8 @@ int main(void)
        if (fileno(stdout) >= 0)
                tty = isatty(fileno(stdout));
 
-       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT,
-                   NULL) < 0)
+       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+                   ASNOTATION_PLAIN) < 0)
                return -1;
 
        peer = peer_create_accept(bgp);
index cf91f5570f94586bf0f0a0198d2e163c0f3e7b3e..e1263ed375fe6ded5663431f0cd016366d2aa1c9 100644 (file)
@@ -63,8 +63,8 @@ int main(int argc, char *argv[])
        vrf_init(NULL, NULL, NULL, NULL);
        bgp_option_set(BGP_OPT_NO_LISTEN);
 
-       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT,
-                   NULL) < 0)
+       if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT, NULL,
+                   ASNOTATION_PLAIN) < 0)
                return -1;
 
        peer = peer_create_accept(bgp);
index 8a46dfc10860909aa8512770a24f3381c36f4f98..b29e1895118d1a9a2f15dce4b547ccb3680c73de 100644 (file)
@@ -1688,10 +1688,14 @@ DEFUNSH(VTYSH_ZEBRA, srv6_locator, srv6_locator_cmd,
 
 #ifdef HAVE_BGPD
 DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd,
-       "router bgp [ASNUM [<view|vrf> VIEWVRFNAME]]",
+       "router bgp [ASNUM [<view|vrf> VIEWVRFNAME] [as-notation <dot|dot+|plain>]]",
        ROUTER_STR BGP_STR AS_STR
        "BGP view\nBGP VRF\n"
-       "View/VRF name\n")
+       "View/VRF name\n"
+       "Force the AS notation output\n"
+       "use 'AA.BB' format for AS 4 byte values\n"
+       "use 'AA.BB' format for all AS values\n"
+       "use plain format for all AS values\n")
 {
        vty->node = BGP_NODE;
        return CMD_SUCCESS;