mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-11-09 20:58:44 +00:00
Merge commit '950775f6fa3d569a9d7cd05e33538d35e895d688' into haugesund
There were quite a lot of conflicts in flowspec validation code which ultimately led to some code being a bit rewritten, not only adapted from this or that branch, yet it is still in a limit of a merge.
This commit is contained in:
commit
cae5979871
@ -530,20 +530,24 @@
|
||||
STATIC_ATTR;
|
||||
ACCESS_RTE;
|
||||
ACCESS_EATTRS;
|
||||
struct rta *rta = fs->rte->attrs;
|
||||
|
||||
switch (sa.sa_code)
|
||||
{
|
||||
case SA_NET: RESULT(sa.type, net, fs->rte->net); break;
|
||||
case SA_PROTO: RESULT(sa.type, s, fs->rte->src->proto->name); break;
|
||||
case SA_DEST: RESULT(sa.type, i, rta->dest); break;
|
||||
default:
|
||||
{
|
||||
struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop *nh = nh_ea ? &((struct nexthop_adata *) nh_ea->u.ptr)->nh : NULL;
|
||||
struct eattr *nhea = ea_find(*fs->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
struct nexthop *nh = nhad ? &nhad->nh : NULL;
|
||||
|
||||
switch (sa.sa_code)
|
||||
{
|
||||
case SA_DEST:
|
||||
RESULT(sa.type, i, nhad ?
|
||||
(NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest)
|
||||
: RTD_NONE);
|
||||
break;
|
||||
case SA_GW:
|
||||
RESULT(sa.type, ip, nh ? nh->gw : IPA_NONE);
|
||||
break;
|
||||
@ -576,36 +580,33 @@
|
||||
|
||||
f_rta_cow(fs);
|
||||
{
|
||||
struct rta *rta = fs->rte->attrs;
|
||||
union {
|
||||
struct nexthop_adata nha;
|
||||
struct {
|
||||
struct adata ad;
|
||||
struct nexthop nh;
|
||||
u32 label;
|
||||
};
|
||||
} nha;
|
||||
|
||||
if (sa.sa_code == SA_DEST)
|
||||
nha.ad = (struct adata) {
|
||||
.length = sizeof (struct nexthop_adata) - sizeof (struct adata),
|
||||
};
|
||||
|
||||
eattr *a = NULL;
|
||||
|
||||
switch (sa.sa_code)
|
||||
{
|
||||
case SA_DEST:
|
||||
{
|
||||
int i = v1.val.i;
|
||||
if ((i != RTD_BLACKHOLE) && (i != RTD_UNREACHABLE) && (i != RTD_PROHIBIT))
|
||||
runtime( "Destination can be changed only to blackhole, unreachable or prohibit" );
|
||||
|
||||
rta->dest = i;
|
||||
ea_unset_attr(fs->eattrs, 1, &ea_gen_nexthop);
|
||||
nha.nha.dest = i;
|
||||
nha.ad.length = NEXTHOP_DEST_SIZE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
union {
|
||||
struct nexthop_adata nha;
|
||||
struct {
|
||||
struct adata ad;
|
||||
struct nexthop nh;
|
||||
u32 label;
|
||||
};
|
||||
} nha;
|
||||
|
||||
nha.ad = (struct adata) {
|
||||
.length = sizeof (struct nexthop_adata) - sizeof (struct adata),
|
||||
};
|
||||
|
||||
eattr *a = NULL;
|
||||
|
||||
switch (sa.sa_code)
|
||||
{
|
||||
case SA_GW:
|
||||
{
|
||||
struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
|
||||
@ -618,7 +619,6 @@
|
||||
if (!n || (n->scope == SCOPE_HOST))
|
||||
runtime( "Invalid gw address" );
|
||||
|
||||
rta->dest = RTD_UNICAST;
|
||||
nha.nh = (struct nexthop) {
|
||||
.gw = ip,
|
||||
.iface = n->iface,
|
||||
@ -632,7 +632,6 @@
|
||||
if (!ifa)
|
||||
runtime( "Invalid iface name" );
|
||||
|
||||
rta->dest = RTD_UNICAST;
|
||||
nha.nh = (struct nexthop) {
|
||||
.iface = ifa,
|
||||
};
|
||||
@ -666,15 +665,16 @@
|
||||
int i = v1.val.i;
|
||||
if (i < 1 || i > 256)
|
||||
runtime( "Setting weight value out of bounds" );
|
||||
if (rta->dest != RTD_UNICAST)
|
||||
runtime( "Setting weight needs regular nexthop " );
|
||||
|
||||
struct eattr *nh_ea = ea_find(*fs->eattrs, &ea_gen_nexthop);
|
||||
if (!nh_ea)
|
||||
runtime( "No nexthop to set weight on" );
|
||||
|
||||
struct nexthop_adata *nhax = (struct nexthop_adata *)
|
||||
tmp_copy_adata(&((struct nexthop_adata *) nh_ea->u.ptr)->ad);
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) nh_ea->u.ptr;
|
||||
if (!NEXTHOP_IS_REACHABLE(nhad))
|
||||
runtime( "Setting weight needs regular nexthop " );
|
||||
|
||||
struct nexthop_adata *nhax = (struct nexthop_adata *) tmp_copy_adata(&nhad->ad);
|
||||
|
||||
/* Set weight on all next hops */
|
||||
NEXTHOP_WALK(nh, nhax)
|
||||
@ -687,15 +687,14 @@
|
||||
|
||||
default:
|
||||
bug("Invalid static attribute access (%u/%u)", sa.type, sa.sa_code);
|
||||
}
|
||||
|
||||
if (!a)
|
||||
a = ea_set_attr(fs->eattrs,
|
||||
EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
|
||||
|
||||
a->originated = 1;
|
||||
a->fresh = 1;
|
||||
}
|
||||
|
||||
if (!a)
|
||||
a = ea_set_attr(fs->eattrs,
|
||||
EA_LITERAL_DIRECT_ADATA(&ea_gen_nexthop, 0, tmp_copy_adata(&nha.ad)));
|
||||
|
||||
a->originated = 1;
|
||||
a->fresh = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
67
lib/route.h
67
lib/route.h
@ -78,9 +78,17 @@ struct nexthop {
|
||||
/* For packing one into eattrs */
|
||||
struct nexthop_adata {
|
||||
struct adata ad;
|
||||
struct nexthop nh;
|
||||
/* There is either a set of nexthops or a special destination (RTD_*) */
|
||||
union {
|
||||
struct nexthop nh;
|
||||
uint dest;
|
||||
};
|
||||
};
|
||||
|
||||
#define NEXTHOP_DEST_SIZE (OFFSETOF(struct nexthop_adata, dest) + sizeof(uint) - OFFSETOF(struct adata, data))
|
||||
#define NEXTHOP_DEST_LITERAL(x) ((struct nexthop_adata) { \
|
||||
.ad.length = NEXTHOP_DEST_SIZE, .dest = (x), })
|
||||
|
||||
#define RNF_ONLINK 0x1 /* Gateway is onlink regardless of IP ranges */
|
||||
|
||||
|
||||
@ -90,7 +98,6 @@ typedef struct rta {
|
||||
u32 hash_key; /* Hash over important fields */
|
||||
struct ea_list *eattrs; /* Extended Attribute chain */
|
||||
u16 cached:1; /* Are attributes cached? */
|
||||
u16 dest:4; /* Route destination type (RTD_...) */
|
||||
} rta;
|
||||
|
||||
#define RTS_STATIC 1 /* Normal static route */
|
||||
@ -111,7 +118,7 @@ typedef struct rta {
|
||||
#define RTS_MAX 16
|
||||
|
||||
#define RTD_NONE 0 /* Undefined next hop */
|
||||
#define RTD_UNICAST 1 /* Next hop is neighbor router */
|
||||
#define RTD_UNICAST 1 /* A standard next hop */
|
||||
#define RTD_BLACKHOLE 2 /* Silently drop packets */
|
||||
#define RTD_UNREACHABLE 3 /* Reject as unreachable */
|
||||
#define RTD_PROHIBIT 4 /* Administratively prohibited */
|
||||
@ -122,10 +129,6 @@ extern const char * rta_dest_names[RTD_MAX];
|
||||
static inline const char *rta_dest_name(uint n)
|
||||
{ return (n < RTD_MAX) ? rta_dest_names[n] : "???"; }
|
||||
|
||||
/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
|
||||
static inline int rte_is_reachable(rte *r)
|
||||
{ return r->attrs->dest == RTD_UNICAST; }
|
||||
|
||||
|
||||
/*
|
||||
* Extended Route Attributes
|
||||
@ -333,9 +336,31 @@ extern struct ea_class ea_gen_source;
|
||||
static inline u32 rt_get_source_attr(const rte *rt)
|
||||
{ return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); }
|
||||
|
||||
/* Flowspec validation result */
|
||||
enum flowspec_valid {
|
||||
FLOWSPEC_UNKNOWN = 0,
|
||||
FLOWSPEC_VALID = 1,
|
||||
FLOWSPEC_INVALID = 2,
|
||||
FLOWSPEC__MAX,
|
||||
};
|
||||
|
||||
extern const char * flowspec_valid_names[FLOWSPEC__MAX];
|
||||
static inline const char *flowspec_valid_name(enum flowspec_valid v)
|
||||
{ return (v < FLOWSPEC__MAX) ? flowspec_valid_names[v] : "???"; }
|
||||
|
||||
extern struct ea_class ea_gen_flowspec_valid;
|
||||
static inline enum flowspec_valid rt_get_flowspec_valid(rte *rt)
|
||||
{ return ea_get_int(rt->attrs->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN); }
|
||||
|
||||
/* Next hop: For now, stored as adata */
|
||||
extern struct ea_class ea_gen_nexthop;
|
||||
|
||||
static inline void ea_set_dest(struct ea_list **to, uint flags, uint dest)
|
||||
{
|
||||
struct nexthop_adata nhad = NEXTHOP_DEST_LITERAL(dest);
|
||||
ea_set_attr_data(to, &ea_gen_nexthop, flags, &nhad.ad.data, nhad.ad.length);
|
||||
}
|
||||
|
||||
/* Next hop structures */
|
||||
|
||||
#define NEXTHOP_ALIGNMENT (_Alignof(struct nexthop))
|
||||
@ -361,7 +386,35 @@ struct nexthop_adata *nexthop_merge(struct nexthop_adata *x, struct nexthop_adat
|
||||
struct nexthop_adata *nexthop_sort(struct nexthop_adata *x, linpool *lp);
|
||||
int nexthop_is_sorted(struct nexthop_adata *x);
|
||||
|
||||
#define NEXTHOP_IS_REACHABLE(nhad) ((nhad)->ad.length > NEXTHOP_DEST_SIZE)
|
||||
|
||||
/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
|
||||
static inline int rte_is_reachable(rte *r)
|
||||
{
|
||||
eattr *nhea = ea_find(r->attrs->eattrs, &ea_gen_nexthop);
|
||||
if (!nhea)
|
||||
return 0;
|
||||
|
||||
struct nexthop_adata *nhad = (void *) nhea->u.ptr;
|
||||
return NEXTHOP_IS_REACHABLE(nhad);
|
||||
}
|
||||
|
||||
static inline int nhea_dest(eattr *nhea)
|
||||
{
|
||||
if (!nhea)
|
||||
return RTD_NONE;
|
||||
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
if (NEXTHOP_IS_REACHABLE(nhad))
|
||||
return RTD_UNICAST;
|
||||
else
|
||||
return nhad->dest;
|
||||
}
|
||||
|
||||
static inline int rte_dest(const rte *r)
|
||||
{
|
||||
return nhea_dest(ea_find(r->attrs->eattrs, &ea_gen_nexthop));
|
||||
}
|
||||
|
||||
void rta_init(void);
|
||||
#define rta_size(...) (sizeof(rta))
|
||||
|
@ -66,6 +66,7 @@ enum btype {
|
||||
|
||||
T_ENUM_BGP_ORIGIN = 0x11, /* BGP Origin enum */
|
||||
T_ENUM_RA_PREFERENCE = 0x13, /* RA Preference enum */
|
||||
T_ENUM_FLOWSPEC_VALID = 0x15, /* Flowspec validation result */
|
||||
|
||||
#define EAF_TYPE__MAX 0x1f
|
||||
#define EAF_EMBEDDED 0x01 /* Data stored in eattr.u.data (part of type spec) */
|
||||
|
@ -133,7 +133,7 @@ CF_KEYWORDS(IPV4, IPV4_MC, IPV4_MPLS, IPV6, IPV6_MC, IPV6_MPLS, IPV6_SADR, VPN4,
|
||||
CF_ENUM(T_ENUM_RTS, RTS_, 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_RTD, RTD_, BLACKHOLE, UNREACHABLE, PROHIBIT)
|
||||
CF_ENUM(T_ENUM_ROA, ROA_, UNKNOWN, VALID, INVALID)
|
||||
CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
|
||||
|
||||
|
@ -166,6 +166,18 @@ const char * rta_dest_names[RTD_MAX] = {
|
||||
[RTD_PROHIBIT] = "prohibited",
|
||||
};
|
||||
|
||||
struct ea_class ea_gen_flowspec_valid = {
|
||||
.name = "flowspec_valid",
|
||||
.type = T_ENUM_FLOWSPEC_VALID,
|
||||
.readonly = 1,
|
||||
};
|
||||
|
||||
const char * flowspec_valid_names[FLOWSPEC__MAX] = {
|
||||
[FLOWSPEC_UNKNOWN] = "unknown",
|
||||
[FLOWSPEC_VALID] = "",
|
||||
[FLOWSPEC_INVALID] = "invalid",
|
||||
};
|
||||
|
||||
pool *rta_pool;
|
||||
|
||||
static slab *rta_slab;
|
||||
@ -1246,20 +1258,13 @@ rta_alloc_hash(void)
|
||||
static inline uint
|
||||
rta_hash(rta *a)
|
||||
{
|
||||
u64 h;
|
||||
mem_hash_init(&h);
|
||||
#define BMIX(f) mem_hash_mix_num(&h, a->f);
|
||||
BMIX(dest);
|
||||
#undef MIX
|
||||
|
||||
return mem_hash_value(&h) ^ ea_hash(a->eattrs);
|
||||
return ea_hash(a->eattrs);
|
||||
}
|
||||
|
||||
static inline int
|
||||
rta_same(rta *x, rta *y)
|
||||
{
|
||||
return (x->dest == y->dest &&
|
||||
ea_same(x->eattrs, y->eattrs));
|
||||
return ea_same(x->eattrs, y->eattrs);
|
||||
}
|
||||
|
||||
static rta *
|
||||
@ -1382,10 +1387,8 @@ rta_do_cow(rta *o, linpool *lp)
|
||||
void
|
||||
rta_dump(rta *a)
|
||||
{
|
||||
static char *rtd[] = { "", " DEV", " HOLE", " UNREACH", " PROHIBIT" };
|
||||
|
||||
debug("uc=%d %s h=%04x",
|
||||
a->uc, rtd[a->dest], a->hash_key);
|
||||
debug("uc=%d h=%04x",
|
||||
a->uc, a->hash_key);
|
||||
if (!a->cached)
|
||||
debug(" !CACHED");
|
||||
if (a->eattrs)
|
||||
@ -1449,6 +1452,7 @@ rta_init(void)
|
||||
ea_register_init(&ea_gen_source);
|
||||
ea_register_init(&ea_gen_nexthop);
|
||||
ea_register_init(&ea_gen_hostentry);
|
||||
ea_register_init(&ea_gen_flowspec_valid);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -79,10 +79,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
|
||||
/* Use iface ID as local source ID */
|
||||
struct rte_src *src = rt_get_source(P, ad->iface->index);
|
||||
|
||||
rta a0 = {
|
||||
.dest = RTD_UNICAST,
|
||||
};
|
||||
|
||||
rta a0 = {};
|
||||
struct nexthop_adata nhad = {
|
||||
.nh = { .iface = ad->iface, },
|
||||
.ad = { .length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data, },
|
||||
|
@ -45,8 +45,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
|
||||
rta *a = e->attrs;
|
||||
int sync_error = d->kernel ? krt_get_sync_error(d->kernel, e) : 0;
|
||||
void (*get_route_info)(struct rte *, byte *buf);
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
eattr *nhea = net_type_match(e->net, NB_DEST) ?
|
||||
ea_find(a->eattrs, &ea_gen_nexthop) : NULL;
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
int dest = nhad ? (NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest) : RTD_NONE;
|
||||
int flowspec_valid = net_is_flow(e->net) ? rt_get_flowspec_valid(e) : FLOWSPEC_UNKNOWN;
|
||||
|
||||
tm_format_time(tm, &config->tf_route, e->lastmod);
|
||||
ip_addr a_from = ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE);
|
||||
@ -68,10 +71,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
|
||||
if (d->last_table != d->tab)
|
||||
rt_show_table(c, d);
|
||||
|
||||
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, rta_dest_name(a->dest),
|
||||
e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
|
||||
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia,
|
||||
net_is_flow(e->net) ? flowspec_valid_name(flowspec_valid) : rta_dest_name(dest),
|
||||
e->src->proto->name, tm, from, primary ? (sync_error ? " !" : " *") : "", info);
|
||||
|
||||
if (a->dest == RTD_UNICAST)
|
||||
if (dest == RTD_UNICAST)
|
||||
NEXTHOP_WALK(nh, nhad)
|
||||
{
|
||||
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
|
||||
|
169
nest/rt-table.c
169
nest/rt-table.c
@ -683,7 +683,7 @@ rte_trace(const char *name, const rte *e, int dir, const char *msg)
|
||||
{
|
||||
log(L_TRACE "%s %c %s %N %uL %uG %s",
|
||||
name, dir, msg, e->net, e->src->private_id, e->src->global_id,
|
||||
rta_dest_name(e->attrs->dest));
|
||||
rta_dest_name(rte_dest(e)));
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1226,29 +1226,29 @@ rte_validate(struct channel *ch, rte *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (net_type_match(n, NB_DEST) == !e->attrs->dest)
|
||||
if (net_type_match(n, NB_DEST))
|
||||
{
|
||||
/* Exception for flowspec that failed validation */
|
||||
if (net_is_flow(n) && (e->attrs->dest == RTD_UNREACHABLE))
|
||||
return 1;
|
||||
eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
|
||||
int dest = nhea_dest(nhea);
|
||||
|
||||
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
|
||||
n, e->attrs->dest, ch->proto->name);
|
||||
return 0;
|
||||
if (dest == RTD_NONE)
|
||||
{
|
||||
log(L_WARN "Ignoring route %N with no destination received via %s",
|
||||
n, ch->proto->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((dest == RTD_UNICAST) &&
|
||||
!nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
|
||||
{
|
||||
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
|
||||
n, ch->proto->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
|
||||
if ((!nhea) != (e->attrs->dest != RTD_UNICAST))
|
||||
else if (ea_find(e->attrs->eattrs, &ea_gen_nexthop))
|
||||
{
|
||||
log(L_WARN "Ignoring route %N with destination %d and %snexthop received via %s",
|
||||
n, e->attrs->dest, (nhea ? "" : "no "), ch->proto->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((e->attrs->dest == RTD_UNICAST) &&
|
||||
!nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
|
||||
{
|
||||
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
|
||||
log(L_WARN "Ignoring route %N having a nexthop attribute received via %s",
|
||||
n, ch->proto->name);
|
||||
return 0;
|
||||
}
|
||||
@ -2547,25 +2547,26 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
|
||||
u32 *labels = head->labels;
|
||||
u32 lnum = (u32 *) (head->ad.data + head->ad.length) - labels;
|
||||
|
||||
a->dest = he->dest;
|
||||
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, he->igp_metric);
|
||||
|
||||
if (a->dest != RTD_UNICAST)
|
||||
if (!he->src)
|
||||
{
|
||||
/* No nexthop */
|
||||
ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!lnum && he->nexthop_linkable)
|
||||
{ /* Just link the nexthop chain, no label append happens. */
|
||||
ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
|
||||
ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
eattr *he_nh_ea = ea_find(he->src->eattrs, &ea_gen_nexthop);
|
||||
ASSERT_DIE(he_nh_ea);
|
||||
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) he_nh_ea->u.ptr;
|
||||
int idest = nhea_dest(he_nh_ea);
|
||||
|
||||
if ((idest != RTD_UNICAST) ||
|
||||
!lnum && he->nexthop_linkable)
|
||||
{ /* Just link the nexthop chain, no label append happens. */
|
||||
ea_copy_attr(&a->eattrs, he->src->eattrs, &ea_gen_nexthop);
|
||||
return;
|
||||
}
|
||||
|
||||
uint total_size = OFFSETOF(struct nexthop_adata, nh);
|
||||
|
||||
@ -2583,10 +2584,14 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
|
||||
|
||||
if (total_size == OFFSETOF(struct nexthop_adata, nh))
|
||||
{
|
||||
a->dest = RTD_UNREACHABLE;
|
||||
log(L_WARN "No valid nexthop remaining, setting route unreachable");
|
||||
|
||||
ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
|
||||
struct nexthop_adata nha = {
|
||||
.ad.length = NEXTHOP_DEST_SIZE,
|
||||
.dest = RTD_UNREACHABLE,
|
||||
};
|
||||
|
||||
ea_set_attr_data(&a->eattrs, &ea_gen_nexthop, 0, &nha.ad.data, nha.ad.length);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2627,19 +2632,28 @@ rta_apply_hostentry(rta *a, struct hostentry_adata *head)
|
||||
static inline struct hostentry_adata *
|
||||
rta_next_hop_outdated(rta *a)
|
||||
{
|
||||
/* First retrieve the hostentry */
|
||||
eattr *heea = ea_find(a->eattrs, &ea_gen_hostentry);
|
||||
if (!heea)
|
||||
return NULL;
|
||||
|
||||
struct hostentry_adata *head = (struct hostentry_adata *) heea->u.ptr;
|
||||
|
||||
if (!head->he->src)
|
||||
return (a->dest != RTD_UNREACHABLE) ? head : NULL;
|
||||
|
||||
eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
|
||||
/* If no nexthop is present, we have to create one */
|
||||
eattr *a_nh_ea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
if (!a_nh_ea)
|
||||
return head;
|
||||
|
||||
return ((a->dest != head->he->dest) ||
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) a_nh_ea->u.ptr;
|
||||
|
||||
/* Shortcut for unresolvable hostentry */
|
||||
if (!head->he->src)
|
||||
return NEXTHOP_IS_REACHABLE(nhad) ? head : NULL;
|
||||
|
||||
/* Comparing our nexthop with the hostentry nexthop */
|
||||
eattr *he_nh_ea = ea_find(head->he->src->eattrs, &ea_gen_nexthop);
|
||||
|
||||
return (
|
||||
(ea_get_int(a->eattrs, &ea_gen_igp_metric, IGP_METRIC_UNKNOWN) != head->he->igp_metric) ||
|
||||
(!head->he->nexthop_linkable) ||
|
||||
(!he_nh_ea != !a_nh_ea) ||
|
||||
@ -2722,7 +2736,7 @@ rta_get_first_asn(rta *a)
|
||||
return (e && as_path_get_first_regular(e->u.ptr, &asn)) ? asn : 0;
|
||||
}
|
||||
|
||||
int
|
||||
static inline enum flowspec_valid
|
||||
rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior)
|
||||
{
|
||||
ASSERT(rt_is_ip(tab_ip));
|
||||
@ -2731,11 +2745,11 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
|
||||
|
||||
/* RFC 8955 6. a) Flowspec has defined dst prefix */
|
||||
if (!net_flow_has_dst_prefix(n))
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
/* RFC 9117 4.1. Accept AS_PATH is empty (fr */
|
||||
if (interior && rta_as_path_is_empty(a))
|
||||
return 1;
|
||||
return FLOWSPEC_VALID;
|
||||
|
||||
|
||||
/* RFC 8955 6. b) Flowspec and its best-match route have the same originator */
|
||||
@ -2757,7 +2771,7 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
|
||||
|
||||
/* No best-match BGP route -> no flowspec */
|
||||
if (!rb || (rt_get_source_attr(rb) != RTS_BGP))
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
/* Find ORIGINATOR_ID values */
|
||||
u32 orig_a = ea_get_int(a->eattrs, "bgp_originator_id", 0);
|
||||
@ -2768,17 +2782,17 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
|
||||
ea_get_ip(a->eattrs, &ea_gen_from, IPA_NONE),
|
||||
ea_get_ip(rb->attrs->eattrs, &ea_gen_from, IPA_NONE)
|
||||
)))
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
|
||||
/* Find ASN of the best-match route, for use in next checks */
|
||||
u32 asn_b = rta_get_first_asn(rb->attrs);
|
||||
if (!asn_b)
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
/* RFC 9117 4.2. For EBGP, flowspec and its best-match route are from the same AS */
|
||||
if (!interior && (rta_get_first_asn(a) != asn_b))
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
/* RFC 8955 6. c) More-specific routes are from the same AS as the best-match route */
|
||||
TRIE_WALK(tab_ip->trie, subnet, &dst)
|
||||
@ -2789,14 +2803,14 @@ rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, i
|
||||
|
||||
const rte *rc = &nc->routes->rte;
|
||||
if (rt_get_source_attr(rc) != RTS_BGP)
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
|
||||
if (rta_get_first_asn(rc->attrs) != asn_b)
|
||||
return 0;
|
||||
return FLOWSPEC_INVALID;
|
||||
}
|
||||
TRIE_WALK_END;
|
||||
|
||||
return 1;
|
||||
return FLOWSPEC_VALID;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_BGP */
|
||||
@ -2812,18 +2826,20 @@ rt_flowspec_update_rte(rtable *tab, net *n, rte *r)
|
||||
if (!bc->base_table)
|
||||
return NULL;
|
||||
|
||||
struct bgp_proto *p = (void *) r->src->proto;
|
||||
int valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior);
|
||||
int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
|
||||
struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, bc->c.proto);
|
||||
|
||||
if (dest == r->attrs->dest)
|
||||
enum flowspec_valid old = rt_get_flowspec_valid(r),
|
||||
valid = rt_flowspec_check(bc->base_table, tab, n->n.addr, r->attrs, p->is_interior);
|
||||
|
||||
if (old == valid)
|
||||
return NULL;
|
||||
|
||||
rta *a = alloca(RTA_MAX_SIZE);
|
||||
*a = *r->attrs;
|
||||
a->dest = dest;
|
||||
a->cached = 0;
|
||||
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
|
||||
|
||||
rte new;
|
||||
memcpy(&new, r, sizeof(rte));
|
||||
new.attrs = a;
|
||||
@ -2838,18 +2854,23 @@ static inline void
|
||||
rt_flowspec_resolve_rte(rte *r, struct channel *c)
|
||||
{
|
||||
#ifdef CONFIG_BGP
|
||||
if (rt_get_source_attr(r) != RTS_BGP)
|
||||
return;
|
||||
|
||||
enum flowspec_valid valid, old = rt_get_flowspec_valid(r);
|
||||
struct bgp_channel *bc = (struct bgp_channel *) c;
|
||||
if (!bc->base_table)
|
||||
return;
|
||||
|
||||
struct bgp_proto *p = (void *) r->src->proto;
|
||||
int valid = rt_flowspec_check(bc->base_table, c->in_req.hook->table, r->net, r->attrs, p->is_interior);
|
||||
int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
|
||||
if ( (rt_get_source_attr(r) == RTS_BGP)
|
||||
&& (c->channel == &channel_bgp)
|
||||
&& (bc->base_table))
|
||||
{
|
||||
struct bgp_proto *p = SKIP_BACK(struct bgp_proto, p, bc->c.proto);
|
||||
valid = rt_flowspec_check(
|
||||
bc->base_table,
|
||||
c->in_req.hook->table,
|
||||
r->net, r->attrs, p->is_interior);
|
||||
}
|
||||
else
|
||||
valid = FLOWSPEC_UNKNOWN;
|
||||
|
||||
if (dest == r->attrs->dest)
|
||||
if (valid == old)
|
||||
return;
|
||||
|
||||
if (r->attrs->cached)
|
||||
@ -2860,7 +2881,10 @@ rt_flowspec_resolve_rte(rte *r, struct channel *c)
|
||||
r->attrs = a;
|
||||
}
|
||||
|
||||
r->attrs->dest = dest;
|
||||
if (valid == FLOWSPEC_UNKNOWN)
|
||||
ea_unset_attr(&r->attrs->eattrs, 0, &ea_gen_flowspec_valid);
|
||||
else
|
||||
ea_set_attr_u32(&r->attrs->eattrs, &ea_gen_flowspec_valid, 0, valid);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -3651,7 +3675,6 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
|
||||
/* Reset the hostentry */
|
||||
he->src = NULL;
|
||||
he->dest = RTD_UNREACHABLE;
|
||||
he->nexthop_linkable = 0;
|
||||
he->igp_metric = 0;
|
||||
|
||||
@ -3672,16 +3695,12 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (a->dest == RTD_UNICAST)
|
||||
{
|
||||
eattr *ea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
if (!ea)
|
||||
{
|
||||
log(L_WARN "No nexthop in unicast route");
|
||||
goto done;
|
||||
}
|
||||
|
||||
NEXTHOP_WALK(nh, (struct nexthop_adata *) ea->u.ptr)
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
ASSERT_DIE(nhea);
|
||||
struct nexthop_adata *nhad = (void *) nhea->u.ptr;
|
||||
|
||||
if (NEXTHOP_IS_REACHABLE(nhad))
|
||||
NEXTHOP_WALK(nh, nhad)
|
||||
if (ipa_zero(nh->gw))
|
||||
{
|
||||
if (if_local_addr(he->addr, nh->iface))
|
||||
@ -3694,10 +3713,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
|
||||
|
||||
direct++;
|
||||
}
|
||||
}
|
||||
|
||||
he->src = rta_clone(a);
|
||||
he->dest = a->dest;
|
||||
he->nexthop_linkable = !direct;
|
||||
he->igp_metric = rt_get_igp_metric(&e->rte);
|
||||
}
|
||||
|
@ -148,7 +148,6 @@ struct hostentry {
|
||||
unsigned hash_key; /* Hash key */
|
||||
unsigned uc; /* Use count */
|
||||
struct rta *src; /* Source rta entry */
|
||||
byte dest; /* Chosen route destination type (RTD_...) */
|
||||
byte nexthop_linkable; /* Nexthop list is completely non-device */
|
||||
u32 igp_metric; /* Chosen route IGP metric */
|
||||
};
|
||||
@ -460,9 +459,6 @@ rta_set_recursive_next_hop(rtable *dep, rta *a, rtable *tab, ip_addr gw, ip_addr
|
||||
}
|
||||
*/
|
||||
|
||||
int rt_flowspec_check(rtable *tab_ip, rtable *tab_flow, const net_addr *n, rta *a, int interior);
|
||||
|
||||
|
||||
/*
|
||||
* Default protocol preferences
|
||||
*/
|
||||
|
@ -677,10 +677,7 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
|
||||
}
|
||||
};
|
||||
|
||||
rta a0 = {
|
||||
.dest = RTD_UNICAST,
|
||||
.eattrs = &eattrs.l,
|
||||
};
|
||||
rta a0 = { .eattrs = &eattrs.l, };
|
||||
|
||||
rte e0 = {
|
||||
.attrs = &a0,
|
||||
@ -693,12 +690,11 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
|
||||
else if (e->valid && (e->router_id != p->router_id))
|
||||
{
|
||||
/* Unreachable */
|
||||
rta a0 = {
|
||||
.dest = RTD_UNREACHABLE,
|
||||
};
|
||||
rta a0 = {};
|
||||
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, 1);
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_BABEL);
|
||||
ea_set_dest(&a0.eattrs, 0, RTD_UNREACHABLE);
|
||||
|
||||
rte e0 = {
|
||||
.attrs = &a0,
|
||||
@ -2266,9 +2262,13 @@ babel_kick_timer(struct babel_proto *p)
|
||||
static int
|
||||
babel_preexport(struct channel *c, struct rte *new)
|
||||
{
|
||||
struct rta *a = new->attrs;
|
||||
if (new->src->proto != c->proto)
|
||||
return 0;
|
||||
|
||||
/* Reject our own unreachable routes */
|
||||
if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == c->proto))
|
||||
eattr *ea = ea_find(new->attrs->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = (void *) ea->u.ptr;
|
||||
if (!NEXTHOP_IS_REACHABLE(nhad))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
|
@ -1715,8 +1715,20 @@ bgp_preexport(struct channel *c, rte *e)
|
||||
return 0;
|
||||
|
||||
/* Reject flowspec that failed validation */
|
||||
if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net))
|
||||
return -1;
|
||||
if (net_is_flow(e->net))
|
||||
switch (rt_get_flowspec_valid(e))
|
||||
{
|
||||
case FLOWSPEC_VALID:
|
||||
break;
|
||||
case FLOWSPEC_INVALID:
|
||||
return -1;
|
||||
case FLOWSPEC_UNKNOWN:
|
||||
ASSUME((rt_get_source_attr(e) != RTS_BGP) ||
|
||||
!((struct bgp_channel *) SKIP_BACK(struct channel, in_req, e->sender->req))->base_table);
|
||||
break;
|
||||
case FLOWSPEC__MAX:
|
||||
bug("This never happens.");
|
||||
}
|
||||
|
||||
/* IBGP route reflection, RFC 4456 */
|
||||
if (p->is_internal && src->is_internal && (p->local_as == src->local_as))
|
||||
|
@ -519,7 +519,9 @@ struct rte_source *bgp_get_source(struct bgp_proto *p, u32 path_id);
|
||||
static inline int
|
||||
rta_resolvable(rta *a)
|
||||
{
|
||||
return a->dest != RTD_UNREACHABLE;
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = (void *) nhea->u.ptr;
|
||||
return NEXTHOP_IS_REACHABLE(nhad) || (nhad->dest != RTD_UNREACHABLE);
|
||||
}
|
||||
|
||||
|
||||
|
@ -968,7 +968,6 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
|
||||
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_igp_metric, 0, c->cf->cost);
|
||||
|
||||
a->dest = RTD_UNICAST;
|
||||
struct nexthop_adata nhad = {
|
||||
.nh = {
|
||||
.gw = nbr->addr,
|
||||
@ -1003,8 +1002,7 @@ bgp_apply_mpls_labels(struct bgp_parse_state *s, rta *a, u32 lnum, u32 labels[ln
|
||||
{
|
||||
REPORT("Too many MPLS labels ($u)", lnum);
|
||||
|
||||
a->dest = RTD_UNREACHABLE;
|
||||
ea_unset_attr(&a->eattrs, 0, &ea_gen_nexthop);
|
||||
ea_set_dest(&a->eattrs, 0, RTD_UNREACHABLE);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1092,17 +1090,14 @@ bgp_use_gateway(struct bgp_export_state *s)
|
||||
if (c->cf->next_hop_self && bgp_match_src(s, c->cf->next_hop_self))
|
||||
return NULL;
|
||||
|
||||
/* Unreachable */
|
||||
if (ra->dest != RTD_UNICAST)
|
||||
return NULL;
|
||||
|
||||
eattr *nhea = ea_find(ra->eattrs, &ea_gen_nexthop);
|
||||
if (!nhea)
|
||||
return NULL;
|
||||
|
||||
/* We need one valid global gateway */
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
|
||||
if (!NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
|
||||
if (!NEXTHOP_IS_REACHABLE(nhad) ||
|
||||
!NEXTHOP_ONE(nhad) || ipa_zero(nhad->nh.gw) ||
|
||||
ipa_is_link_local(nhad->nh.gw))
|
||||
return NULL;
|
||||
|
||||
|
@ -1983,8 +1983,7 @@ ort_changed(ort *nf, rta *nr)
|
||||
|
||||
if (!or ||
|
||||
(nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
|
||||
(nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
|
||||
(nr->dest != or->dest))
|
||||
(nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid))
|
||||
return 1;
|
||||
|
||||
eattr *nhea_n = ea_find(nr->eattrs, &ea_gen_nexthop);
|
||||
@ -2049,7 +2048,6 @@ again1:
|
||||
if (nf->n.type) /* Add the route */
|
||||
{
|
||||
rta a0 = {
|
||||
.dest = RTD_UNICAST,
|
||||
};
|
||||
|
||||
struct {
|
||||
|
@ -1366,20 +1366,11 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, const net_addr *n, rt
|
||||
uint tag = ea_get_int(a->eattrs, &ea_ospf_tag, 0);
|
||||
|
||||
ip_addr fwd = IPA_NONE;
|
||||
if (a->dest == RTD_UNICAST)
|
||||
{
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
if (!nhea)
|
||||
{
|
||||
log(L_ERR "%s: Unicast route without nexthop for %N",
|
||||
p->p.name, n);
|
||||
return;
|
||||
}
|
||||
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
|
||||
if (NEXTHOP_IS_REACHABLE(nhad))
|
||||
if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface))
|
||||
fwd = nhad->nh.gw;
|
||||
}
|
||||
|
||||
/* NSSA-LSA with P-bit set must have non-zero forwarding address */
|
||||
if (oa && ipa_zero(fwd))
|
||||
|
@ -142,9 +142,7 @@ perf_loop(void *data)
|
||||
*((net_addr_ip4 *) &(p->data[i].net)) = random_net_ip4();
|
||||
|
||||
if (!p->attrs_per_rte || !(i % p->attrs_per_rte)) {
|
||||
struct rta a0 = {
|
||||
.dest = RTD_UNICAST,
|
||||
};
|
||||
struct rta a0 = {};
|
||||
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_PERF);
|
||||
|
@ -151,9 +151,7 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
|
||||
if (rt)
|
||||
{
|
||||
/* Update */
|
||||
rta a0 = {
|
||||
.dest = RTD_UNICAST,
|
||||
};
|
||||
rta a0 = {};
|
||||
|
||||
struct {
|
||||
ea_list l;
|
||||
|
@ -120,9 +120,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
|
||||
{
|
||||
struct rpki_proto *p = cache->p;
|
||||
|
||||
rta a0 = {
|
||||
.dest = RTD_NONE,
|
||||
};
|
||||
rta a0 = {};
|
||||
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_preference, 0, channel->preference);
|
||||
ea_set_attr_u32(&a0.eattrs, &ea_gen_source, 0, RTS_RPKI);
|
||||
|
@ -55,7 +55,6 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||
{
|
||||
rta *a = allocz(RTA_MAX_SIZE);
|
||||
struct rte_src *src = static_get_source(p, r->index);
|
||||
a->dest = r->dest;
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_preference, 0, p->p.main_channel->preference);
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_source, 0, RTS_STATIC);
|
||||
|
||||
@ -97,7 +96,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||
nhad->ad.data, (void *) nh - (void *) nhad->ad.data);
|
||||
}
|
||||
|
||||
if (r->dest == RTDX_RECURSIVE)
|
||||
else if (r->dest == RTDX_RECURSIVE)
|
||||
{
|
||||
rtable *tab = ipa_is_ip4(r->via) ? p->igp_table_ip4 : p->igp_table_ip6;
|
||||
u32 *labels = r->mls ? (void *) r->mls->data : NULL;
|
||||
@ -107,6 +106,9 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
|
||||
r->via, IPA_NONE, lnum, labels);
|
||||
}
|
||||
|
||||
else if (r->dest)
|
||||
ea_set_dest(&a->eattrs, 0, r->dest);
|
||||
|
||||
/* Already announced */
|
||||
if (r->state == SRS_CLEAN)
|
||||
return;
|
||||
|
@ -1407,11 +1407,16 @@ HASH_DEFINE_REHASH_FN(RTH, struct krt_proto)
|
||||
int
|
||||
krt_capable(rte *e)
|
||||
{
|
||||
rta *a = e->attrs;
|
||||
eattr *ea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
|
||||
if (!ea)
|
||||
return 0;
|
||||
|
||||
switch (a->dest)
|
||||
struct nexthop_adata *nhad = (void *) ea->u.ptr;
|
||||
if (NEXTHOP_IS_REACHABLE(nhad))
|
||||
return 1;
|
||||
|
||||
switch (nhad->dest)
|
||||
{
|
||||
case RTD_UNICAST:
|
||||
case RTD_BLACKHOLE:
|
||||
case RTD_UNREACHABLE:
|
||||
case RTD_PROHIBIT:
|
||||
@ -1590,7 +1595,7 @@ nl_add_rte(struct krt_proto *p, rte *e)
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
|
||||
if (krt_ecmp6(p) && nhad && !NEXTHOP_ONE(nhad))
|
||||
if (krt_ecmp6(p) && nhad && NEXTHOP_IS_REACHABLE(nhad) && !NEXTHOP_ONE(nhad))
|
||||
{
|
||||
uint cnt = 0;
|
||||
NEXTHOP_WALK(nh, nhad)
|
||||
@ -1615,7 +1620,8 @@ nl_add_rte(struct krt_proto *p, rte *e)
|
||||
return err;
|
||||
}
|
||||
|
||||
return nl_send_route(p, e, NL_OP_ADD, a->dest, nhad);
|
||||
return nl_send_route(p, e, NL_OP_ADD,
|
||||
NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
|
||||
}
|
||||
|
||||
static inline int
|
||||
@ -1637,7 +1643,8 @@ nl_replace_rte(struct krt_proto *p, rte *e)
|
||||
rta *a = e->attrs;
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
return nl_send_route(p, e, NL_OP_REPLACE, a->dest, nhad);
|
||||
return nl_send_route(p, e, NL_OP_REPLACE,
|
||||
NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest, nhad);
|
||||
}
|
||||
|
||||
|
||||
@ -1900,8 +1907,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
switch (i->rtm_type)
|
||||
{
|
||||
case RTN_UNICAST:
|
||||
ra->dest = RTD_UNICAST;
|
||||
|
||||
if (a[RTA_MULTIPATH])
|
||||
{
|
||||
struct nexthop_adata *nh = nl_parse_multipath(s, p, net, a[RTA_MULTIPATH], i->rtm_family, krt_src);
|
||||
@ -1952,15 +1957,40 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
|
||||
nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
|
||||
|
||||
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
|
||||
{
|
||||
switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
|
||||
{
|
||||
case LWTUNNEL_ENCAP_MPLS:
|
||||
{
|
||||
struct rtattr *enca[BIRD_RTA_MAX];
|
||||
nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
|
||||
nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
|
||||
nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Finalize the nexthop */
|
||||
nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
|
||||
break;
|
||||
case RTN_BLACKHOLE:
|
||||
ra->dest = RTD_BLACKHOLE;
|
||||
nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_BLACKHOLE);
|
||||
break;
|
||||
case RTN_UNREACHABLE:
|
||||
ra->dest = RTD_UNREACHABLE;
|
||||
nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_UNREACHABLE);
|
||||
break;
|
||||
case RTN_PROHIBIT:
|
||||
ra->dest = RTD_PROHIBIT;
|
||||
nhad.nhad = NEXTHOP_DEST_LITERAL(RTD_PROHIBIT);
|
||||
break;
|
||||
/* FIXME: What about RTN_THROW? */
|
||||
default:
|
||||
@ -1968,32 +1998,6 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MPLS_KERNEL
|
||||
if ((i->rtm_family == AF_MPLS) && a[RTA_NEWDST] && !a[RTA_MULTIPATH])
|
||||
nhad.nh.labels = rta_get_mpls(a[RTA_NEWDST], nhad.nh.label);
|
||||
|
||||
if (a[RTA_ENCAP] && a[RTA_ENCAP_TYPE] && !a[RTA_MULTIPATH])
|
||||
{
|
||||
switch (rta_get_u16(a[RTA_ENCAP_TYPE]))
|
||||
{
|
||||
case LWTUNNEL_ENCAP_MPLS:
|
||||
{
|
||||
struct rtattr *enca[BIRD_RTA_MAX];
|
||||
nl_attr_len = RTA_PAYLOAD(a[RTA_ENCAP]);
|
||||
nl_parse_attrs(RTA_DATA(a[RTA_ENCAP]), encap_mpls_want, enca, sizeof(enca));
|
||||
nhad.nh.labels = rta_get_mpls(enca[RTA_DST], nhad.nh.label);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
SKIP("unknown encapsulation method %d\n", rta_get_u16(a[RTA_ENCAP_TYPE]));
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Finalize the nexthop */
|
||||
nhad.ad.length = (void *) NEXTHOP_NEXT(&nhad.nh) - (void *) nhad.ad.data;
|
||||
|
||||
if (i->rtm_scope != def_scope)
|
||||
ea_set_attr(&ra->eattrs,
|
||||
EA_LITERAL_EMBEDDED(&ea_krt_scope, 0, i->rtm_scope));
|
||||
|
@ -618,17 +618,10 @@ krt_same_dest(rte *k, rte *e)
|
||||
{
|
||||
rta *ka = k->attrs, *ea = e->attrs;
|
||||
|
||||
if (ka->dest != ea->dest)
|
||||
return 0;
|
||||
|
||||
if (ka->dest != RTD_UNICAST)
|
||||
return 1;
|
||||
|
||||
eattr *nhea_k = ea_find(ka->eattrs, &ea_gen_nexthop);
|
||||
eattr *nhea_e = ea_find(ea->eattrs, &ea_gen_nexthop);
|
||||
|
||||
ASSUME(nhea_k && nhea_e);
|
||||
return adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
|
||||
return (!nhea_k == !nhea_e) && adata_same(nhea_k->u.ptr, nhea_e->u.ptr);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user