0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-09-16 18:35:19 +00:00

Add ASPA functionality to BIRD

ASPA [1] is a new IETF draft for BGP that adds new RPKI objects and
create an AS_PATH validation mechanism [2] based on this objects.

[1] https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-profile/
[2] https://datatracker.ietf.org/doc/draft-ietf-sidrops-aspa-verification/

(Minor changes done by commiter)
This commit is contained in:
Eugene Bogomazov 2019-10-02 16:26:05 +02:00 committed by Ondrej Zajicek (work)
parent 0edf0c8cd9
commit e4df8a3e4c
16 changed files with 392 additions and 9 deletions

View File

@ -31,6 +31,8 @@ class BIRDFValPrinter(BIRDPrinter):
"T_ENUM_NETTYPE": "i",
"T_ENUM_RA_PREFERENCE": "i",
"T_ENUM_AF": "i",
"T_ENUM_ASPA": "i",
"T_ENUM_BGP_DIR": "i",
"T_IP": "ip",
"T_NET": "net",
"T_STRING": "s",

View File

@ -107,7 +107,7 @@ CF_DECLS
%type <time> expr_us time
%type <a> ipa
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_ipa
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_
%type <net_ptr> net_ net_any net_vpn4_ net_vpn6_ net_vpn_ net_roa4_ net_roa6_ net_roa_ net_ip6_sadr_ net_mpls_ net_aspa4_ net_aspa6_ net_aspa_
%type <mls> label_stack_start label_stack
%type <t> text opttext
@ -123,7 +123,7 @@ CF_DECLS
%start config
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, FROM)
CF_KEYWORDS(DEFINE, ON, OFF, YES, NO, S, MS, US, PORT, VPN, MPLS, ASPA4, ASPA6, FROM)
CF_GRAMMAR
@ -283,9 +283,22 @@ net_mpls_: MPLS NUM
net_fill_mpls($$, $2);
}
net_aspa4_: ASPA4 NUM NUM
{
$$ = cfg_alloc(sizeof(net_addr_aspa));
net_fill_aspa($$, $2, $3, AFI_IPV4);
};
net_aspa6_: ASPA6 NUM NUM
{
$$ = cfg_alloc(sizeof(net_addr_aspa));
net_fill_aspa($$, $2, $3, AFI_IPV6);
};
net_ip_: net_ip4_ | net_ip6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
net_aspa_: net_aspa4_ | net_aspa6_ ;
net_:
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
@ -294,6 +307,7 @@ net_:
| net_flow_
| net_ip6_sadr_
| net_mpls_
| net_aspa_
;

View File

@ -434,6 +434,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
PREFERENCE,
ROA_CHECK, ASN, SRC,
ASPA_CHECK,
IS_V4, IS_V6,
LEN, MAXLEN,
DEFINED,
@ -966,6 +967,9 @@ term:
| ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
| ROA_CHECK '(' rtable ',' term ',' term ')' { $$ = f_new_inst(FI_ROA_CHECK_EXPLICIT, $5, $7, $3); }
| ASPA_CHECK '(' rtable ',' term ')' { $$ = f_new_inst(FI_ASPA_CHECK_IMPLICIT, $5, $3); }
| ASPA_CHECK '(' rtable ',' term ',' term ',' term ')' { $$ = f_new_inst(FI_ASPA_CHECK_EXPLICIT, $5, $7, $9, $3); }
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
/* | term '.' LEN { $$->code = P('P','l'); } */

View File

