diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/asn.c | 260 | ||||
| -rw-r--r-- | lib/asn.h | 81 | ||||
| -rw-r--r-- | lib/command.c | 1 | ||||
| -rw-r--r-- | lib/command.h | 3 | ||||
| -rw-r--r-- | lib/command_graph.c | 2 | ||||
| -rw-r--r-- | lib/command_graph.h | 1 | ||||
| -rw-r--r-- | lib/command_lex.l | 2 | ||||
| -rw-r--r-- | lib/command_match.c | 6 | ||||
| -rw-r--r-- | lib/command_parse.y | 6 | ||||
| -rw-r--r-- | lib/command_py.c | 1 | ||||
| -rw-r--r-- | lib/prefix.h | 5 | ||||
| -rw-r--r-- | lib/subdir.am | 2 |
12 files changed, 367 insertions, 3 deletions
diff --git a/lib/asn.c b/lib/asn.c new file mode 100644 index 0000000000..c64666375d --- /dev/null +++ b/lib/asn.c @@ -0,0 +1,260 @@ +/* + * 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; + +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, + 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; + + 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) + *asn = (high << 16) + low; + ret = true; + if (high == 0) + val = ASNOTATION_DOTPLUS; + else + val = ASNOTATION_DOT; + 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; + if (mode) + *mode = val; + return ret; +} + +static void asn_asn2asdot(as_t asn, char *asstring, size_t len) +{ + uint16_t low, high; + + high = (asn >> 16) & 0xffff; + low = asn & 0xffff; + snprintf(asstring, len, "%hu.%hu", high, low); +} + +bool asn_str2asn(const char *asstring, as_t *asn) +{ + return asn_str2asn_internal(asstring, asn, NULL, 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, 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, NULL); + if (found && !partial) + return exact_match; + + if (partial) + return partly_match; + + 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"); +} + +void asn_asn2json(json_object *json, const char *attr, + as_t asn, enum asnotation_mode asnotation) +{ + static char as_str[ASN_STRING_MAX_SIZE]; + + if ((asnotation == ASNOTATION_PLAIN) || + ((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX)) + json_object_int_add(json, attr, asn); + else { + asn_asn2asdot(asn, as_str, sizeof(as_str)); + json_object_string_add(json, attr, as_str); + } +} + +void asn_asn2json_array(json_object *jseg_list, as_t asn, + enum asnotation_mode asnotation) +{ + static char as_str[ASN_STRING_MAX_SIZE]; + + if ((asnotation == ASNOTATION_PLAIN) || + ((asnotation == ASNOTATION_DOT) && asn < UINT16_MAX)) + json_object_array_add(jseg_list, + json_object_new_int64(asn)); + else { + asn_asn2asdot(asn, as_str, sizeof(as_str)); + json_array_string_add(jseg_list, as_str); + } +} + +char *asn_asn2string(const as_t *asn, char *buf, size_t len, + enum asnotation_mode asnotation) +{ + if ((asnotation == ASNOTATION_PLAIN) || + ((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX)) + snprintf(buf, len, "%u", *asn); + else + asn_asn2asdot(*asn, buf, len); + return buf; +} + +static ssize_t printfrr_asnotation(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr, + enum asnotation_mode asnotation) +{ + /* for alignemnt up to 33 chars - %33pASD for instance - */ + char as_str[ASN_STRING_MAX_SIZE*3]; + const as_t *asn; + + if (!ptr) + return bputs(buf, "(null)"); + asn = ptr; + asn_asn2string(asn, as_str, sizeof(as_str), asnotation); + return bputs(buf, as_str); +} + +printfrr_ext_autoreg_p("ASP", printfrr_asplain); +static ssize_t printfrr_asplain(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_PLAIN); +} + +printfrr_ext_autoreg_p("ASD", printfrr_asdot); +static ssize_t printfrr_asdot(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOT); +} + +printfrr_ext_autoreg_p("ASE", printfrr_asdotplus); +static ssize_t printfrr_asdotplus(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + return printfrr_asnotation(buf, ea, ptr, ASNOTATION_DOTPLUS); +} diff --git a/lib/asn.h b/lib/asn.h new file mode 100644 index 0000000000..81a42c658d --- /dev/null +++ b/lib/asn.h @@ -0,0 +1,81 @@ +/* + * 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" +#include "json.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#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); +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); +void asn_asn2json_array(json_object *jseg_list, as_t asn, + enum asnotation_mode asnotation); +void asn_asn2json(json_object *jseg_list, const char *attr, + as_t asn, enum asnotation_mode asnotation); +extern char *asn_asn2string(const as_t *as, char *buf, size_t len, + enum asnotation_mode asnotation); +/* display AS in appropriate format */ +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pASP" (as_t *) +#pragma FRR printfrr_ext "%pASD" (as_t *) +#pragma FRR printfrr_ext "%pASE" (as_t *) +#endif + +#define ASN_FORMAT(mode) \ + ((mode == ASNOTATION_DOT) ? "%pASD" : \ + ((mode == ASNOTATION_DOTPLUS) ? "%pASE" : \ + "%pASP")) +#define ASN_FORMAT_SPACE(mode) \ + ((mode == ASNOTATION_DOT) ? "%10pASD" : \ + ((mode == ASNOTATION_DOTPLUS) ? "%10pASE" : \ + "%10pASP")) + +/* for test */ +extern void asn_relax_as_zero(bool relax); + +#ifdef __cplusplus +} +#endif + +#endif /* _FRR_ASN_H */ diff --git a/lib/command.c b/lib/command.c index cf96df6f95..ee5a3889e8 100644 --- a/lib/command.c +++ b/lib/command.c @@ -56,6 +56,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), diff --git a/lib/command.h b/lib/command.h index 2121bfd623..6538e56588 100644 --- a/lib/command.h +++ b/lib/command.h @@ -391,7 +391,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" diff --git a/lib/command_graph.c b/lib/command_graph.c index 850fdeafcd..ff3c11db69 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -266,6 +266,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; } @@ -535,6 +536,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; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 8e84fa928d..25aa47db7b 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -45,6 +45,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 diff --git a/lib/command_lex.l b/lib/command_lex.l index 64f74498b8..dc89191c13 100644 --- a/lib/command_lex.l +++ b/lib/command_lex.l @@ -38,6 +38,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 @@ -57,6 +58,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;} diff --git a/lib/command_match.c b/lib/command_match.c index 5ed643bc91..ff3c48fc31 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -10,6 +10,7 @@ #include "command_match.h" #include "memory.h" +#include "asn.h" DEFINE_MTYPE_STATIC(LIB, CMD_MATCHSTACK, "Command Match Stack"); @@ -541,6 +542,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; } @@ -564,6 +566,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: @@ -698,6 +701,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: @@ -840,7 +845,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 diff --git a/lib/command_parse.y b/lib/command_parse.y index a29e090ef0..8867e98ccc 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -88,6 +88,7 @@ %token <string> RANGE %token <string> MAC %token <string> MAC_PREFIX +%token <string> ASNUM /* special syntax, value is irrelevant */ %token <string> EXCL_BRACKET @@ -277,6 +278,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 diff --git a/lib/command_py.c b/lib/command_py.c index ceea5883d5..f8abcf8ef4 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -201,6 +201,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); diff --git a/lib/prefix.h b/lib/prefix.h index 1fd652507f..a6435be1b4 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -644,7 +644,10 @@ static inline bool ipv4_mcast_ssm(const struct in_addr *addr) #pragma FRR printfrr_ext "%pFX" (struct prefix_eth *) #pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *) #pragma FRR printfrr_ext "%pFX" (struct prefix_fs *) -#pragma FRR printfrr_ext "%pRD" (struct prefix_rd *) +#pragma FRR printfrr_ext "%pRDP" (struct prefix_rd *) +/* RD with AS4B with dot and dot+ format */ +#pragma FRR printfrr_ext "%pRDD" (struct prefix_rd *) +#pragma FRR printfrr_ext "%pRDE" (struct prefix_rd *) #pragma FRR printfrr_ext "%pPSG4" (struct prefix_sg *) #endif diff --git a/lib/subdir.am b/lib/subdir.am index 8d00668c8c..beef8675aa 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -13,6 +13,7 @@ lib_libfrr_la_SOURCES = \ lib/affinitymap_northbound.c \ lib/agg_table.c \ lib/atomlist.c \ + lib/asn.c \ lib/base64.c \ lib/bfd.c \ lib/buffer.c \ @@ -169,6 +170,7 @@ pkginclude_HEADERS += \ lib/admin_group.h \ lib/affinitymap.h \ lib/agg_table.h \ + lib/asn.h \ lib/atomlist.h \ lib/base64.h \ lib/bfd.h \ |
