Several minor fixes

This commit is contained in:
Ondrej Zajicek (work) 2017-02-20 02:26:45 +01:00
parent d311368bc5
commit 62e64905b7
22 changed files with 251 additions and 259 deletions

View file

@ -124,39 +124,56 @@ include ^{WHITE}*include{WHITE}*\".*\"{WHITE}*;
} }
[02]:{DIGIT}+:{DIGIT}+ { [02]:{DIGIT}+:{DIGIT}+ {
unsigned long int l, len1, len2;
char *e; char *e;
unsigned long int l;
if (yytext[0] == '0') if (yytext[0] == '0')
{
cf_lval.i64 = 0; cf_lval.i64 = 0;
len1 = 16;
len2 = 32;
}
else else
cf_lval.i64 = 0x2000000000000ULL; {
cf_lval.i64 = 2ULL << 48;
len1 = 32;
len2 = 16;
}
errno = 0; errno = 0;
l = strtoul(yytext+2, &e, 10); l = strtoul(yytext+2, &e, 10);
if (e && (*e != ':') || errno == ERANGE || (yytext[0] == '0') && (l >= (1<<16))) if (e && (*e != ':') || (errno == ERANGE) || (l >> len1))
cf_error("ASN out of range"); cf_error("ASN out of range");
cf_lval.i64 |= (((u64) l) << 32); cf_lval.i64 |= ((u64) l) << len2;
errno = 0; errno = 0;
l = strtoul(e+1, &e, 10); l = strtoul(e+1, &e, 10);
if (e && *e || errno == ERANGE || (yytext[0] == '2') && (l >= (1<<16))) if (e && *e || (errno == ERANGE) || (l >> len2))
cf_error("Assigned number out of range"); cf_error("Number out of range");
cf_lval.i64 |= l; cf_lval.i64 |= l;
return VPN_RD; return VPN_RD;
} }
1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ { 1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ {
unsigned long int l; unsigned long int l;
char *e = strchr(yytext+2, ':');
*e++ = '\0';
ip4_addr ip4; ip4_addr ip4;
char *e;
cf_lval.i64 = 1ULL << 48;
e = strchr(yytext+2, ':');
*e++ = '\0';
if (!ip4_pton(yytext+2, &ip4)) if (!ip4_pton(yytext+2, &ip4))
cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2); cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2);
cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
errno = 0; errno = 0;
l = strtoul(e, &e, 10); l = strtoul(e, &e, 10);
if (e && *e || errno == ERANGE || (l >= (1<<16))) if (e && *e || (errno == ERANGE) || (l >> 16))
cf_error("Assigned number out of range"); cf_error("Number out of range");
cf_lval.i64 = (1ULL<<48) | (((u64)ip4_to_u32(ip4)) << 16) | ((u64)l); cf_lval.i64 |= l;
return VPN_RD; return VPN_RD;
} }

View file

@ -203,13 +203,13 @@ net_ip6_: IP6 '/' NUM
net_vpn4_: VPN_RD net_ip4_ net_vpn4_: VPN_RD net_ip4_
{ {
$$ = cfg_alloc(sizeof(net_addr_vpn4)); $$ = cfg_alloc(sizeof(net_addr_vpn4));
net_fill_vpn4($$, ((net_addr_ip4 *)&$2)->prefix, $2.pxlen, $1); net_fill_vpn4($$, net4_prefix(&$2), net4_pxlen(&$2), $1);
} }
net_vpn6_: VPN_RD net_ip6_ net_vpn6_: VPN_RD net_ip6_
{ {
$$ = cfg_alloc(sizeof(net_addr_vpn6)); $$ = cfg_alloc(sizeof(net_addr_vpn6));
net_fill_vpn6($$, ((net_addr_ip6 *)&$2)->prefix, $2.pxlen, $1); net_fill_vpn6($$, net6_prefix(&$2), net6_pxlen(&$2), $1);
} }
net_roa4_: net_ip4_ MAX NUM AS NUM net_roa4_: net_ip4_ MAX NUM AS NUM
@ -229,8 +229,8 @@ net_roa6_: net_ip6_ MAX NUM AS NUM
}; };
net_ip_: net_ip4_ | net_ip6_ ; net_ip_: net_ip4_ | net_ip6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ; net_vpn_: net_vpn4_ | net_vpn6_ ;
net_roa_: net_roa4_ | net_roa6_ ;
net_: net_:
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); } net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
@ -297,8 +297,9 @@ label_stack:
label_stack_start label_stack_start
| label_stack '/' NUM { | label_stack '/' NUM {
if ($1[0] >= MPLS_MAX_LABEL_STACK) if ($1[0] >= MPLS_MAX_LABEL_STACK)
cf_error("Too many labels in stack."); cf_error("Too many labels in stack");
$1[++$1[0]] = $3; $1[0]++;
$1[*$1] = $3;
$$ = $1; $$ = $1;
} }
; ;

View file