@ -39,6 +39,8 @@ enum f_type {
T_ENUM_NETTYPE = 0x36,
T_ENUM_RA_PREFERENCE = 0x37,
T_ENUM_AF = 0x38,
T_ENUM_ASPA = 0x39,
T_ENUM_BGP_DIR = 0x3a,
/* new enums go here */
T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */

View File

@ -1170,6 +1170,58 @@
}
INST(FI_ASPA_CHECK_IMPLICIT, 1, 1) { /* ASPA Check */
NEVER_CONSTANT;
ARG(1, T_ENUM_BGP_DIR);
RTC(2);
struct rtable *table = rtc->table;
ACCESS_RTE;
ACCESS_EATTRS;
const net_addr *net = (*fs->rte)->net->n.addr;
if (!table)
runtime("Missing ASPA table");
if (table->addr_type != NET_ASPA)
runtime("Table type must be ASPA");
/* We ignore temporary attributes, probably not a problem here */
/* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
eattr *e = ea_find(*fs->eattrs, EA_CODE(PROTOCOL_BGP, 0x02));
if (!e || ((e->type & EAF_TYPE_MASK) != EAF_TYPE_AS_PATH))
runtime("Missing AS_PATH attribute");
uint dir = v1.val.i;
if (!net_is_ip(net))
runtime("Network type must be IPv4 or IPv6");
uint afi = (net->type == NET_IP4) ? AFI_IPV4 : AFI_IPV6;
RESULT(T_ENUM_ASPA, i, [[ net_aspa_check(fpool, table, e->u.ptr, dir, afi) ]]);
}
INST(FI_ASPA_CHECK_EXPLICIT, 3, 1) { /* ASPA Check */
NEVER_CONSTANT;
ARG(1, T_PATH);
ARG(2, T_ENUM_BGP_DIR);
ARG(3, T_ENUM_AF);
RTC(4);
struct rtable *table = rtc->table;
if (!table)
runtime("Missing ASPA table");
if (table->addr_type != NET_ASPA)
runtime("Table type must be ASPA");
if ((v3.val.i != AFI_IPV4) && (v3.val.i != AFI_IPV6))
runtime("Address family must be AF_IPV4 or AF_IPV6");
RESULT(T_ENUM_ASPA, i, [[ net_aspa_check(fpool, table, v1.val.ad, v2.val.i, v3.val.i) ]]);
}
INST(FI_FORMAT, 1, 0) { /* Format */
ARG_ANY(1);
RESULT(T_STRING, s, val_format_str(fpool, &v1));

View File

@ -1245,6 +1245,14 @@ int j;
accept "ok I take that";
}
/*
* Testing ROA checks
* ------------------
*/
filter roa_filter
{
if net ~ [ 10.0.0.0/8{16,24}, 2000::/3{16,96} ] then {
@ -1331,6 +1339,85 @@ prefix pfx;
bt_test_suite(test_roa_check, "Testing ROA");
/*
* Testing ASPA checks
* -------------------
*/
aspa table at;
protocol static
{
aspa;
route aspa4 65000 65001;
route aspa4 65000 65002;
route aspa4 64999 65001;
route aspa4 65004 64999;
route aspa4 65001 0;
route aspa4 65006 65100;
route aspa6 65000 65003;
}
function t_aspa_check()
bgppath p1;
bgppath p2;
{
# empty path
p1 = + empty + ;
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_VALID);
# 65000
p1 = prepend(p1, 65000);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_VALID);
# 65000 65000
p1 = prepend(p1, 65000);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_VALID);
# 65001 65000 65000
p1 = prepend(p1, 65001);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_VALID);
# 65003 65000
p1 = prepend(+ empty +, 65000);
p1 = prepend(p1, 65003);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_INVALID);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV6) = ASPA_VALID);
# 65000 65003
p1 = prepend(+ empty +, 65003);
p1 = prepend(p1, 65000);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_UNKNOWN);
# 65004 64999 65001 65001 65000
p1 = prepend(+ empty +, 65000);
p1 = prepend(p1, 65001);
p1 = prepend(p1, 65001);
p1 = prepend(p1, 64999);
p1 = prepend(p1, 65004);
bt_assert(aspa_check(at, p1, BGP_DIR_UP, AF_IPV4) = ASPA_INVALID);
bt_assert(aspa_check(at, p1, BGP_DIR_DOWN, AF_IPV4) = ASPA_VALID);
# 65005 65004 64999 65001 65001 65000
p2 = prepend(p1, 65005);
bt_assert(aspa_check(at, p2, BGP_DIR_UP, AF_IPV4) = ASPA_INVALID);
bt_assert(aspa_check(at, p2, BGP_DIR_DOWN, AF_IPV4) = ASPA_UNKNOWN);
# 65006 65004 64999 65001 65001 65000
p2 = prepend(p1, 65006);
bt_assert(aspa_check(at, p2, BGP_DIR_UP, AF_IPV4) = ASPA_INVALID);
bt_assert(aspa_check(at, p2, BGP_DIR_DOWN, AF_IPV4) = ASPA_INVALID);
}
bt_test_suite(t_aspa_check, "Testing ASPA");
/*
* Testing Mixed Net Types
* -----------------------

View File

@ -16,6 +16,7 @@ const char * const net_label[] = {
[NET_FLOW6] = "flow6",
[NET_IP6_SADR]= "ipv6-sadr",
[NET_MPLS] = "mpls",
[NET_ASPA] = "aspa",
};
const u16 net_addr_length[] = {
@ -29,6 +30,7 @@ const u16 net_addr_length[] = {
[NET_FLOW6] = 0,
[NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
[NET_MPLS] = sizeof(net_addr_mpls),
[NET_ASPA] = sizeof(net_addr_aspa),
};
const u8 net_max_prefix_length[] = {
@ -42,6 +44,7 @@ const u8 net_max_prefix_length[] = {
[NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
[NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
[NET_MPLS] = 0,
[NET_ASPA] = 0,
};
const u16 net_max_text_length[] = {
@ -55,6 +58,7 @@ const u16 net_max_text_length[] = {
[NET_FLOW6] = 0, /* "flow6 { ... }" */
[NET_IP6_SADR]= 92, /* "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128 from ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128" */
[NET_MPLS] = 7, /* "1048575" */
[NET_ASPA] = 31, /* "aspaX AS4294967295 AS4294967295" */
};
@ -110,6 +114,8 @@ net_format(const net_addr *N, char *buf, int buflen)
return bsnprintf(buf, buflen, "%I6/%d from %I6/%d", n->ip6_sadr.dst_prefix, n->ip6_sadr.dst_pxlen, n->ip6_sadr.src_prefix, n->ip6_sadr.src_pxlen);
case NET_MPLS:
return bsnprintf(buf, buflen, "%u", n->mpls.label);
case NET_ASPA:
return bsnprintf(buf, buflen, "aspa%u AS%u AS%u", (n->aspa.afi == AFI_IPV4) ? 4 : 6, n->aspa.customer_asn, n->aspa.provider_asn);
}
bug("unknown network type");
@ -133,6 +139,7 @@ net_pxmask(const net_addr *a)
case NET_IP6_SADR:
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
case NET_ASPA:
case NET_MPLS:
default:
return IPA_NONE;
@ -167,6 +174,8 @@ net_compare(const net_addr *a, const net_addr *b)
return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b);
case NET_MPLS:
return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
case NET_ASPA:
return net_compare_aspa((const net_addr_aspa *) a, (const net_addr_aspa *) b);
}
return 0;
}
@ -188,6 +197,7 @@ net_hash(const net_addr *n)
case NET_FLOW6: return NET_HASH(n, flow6);
case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
case NET_MPLS: return NET_HASH(n, mpls);
case NET_ASPA: return NET_HASH(n, aspa);
default: bug("invalid type");
}
}
@ -210,6 +220,7 @@ net_validate(const net_addr *n)
case NET_FLOW6: return NET_VALIDATE(n, flow6);
case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
case NET_MPLS: return NET_VALIDATE(n, mpls);
case NET_ASPA: return NET_VALIDATE(n, aspa);
default: return 0;
}
}
@ -237,6 +248,7 @@ net_normalize(net_addr *N)
return net_normalize_ip6_sadr(&n->ip6_sadr);
case NET_MPLS:
case NET_ASPA:
return;
}
}
@ -264,6 +276,7 @@ net_classify(const net_addr *N)
return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix);
case NET_MPLS:
case NET_ASPA:
return IADDR_HOST | SCOPE_UNIVERSE;
}
@ -297,6 +310,7 @@ ipa_in_netX(const ip_addr a, const net_addr *n)
ip6_mkmask(net6_pxlen(n))));
case NET_MPLS:
case NET_ASPA:
default:
return 0;
}
@ -328,4 +342,5 @@ net_init(void)
CHECK_NET(net_addr_flow6, 20);
CHECK_NET(net_addr_ip6_sadr, 40);
CHECK_NET(net_addr_mpls, 8);
CHECK_NET(net_addr_aspa, 12);
}

