summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorRuss White <russ@riw.us>2023-02-21 08:01:03 -0500
committerGitHub <noreply@github.com>2023-02-21 08:01:03 -0500
commitba755d35e508c2452e5459bdd7c0dd67a70a88a4 (patch)
treeadc08f46788b8012240faec23ae7e7271bb0d40d /lib
parent39c664c4ea530a9460efa1a78fe669ae56c85f83 (diff)
parent616e9f0d9f0458788adf4b30707016c8db383b02 (diff)
Merge pull request #12248 from pguibert6WIND/bgpasdot
lib, bgp: add initial support for asdot format
Diffstat (limited to 'lib')
-rw-r--r--lib/asn.c260
-rw-r--r--lib/asn.h81
-rw-r--r--lib/command.c1
-rw-r--r--lib/command.h3
-rw-r--r--lib/command_graph.c2
-rw-r--r--lib/command_graph.h1
-rw-r--r--lib/command_lex.l2
-rw-r--r--lib/command_match.c6
-rw-r--r--lib/command_parse.y6
-rw-r--r--lib/command_py.c1
-rw-r--r--lib/prefix.h5
-rw-r--r--lib/subdir.am2
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 \