mirror of
https://codeberg.org/1414codeforge/ubgpsuite.git
synced 2025-06-05 21:29:11 +02:00
[*] Initial commit
This commit is contained in:
191
lonetix/bgp/prefix.c
Normal file
191
lonetix/bgp/prefix.c
Normal file
@@ -0,0 +1,191 @@
|
||||
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||
|
||||
/**
|
||||
* \file bgp/prefix.c
|
||||
*
|
||||
* Deal with network prefixes.
|
||||
*
|
||||
* \copyright The DoubleFourteen Code Forge (C) All Rights Reserved
|
||||
* \author Lorenzo Cogotti
|
||||
*/
|
||||
|
||||
#include "bgp/bgp_local.h"
|
||||
#include "sys/endian.h"
|
||||
#include "sys/ip.h"
|
||||
#include "numlib.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
// ===========================================================================
|
||||
// Some performance oriented macros to avoid branching during prefix iteration
|
||||
|
||||
/// Calculate the minimum size of a possibly ADD_PATH enabled prefix.
|
||||
#define MINPFXSIZ(isAddPath) \
|
||||
((((isAddPath) != 0) << 2) + 1)
|
||||
|
||||
/// Extract the prefix portion out of a possibly ADD_PATH enabled prefix pointer.
|
||||
#define RAWPFXPTR(base, isAddPath) \
|
||||
((RawPrefix *) ((Uint8 *) (base) + (((isAddPath) != 0) << 2)))
|
||||
|
||||
/// Calculate maximum prefix width in bits given an address family
|
||||
#define MAXPFXWIDTH(family) (((family) == AFI_IP6) ? IPV6_WIDTH : IPV4_WIDTH) // simple CMOV
|
||||
|
||||
// ===========================================================================
|
||||
|
||||
char *Bgp_PrefixToString(Afi afi, const RawPrefix *prefix, char *dest)
|
||||
{
|
||||
Ipv4adr adr;
|
||||
Ipv6adr adr6;
|
||||
|
||||
switch (afi) {
|
||||
case AFI_IP:
|
||||
memset(&adr, 0, sizeof(adr));
|
||||
memcpy(&adr, prefix->bytes, PFXLEN(prefix->width));
|
||||
dest = Ipv4_AdrToString(&adr, dest);
|
||||
break;
|
||||
|
||||
case AFI_IP6:
|
||||
memset(&adr6, 0, sizeof(adr6));
|
||||
memcpy(&adr6, prefix->bytes, PFXLEN(prefix->width));
|
||||
dest = Ipv6_AdrToString(&adr6, dest);
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL; // invalid argument
|
||||
}
|
||||
|
||||
*dest++ = '/';
|
||||
dest = Utoa(prefix->width, dest);
|
||||
return dest;
|
||||
}
|
||||
|
||||
char *Bgp_ApPrefixToString(Afi afi, const ApRawPrefix *prefix, char *dest)
|
||||
{
|
||||
// NOTE: Test early to avoid polluting `dest` in case of invalid argument;
|
||||
// hopefully compilers will flatten this function to
|
||||
// eliminate duplicate test inside switch
|
||||
if (afi != AFI_IP && afi != AFI_IP6)
|
||||
return NULL; // invalid argument
|
||||
|
||||
dest = Utoa(beswap32(prefix->pathId), dest);
|
||||
*dest++ = ' ';
|
||||
return Bgp_PrefixToString(afi, PLAINPFX(prefix), dest);
|
||||
}
|
||||
|
||||
Judgement Bgp_StringToPrefix(const char *s, Prefix *dest)
|
||||
{
|
||||
Ipadr adr;
|
||||
unsigned width;
|
||||
NumConvRet res;
|
||||
|
||||
const char *ptr = s;
|
||||
while (*ptr != '/' && *ptr != '\0') ptr++;
|
||||
|
||||
size_t len = ptr - s;
|
||||
char *buf = (char *) alloca(len + 1);
|
||||
|
||||
memcpy(buf, s, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
if (Ip_StringToAdr(buf, &adr) != OK)
|
||||
return NG; // Bad IP string
|
||||
|
||||
if (*ptr == '/') {
|
||||
ptr++; // skip '/' separator
|
||||
|
||||
char *eptr;
|
||||
width = Atou(ptr, &eptr, 10, &res);
|
||||
|
||||
if (res != NCVENOERR || *eptr != '\0')
|
||||
return NG;
|
||||
} else
|
||||
width = (adr.family == IP6) ? IPV6_WIDTH : IPV4_WIDTH; // implicit full prefix
|
||||
|
||||
switch (adr.family) {
|
||||
case IP4:
|
||||
if (width > IPV4_WIDTH) return NG; // illegal prefix length
|
||||
|
||||
dest->afi = AFI_IP;
|
||||
break;
|
||||
|
||||
case IP6:
|
||||
if (width > IPV6_WIDTH) return NG; // illegal prefix length
|
||||
|
||||
dest->afi = AFI_IP6;
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE;
|
||||
return NG;
|
||||
}
|
||||
|
||||
dest->isAddPath = FALSE;
|
||||
dest->width = width;
|
||||
memcpy(dest->bytes, adr.bytes, PFXLEN(width));
|
||||
return OK;
|
||||
}
|
||||
|
||||
Judgement Bgp_StartPrefixes(Prefixiter *it,
|
||||
Afi afi,
|
||||
Safi safi,
|
||||
const void *data,
|
||||
size_t nbytes,
|
||||
Boolean isAddPath)
|
||||
{
|
||||
if (afi != AFI_IP && afi != AFI_IP6) {
|
||||
Bgp_SetErrStat(BGPEAFIUNSUP);
|
||||
return NG;
|
||||
}
|
||||
if (safi != SAFI_UNICAST && safi != SAFI_MULTICAST) {
|
||||
Bgp_SetErrStat(BGPESAFIUNSUP);
|
||||
return NG;
|
||||
}
|
||||
|
||||
it->afi = afi;
|
||||
it->safi = safi;
|
||||
it->isAddPath = isAddPath;
|
||||
it->base = (Uint8 *) data;
|
||||
it->lim = it->base + nbytes;
|
||||
it->ptr = it->base;
|
||||
|
||||
Bgp_SetErrStat(BGPENOERR);
|
||||
return OK;
|
||||
}
|
||||
|
||||
void *Bgp_NextPrefix(Prefixiter *it)
|
||||
{
|
||||
if (it->ptr >= it->lim) {
|
||||
Bgp_SetErrStat(BGPENOERR);
|
||||
return NULL; // end of iteration
|
||||
}
|
||||
|
||||
// Basic check for prefix initial bytes
|
||||
size_t left = it->lim - it->ptr;
|
||||
size_t siz = MINPFXSIZ(it->isAddPath);
|
||||
if (left < siz) {
|
||||
Bgp_SetErrStat(BGPETRUNCPFX);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Adjust a pointer to skip Path identifier info if necessary
|
||||
const RawPrefix *rawPfx = RAWPFXPTR(it->ptr, it->isAddPath);
|
||||
if (rawPfx->width > MAXPFXWIDTH(it->afi)) {
|
||||
Bgp_SetErrStat(BGPEBADPFXWIDTH);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Ensure all the necessary prefix bytes are present
|
||||
siz += PFXLEN(rawPfx->width);
|
||||
if (left < siz) {
|
||||
Bgp_SetErrStat(BGPETRUNCPFX);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// All good, advance and return
|
||||
void *pfx = it->ptr;
|
||||
it->ptr += siz;
|
||||
Bgp_SetErrStat(BGPENOERR);
|
||||
|
||||
return pfx;
|
||||
}
|
Reference in New Issue
Block a user