mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Route destination field merged with nexthop attribute; splitting flowspec validation result out.
As there is either a nexthop or another destination specification (or othing in case of ROAs and Flowspec), it may be merged together. This code is somehow quirky and should be replaced in future by better implementation of nexthop. Also flowspec validation result has its own attribute now as it doesn't have anything to do with route nexthop.
This commit is contained in:
parent
4fe9881d62
commit
950775f6fa
@ -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->n.addr); 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
60
lib/route.h
60
lib/route.h
@ -76,9 +76,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 */
|
||||
|
||||
|
||||
@ -88,7 +96,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 */
|
||||
@ -109,7 +116,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 */
|
||||
@ -120,10 +127,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
|
||||
@ -331,9 +334,24 @@ extern struct ea_class ea_gen_source;
|
||||
static inline u32 rt_get_source_attr(rte *rt)
|
||||
{ return ea_get_int(rt->attrs->eattrs, &ea_gen_source, 0); }
|
||||
|
||||
/* Flowspec validation result */
|
||||
#define FLOWSPEC_UNKNOWN 0
|
||||
#define FLOWSPEC_VALID 1
|
||||
#define FLOWSPEC_INVALID 2
|
||||
|
||||
extern struct ea_class ea_gen_flowspec_valid;
|
||||
static inline u32 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))
|
||||
@ -359,7 +377,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(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,12 @@ 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,
|
||||
};
|
||||
|
||||
pool *rta_pool;
|
||||
|
||||
static slab *rta_slab;
|
||||
@ -1246,20 +1252,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 +1381,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 +1446,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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -82,10 +82,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, },
|
||||
|
@ -47,6 +47,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, int primary
|
||||
void (*get_route_info)(struct rte *, byte *buf);
|
||||
eattr *nhea = ea_find(a->eattrs, &ea_gen_nexthop);
|
||||
struct nexthop_adata *nhad = nhea ? (struct nexthop_adata *) nhea->u.ptr : NULL;
|
||||
int dest = NEXTHOP_IS_REACHABLE(nhad) ? RTD_UNICAST : nhad->dest;
|
||||
|
||||
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 +69,10 @@ 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),
|
||||
cli_printf(c, -1007, "%-20s %s [%s %s%s]%s%s", ia, 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;
|
||||
|
100
nest/rt-table.c
100
nest/rt-table.c
@ -699,7 +699,7 @@ rte_trace(struct channel *c, rte *e, int dir, char *msg)
|
||||
{
|
||||
log(L_TRACE "%s.%s %c %s %N %uL %uG %s",
|
||||
c->proto->name, c->name ?: "?", dir, msg, e->net->n.addr, e->src->private_id, e->src->global_id,
|
||||
rta_dest_name(e->attrs->dest));
|
||||
rta_dest_name(rte_dest(e)));
|
||||
}
|
||||
|
||||
static inline void
|
||||
@ -1177,26 +1177,17 @@ rte_validate(rte *e)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
|
||||
{
|
||||
/* Exception for flowspec that failed validation */
|
||||
if (net_is_flow(n->n.addr) && (e->attrs->dest == RTD_UNREACHABLE))
|
||||
return 1;
|
||||
|
||||
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
|
||||
n->n.addr, e->attrs->dest, e->sender->proto->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
eattr *nhea = ea_find(e->attrs->eattrs, &ea_gen_nexthop);
|
||||
if ((!nhea) != (e->attrs->dest != RTD_UNICAST))
|
||||
int dest = nhea_dest(nhea);
|
||||
|
||||
if (net_type_match(n->n.addr, NB_DEST) == !dest)
|
||||
{
|
||||
log(L_WARN "Ignoring route %N with destination %d and %snexthop received via %s",
|
||||
n->n.addr, e->attrs->dest, (nhea ? "" : "no "), e->sender->proto->name);
|
||||
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
|
||||
n->n.addr, dest, e->sender->proto->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((e->attrs->dest == RTD_UNICAST) &&
|
||||
if ((dest == RTD_UNICAST) &&
|
||||
!nexthop_is_sorted((struct nexthop_adata *) nhea->u.ptr))
|
||||
{
|
||||
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
|
||||
@ -2431,25 +2422,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);
|
||||
|
||||
@ -2467,10 +2459,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;
|
||||
}
|
||||
|
||||
@ -2511,19 +2507,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) ||
|
||||
@ -2682,16 +2687,16 @@ rt_flowspec_update_rte(rtable *tab, rte *r)
|
||||
const net_addr *n = r->net->n.addr;
|
||||
struct bgp_proto *p = (void *) r->src->proto;
|
||||
int valid = rt_flowspec_check(bc->base_table, tab, n, r->attrs, p->is_interior);
|
||||
int dest = valid ? RTD_NONE : RTD_UNREACHABLE;
|
||||
|
||||
if (dest == r->attrs->dest)
|
||||
int old = rt_get_flowspec_valid(r);
|
||||
if (old == valid)
|
||||
return NULL;
|
||||
|
||||
rta *a = alloca(RTA_MAX_SIZE);
|
||||
memcpy(a, r->attrs, rta_size(r->attrs));
|
||||
a->dest = dest;
|
||||
a->cached = 0;
|
||||
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
|
||||
|
||||
rte *new = sl_alloc(rte_slab);
|
||||
memcpy(new, r, sizeof(rte));
|
||||
new->attrs = rta_lookup(a);
|
||||
@ -3524,7 +3529,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;
|
||||
|
||||
@ -3545,16 +3549,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))
|
||||
@ -3567,10 +3567,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);
|
||||
}
|
||||
|
@ -144,7 +144,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 */
|
||||
};
|
||||
|
@ -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, };
|
||||
|
||||
rta *a = rta_lookup(&a0);
|
||||
rte *rte = rte_get_temp(a, p->p.main_source);
|
||||
@ -691,12 +688,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);
|
||||
|
||||
rta *a = rta_lookup(&a0);
|
||||
rte *rte = rte_get_temp(a, p->p.main_source);
|
||||
@ -2263,9 +2259,13 @@ babel_kick_timer(struct babel_proto *p)
|
||||
static int
|
||||
babel_preexport(struct proto *P, struct rte *new)
|
||||
{
|
||||
struct rta *a = new->attrs;
|
||||
if (new->src->proto != P)
|
||||
return 0;
|
||||
|
||||
/* Reject our own unreachable routes */
|
||||
if ((a->dest == RTD_UNREACHABLE) && (new->src->proto == P))
|
||||
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;
|
||||
|
@ -1711,9 +1711,20 @@ bgp_preexport(struct proto *P, rte *e)
|
||||
if (src == NULL)
|
||||
return 0;
|
||||
|
||||
/* Reject flowspec that failed validation */
|
||||
if ((e->attrs->dest == RTD_UNREACHABLE) && net_is_flow(e->net->n.addr))
|
||||
return -1;
|
||||
/* Reject flowspec that failed or are pending validation */
|
||||
if (net_is_flow(e->net->n.addr))
|
||||
switch (rt_get_flowspec_valid(e))
|
||||
{
|
||||
case FLOWSPEC_VALID:
|
||||
break;
|
||||
case FLOWSPEC_INVALID:
|
||||
return -1;
|
||||
case FLOWSPEC_UNKNOWN:
|
||||
if ((rt_get_source_attr(e) == RTS_BGP) &&
|
||||
((struct bgp_channel *) e->sender)->base_table)
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* 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
|
||||
rte_resolvable(rte *rt)
|
||||
{
|
||||
return rt->attrs->dest != RTD_UNREACHABLE;
|
||||
eattr *nhea = ea_find(rt->attrs->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;
|
||||
}
|
||||
|
||||
@ -1039,15 +1037,21 @@ static void
|
||||
bgp_apply_flow_validation(struct bgp_parse_state *s, const net_addr *n, rta *a)
|
||||
{
|
||||
struct bgp_channel *c = s->channel;
|
||||
int valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
|
||||
a->dest = valid ? RTD_NONE : RTD_UNREACHABLE;
|
||||
uint valid = rt_flowspec_check(c->base_table, c->c.table, n, a, s->proto->is_interior);
|
||||
|
||||
/* Invalidate cached rta if dest changes */
|
||||
if (s->cached_rta && (s->cached_rta->dest != a->dest))
|
||||
/* Invalidate cached rta */
|
||||
if (s->cached_rta)
|
||||
{
|
||||
/* Has't changed */
|
||||
if (valid == ea_get_int(s->cached_rta->eattrs, &ea_gen_flowspec_valid, FLOWSPEC_UNKNOWN))
|
||||
return;
|
||||
|
||||
rta_free(s->cached_rta);
|
||||
s->cached_rta = NULL;
|
||||
}
|
||||
|
||||
/* Set the value */
|
||||
ea_set_attr_u32(&a->eattrs, &ea_gen_flowspec_valid, 0, valid);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1107,17 +1111,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,16 +1366,9 @@ ospf_rt_notify(struct proto *P, struct channel *ch UNUSED, net *n, rte *new, rte
|
||||
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)
|
||||
{
|
||||
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->n.addr);
|
||||
return;
|
||||
}
|
||||
|
||||
struct nexthop_adata *nhad = (struct nexthop_adata *) nhea->u.ptr;
|
||||
if (use_gw_for_fwaddr(p, nhad->nh.gw, nhad->nh.iface))
|
||||
fwd = nhad->nh.gw;
|
||||
|
@ -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:
|
||||
@ -1591,7 +1596,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)
|
||||
@ -1616,7 +1621,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
|
||||
@ -1638,7 +1644,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);
|
||||
}
|
||||
|
||||
|
||||
@ -1901,8 +1908,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, n, a[RTA_MULTIPATH], i->rtm_family, krt_src);
|
||||
@ -1953,15 +1958,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:
|
||||
@ -1969,32 +1999,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));
|
||||
|
@ -608,17 +608,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