]> git.proxmox.com Git - mirror_frr.git/commitdiff
lib: add CLI token for 48-bit mac addresses
authorQuentin Young <qlyoung@cumulusnetworks.com>
Tue, 8 Aug 2017 21:10:23 +0000 (17:10 -0400)
committerQuentin Young <qlyoung@cumulusnetworks.com>
Fri, 11 Aug 2017 16:42:01 +0000 (12:42 -0400)
Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
doc/cli.md
lib/command_graph.c
lib/command_graph.h
lib/command_lex.l
lib/command_match.c
lib/command_parse.y
lib/grammar_sandbox.c

index cfb4d629f953a3e408417c84fc00c139b30431a4..ef867362c393226fab97bc61b056ab93ac76ee40 100644 (file)
@@ -30,15 +30,17 @@ Characters allowed in each token type:
 Tokens
 ------
 * `WORD`        -- A token that begins with +, -, or a lowercase letter. It is
-                  an unchanging part of the command and will only match itself.
-                  Example: "show ip bgp", every token is a WORD.
+                   an unchanging part of the command and will only match itself.
+                   Example: "show ip bgp", 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`         -- 'M:A:C', matches a 48-bit mac address
+* `MAC_PREFIX`  -- 'M:A:C/M', matches a 48-bit mac address with a mask
 * `VARIABLE`    -- Begins with a capital letter. Matches any input.
 * `RANGE`       -- Numeric range delimited by parentheses, e.g. (-100 - 100) or
-                 (10-20). Will only match numbers in the range.
+                   (10-20). Will only match numbers in the range.
 
 Rules
 -----
index dc7233c1fe2df461dd5d6eadee7dbfeafaaeb9bb..fce11a70cc9053deed10e5f03611814ea7d33953 100644 (file)
@@ -379,6 +379,8 @@ static void cmd_node_names(struct graph_node *gn, struct graph_node *join,
        case IPV4_PREFIX_TKN:
        case IPV6_TKN:
        case IPV6_PREFIX_TKN:
+       case MAC_TKN:
+       case MAC_PREFIX_TKN:
                if (!tok->varname && prevname)
                        cmd_token_varname_set(tok, prevname);
                prevname = NULL;
index 879148844c5ec3cae2ef754e97323e9d488f9cb3..ec68e284ed308637442ec0a2c0f90ee776568b16 100644 (file)
@@ -42,14 +42,17 @@ struct vty;
  * The type determines what kind of data the token can match (in the
  * matching use case) or hold (in the argv use case).
  */
+/* clang-format off */
 enum cmd_token_type {
-       WORD_TKN,       // words
+       WORD_TKN,        // words
        VARIABLE_TKN,    // almost anything
        RANGE_TKN,       // integer range
-       IPV4_TKN,       // IPV4 addresses
+       IPV4_TKN,        // IPV4 addresses
        IPV4_PREFIX_TKN, // IPV4 network prefixes
-       IPV6_TKN,       // IPV6 prefixes
+       IPV6_TKN,        // IPV6 prefixes
        IPV6_PREFIX_TKN, // IPV6 network prefixes
+       MAC_TKN,         // Ethernet address
+       MAC_PREFIX_TKN,  // Ethernet address w/ CIDR mask
 
        /* plumbing types */
        FORK_TKN,  // marks subgraph beginning
@@ -59,6 +62,7 @@ enum cmd_token_type {
 
        SPECIAL_TKN = FORK_TKN,
 };
+/* clang-format on */
 
 #define IS_VARYING_TOKEN(x) ((x) >= VARIABLE_TKN && (x) < FORK_TKN)
 
index fddbf7b2873cf314ead02a7c7a475926fc419352..59d0d840a88a8325cd1b66aa6bb794d99b291544 100644 (file)
@@ -40,6 +40,8 @@ IPV4            A\.B\.C\.D
 IPV4_PREFIX     A\.B\.C\.D\/M
 IPV6            X:X::X:X
 IPV6_PREFIX     X:X::X:X\/M
+MAC             M:A:C
+MAC_PREFIX      M:A:C\/M
 VARIABLE        [A-Z][-_a-zA-Z:0-9]+
 NUMBER          (\-|\+)?[0-9]{1,20}
 RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
@@ -67,6 +69,8 @@ RANGE           \({NUMBER}[ ]?\-[ ]?{NUMBER}\)
 {IPV4_PREFIX}   {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV4_PREFIX;}
 {IPV6}          {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV6;}
 {IPV6_PREFIX}   {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return IPV6_PREFIX;}
+{MAC}           {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return MAC;}
+{MAC_PREFIX}    {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return MAC_PREFIX;}
 {VARIABLE}      {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return VARIABLE;}
 {RANGE}         {yylval->string = XSTRDUP(MTYPE_LEX, yytext); return RANGE;}
 .               {return yytext[0];}
index bc54f1bb09bb915a2ed74f7b493c4efe7a627394..f07448d716c4783cfbeb3b7a3189100209a6f0b0 100644 (file)
@@ -78,6 +78,8 @@ static enum match_type match_word(struct cmd_token *, const char *);
 
 static enum match_type match_variable(struct cmd_token *, const char *);
 
+static enum match_type match_mac(const char *, bool);
+
 /* matching functions */
 static enum matcher_rv matcher_rv;
 
@@ -537,6 +539,8 @@ static int score_precedence(enum cmd_token_type type)
        case IPV4_PREFIX_TKN:
        case IPV6_TKN:
        case IPV6_PREFIX_TKN:
+       case MAC_TKN:
+       case MAC_PREFIX_TKN:
        case RANGE_TKN:
                return 2;
        case WORD_TKN:
@@ -658,6 +662,10 @@ static enum match_type match_token(struct cmd_token *token, char *input_token)
                return match_range(token, input_token);
        case VARIABLE_TKN:
                return match_variable(token, input_token);
+       case MAC_TKN:
+               return match_mac(input_token, false);
+       case MAC_PREFIX_TKN:
+               return match_mac(input_token, true);
        case END_TKN:
        default:
                return no_match;
@@ -964,3 +972,50 @@ static enum match_type match_variable(struct cmd_token *token, const char *word)
        assert(token->type == VARIABLE_TKN);
        return exact_match;
 }
+
+#define MAC_CHARS "ABCDEFabcdef0123456789:"
+
+static enum match_type match_mac(const char *word, bool prefix)
+{
+       /* 6 2-digit hex numbers separated by 5 colons */
+       size_t mac_explen = 6 * 2 + 5;
+       /* '/' + 2-digit integer */
+       size_t mask_len = 1 + 2;
+       unsigned int i;
+       char *eptr;
+       unsigned int maskval;
+
+       /* length check */
+       if (strlen(word) > mac_explen + (prefix ? mask_len : 0))
+               return no_match;
+
+       /* address check */
+       for (i = 0; i < mac_explen; i++) {
+               if (word[i] == '\0' || !strchr(MAC_CHARS, word[i]))
+                       break;
+               if (((i + 1) % 3 == 0) != (word[i] == ':'))
+                       return no_match;
+       }
+
+       /* incomplete address */
+       if (i < mac_explen && word[i] == '\0')
+               return partly_match;
+       else if (i < mac_explen)
+               return no_match;
+
+       /* mask check */
+       if (prefix && word[i] == '/') {
+               if (word[++i] == '\0')
+                       return partly_match;
+
+               maskval = strtoul(&word[i], &eptr, 10);
+               if (*eptr != '\0' || maskval > 48)
+                       return no_match;
+       } else if (prefix && word[i] == '\0') {
+               return partly_match;
+       } else if (prefix) {
+               return no_match;
+       }
+
+       return exact_match;
+}
index 1bc8ea1a445336f89c0a5da09908cf00ab7a21ff..0f3e42219ed86ce9766e6a5aade75db6ec5d0a99 100644 (file)
 %token <string> IPV6_PREFIX
 %token <string> VARIABLE
 %token <string> RANGE
+%token <string> MAC
+%token <string> MAC_PREFIX
 
 /* union types for parsed rules */
 %type <node> start
@@ -273,6 +275,16 @@ placeholder_token_real:
 
   XFREE (MTYPE_LEX, $1);
 }
+| MAC
+{
+  $$ = new_token_node (ctx, MAC_TKN, $1, doc_next(ctx));
+  XFREE (MTYPE_LEX, $1);
+}
+| MAC_PREFIX
+{
+  $$ = new_token_node (ctx, MAC_PREFIX_TKN, $1, doc_next(ctx));
+  XFREE (MTYPE_LEX, $1);
+}
 
 placeholder_token:
   placeholder_token_real varname_token
index 8dd8d2e2bb28c1b8a6c20b661fcf3915f78885c7..96ecfa44d385d7f090217c9f0ecb4952c74390e8 100644 (file)
@@ -498,6 +498,8 @@ struct message tokennames[] = {item(WORD_TKN),      // words
                               item(IPV4_PREFIX_TKN), // IPV4 network prefixes
                               item(IPV6_TKN),  // IPV6 prefixes
                               item(IPV6_PREFIX_TKN), // IPV6 network prefixes
+                              item(MAC_TKN),    // MAC address
+                              item(MAC_PREFIX_TKN),  // MAC address w/ mask
 
                               /* plumbing types */
                               item(FORK_TKN),