mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 17:51:53 +00:00
ASPA: checks done in filters; no autoreload yet
This commit is contained in:
parent
08571b2059
commit
bc10975adb
@ -364,7 +364,7 @@ CF_KEYWORDS(FUNCTION, PRINT, PRINTN, UNSET, RETURN,
|
|||||||
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
|
TRUE, FALSE, RT, RO, UNKNOWN, GENERIC,
|
||||||
FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, GW_MPLS_STACK, ONLINK,
|
FROM, GW, NET, PROTO, SOURCE, SCOPE, DEST, IFNAME, IFINDEX, WEIGHT, GW_MPLS, GW_MPLS_STACK, ONLINK,
|
||||||
PREFERENCE,
|
PREFERENCE,
|
||||||
ROA_CHECK,
|
ROA_CHECK, ASPA_CHECK,
|
||||||
DEFINED,
|
DEFINED,
|
||||||
ADD, DELETE, RESET,
|
ADD, DELETE, RESET,
|
||||||
PREPEND,
|
PREPEND,
|
||||||
@ -946,6 +946,7 @@ 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_EXPLICIT, $5, $3); }
|
||||||
|
|
||||||
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
|
| FORMAT '(' term ')' { $$ = f_new_inst(FI_FORMAT, $3); }
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ static const char * const f_type_str[] = {
|
|||||||
[T_ENUM_RTC] = "enum rtc",
|
[T_ENUM_RTC] = "enum rtc",
|
||||||
[T_ENUM_RTD] = "enum rtd",
|
[T_ENUM_RTD] = "enum rtd",
|
||||||
[T_ENUM_ROA] = "enum roa",
|
[T_ENUM_ROA] = "enum roa",
|
||||||
|
[T_ENUM_ASPA] = "enum aspa",
|
||||||
[T_ENUM_NETTYPE] = "enum nettype",
|
[T_ENUM_NETTYPE] = "enum nettype",
|
||||||
[T_ENUM_RA_PREFERENCE] = "enum ra_preference",
|
[T_ENUM_RA_PREFERENCE] = "enum ra_preference",
|
||||||
[T_ENUM_AF] = "enum af",
|
[T_ENUM_AF] = "enum af",
|
||||||
|
@ -43,6 +43,7 @@ enum f_type {
|
|||||||
T_ENUM_RA_PREFERENCE = 0x37,
|
T_ENUM_RA_PREFERENCE = 0x37,
|
||||||
T_ENUM_AF = 0x38,
|
T_ENUM_AF = 0x38,
|
||||||
T_ENUM_MPLS_POLICY = 0x39,
|
T_ENUM_MPLS_POLICY = 0x39,
|
||||||
|
T_ENUM_ASPA = 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 */
|
||||||
|
@ -1606,6 +1606,21 @@
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INST(FI_ASPA_CHECK_EXPLICIT, 1, 1) { /* ASPA Check */
|
||||||
|
NEVER_CONSTANT;
|
||||||
|
ARG(1, T_PATH);
|
||||||
|
RTC(2);
|
||||||
|
struct rtable *table = rtc->table;
|
||||||
|
|
||||||
|
if (!table)
|
||||||
|
runtime("Missing ASPA table");
|
||||||
|
|
||||||
|
if (table->addr_type != NET_ASPA)
|
||||||
|
runtime("Table type must be ASPA");
|
||||||
|
|
||||||
|
RESULT(T_ENUM_ASPA, i, [[ aspa_check(table, v1.val.ad) ]]);
|
||||||
|
}
|
||||||
|
|
||||||
INST(FI_FROM_HEX, 1, 1) { /* Convert hex text to bytestring */
|
INST(FI_FROM_HEX, 1, 1) { /* Convert hex text to bytestring */
|
||||||
ARG(1, T_STRING);
|
ARG(1, T_STRING);
|
||||||
|
|
||||||
|
@ -139,6 +139,7 @@ CF_ENUM(T_ENUM_RTS, RTS_, STATIC, INHERIT, DEVICE, STATIC_DEVICE, REDIRECT,
|
|||||||
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)
|
||||||
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
|
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
|
||||||
CF_ENUM(T_ENUM_MPLS_POLICY, MPLS_POLICY_, NONE, STATIC, PREFIX, AGGREGATE, VRF)
|
CF_ENUM(T_ENUM_MPLS_POLICY, MPLS_POLICY_, NONE, STATIC, PREFIX, AGGREGATE, VRF)
|
||||||
|
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
#include "lib/net.h"
|
#include "lib/net.h"
|
||||||
|
|
||||||
struct ea_list;
|
struct ea_list;
|
||||||
|
struct adata;
|
||||||
struct protocol;
|
struct protocol;
|
||||||
struct proto;
|
struct proto;
|
||||||
struct rte_src;
|
struct rte_src;
|
||||||
@ -320,6 +321,7 @@ static inline net *net_get(rtable *tab, const net_addr *addr) { return (net *) f
|
|||||||
net *net_get(rtable *tab, const net_addr *addr);
|
net *net_get(rtable *tab, const net_addr *addr);
|
||||||
net *net_route(rtable *tab, const net_addr *n);
|
net *net_route(rtable *tab, const net_addr *n);
|
||||||
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
|
int net_roa_check(rtable *tab, const net_addr *n, u32 asn);
|
||||||
|
int aspa_check(rtable *tab, const struct adata *path);
|
||||||
rte *rte_find(net *net, struct rte_src *src);
|
rte *rte_find(net *net, struct rte_src *src);
|
||||||
rte *rte_get_temp(struct rta *, struct rte_src *src);
|
rte *rte_get_temp(struct rta *, struct rte_src *src);
|
||||||
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
|
void rte_update2(struct channel *c, const net_addr *n, rte *new, struct rte_src *src);
|
||||||
@ -781,4 +783,9 @@ int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *
|
|||||||
#define ROA_VALID 1
|
#define ROA_VALID 1
|
||||||
#define ROA_INVALID 2
|
#define ROA_INVALID 2
|
||||||
|
|
||||||
|
#define ASPA_UNKNOWN 0
|
||||||
|
#define ASPA_VALID 1
|
||||||
|
#define ASPA_INVALID 2
|
||||||
|
#define ASPA_CONTAINS_CONFED 3
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -346,6 +346,95 @@ net_roa_check(rtable *tab, const net_addr *n, u32 asn)
|
|||||||
#undef FW
|
#undef FW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* aspa_check - check validity of AS Path in an ASPA table
|
||||||
|
* @tab: ASPA table
|
||||||
|
* @path: AS Path to check
|
||||||
|
*
|
||||||
|
* Implements draft-ietf-sidrops-aspa-verification-16.
|
||||||
|
*/
|
||||||
|
int aspa_check(rtable *tab, const adata *path)
|
||||||
|
{
|
||||||
|
struct lp_state lps;
|
||||||
|
lp_save(tmp_linpool, &lps);
|
||||||
|
|
||||||
|
/* No support for confed paths */
|
||||||
|
if (as_path_contains_confed(path))
|
||||||
|
return ASPA_CONTAINS_CONFED;
|
||||||
|
|
||||||
|
/* Normalize the AS Path: drop stuffings */
|
||||||
|
uint len = as_path_getlen(path);
|
||||||
|
u32 *asns = alloca(sizeof(u32) * len);
|
||||||
|
uint ppos = 0;
|
||||||
|
int nsz = 0;
|
||||||
|
while (as_path_walk(path, &ppos, &asns[nsz]))
|
||||||
|
if ((nsz == 0) || (asns[nsz] != asns[nsz-1]))
|
||||||
|
nsz++;
|
||||||
|
|
||||||
|
/* Find the provider blocks for every AS on the path
|
||||||
|
* and check allowed directions */
|
||||||
|
bool *up = alloca(sizeof(bool) * nsz);
|
||||||
|
bool *down = alloca(sizeof(bool) * nsz);
|
||||||
|
bool unknown_flag = false;
|
||||||
|
|
||||||
|
for (int ap=0; ap<nsz; ap++)
|
||||||
|
{
|
||||||
|
net_addr_union nau = { .aspa = NET_ADDR_ASPA(asns[ap]), };
|
||||||
|
net *n = net_find(tab, &nau.n);
|
||||||
|
if (!n || !n->routes)
|
||||||
|
{
|
||||||
|
/* No ASPA for this ASN, therefore UNKNOWN */
|
||||||
|
unknown_flag = up[ap] = down[ap] = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
up[ap] = down[ap] = false;
|
||||||
|
|
||||||
|
for (rte *e = n->routes; e; e = e->next)
|
||||||
|
{
|
||||||
|
if (!rte_is_valid(e))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
eattr *ea = ea_find(e->attrs->eattrs, EA_ASPA_PROVIDERS);
|
||||||
|
if (!ea)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (uint i=0; i * sizeof(u32) < ea->u.ptr->length; i++)
|
||||||
|
{
|
||||||
|
if ((ap > 0) && ((u32 *) ea->u.ptr->data)[i] == asns[ap-1])
|
||||||
|
down[ap] = true;
|
||||||
|
if ((ap + 1 < nsz) && ((u32 *) ea->u.ptr->data)[i] == asns[ap+1])
|
||||||
|
up[ap] = true;
|
||||||
|
|
||||||
|
if (down[ap] || up[ap])
|
||||||
|
goto peering_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
peering_found:;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check whether the topology is first ramp up and then ramp down. */
|
||||||
|
int up_end = 0;
|
||||||
|
while (up_end < nsz && up[up_end])
|
||||||
|
up_end++;
|
||||||
|
|
||||||
|
int down_end = nsz - 1;
|
||||||
|
while (down_end > 0 && down[down_end])
|
||||||
|
down_end--;
|
||||||
|
|
||||||
|
/* A significant overlap of obvious unknowns or misconfigured ASPAs. */
|
||||||
|
if (up_end - down_end >= 2)
|
||||||
|
return ASPA_UNKNOWN;
|
||||||
|
|
||||||
|
/* The path has either a single transit provider, or a peering pair on top */
|
||||||
|
else if (up_end - down_end >= 0)
|
||||||
|
return unknown_flag ? ASPA_UNKNOWN : ASPA_VALID;
|
||||||
|
|
||||||
|
/* There is a gap between valid ramp up and valid ramp down */
|
||||||
|
else
|
||||||
|
return ASPA_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rte_find - find a route
|
* rte_find - find a route
|
||||||
* @net: network node
|
* @net: network node
|
||||||
|
Loading…
Reference in New Issue
Block a user