View File

@ -23,7 +23,8 @@
#define NET_FLOW6 8
#define NET_IP6_SADR 9
#define NET_MPLS 10
#define NET_MAX 11
#define NET_ASPA 11
#define NET_MAX 12
#define NB_IP4 (1 << NET_IP4)
#define NB_IP6 (1 << NET_IP6)
@ -35,6 +36,7 @@
#define NB_FLOW6 (1 << NET_FLOW6)
#define NB_IP6_SADR (1 << NET_IP6_SADR)
#define NB_MPLS (1 << NET_MPLS)
#define NB_ASPA (1 << NET_ASPA)
#define NB_IP (NB_IP4 | NB_IP6)
#define NB_VPN (NB_VPN4 | NB_VPN6)
@ -123,6 +125,15 @@ typedef struct net_addr_mpls {
u32 label;
} net_addr_mpls;
typedef struct net_addr_aspa {
u8 type;
u8 afi; /* Only IPv4 and IPv6 are allowed */
u16 length;
u32 customer_asn;
u32 provider_asn;
} net_addr_aspa;
typedef struct net_addr_ip6_sadr {
u8 type;
u8 dst_pxlen;
@ -144,6 +155,7 @@ typedef union net_addr_union {
net_addr_flow6 flow6;
net_addr_ip6_sadr ip6_sadr;
net_addr_mpls mpls;
net_addr_aspa aspa;
} net_addr_union;
@ -185,6 +197,8 @@ extern const u16 net_max_text_length[];
#define NET_ADDR_MPLS(label) \
((net_addr_mpls) { NET_MPLS, 20, sizeof(net_addr_mpls), label })
#define NET_ADDR_ASPA(customer_asn, provider_asn, afi) \
((net_addr_aspa) { NET_ASPA, afi, sizeof(net_addr_aspa), customer_asn, provider_asn })
static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
{ *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, pxlen); }
@ -210,6 +224,9 @@ static inline void net_fill_ip6_sadr(net_addr *a, ip6_addr dst_prefix, uint dst_
static inline void net_fill_mpls(net_addr *a, u32 label)
{ *(net_addr_mpls *)a = NET_ADDR_MPLS(label); }
static inline void net_fill_aspa(net_addr *a, u32 customer_asn, u32 provider_asn, u8 afi)
{ *(net_addr_aspa *)a = NET_ADDR_ASPA(customer_asn, provider_asn, afi); }
static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
{
if (ipa_is_ip4(prefix))
@ -271,6 +288,10 @@ static inline int net_is_flow(const net_addr *a)
static inline int net_is_sadr(const net_addr *a)
{ return (a->type == NET_IP6_SADR); }
static inline int net_is_aspa(const net_addr *a)
{ return (a->type == NET_ASPA); }
static inline ip4_addr net4_prefix(const net_addr *a)
{ return ((net_addr_ip4 *) a)->prefix; }
@ -295,6 +316,7 @@ static inline ip_addr net_prefix(const net_addr *a)
return ipa_from_ip6(net6_prefix(a));
case NET_MPLS:
case NET_ASPA:
default:
return IPA_NONE;
}
@ -365,6 +387,9 @@ static inline int net_equal_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
static inline int net_equal_aspa(const net_addr_aspa *a, const net_addr_aspa *b)
{ return !memcmp(a, b, sizeof(net_addr_aspa)); }
static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_roa4 *b)
{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
@ -378,6 +403,9 @@ static inline int net_equal_dst_ip6_sadr(const net_addr_ip6_sadr *a, const net_a
static inline int net_equal_src_ip6_sadr(const net_addr_ip6_sadr *a, const net_addr_ip6_sadr *b)
{ return ip6_equal(a->src_prefix, b->src_prefix) && (a->src_pxlen == b->src_pxlen); }
static inline int net_equal_customer_aspa(const net_addr_aspa *a, const net_addr_aspa *b)
{ return ((a->afi == b->afi) && (a->customer_asn == b->customer_asn)); }
static inline int net_zero_ip4(const net_addr_ip4 *a)
{ return !a->pxlen && ip4_zero(a->prefix); }
@ -406,6 +434,9 @@ static inline int net_zero_flow6(const net_addr_flow6 *a)
static inline int net_zero_mpls(const net_addr_mpls *a)
{ return !a->label; }
static inline int net_zero_aspa(const net_addr_aspa *a)
{ return !a->afi && !a->customer_asn && !a->provider_asn; }
static inline int net_compare_ip4(const net_addr_ip4 *a, const net_addr_ip4 *b)
{ return ip4_compare(a->prefix, b->prefix) ?: uint_cmp(a->pxlen, b->pxlen); }
@ -441,6 +472,9 @@ static inline int net_compare_ip6_sadr(const net_addr_ip6_sadr *a, const net_add
static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return uint_cmp(a->label, b->label); }
static inline int net_compare_aspa(const net_addr_aspa *a, const net_addr_aspa *b)
{ return uint_cmp(a->afi, b->afi) ?: uint_cmp(a->customer_asn, b->customer_asn) ?: uint_cmp(a->provider_asn, b->provider_asn); }
int net_compare(const net_addr *a, const net_addr *b);
@ -477,6 +511,8 @@ static inline void net_copy_ip6_sadr(net_addr_ip6_sadr *dst, const net_addr_ip6_
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
static inline void net_copy_aspa(net_addr_aspa *dst, const net_addr_aspa *src)
{ memcpy(dst, src, sizeof(net_addr_aspa)); }
/* XXXX */
static inline u32 u64_hash(u64 a)
@ -512,6 +548,9 @@ static inline u32 net_hash_ip6_sadr(const net_addr_ip6_sadr *n)
static inline u32 net_hash_mpls(const net_addr_mpls *n)
{ return n->label; }
static inline u32 net_hash_aspa(const net_addr_aspa *n)
{ return n->afi ^ u32_hash(n->customer_asn); }
u32 net_hash(const net_addr *a);
@ -564,6 +603,9 @@ static inline int net_validate_mpls(const net_addr_mpls *n)
static inline int net_validate_ip6_sadr(const net_addr_ip6_sadr *n)
{ return net_validate_px6(n->dst_prefix, n->dst_pxlen) && net_validate_px6(n->src_prefix, n->src_pxlen); }
static inline int net_validate_aspa(const net_addr_aspa *n)
{ return (n->customer_asn > 0) && ((n->afi == 1) || (n->afi == 2)); }
int net_validate(const net_addr *N);

View File

@ -169,6 +169,27 @@ as_path_contains_confed(const struct adata *path)
return 0;
}
int
as_path_contains_set(const struct adata *path)
{
const byte *pos = path->data;
const byte *end = pos + path->length;
while (pos < end)
{
uint type = pos[0];
uint slen = 2 + BS * pos[1];
if ((type == AS_PATH_SET) ||
(type == AS_PATH_CONFED_SET))
return 1;
pos += slen;
}
return 0;
}
struct adata *
as_path_strip_confed(struct linpool *pool, const struct adata *path)
{
@ -198,6 +219,55 @@ as_path_strip_confed(struct linpool *pool, const struct adata *path)
return res;
}
int
as_path_get_reverse_unique_asns(struct linpool *pool, const struct adata *path, u32 **data)
{
u32 *asns = lp_alloc(pool, as_path_getlen(path) * sizeof(u32));
const byte *src = path->data;
const byte *end = src + path->length;
u32 *dst = asns;
u32 prev_as = 0;
u32 as;
uint i;
/* Step 1: create array of unique asns */
while (src < end)
{
uint t = src[0];
uint l = src[1];
src += 2;
if (t == AS_PATH_SEQUENCE)
{
for (i = 0; i < l; i++)
{
as = get_as(src);
if (as != prev_as)
*dst++ = as;
prev_as = as;
src += BS;
}
}
else
src += BS * l;
}
u32 num = dst - asns;
/* Step 2: Reverse the array */
u32 as_1, as_2;
for (i = 0; i < num/2; i++)
{
as_1 = asns[i];
as_2 = asns[num-i-1];
asns[i] = as_2;
asns[num-i-1] = as_1;
}
*data = asns;
return num;
}
struct adata *
as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as)
{

View File

@ -35,12 +35,14 @@ int as_path_16to32(byte *dst, const byte *src, uint len);
int as_path_32to16(byte *dst, const byte *src, uint len);
int as_path_contains_as4(const struct adata *path);
int as_path_contains_confed(const struct adata *path);
int as_path_contains_set(const struct adata *path);
struct adata *as_path_strip_confed(struct linpool *pool, const struct adata *op);
struct adata *as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as);
struct adata *as_path_to_old(struct linpool *pool, const struct adata *path);
struct adata *as_path_cut(struct linpool *pool, const struct adata *path, uint num);
const struct adata *as_path_merge(struct linpool *pool, const struct adata *p1, const struct adata *p2);
void as_path_format(const struct adata *path, byte *buf, uint size);
int as_path_get_reverse_unique_asns(struct linpool *pool, const struct adata *path, u32 **data);
int as_path_getlen(const struct adata *path);
int as_path_getlen_int(const struct adata *path, int bs);
int as_path_get_first(const struct adata *path, u32 *orig_as);

View File

@ -66,7 +66,7 @@ CF_DECLS
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
CF_KEYWORDS(INTERFACE, IMPORT, EXPORT, FILTER, NONE, VRF, DEFAULT, TABLE, STATES, ROUTES, FILTERS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS)
CF_KEYWORDS(IPV4, IPV6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, SADR, MPLS, ASPA)
CF_KEYWORDS(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
@ -78,13 +78,15 @@ CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(CHECK, LINK)
/* For r_args_channel */
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, PRI, SEC)
CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4, VPN4_MC, VPN4_MPLS, VPN6, VPN6_MC, VPN6_MPLS, ROA4, ROA6, FLOW4, FLOW6, MPLS, ASPA, PRI, SEC)
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
CF_ENUM(T_ENUM_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
CF_ENUM(T_ENUM_ASPA, ASPA_, UNKNOWN, VALID, INVALID, UNVERIFIED)
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
%type <i32> idval
@ -144,9 +146,10 @@ net_type:
| FLOW4{ $$ = NET_FLOW4; }
| FLOW6{ $$ = NET_FLOW6; }
| MPLS { $$ = NET_MPLS; }
| ASPA { $$ = NET_ASPA; }
;
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR)
CF_ENUM(T_ENUM_NETTYPE, NET_, IP4, IP6, VPN4, VPN6, ROA4, ROA6, FLOW4, FLOW6, IP6_SADR, ASPA)
/* Creation of routing tables */
@ -707,6 +710,7 @@ r_args_channel:
| FLOW4 { $$ = "flow4"; }
| FLOW6 { $$ = "flow6"; }
| MPLS { $$ = "mpls"; }
| ASPA { $$ = "aspa"; }
| PRI { $$ = "pri"; }
| SEC { $$ = "sec"; }
;