@ -4140,12 +4140,12 @@ return packets as undeliverable if they are in your IP block, you don't have any
specific destination for them and you don't want to send them out through the specific destination for them and you don't want to send them out through the
default route to prevent routing loops). default route to prevent routing loops).
<p>There are five types of static routes: `classical' routes telling to forward <p>There are four types of static routes: `classical' routes telling to forward
packets to a neighboring router (single path or multipath, possibly weighted), packets to a neighboring router (single path or multipath, possibly weighted),
device routes specifying forwarding to hosts on a device routes specifying forwarding to hosts on a directly connected network,
directly connected network, recursive routes computing their nexthops by doing recursive routes computing their nexthops by doing route table lookups for a
route table lookups for a given IP, and special routes (sink, blackhole etc.) given IP, and special routes (sink, blackhole etc.) which specify a special
which specify a special action to be done instead of forwarding the packet. action to be done instead of forwarding the packet.
<p>When the particular destination is not available (the interface is down or <p>When the particular destination is not available (the interface is down or
the next hop of the route is not a neighbor at the moment), Static just the next hop of the route is not a neighbor at the moment), Static just

View file

@ -174,9 +174,9 @@ void val_format(struct f_val v, buffer *buf);
#define SA_PROTO 4 #define SA_PROTO 4
#define SA_SOURCE 5 #define SA_SOURCE 5
#define SA_SCOPE 6 #define SA_SCOPE 6
#define SA_DEST 8 #define SA_DEST 7
#define SA_IFNAME 9 #define SA_IFNAME 8
#define SA_IFINDEX 10 #define SA_IFINDEX 9
struct f_tree { struct f_tree {

View file

@ -15,4 +15,6 @@
#include <stdlib.h> #include <stdlib.h>
#endif #endif
#define allocz(len) ({ void *_x = alloca(len); memset(_x, 0, len); _x; })
#endif #endif

View file

@ -69,21 +69,20 @@ net_format(const net_addr *N, char *buf, int buflen)
case NET_VPN4: case NET_VPN4:
switch (n->vpn4.rd >> 48) switch (n->vpn4.rd >> 48)
{ {
case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen); case 0: return bsnprintf(buf, buflen, "0:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I4/%d", ip4_from_u32(n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen); case 2: return bsnprintf(buf, buflen, "2:%u:%u %I4/%d", (u32) (n->vpn4.rd >> 16), (u32) (n->vpn4.rd & 0xffff), n->vpn4.prefix, n->vpn4.pxlen);
default: return bsnprintf(buf, buflen, "X:%08x:%08x %I4/%d", (u32) (n->vpn4.rd >> 32), (u32) n->vpn4.rd, n->vpn4.prefix, n->vpn4.pxlen);
} }
return bsnprintf(buf, buflen, "X: %016x %I4/%d", (n->vpn4.rd), n->vpn4.prefix, n->vpn4.pxlen);
/* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4. */
case NET_VPN6: case NET_VPN6:
/* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4 */
switch (n->vpn6.rd >> 48) switch (n->vpn6.rd >> 48)
{ {
case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen); case 0: return bsnprintf(buf, buflen, "0:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); case 1: return bsnprintf(buf, buflen, "1:%I4:%u %I6/%d", ip4_from_u32(n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen); case 2: return bsnprintf(buf, buflen, "2:%u:%u %I6/%d", (u32) (n->vpn6.rd >> 16), (u32) (n->vpn6.rd & 0xffff), n->vpn6.prefix, n->vpn6.pxlen);
default: return bsnprintf(buf, buflen, "X:%08x:%08x %I6/%d", (u32) (n->vpn6.rd >> 32), (u32) n->vpn6.rd, n->vpn6.prefix, n->vpn6.pxlen);
} }
return bsnprintf(buf, buflen, "X: %016x %I6/%d", (n->vpn6.rd), n->vpn6.prefix, n->vpn6.pxlen);
case NET_ROA4: case NET_ROA4:
return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn); return bsnprintf(buf, buflen, "%I4/%u-%u AS%u", n->roa4.prefix, n->roa4.pxlen, n->roa4.max_pxlen, n->roa4.asn);
case NET_ROA6: case NET_ROA6:

View file

@ -306,6 +306,9 @@ static inline int net_equal_flow4(const net_addr_flow4 *a, const net_addr_flow4
static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b) static inline int net_equal_flow6(const net_addr_flow6 *a, const net_addr_flow6 *b)
{ return net_equal((const net_addr *) a, (const net_addr *) b); } { return net_equal((const net_addr *) a, (const net_addr *) 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)); }
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); }
@ -313,8 +316,6 @@ static inline int net_equal_prefix_roa4(const net_addr_roa4 *a, const net_addr_r
static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b) static inline int net_equal_prefix_roa6(const net_addr_roa6 *a, const net_addr_roa6 *b)
{ return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); } { return ip6_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
static inline int net_equal_mpls(const net_addr_mpls *a, const net_addr_mpls *b)
{ return !memcmp(a, b, sizeof(net_addr_mpls)); }
static inline int net_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); }
@ -404,16 +405,17 @@ static inline void net_copy_flow6(net_addr_flow6 *dst, const net_addr_flow6 *src
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)); }
/* XXXX */
static inline u32 u64_hash(u64 a)
{ return u32_hash(a); }
static inline u32 net_hash_ip4(const net_addr_ip4 *n) static inline u32 net_hash_ip4(const net_addr_ip4 *n)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); } { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
static inline u32 net_hash_ip6(const net_addr_ip6 *n) static inline u32 net_hash_ip6(const net_addr_ip6 *n)
{ return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); } { return ip6_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
/* XXXX */
static inline u32 u64_hash(u64 a)
{ return u32_hash(a); }
static inline u32 net_hash_vpn4(const net_addr_vpn4 *n) static inline u32 net_hash_vpn4(const net_addr_vpn4 *n)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); } { return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
@ -452,7 +454,7 @@ static inline int net_validate_ip6(const net_addr_ip6 *n)
static inline int net_validate_mpls(const net_addr_mpls *n) static inline int net_validate_mpls(const net_addr_mpls *n)
{ {
return n->label < (1<<20); return n->label < (1 << 20);
} }
int net_validate(const net_addr *N); int net_validate(const net_addr *N);

View file

@ -390,11 +390,11 @@ typedef struct rta {
#define RTC_MULTICAST 2 #define RTC_MULTICAST 2
#define RTC_ANYCAST 3 /* IPv6 Anycast */ #define RTC_ANYCAST 3 /* IPv6 Anycast */
#define RTD_UNICAST 0 /* Next hop is neighbor router */ #define RTD_NONE 0 /* Undefined next hop */
#define RTD_UNICAST 1 /* Next hop is neighbor router */
#define RTD_BLACKHOLE 2 /* Silently drop packets */ #define RTD_BLACKHOLE 2 /* Silently drop packets */
#define RTD_UNREACHABLE 3 /* Reject as unreachable */ #define RTD_UNREACHABLE 3 /* Reject as unreachable */
#define RTD_PROHIBIT 4 /* Administratively prohibited */ #define RTD_PROHIBIT 4 /* Administratively prohibited */
#define RTD_NONE 6 /* Invalid RTD */
/* Flags for net->n.flags, used by kernel syncer */ /* Flags for net->n.flags, used by kernel syncer */
#define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */ #define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */
@ -408,7 +408,7 @@ typedef struct rta {
/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */ /* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
static inline int rte_is_reachable(rte *r) static inline int rte_is_reachable(rte *r)
{ uint d = r->attrs->dest; return (d == RTD_UNICAST); } { return r->attrs->dest == RTD_UNICAST; }
/* /*
@ -523,7 +523,7 @@ static inline int nexthop_same(struct nexthop *x, struct nexthop *y)
struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp); struct nexthop *nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, linpool *lp);
static inline void nexthop_link(struct rta *a, struct nexthop *from) static inline void nexthop_link(struct rta *a, struct nexthop *from)
{ memcpy(&a->nh, from, nexthop_size(from)); } { memcpy(&a->nh, from, nexthop_size(from)); }
void nexthop_insert(struct nexthop *n, struct nexthop *y); void nexthop_insert(struct nexthop **n, struct nexthop *y);
int nexthop_is_sorted(struct nexthop *x); int nexthop_is_sorted(struct nexthop *x);
void rta_init(void); void rta_init(void);

View file

@ -150,7 +150,8 @@ nexthop_hash(struct nexthop *x)
for (; x; x = x->next) for (; x; x = x->next)
{ {
h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9); h ^= ipa_hash(x->gw) ^ (h << 5) ^ (h >> 9);
for (int i=0; i<x->labels; i++)
for (int i = 0; i < x->labels; i++)
h ^= x->label[i] ^ (h << 6) ^ (h >> 7); h ^= x->label[i] ^ (h << 6) ^ (h >> 7);
} }
@ -164,12 +165,13 @@ nexthop__same(struct nexthop *x, struct nexthop *y)
{ {
if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels)) if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels))
return 0; return 0;
for (int i=0; i<x->labels; i++)
for (int i = 0; i < x->labels; i++)
if (x->label[i] != y->label[i]) if (x->label[i] != y->label[i])
return 0; return 0;
} }
return 1; return x == y;
} }
static int static int
@ -195,7 +197,7 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y)
if (r) if (r)
return r; return r;
for (int i=0; i<y->labels; i++) for (int i = 0; i < y->labels; i++)
{ {
r = ((int) y->label[i]) - ((int) x->label[i]); r = ((int) y->label[i]) - ((int) x->label[i]);
if (r) if (r)
@ -271,34 +273,22 @@ nexthop_merge(struct nexthop *x, struct nexthop *y, int rx, int ry, int max, lin
} }
void void
nexthop_insert(struct nexthop *n, struct nexthop *x) nexthop_insert(struct nexthop **n, struct nexthop *x)
{ {
struct nexthop tmp; for (; *n; n = &((*n)->next))
memcpy(&tmp, n, sizeof(struct nexthop));
if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */
{ {
memcpy(n, x, sizeof(struct nexthop)); int cmp = nexthop_compare_node(*n, x);
memcpy(x, &tmp, sizeof(struct nexthop));
n->next = x;
return;
}
for (struct nexthop **nn = &(n->next); *nn; nn = &((*nn)->next))
{
int cmp = nexthop_compare_node(*nn, x);
if (cmp < 0) if (cmp < 0)
continue; continue;
else if (cmp > 0)
if (cmp > 0) break;
{ else
x->next = *nn; return;
*nn = x;
}
return;
} }
x->next = *n;
*n = x;
} }
int int
@ -314,7 +304,7 @@ nexthop_is_sorted(struct nexthop *x)
static inline slab * static inline slab *
nexthop_slab(struct nexthop *nh) nexthop_slab(struct nexthop *nh)
{ {
return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels]; return nexthop_slab_[MIN(nh->labels, 3)];
} }
static struct nexthop * static struct nexthop *

