mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-05-28 10:50:18 +00:00

Each BGP prefix may have an as-path list attached. A forged string is stored in the BGP attribute and shows the as-path list output. Before this commit, the as-path list output was expressed as a list of AS values in plain format. Now, if a given BGP instance uses a specific asnotation, then the output is changed: new output: router bgp 1.1 asnotation dot ! address-family ipv4 unicast network 10.200.0.0/24 route-map rmap network 10.201.0.0/24 route-map rmap redistribute connected route-map rmap exit-address-family exit ! route-map rmap permit 1 set as-path prepend 1.1 5433.55 264564564 exit ubuntu2004# do show bgp ipv4 BGP table version is 2, local router ID is 10.0.2.15, vrf id 0 Default local pref 100, local AS 1.1 Status codes: s suppressed, d damped, h history, * valid, > best, = multipath, i internal, r RIB-failure, S Stale, R Removed Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self Origin codes: i - IGP, e - EGP, ? - incomplete RPKI validation codes: V valid, I invalid, N Not found Network Next Hop Metric LocPrf Weight Path *> 4.4.4.4/32 0.0.0.0 0 32768 1.1 5433.55 4036.61268 ? *> 10.0.2.0/24 0.0.0.0 0 32768 1.1 5433.55 4036.61268 ? 10.200.0.0/24 0.0.0.0 0 32768 1.1 5433.55 4036.61268 i 10.201.0.0/24 0.0.0.0 0 32768 1.1 5433.55 4036.61268 i The changes include: - the aspath structure has a new field: asnotation type The ashash list will differentiate 2 aspaths using a different asnotation. - 3 new printf extensions display the as number in the wished format: pASP, pASD, pASE for plain, dot, or dot+ format (extended). Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
240 lines
5.6 KiB
C
240 lines
5.6 KiB
C
/*
|
|
* 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_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);
|
|
}
|
|
}
|
|
|
|
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;
|
|
if ((asnotation == ASNOTATION_PLAIN) ||
|
|
((asnotation == ASNOTATION_DOT) && *asn < UINT16_MAX))
|
|
snprintf(as_str, sizeof(as_str), "%u", *asn);
|
|
else
|
|
asn_asn2asdot(*asn, as_str, sizeof(as_str));
|
|
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);
|
|
}
|