View File

@ -535,6 +535,7 @@ lp_alloc_adata(struct linpool *pool, uint len)
static inline int adata_same(const struct adata *a, const struct adata *b)
{ return (a->length == b->length && !memcmp(a->data, b->data, a->length)); }
int net_aspa_check(struct linpool *lp, rtable *tab, const struct adata *path, uint dir, u8 afi);
typedef struct ea_list {
struct ea_list *next; /* In case we have an override list */
@ -708,4 +709,13 @@ static inline void rt_unlock_hostentry(struct hostentry *he) { if (he) he->uc--;
#define ROA_VALID 1
#define ROA_INVALID 2
/*
* ASPA verification status
*/
#define ASPA_UNKNOWN 0
#define ASPA_VALID 1
#define ASPA_INVALID 2
#define ASPA_UNVERIFIED 3
#endif

View File

@ -279,6 +279,7 @@ fib_find(struct fib *f, const net_addr *a)
case NET_FLOW6: return FIB_FIND(f, a, flow6);
case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
case NET_MPLS: return FIB_FIND(f, a, mpls);
case NET_ASPA: return FIB_FIND(f, a, aspa);
default: bug("invalid type");
}
}
@ -300,6 +301,7 @@ fib_insert(struct fib *f, const net_addr *a, struct fib_node *e)
case NET_FLOW6: FIB_INSERT(f, a, e, flow6); return;
case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); return;
case NET_MPLS: FIB_INSERT(f, a, e, mpls); return;
case NET_ASPA: FIB_INSERT(f, a, e, aspa); return;
default: bug("invalid type");
}
}