View file

@ -79,9 +79,7 @@ dev_ifa_notify(struct proto *P, uint flags, struct ifa *ad)
.source = RTS_DEVICE, .source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE, .scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST, .dest = RTD_UNICAST,
.nh = { .nh.iface = ad->iface,
.iface = ad->iface
}
}; };
a = rta_lookup(&a0); a = rta_lookup(&a0);

View file

@ -1768,7 +1768,6 @@ static inline void
rta_apply_hostentry(rta *a, struct hostentry *he) rta_apply_hostentry(rta *a, struct hostentry *he)
{ {
a->hostentry = he; a->hostentry = he;
a->dest = he->dest; a->dest = he->dest;
a->igp_metric = he->igp_metric; a->igp_metric = he->igp_metric;
@ -1810,14 +1809,14 @@ rta_apply_hostentry(rta *a, struct hostentry *he)
static inline rte * static inline rte *
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old) rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
{ {
rta *ap = alloca(RTA_MAX_SIZE); rta *a = alloca(RTA_MAX_SIZE);
memcpy(ap, old->attrs, rta_size(old->attrs)); memcpy(a, old->attrs, rta_size(old->attrs));
rta_apply_hostentry(ap, old->attrs->hostentry); rta_apply_hostentry(a, old->attrs->hostentry);
ap->aflags = 0; a->aflags = 0;
rte *e = sl_alloc(rte_slab); rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte)); memcpy(e, old, sizeof(rte));
e->attrs = rta_lookup(ap); e->attrs = rta_lookup(a);
return e; return e;
} }
@ -2373,7 +2372,8 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
} }
if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next) if ((a->dest == RTD_UNICAST) && ipa_zero(a->nh.gw) && !a->next)
{ /* We have singlepath device route */ {
/* We have singlepath device route */
if (if_local_addr(he->addr, a->nh.iface)) if (if_local_addr(he->addr, a->nh.iface))
{ {
/* The host address is a local address, this is not valid */ /* The host address is a local address, this is not valid */
@ -2389,7 +2389,7 @@ rt_update_hostentry(rtable *tab, struct hostentry *he)
else else
{ {
/* The host is reachable through some route entry */ /* The host is reachable through some route entry */
he->nh = (&a->nh); he->nh = &(a->nh);
he->dest = a->dest; he->dest = a->dest;
} }

View file

@ -1461,8 +1461,7 @@ bgp_get_neighbor(rte *r)
static inline int static inline int
rte_resolvable(rte *rt) rte_resolvable(rte *rt)
{ {
int rd = rt->attrs->dest; return rt->attrs->dest == RTD_UNICAST;
return (rd == RTD_UNICAST);
} }
int int

View file

@ -700,9 +700,7 @@ bgp_apply_next_hop(struct bgp_parse_state *s, rta *a, ip_addr gw, ip_addr ll)
WITHDRAW(BAD_NEXT_HOP); WITHDRAW(BAD_NEXT_HOP);
a->dest = RTD_UNICAST; a->dest = RTD_UNICAST;
a->nh.gw = nbr->addr; a->nh = (struct nexthop){ .gw = nbr->addr, .iface = nbr->iface };
a->nh.iface = nbr->iface;
a->nh.next = NULL;
a->hostentry = NULL; a->hostentry = NULL;
a->igp_metric = 0; a->igp_metric = 0;
} }
@ -749,8 +747,8 @@ bgp_use_gateway(struct bgp_export_state *s)
if (s->channel->cf->next_hop_self) if (s->channel->cf->next_hop_self)
return 0; return 0;
/* We need valid global gateway */ /* We need one valid global gateway */
if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw)) if ((ra->dest != RTD_UNICAST) || ra->nh.next || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw))
return 0; return 0;
/* Use it when exported to internal peers */ /* Use it when exported to internal peers */
@ -1434,12 +1432,10 @@ bgp_decode_nlri(struct bgp_parse_state *s, u32 afi, byte *nlri, uint len, ea_lis
if (ea) if (ea)
{ {
a = alloca(sizeof(struct rta)); a = allocz(sizeof(struct rta));
memset(a, 0, sizeof(struct rta));
a->source = RTS_BGP; a->source = RTS_BGP;
a->scope = SCOPE_UNIVERSE; a->scope = SCOPE_UNIVERSE;
a->dest = RTD_UNREACHABLE;
a->from = s->proto->cf->remote_ip; a->from = s->proto->cf->remote_ip;
a->eattrs = ea; a->eattrs = ea;

View file

@ -36,11 +36,9 @@ unresolved_vlink(ort *ort)
static inline struct nexthop * static inline struct nexthop *
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight) new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
{ {
struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop)); struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop));
nh->labels = 0;
nh->gw = gw; nh->gw = gw;
nh->iface = iface; nh->iface = iface;
nh->next = NULL;
nh->weight = weight; nh->weight = weight;
return nh; return nh;
} }
@ -1907,7 +1905,6 @@ ort_changed(ort *nf, rta *nr)
(nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) || (nf->n.metric1 != nf->old_metric1) || (nf->n.metric2 != nf->old_metric2) ||
(nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) || (nf->n.tag != nf->old_tag) || (nf->n.rid != nf->old_rid) ||
(nr->source != or->source) || (nr->dest != or->dest) || (nr->source != or->source) || (nr->dest != or->dest) ||
(nr->nh.iface != or->nh.iface) || !ipa_equal(nr->nh.gw, or->nh.gw) ||
!nexthop_same(&(nr->nh), &(or->nh)); !nexthop_same(&(nr->nh), &(or->nh));
} }
@ -1952,11 +1949,10 @@ again1:
.src = p->p.main_source, .src = p->p.main_source,
.source = nf->n.type, .source = nf->n.type,
.scope = SCOPE_UNIVERSE, .scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
.nh = *(nf->n.nhs),
}; };
nexthop_link(&a0, nf->n.nhs);
a0.dest = RTD_UNICAST;
if (reload || ort_changed(nf, &a0)) if (reload || ort_changed(nf, &a0))
{ {
rta *a = rta_lookup(&a0); rta *a = rta_lookup(&a0);

View file

@ -43,8 +43,6 @@
#include "pipe.h" #include "pipe.h"
#include <alloca.h>
static void static void
pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs) pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs)
{ {

View file

@ -147,20 +147,16 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
.src = p->p.main_source, .src = p->p.main_source,
.source = RTS_RIP, .source = RTS_RIP,
.scope = SCOPE_UNIVERSE, .scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
}; };
u8 rt_metric = rt->metric; u8 rt_metric = rt->metric;
u16 rt_tag = rt->tag; u16 rt_tag = rt->tag;
struct rip_rte *rt2 = rt->next;
/* Find second valid rte */ if (p->ecmp)
while (rt2 && !rip_valid_rte(rt2))
rt2 = rt2->next;
a0.dest = RTD_UNICAST;
if (p->ecmp && rt2)
{ {
/* ECMP route */ /* ECMP route */
struct nexthop *nhs = NULL;
int num = 0; int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next) for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
@ -168,28 +164,27 @@ rip_announce_rte(struct rip_proto *p, struct rip_entry *en)
if (!rip_valid_rte(rt)) if (!rip_valid_rte(rt))
continue; continue;
struct nexthop *nh = (a0.nh.next ? &(a0.nh) : alloca(sizeof(struct nexthop))); struct nexthop *nh = allocz(sizeof(struct nexthop));
nh->gw = rt->next_hop; nh->gw = rt->next_hop;
nh->iface = rt->from->nbr->iface; nh->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight; nh->weight = rt->from->ifa->cf->ecmp_weight;
if (a0.nh.next) nexthop_insert(&nhs, nh);
nexthop_insert(&(a0.nh), nh);
num++; num++;
if (rt->tag != rt_tag) if (rt->tag != rt_tag)
rt_tag = 0; rt_tag = 0;
} }
a0.nh = *nhs;
} }
else else
{ {
/* Unipath route */ /* Unipath route */
a0.nh.next = NULL; a0.from = rt->from->nbr->addr;
a0.nh.gw = rt->next_hop; a0.nh.gw = rt->next_hop;
a0.nh.iface = rt->from->nbr->iface; a0.nh.iface = rt->from->nbr->iface;
a0.from = rt->from->nbr->addr;
} }
rta *a = rta_lookup(&a0); rta *a = rta_lookup(&a0);

