mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-08 12:18:42 +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:
parent
0edf0c8cd9
commit
e4df8a3e4c
@ -31,6 +31,8 @@ class BIRDFValPrinter(BIRDPrinter):
|
|||||||
"T_ENUM_NETTYPE": "i",
|
"T_ENUM_NETTYPE": "i",
|
||||||
"T_ENUM_RA_PREFERENCE": "i",
|
"T_ENUM_RA_PREFERENCE": "i",
|
||||||
"T_ENUM_AF": "i",
|
"T_ENUM_AF": "i",
|
||||||
|
"T_ENUM_ASPA": "i",
|
||||||
|
"T_ENUM_BGP_DIR": "i",
|
||||||
"T_IP": "ip",
|
"T_IP": "ip",
|
||||||
"T_NET": "net",
|
"T_NET": "net",
|
||||||
"T_STRING": "s",
|
"T_STRING": "s",
|
||||||
|
@ -107,7 +107,7 @@ CF_DECLS
|
|||||||
%type <time> expr_us time
|
%type <time> expr_us time
|
||||||
%type <a> ipa
|
%type <a> ipa
|
||||||
%type <net> net_ip4_ net_ip6_ net_ip6 net_ip_ net_ip net_or_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 <mls> label_stack_start label_stack
|
||||||
|
|
||||||
%type <t> text opttext
|
%type <t> text opttext
|
||||||
@ -123,7 +123,7 @@ CF_DECLS
|
|||||||
|
|
||||||
%start config
|
%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
|
CF_GRAMMAR
|
||||||
|
|
||||||
@ -283,9 +283,22 @@ net_mpls_: MPLS NUM
|
|||||||
net_fill_mpls($$, $2);
|
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_ip_: net_ip4_ | net_ip6_ ;
|
||||||
net_vpn_: net_vpn4_ | net_vpn6_ ;
|
net_vpn_: net_vpn4_ | net_vpn6_ ;
|
||||||
net_roa_: net_roa4_ | net_roa6_ ;
|
net_roa_: net_roa4_ | net_roa6_ ;
|
||||||
|
net_aspa_: net_aspa4_ | net_aspa6_ ;
|
||||||
|
|
||||||
net_:
|
net_:
|
||||||
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
|
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
|
||||||
@ -294,6 +307,7 @@ net_:
|
|||||||
| net_flow_
|
| net_flow_
|
||||||
| net_ip6_sadr_
|
| net_ip6_sadr_
|
||||||
| net_mpls_
|
| net_mpls_
|
||||||
|
| net_aspa_
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
|
@ -434,6 +434,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
|||||||
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
|
FROM, GW, NET, MASK, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX,
|
||||||
PREFERENCE,
|
PREFERENCE,
|
||||||
ROA_CHECK, ASN, SRC,
|
ROA_CHECK, ASN, SRC,
|
||||||
|
ASPA_CHECK,
|
||||||
IS_V4, IS_V6,
|
IS_V4, IS_V6,
|
||||||
LEN, MAXLEN,
|
LEN, MAXLEN,
|
||||||
DEFINED,
|
DEFINED,
|
||||||
@ -966,6 +967,9 @@ term:
|
|||||||
| ROA_CHECK '(' rtable ')' { $$ = f_new_inst(FI_ROA_CHECK_IMPLICIT, $3); }
|
| 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); }
|
| 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); }
|
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
|
||||||
|
|
||||||
/* | term '.' LEN { $$->code = P('P','l'); } */
|
/* | term '.' LEN { $$->code = P('P','l'); } */
|
||||||
|
@ -39,6 +39,8 @@ enum f_type {
|
|||||||
T_ENUM_NETTYPE = 0x36,
|
T_ENUM_NETTYPE = 0x36,
|
||||||
T_ENUM_RA_PREFERENCE = 0x37,
|
T_ENUM_RA_PREFERENCE = 0x37,
|
||||||
T_ENUM_AF = 0x38,
|
T_ENUM_AF = 0x38,
|
||||||
|
T_ENUM_ASPA = 0x39,
|
||||||
|
T_ENUM_BGP_DIR = 0x3a,
|
||||||
|
|
||||||
/* new enums go here */
|
/* new enums go here */
|
||||||
T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
|
T_ENUM_EMPTY = 0x3f, /* Special hack for atomic_aggr */
|
||||||
|
@ -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 */
|
INST(FI_FORMAT, 1, 0) { /* Format */
|
||||||
ARG_ANY(1);
|
ARG_ANY(1);
|
||||||
RESULT(T_STRING, s, val_format_str(fpool, &v1));
|
RESULT(T_STRING, s, val_format_str(fpool, &v1));
|
||||||
|
@ -1245,6 +1245,14 @@ int j;
|
|||||||
accept "ok I take that";
|
accept "ok I take that";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Testing ROA checks
|
||||||
|
* ------------------
|
||||||
|
*/
|
||||||
|
|
||||||
filter roa_filter
|
filter roa_filter
|
||||||
{
|
{
|
||||||
if net ~ [ 10.0.0.0/8{16,24}, 2000::/3{16,96} ] then {
|
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");
|
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
|
* Testing Mixed Net Types
|
||||||
* -----------------------
|
* -----------------------
|
||||||
|
15
lib/net.c
15
lib/net.c
@ -16,6 +16,7 @@ const char * const net_label[] = {
|
|||||||
[NET_FLOW6] = "flow6",
|
[NET_FLOW6] = "flow6",
|
||||||
[NET_IP6_SADR]= "ipv6-sadr",
|
[NET_IP6_SADR]= "ipv6-sadr",
|
||||||
[NET_MPLS] = "mpls",
|
[NET_MPLS] = "mpls",
|
||||||
|
[NET_ASPA] = "aspa",
|
||||||
};
|
};
|
||||||
|
|
||||||
const u16 net_addr_length[] = {
|
const u16 net_addr_length[] = {
|
||||||
@ -29,6 +30,7 @@ const u16 net_addr_length[] = {
|
|||||||
[NET_FLOW6] = 0,
|
[NET_FLOW6] = 0,
|
||||||
[NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
|
[NET_IP6_SADR]= sizeof(net_addr_ip6_sadr),
|
||||||
[NET_MPLS] = sizeof(net_addr_mpls),
|
[NET_MPLS] = sizeof(net_addr_mpls),
|
||||||
|
[NET_ASPA] = sizeof(net_addr_aspa),
|
||||||
};
|
};
|
||||||
|
|
||||||
const u8 net_max_prefix_length[] = {
|
const u8 net_max_prefix_length[] = {
|
||||||
@ -42,6 +44,7 @@ const u8 net_max_prefix_length[] = {
|
|||||||
[NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
|
[NET_FLOW6] = IP6_MAX_PREFIX_LENGTH,
|
||||||
[NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
|
[NET_IP6_SADR]= IP6_MAX_PREFIX_LENGTH,
|
||||||
[NET_MPLS] = 0,
|
[NET_MPLS] = 0,
|
||||||
|
[NET_ASPA] = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
const u16 net_max_text_length[] = {
|
const u16 net_max_text_length[] = {
|
||||||
@ -55,6 +58,7 @@ const u16 net_max_text_length[] = {
|
|||||||
[NET_FLOW6] = 0, /* "flow6 { ... }" */
|
[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_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_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);
|
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:
|
case NET_MPLS:
|
||||||
return bsnprintf(buf, buflen, "%u", n->mpls.label);
|
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");
|
bug("unknown network type");
|
||||||
@ -133,6 +139,7 @@ net_pxmask(const net_addr *a)
|
|||||||
case NET_IP6_SADR:
|
case NET_IP6_SADR:
|
||||||
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
|
return ipa_from_ip6(ip6_mkmask(net6_pxlen(a)));
|
||||||
|
|
||||||
|
case NET_ASPA:
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
default:
|
default:
|
||||||
return IPA_NONE;
|
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);
|
return net_compare_ip6_sadr((const net_addr_ip6_sadr *) a, (const net_addr_ip6_sadr *) b);
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
return net_compare_mpls((const net_addr_mpls *) a, (const net_addr_mpls *) b);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -188,6 +197,7 @@ net_hash(const net_addr *n)
|
|||||||
case NET_FLOW6: return NET_HASH(n, flow6);
|
case NET_FLOW6: return NET_HASH(n, flow6);
|
||||||
case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
|
case NET_IP6_SADR: return NET_HASH(n, ip6_sadr);
|
||||||
case NET_MPLS: return NET_HASH(n, mpls);
|
case NET_MPLS: return NET_HASH(n, mpls);
|
||||||
|
case NET_ASPA: return NET_HASH(n, aspa);
|
||||||
default: bug("invalid type");
|
default: bug("invalid type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -210,6 +220,7 @@ net_validate(const net_addr *n)
|
|||||||
case NET_FLOW6: return NET_VALIDATE(n, flow6);
|
case NET_FLOW6: return NET_VALIDATE(n, flow6);
|
||||||
case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
|
case NET_IP6_SADR: return NET_VALIDATE(n, ip6_sadr);
|
||||||
case NET_MPLS: return NET_VALIDATE(n, mpls);
|
case NET_MPLS: return NET_VALIDATE(n, mpls);
|
||||||
|
case NET_ASPA: return NET_VALIDATE(n, aspa);
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,6 +248,7 @@ net_normalize(net_addr *N)
|
|||||||
return net_normalize_ip6_sadr(&n->ip6_sadr);
|
return net_normalize_ip6_sadr(&n->ip6_sadr);
|
||||||
|
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
|
case NET_ASPA:
|
||||||
return;
|
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);
|
return ip6_zero(n->ip6_sadr.dst_prefix) ? (IADDR_HOST | SCOPE_UNIVERSE) : ip6_classify(&n->ip6_sadr.dst_prefix);
|
||||||
|
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
|
case NET_ASPA:
|
||||||
return IADDR_HOST | SCOPE_UNIVERSE;
|
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))));
|
ip6_mkmask(net6_pxlen(n))));
|
||||||
|
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
|
case NET_ASPA:
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -328,4 +342,5 @@ net_init(void)
|
|||||||
CHECK_NET(net_addr_flow6, 20);
|
CHECK_NET(net_addr_flow6, 20);
|
||||||
CHECK_NET(net_addr_ip6_sadr, 40);
|
CHECK_NET(net_addr_ip6_sadr, 40);
|
||||||
CHECK_NET(net_addr_mpls, 8);
|
CHECK_NET(net_addr_mpls, 8);
|
||||||
|
CHECK_NET(net_addr_aspa, 12);
|
||||||
}
|
}
|
||||||
|
44
lib/net.h
44
lib/net.h
@ -23,7 +23,8 @@
|
|||||||
#define NET_FLOW6 8
|
#define NET_FLOW6 8
|
||||||
#define NET_IP6_SADR 9
|
#define NET_IP6_SADR 9
|
||||||
#define NET_MPLS 10
|
#define NET_MPLS 10
|
||||||
#define NET_MAX 11
|
#define NET_ASPA 11
|
||||||
|
#define NET_MAX 12
|
||||||
|
|
||||||
#define NB_IP4 (1 << NET_IP4)
|
#define NB_IP4 (1 << NET_IP4)
|
||||||
#define NB_IP6 (1 << NET_IP6)
|
#define NB_IP6 (1 << NET_IP6)
|
||||||
@ -35,6 +36,7 @@
|
|||||||
#define NB_FLOW6 (1 << NET_FLOW6)
|
#define NB_FLOW6 (1 << NET_FLOW6)
|
||||||
#define NB_IP6_SADR (1 << NET_IP6_SADR)
|
#define NB_IP6_SADR (1 << NET_IP6_SADR)
|
||||||
#define NB_MPLS (1 << NET_MPLS)
|
#define NB_MPLS (1 << NET_MPLS)
|
||||||
|
#define NB_ASPA (1 << NET_ASPA)
|
||||||
|
|
||||||
#define NB_IP (NB_IP4 | NB_IP6)
|
#define NB_IP (NB_IP4 | NB_IP6)
|
||||||
#define NB_VPN (NB_VPN4 | NB_VPN6)
|
#define NB_VPN (NB_VPN4 | NB_VPN6)
|
||||||
@ -123,6 +125,15 @@ typedef struct net_addr_mpls {
|
|||||||
u32 label;
|
u32 label;
|
||||||
} net_addr_mpls;
|
} 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 {
|
typedef struct net_addr_ip6_sadr {
|
||||||
u8 type;
|
u8 type;
|
||||||
u8 dst_pxlen;
|
u8 dst_pxlen;
|
||||||
@ -144,6 +155,7 @@ typedef union net_addr_union {
|
|||||||
net_addr_flow6 flow6;
|
net_addr_flow6 flow6;
|
||||||
net_addr_ip6_sadr ip6_sadr;
|
net_addr_ip6_sadr ip6_sadr;
|
||||||
net_addr_mpls mpls;
|
net_addr_mpls mpls;
|
||||||
|
net_addr_aspa aspa;
|
||||||
} net_addr_union;
|
} net_addr_union;
|
||||||
|
|
||||||
|
|
||||||
@ -185,6 +197,8 @@ extern const u16 net_max_text_length[];
|
|||||||
#define NET_ADDR_MPLS(label) \
|
#define NET_ADDR_MPLS(label) \
|
||||||
((net_addr_mpls) { NET_MPLS, 20, sizeof(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)
|
static inline void net_fill_ip4(net_addr *a, ip4_addr prefix, uint pxlen)
|
||||||
{ *(net_addr_ip4 *)a = NET_ADDR_IP4(prefix, 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)
|
static inline void net_fill_mpls(net_addr *a, u32 label)
|
||||||
{ *(net_addr_mpls *)a = NET_ADDR_MPLS(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)
|
static inline void net_fill_ipa(net_addr *a, ip_addr prefix, uint pxlen)
|
||||||
{
|
{
|
||||||
if (ipa_is_ip4(prefix))
|
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)
|
static inline int net_is_sadr(const net_addr *a)
|
||||||
{ return (a->type == NET_IP6_SADR); }
|
{ 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)
|
static inline ip4_addr net4_prefix(const net_addr *a)
|
||||||
{ return ((net_addr_ip4 *) a)->prefix; }
|
{ 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));
|
return ipa_from_ip6(net6_prefix(a));
|
||||||
|
|
||||||
case NET_MPLS:
|
case NET_MPLS:
|
||||||
|
case NET_ASPA:
|
||||||
default:
|
default:
|
||||||
return IPA_NONE;
|
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)
|
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
|
||||||
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
|
{ 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)
|
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); }
|
{ 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)
|
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); }
|
{ 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)
|
static inline int net_zero_ip4(const net_addr_ip4 *a)
|
||||||
{ return !a->pxlen && ip4_zero(a->prefix); }
|
{ 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)
|
static inline int net_zero_mpls(const net_addr_mpls *a)
|
||||||
{ return !a->label; }
|
{ 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)
|
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); }
|
{ 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)
|
static inline int net_compare_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
|
||||||
{ return uint_cmp(a->label, b->label); }
|
{ 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);
|
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)
|
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
|
||||||
{ memcpy(dst, src, sizeof(net_addr_mpls)); }
|
{ 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 */
|
/* XXXX */
|
||||||
static inline u32 u64_hash(u64 a)
|
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)
|
static inline u32 net_hash_mpls(const net_addr_mpls *n)
|
||||||
{ return n->label; }
|
{ 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);
|
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)
|
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); }
|
{ 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);
|
int net_validate(const net_addr *N);
|
||||||
|
|
||||||
|
|
||||||
|
@ -169,6 +169,27 @@ as_path_contains_confed(const struct adata *path)
|
|||||||
return 0;
|
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 *
|
struct adata *
|
||||||
as_path_strip_confed(struct linpool *pool, const struct adata *path)
|
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;
|
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 *
|
struct adata *
|
||||||
as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as)
|
as_path_prepend2(struct linpool *pool, const struct adata *op, int seq, u32 as)
|
||||||
{
|
{
|
||||||
|
@ -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_32to16(byte *dst, const byte *src, uint len);
|
||||||
int as_path_contains_as4(const struct adata *path);
|
int as_path_contains_as4(const struct adata *path);
|
||||||
int as_path_contains_confed(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_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_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_to_old(struct linpool *pool, const struct adata *path);
|
||||||
struct adata *as_path_cut(struct linpool *pool, const struct adata *path, uint num);
|
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);
|
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);
|
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(const struct adata *path);
|
||||||
int as_path_getlen_int(const struct adata *path, int bs);
|
int as_path_getlen_int(const struct adata *path, int bs);
|
||||||
int as_path_get_first(const struct adata *path, u32 *orig_as);
|
int as_path_get_first(const struct adata *path, u32 *orig_as);
|
||||||
|
@ -66,7 +66,7 @@ CF_DECLS
|
|||||||
|
|
||||||
CF_KEYWORDS(ROUTER, ID, PROTOCOL, TEMPLATE, PREFERENCE, DISABLED, DEBUG, ALL, OFF, DIRECT)
|
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(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(RECEIVE, LIMIT, ACTION, WARN, BLOCK, RESTART, DISABLE, KEEP, FILTERED)
|
||||||
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
CF_KEYWORDS(PASSWORD, FROM, PASSIVE, TO, ID, EVENTS, PACKETS, PROTOCOLS, INTERFACES)
|
||||||
CF_KEYWORDS(ALGORITHM, KEYED, HMAC, MD5, SHA1, SHA256, SHA384, SHA512)
|
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)
|
CF_KEYWORDS(CHECK, LINK)
|
||||||
|
|
||||||
/* For r_args_channel */
|
/* 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,
|
CF_ENUM(T_ENUM_RTS, RTS_, DUMMY, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
||||||
RIP, OSPF, OSPF_IA, OSPF_EXT1, OSPF_EXT2, BGP, PIPE, BABEL)
|
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_SCOPE, SCOPE_, HOST, LINK, SITE, ORGANIZATION, UNIVERSE, UNDEFINED)
|
||||||
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
|
CF_ENUM(T_ENUM_RTD, RTD_, UNICAST, BLACKHOLE, UNREACHABLE, PROHIBIT)
|
||||||
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
|
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)
|
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
|
||||||
|
|
||||||
%type <i32> idval
|
%type <i32> idval
|
||||||
@ -144,9 +146,10 @@ net_type:
|
|||||||
| FLOW4{ $$ = NET_FLOW4; }
|
| FLOW4{ $$ = NET_FLOW4; }
|
||||||
| FLOW6{ $$ = NET_FLOW6; }
|
| FLOW6{ $$ = NET_FLOW6; }
|
||||||
| MPLS { $$ = NET_MPLS; }
|
| 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 */
|
/* Creation of routing tables */
|
||||||
@ -707,6 +710,7 @@ r_args_channel:
|
|||||||
| FLOW4 { $$ = "flow4"; }
|
| FLOW4 { $$ = "flow4"; }
|
||||||
| FLOW6 { $$ = "flow6"; }
|
| FLOW6 { $$ = "flow6"; }
|
||||||
| MPLS { $$ = "mpls"; }
|
| MPLS { $$ = "mpls"; }
|
||||||
|
| ASPA { $$ = "aspa"; }
|
||||||
| PRI { $$ = "pri"; }
|
| PRI { $$ = "pri"; }
|
||||||
| SEC { $$ = "sec"; }
|
| SEC { $$ = "sec"; }
|
||||||
;
|
;
|
||||||
|
10
nest/route.h
10
nest/route.h
@ -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)
|
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)); }
|
{ 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 {
|
typedef struct ea_list {
|
||||||
struct ea_list *next; /* In case we have an override 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_VALID 1
|
||||||
#define ROA_INVALID 2
|
#define ROA_INVALID 2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ASPA verification status
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ASPA_UNKNOWN 0
|
||||||
|
#define ASPA_VALID 1
|
||||||
|
#define ASPA_INVALID 2
|
||||||
|
#define ASPA_UNVERIFIED 3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -279,6 +279,7 @@ fib_find(struct fib *f, const net_addr *a)
|
|||||||
case NET_FLOW6: return FIB_FIND(f, a, flow6);
|
case NET_FLOW6: return FIB_FIND(f, a, flow6);
|
||||||
case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
|
case NET_IP6_SADR: return FIB_FIND(f, a, ip6_sadr);
|
||||||
case NET_MPLS: return FIB_FIND(f, a, mpls);
|
case NET_MPLS: return FIB_FIND(f, a, mpls);
|
||||||
|
case NET_ASPA: return FIB_FIND(f, a, aspa);
|
||||||
default: bug("invalid type");
|
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_FLOW6: FIB_INSERT(f, a, e, flow6); return;
|
||||||
case NET_IP6_SADR: FIB_INSERT(f, a, e, ip6_sadr); 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_MPLS: FIB_INSERT(f, a, e, mpls); return;
|
||||||
|
case NET_ASPA: FIB_INSERT(f, a, e, aspa); return;
|
||||||
default: bug("invalid type");
|
default: bug("invalid type");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -249,6 +249,78 @@ net_roa_check(rtable *tab, const net_addr *n, u32 asn)
|
|||||||
return ROA_UNKNOWN; /* Should not happen */
|
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
|
* rte_find - find a route
|
||||||
* @net: network node
|
* @net: network node
|
||||||
|
@ -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_EGP 1
|
||||||
#define ORIGIN_INCOMPLETE 2
|
#define ORIGIN_INCOMPLETE 2
|
||||||
|
|
||||||
|
/* BGP dir */
|
||||||
|
|
||||||
|
#define BGP_DIR_DOWN 0
|
||||||
|
#define BGP_DIR_UP 1
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,6 +32,9 @@ CF_KEYWORDS(BGP, LOCAL, NEIGHBOR, AS, HOLD, TIME, CONNECT, RETRY, KEEPALIVE,
|
|||||||
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL,
|
LIVED, STALE, IMPORT, IBGP, EBGP, MANDATORY, INTERNAL, EXTERNAL,
|
||||||
DYNAMIC, RANGE, NAME, DIGITS, BGP_AIGP, AIGP, ORIGINATE, COST)
|
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 <i> bgp_nh
|
||||||
%type <i32> bgp_afi
|
%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)); } ;
|
{ $$ = 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_CODE
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
Loading…
Reference in New Issue
Block a user