View File

@ -249,6 +249,78 @@ net_roa_check(rtable *tab, const net_addr *n, u32 asn)
return ROA_UNKNOWN; /* Should not happen */
}
static int
net_aspa_pair_check(rtable *tab, u32 customer_asn, u32 provider_asn, u8 afi)
{
struct net_addr_aspa n = NET_ADDR_ASPA(customer_asn, provider_asn, afi);
struct fib_node *fn;
int anything = 0;
for (fn = fib_get_chain(&tab->fib, (net_addr *) &n); fn; fn = fn->next)
{
net_addr_aspa *aspa = (void *) fn->addr;
net *r = fib_node_to_user(&tab->fib, fn);
if (net_equal_customer_aspa(aspa, &n) && rte_is_valid(r->routes))
{
anything = 1;
if (net_equal_aspa(aspa, &n))
return ASPA_VALID;
}
}
return anything ? ASPA_INVALID : ASPA_UNKNOWN;
}
int
net_aspa_check(linpool *lp, rtable *tab, const struct adata *path, uint dir, u8 afi)
{
ASSERT(tab->addr_type == NET_ASPA);
if (as_path_contains_set(path))
return ASPA_UNVERIFIED;
u32 *asns;
int asn_count = as_path_get_reverse_unique_asns(lp, path, &asns);
int invalid_count = 0;
int unknown_count = 0;
u32 customer_asn;
u32 provider_asn;
if (asn_count < 2)
return ASPA_VALID;
for (int i = 0; i < (asn_count - 1); i++)
{
if (!invalid_count)
{
customer_asn = asns[i];
provider_asn = asns[i+1];
}
else
{
customer_asn = asns[i+1];
provider_asn = asns[i];
}
int pair_status = net_aspa_pair_check(tab, customer_asn, provider_asn, afi);
if (pair_status == ASPA_INVALID)
{
if ((dir == 1) || invalid_count)
return ASPA_INVALID;
else
invalid_count++;
}
if (pair_status == ASPA_UNKNOWN)
unknown_count++;
}
return unknown_count ? ASPA_UNKNOWN : ASPA_VALID;
}
/**
* rte_find - find a route
* @net: network node

View File

@ -733,5 +733,10 @@ void bgp_update_next_hop(struct bgp_export_state *s, eattr *a, ea_list **to);
#define ORIGIN_EGP 1
#define ORIGIN_INCOMPLETE 2
/* BGP dir */
#define BGP_DIR_DOWN 0
#define BGP_DIR_UP 1
#endif

View File

@ -32,6 +32,9 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL,
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST)
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
CF_ENUM(T_ENUM_BGP_DIR, BGP_DIR_, DOWN, UP)
%type <i> bgp_nh
%type <i32> bgp_afi
@ -322,9 +325,6 @@ dynamic_attr: BGP_LARGE_COMMUNITY
{ $$ = f_new_dynamic_attr(EAF_TYPE_LC_SET, T_LCLIST, EA_CODE(PROTOCOL_BGP, BA_LARGE_COMMUNITY)); } ;
CF_ENUM(T_ENUM_BGP_ORIGIN, ORIGIN_, IGP, EGP, INCOMPLETE)
CF_CODE
CF_END