View file

@ -124,7 +124,7 @@ rpki_table_add_roa(struct rpki_cache *cache, struct channel *channel, const net_
.src = p->p.main_source, .src = p->p.main_source,
.source = RTS_RPKI, .source = RTS_RPKI,
.scope = SCOPE_UNIVERSE, .scope = SCOPE_UNIVERSE,
.dest = RTD_BLACKHOLE, .dest = RTD_NONE,
}; };
rta *a = rta_lookup(&a0); rta *a = rta_lookup(&a0);

View file

@ -13,9 +13,33 @@ CF_HDR
CF_DEFINES CF_DEFINES
#define STATIC_CFG ((struct static_config *) this_proto) #define STATIC_CFG ((struct static_config *) this_proto)
static struct static_route *this_srt, *last_srt; static struct static_route *this_srt, *this_snh;
static struct f_inst **this_srt_last_cmd; static struct f_inst **this_srt_last_cmd;
static struct static_route *
static_nexthop_new(void)
{
struct static_route *nh;
if (!this_snh)
{
/* First next hop */
nh = this_srt;
rem_node(&this_srt->n);
}
else
{
/* Additional next hop */
nh = cfg_allocz(sizeof(struct static_route));
nh->net = this_srt->net;
this_snh->mp_next = nh;
}
nh->dest = RTD_UNICAST;
nh->mp_head = this_srt;
return nh;
};
static void static void
static_route_finish(void) static_route_finish(void)
{ } { }
@ -45,48 +69,35 @@ static_proto:
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(); } | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
; ;
stat_nexthop_via: VIA stat_nexthop:
{ VIA ipa ipa_scope {
if (last_srt) this_snh = static_nexthop_new();
{ this_snh->via = $2;
last_srt = (last_srt->mp_next = cfg_allocz(sizeof(struct static_route))); this_snh->iface = $3;
last_srt->net = this_srt->net; add_tail(&STATIC_CFG->neigh_routes, &this_snh->n);
}
else
{
last_srt = this_srt;
rem_node(&this_srt->n);
}
last_srt->mp_head = this_srt;
last_srt->dest = RTD_UNICAST;
};
stat_nexthop_ident:
stat_nexthop_via ipa ipa_scope {
last_srt->via = $2;
last_srt->iface = $3;
add_tail(&STATIC_CFG->neigh_routes, &last_srt->n);
} }
| stat_nexthop_via TEXT { | VIA TEXT {
last_srt->via = IPA_NONE; this_snh = static_nexthop_new();
last_srt->if_name = $2; this_snh->via = IPA_NONE;
add_tail(&STATIC_CFG->iface_routes, &last_srt->n); this_snh->if_name = $2;
add_tail(&STATIC_CFG->iface_routes, &this_snh->n);
} }
| stat_nexthop_ident MPLS label_stack { | stat_nexthop MPLS label_stack {
last_srt->label_count = $3[0]; this_snh->label_count = $3[0];
last_srt->label_stack = &($3[1]); this_snh->label_stack = &($3[1]);
} }
| stat_nexthop_ident WEIGHT expr { | stat_nexthop WEIGHT expr {
last_srt->weight = $3 - 1; this_snh->weight = $3 - 1;
if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
} }
| stat_nexthop_ident BFD bool { last_srt->use_bfd = $3; cf_check_bfd($3); } | stat_nexthop BFD bool {
this_snh->use_bfd = $3; cf_check_bfd($3);
}
; ;
stat_nexthop: stat_nexthops:
stat_nexthop_ident stat_nexthop
| stat_nexthop stat_nexthop_ident | stat_nexthops stat_nexthop
; ;
stat_route0: ROUTE net_any { stat_route0: ROUTE net_any {
@ -95,12 +106,12 @@ stat_route0: ROUTE net_any {
this_srt->net = $2; this_srt->net = $2;
this_srt_last_cmd = &(this_srt->cmds); this_srt_last_cmd = &(this_srt->cmds);
this_srt->mp_next = NULL; this_srt->mp_next = NULL;
last_srt = NULL; this_snh = NULL;
} }
; ;
stat_route: stat_route:
stat_route0 stat_nexthop stat_route0 stat_nexthops
| stat_route0 RECURSIVE ipa { | stat_route0 RECURSIVE ipa {
this_srt->dest = RTDX_RECURSIVE; this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3; this_srt->via = $3;

View file

@ -60,54 +60,44 @@ p_igp_table(struct proto *p)
static void static void
static_install(struct proto *p, struct static_route *r) static_install(struct proto *p, struct static_route *r)
{ {
rta *ap = alloca(RTA_MAX_SIZE); rta *ap = allocz(RTA_MAX_SIZE);
rte *e; rte *e;
if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST) if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST)
goto drop; goto drop;
DBG("Installing static route %N, rtd=%d\n", r->net, r->dest); DBG("Installing static route %N, rtd=%d\n", r->net, r->dest);
bzero(ap, RTA_MAX_SIZE);
ap->src = p->main_source; ap->src = p->main_source;
ap->source = ((r->dest == RTD_UNICAST) && ipa_zero(r->via)) ? RTS_STATIC_DEVICE : RTS_STATIC; ap->source = RTS_STATIC;
ap->scope = SCOPE_UNIVERSE; ap->scope = SCOPE_UNIVERSE;
ap->dest = r->dest; ap->dest = r->dest;
if (r->dest == RTD_UNICAST) if (r->dest == RTD_UNICAST)
{ {
struct nexthop *nhs = NULL;
struct static_route *r2; struct static_route *r2;
int num = 0, update = 0; int update = 0;
r = r->mp_head;
for (r2 = r; r2; r2 = r2->mp_next) for (r2 = r; r2; r2 = r2->mp_next)
{ {
if ((r2->state & STS_FORCE) || if ((r2->state & STS_FORCE) ||
(!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT))) (!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT)))
update++; update++;
if (r2->state & STS_WANT) if (r2->state & STS_WANT)
{ {
struct nexthop *nh = (ap->nh.next) ? alloca(NEXTHOP_MAX_SIZE) : &(ap->nh); struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE);
if (ipa_zero(r2->via)) // Device nexthop
{
nh->gw = IPA_NONE;
nh->iface = r2->iface;
}
else // Router nexthop
{
nh->gw = r2->via;
nh->iface = r2->neigh->iface;
}
nh->weight = r2->weight;
nh->labels = r2->label_count;
for (int i=0; i<nh->labels; i++)
nh->label[i] = r2->label_stack[i];
if (ap->nh.next) nh->gw = r2->via;
nexthop_insert(&(ap->nh), nh); nh->iface = r2->neigh ? r2->neigh->iface : r2->iface;
r2->state |= STS_INSTALLED; nh->weight = r2->weight;
num++; nh->labels = r2->label_count;
} memcpy(nh->label, r2->label_stack, r2->label_count * sizeof(u32));
r2->state |= STS_INSTALLED;
nexthop_insert(&nhs, nh);
}
else else
r2->state = 0; r2->state = 0;
} }
@ -115,14 +105,15 @@ static_install(struct proto *p, struct static_route *r)
if (!update) // Nothing changed if (!update) // Nothing changed
return; return;
r = r->mp_head; if (!nhs) // No nexthop to install
if (!num) // No nexthop to install
{ {
drop: drop:
rte_update(p, r->net, NULL); rte_update(p, r->net, NULL);
return; return;
} }
ap->dest = RTD_UNICAST;
nexthop_link(ap, nhs);
} }
else else
r->state |= STS_INSTALLED; r->state |= STS_INSTALLED;

View file

@ -193,7 +193,6 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
struct ks_msg msg; struct ks_msg msg;
char *body = (char *)msg.buf; char *body = (char *)msg.buf;
sockaddr gate, mask, dst; sockaddr gate, mask, dst;
ip_addr gw;
DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw); DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
@ -223,14 +222,12 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
msg.rtm.rtm_flags |= RTF_BLACKHOLE; msg.rtm.rtm_flags |= RTF_BLACKHOLE;
#endif #endif
/* This is really very nasty, but I'm not able /*
* to add "(reject|blackhole)" route without * This is really very nasty, but I'm not able to add reject/blackhole route
* gateway set * without gateway address.
*/ */
if(!i) if (!i)
{ {
i = HEAD(iface_list);
WALK_LIST(j, iface_list) WALK_LIST(j, iface_list)
{ {
if (j->flags & IF_LOOPBACK) if (j->flags & IF_LOOPBACK)
@ -239,14 +236,14 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
break; break;
} }
} }
if (!i)
{
log(L_ERR "KRT: Cannot find loopback iface");
return -1;
}
} }
gw = a->nh.gw;
/* Embed interface ID to link-local address */
if (ipa_is_link_local(gw))
_I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
int af = AF_UNSPEC; int af = AF_UNSPEC;
switch (net->n.addr->type) { switch (net->n.addr->type) {
@ -261,45 +258,51 @@ krt_send_route(struct krt_proto *p, int cmd, rte *e)
return -1; return -1;
} }
sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0); sockaddr_fill(&dst, af, net_prefix(net->n.addr), NULL, 0);
sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0); sockaddr_fill(&mask, af, net_pxmask(net->n.addr), NULL, 0);
sockaddr_fill(&gate, af, gw, NULL, 0);
switch (a->dest) switch (a->dest)
{ {
case RTD_UNICAST: case RTD_UNICAST:
if (ipa_zero(gw)) if (ipa_nonzero(a->nh.gw))
{ {
if(i) ip_addr gw = a->nh.gw;
{
#ifdef RTF_CLONING
if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
msg.rtm.rtm_flags |= RTF_CLONING;
#endif
if(!i->addr) { /* Embed interface ID to link-local address */
log(L_ERR "KRT: interface %s has no IP addess", i->name); if (ipa_is_link_local(gw))
return -1; _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
}
sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0); sockaddr_fill(&gate, af, gw, NULL, 0);
msg.rtm.rtm_addrs |= RTA_GATEWAY; msg.rtm.rtm_flags |= RTF_GATEWAY;
} msg.rtm.rtm_addrs |= RTA_GATEWAY;
} else {
msg.rtm.rtm_flags |= RTF_GATEWAY;
msg.rtm.rtm_addrs |= RTA_GATEWAY;
}
break; break;
}
#ifdef RTF_REJECT #ifdef RTF_REJECT
case RTD_UNREACHABLE: case RTD_UNREACHABLE:
#endif #endif
#ifdef RTF_BLACKHOLE #ifdef RTF_BLACKHOLE
case RTD_BLACKHOLE: case RTD_BLACKHOLE:
#endif #endif
default: {
bug("krt-sock: unknown flags, but not filtered"); /* Fallback for all other valid cases */
if (!i->addr)
{
log(L_ERR "KRT: interface %s has no IP addess", i->name);
return -1;
}
#ifdef RTF_CLONING
if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
msg.rtm.rtm_flags |= RTF_CLONING;
#endif
sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
msg.rtm.rtm_addrs |= RTA_GATEWAY;
}
default:
bug("krt-sock: unknown flags, but not filtered");
} }
msg.rtm.rtm_index = i->index; msg.rtm.rtm_index = i->index;
@ -497,7 +500,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
} }
a.dest = RTD_UNICAST; a.dest = RTD_UNICAST;
a.nh.next = NULL;
if (flags & RTF_GATEWAY) if (flags & RTF_GATEWAY)
{ {
neighbor *ng; neighbor *ng;
@ -520,8 +522,6 @@ krt_read_route(struct ks_msg *msg, struct krt_proto *p, int scan)
return; return;
} }
} }
else
a.nh.gw = IPA_NONE;
done: done:
e = rte_get_temp(&a); e = rte_get_temp(&a);

View file

@ -320,6 +320,7 @@ static struct nl_want_attrs ifa_attr_want4[BIRD_IFA_MAX] = {
[IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) }, [IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) },
[IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) }, [IFA_LOCAL] = { 1, 1, sizeof(ip4_addr) },
[IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) }, [IFA_BROADCAST] = { 1, 1, sizeof(ip4_addr) },
[IFA_FLAGS] = { 1, 1, sizeof(u32) },
}; };
static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = { static struct nl_want_attrs ifa_attr_want6[BIRD_IFA_MAX] = {
@ -543,18 +544,17 @@ nl_add_attr_via(struct nlmsghdr *h, uint bufsize, ip_addr ipa)
h->nlmsg_len += sizeof(*via); h->nlmsg_len += sizeof(*via);
if (ipa_is_ip4(ipa)) { if (ipa_is_ip4(ipa))
ip4_addr ip4 = ipa_to_ip4(ipa); {
ip4 = ip4_hton(ip4);
via->rtvia_family = AF_INET; via->rtvia_family = AF_INET;
memcpy(via->rtvia_addr, &ip4, sizeof(ip4)); put_ip4(via->rtvia_addr, ipa_to_ip4(ipa));
h->nlmsg_len += sizeof(ip4); h->nlmsg_len += sizeof(ip4_addr);
} else { }
ip6_addr ip6 = ipa_to_ip6(ipa); else
ip6 = ip6_hton(ip6); {
via->rtvia_family = AF_INET6; via->rtvia_family = AF_INET6;
memcpy(via->rtvia_addr, &ip6, sizeof(ip6)); put_ip6(via->rtvia_addr, ipa_to_ip6(ipa));
h->nlmsg_len += sizeof(ip6); h->nlmsg_len += sizeof(ip6_addr);
} }
nl_close_attr(h, nest); nl_close_attr(h, nest);
@ -669,6 +669,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
} }
else else
rv->gw = IPA_NONE; rv->gw = IPA_NONE;
if (a[RTA_ENCAP_TYPE]) if (a[RTA_ENCAP_TYPE])
{ {
if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) { if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) {
@ -1092,20 +1093,16 @@ krt_capable(rte *e)
rta *a = e->attrs; rta *a = e->attrs;
switch (a->dest) switch (a->dest)
{ {
case RTD_UNICAST: case RTD_UNICAST:
for (struct nexthop *nh = &(a->nh); nh; nh = nh->next)
if (nh->iface)
return 1;
return 0;
case RTD_BLACKHOLE: case RTD_BLACKHOLE:
case RTD_UNREACHABLE: case RTD_UNREACHABLE:
case RTD_PROHIBIT: case RTD_PROHIBIT:
break; return 1;
default: default:
return 0; return 0;
} }
return 1;
} }
static inline int static inline int
@ -1210,7 +1207,6 @@ nl_send_route(struct krt_proto *p, rte *e, struct ea_list *eattrs, int op, int d
dest: dest:
/* a->iface != NULL checked in krt_capable() for router and device routes */
switch (dest) switch (dest)
{ {
case RTD_UNICAST: case RTD_UNICAST:
@ -1502,6 +1498,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
switch (i->rtm_type) switch (i->rtm_type)
{ {
case RTN_UNICAST: case RTN_UNICAST:
ra->dest = RTD_UNICAST;
if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET)) if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
{ {
@ -1512,7 +1509,7 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
return; return;
} }
nexthop_link(ra, nh); ra->nh = *nh;
break; break;
} }
@ -1698,9 +1695,20 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
else else
{ {
/* Merge next hops with the stored route */ /* Merge next hops with the stored route */
rta *a = s->attrs; rta *oa = s->attrs;
nexthop_insert(&a->nh, &ra->nh); struct nexthop *nhs = &oa->nh;
nexthop_insert(&nhs, &ra->nh);
/* Perhaps new nexthop is inserted at the first position */
if (nhs == &ra->nh)
{
/* Swap rtas */
s->attrs = ra;
/* Keep old eattrs */
ra->eattrs = oa->eattrs;
}
} }
} }

View file

@ -984,7 +984,7 @@ krt_store_tmp_attrs(rte *rt, struct ea_list *attrs)
static int static int
krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED) krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
{ {
struct krt_proto *p = (struct krt_proto *) P; // struct krt_proto *p = (struct krt_proto *) P;
rte *e = *new; rte *e = *new;
if (e->attrs->src->proto == P) if (e->attrs->src->proto == P)
@ -1005,17 +1005,6 @@ krt_import_control(struct proto *P, rte **new, ea_list **attrs UNUSED, struct li
return -1; return -1;
} }
if (!KRT_CF->devroutes && (e->attrs->source != RTS_STATIC_DEVICE))
{
struct nexthop *nh = &(e->attrs->nh);
for (; nh; nh = nh->next)
if (ipa_nonzero(nh->gw))
break;
if (!nh) /* Gone through all the nexthops and no explicit GW found */
return -1;
}
if (!krt_capable(e)) if (!krt_capable(e))
return -1; return -1;