}
[02]:{DIGIT}+:{DIGIT}+ {
+ unsigned long int l, len1, len2;
char *e;
- unsigned long int l;
if (yytext[0] == '0')
+ {
cf_lval.i64 = 0;
+ len1 = 16;
+ len2 = 32;
+ }
else
- cf_lval.i64 = 0x2000000000000ULL;
+ {
+ cf_lval.i64 = 2ULL << 48;
+ len1 = 32;
+ len2 = 16;
+ }
errno = 0;
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_lval.i64 |= (((u64) l) << 32);
+ cf_lval.i64 |= ((u64) l) << len2;
+
errno = 0;
l = strtoul(e+1, &e, 10);
- if (e && *e || errno == ERANGE || (yytext[0] == '2') && (l >= (1<<16)))
- cf_error("Assigned number out of range");
+ if (e && *e || (errno == ERANGE) || (l >> len2))
+ cf_error("Number out of range");
cf_lval.i64 |= l;
+
return VPN_RD;
}
1:{DIGIT}+\.{DIGIT}+\.{DIGIT}+\.{DIGIT}+:{DIGIT}+ {
unsigned long int l;
- char *e = strchr(yytext+2, ':');
- *e++ = '\0';
ip4_addr ip4;
+ char *e;
+
+ cf_lval.i64 = 1ULL << 48;
+
+ e = strchr(yytext+2, ':');
+ *e++ = '\0';
if (!ip4_pton(yytext+2, &ip4))
cf_error("Invalid IPv4 address %s in Route Distinguisher", yytext+2);
+ cf_lval.i64 |= ((u64) ip4_to_u32(ip4)) << 16;
+
errno = 0;
l = strtoul(e, &e, 10);
- if (e && *e || errno == ERANGE || (l >= (1<<16)))
- cf_error("Assigned number out of range");
- cf_lval.i64 = (1ULL<<48) | (((u64)ip4_to_u32(ip4)) << 16) | ((u64)l);
+ if (e && *e || (errno == ERANGE) || (l >> 16))
+ cf_error("Number out of range");
+ cf_lval.i64 |= l;
+
return VPN_RD;
}
net_vpn4_: VPN_RD net_ip4_
{
$$ = 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_
{
$$ = 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_ip_: net_ip4_ | net_ip6_ ;
-net_roa_: net_roa4_ | net_roa6_ ;
net_vpn_: net_vpn4_ | net_vpn6_ ;
+net_roa_: net_roa4_ | net_roa6_ ;
net_:
net_ip_ { $$ = cfg_alloc($1.length); net_copy($$, &($1)); }
label_stack_start
| label_stack '/' NUM {
if ($1[0] >= MPLS_MAX_LABEL_STACK)
- cf_error("Too many labels in stack.");
- $1[++$1[0]] = $3;
+ cf_error("Too many labels in stack");
+ $1[0]++;
+ $1[*$1] = $3;
$$ = $1;
}
;
specific destination for them and you don't want to send them out through the
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),
-device routes specifying forwarding to hosts on a
-directly connected network, recursive routes computing their nexthops by doing
-route table lookups for a given IP, and special routes (sink, blackhole etc.)
-which specify a special action to be done instead of forwarding the packet.
+device routes specifying forwarding to hosts on a directly connected network,
+recursive routes computing their nexthops by doing route table lookups for a
+given IP, and special routes (sink, blackhole etc.) which specify a special
+action to be done instead of forwarding the packet.
<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
#define SA_PROTO 4
#define SA_SOURCE 5
#define SA_SCOPE 6
-#define SA_DEST 8
-#define SA_IFNAME 9
-#define SA_IFINDEX 10
+#define SA_DEST 7
+#define SA_IFNAME 8
+#define SA_IFINDEX 9
struct f_tree {
#include <stdlib.h>
#endif
+#define allocz(len) ({ void *_x = alloca(len); memset(_x, 0, len); _x; })
+
#endif
case NET_VPN4:
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 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 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 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:
+ /* XXX: RD format is specified for VPN4; not found any for VPN6, reusing the same as for VPN4 */
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 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 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 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:
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:
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); }
+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)
{ return ip4_equal(a->prefix, b->prefix) && (a->pxlen == b->pxlen); }
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); }
-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)
{ return !a->pxlen && ip4_zero(a->prefix); }
static inline void net_copy_mpls(net_addr_mpls *dst, const net_addr_mpls *src)
{ 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)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26); }
static inline u32 net_hash_ip6(const net_addr_ip6 *n)
{ 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)
{ return ip4_hash(n->prefix) ^ ((u32) n->pxlen << 26) ^ u64_hash(n->rd); }
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);
#define RTC_MULTICAST 2
#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_UNREACHABLE 3 /* Reject as unreachable */
#define RTD_PROHIBIT 4 /* Administratively prohibited */
-#define RTD_NONE 6 /* Invalid RTD */
/* Flags for net->n.flags, used by kernel syncer */
#define KRF_INSTALLED 0x80 /* This route should be installed in the kernel */
/* Route has regular, reachable nexthop (i.e. not RTD_UNREACHABLE and like) */
static inline int rte_is_reachable(rte *r)
-{ uint d = r->attrs->dest; return (d == RTD_UNICAST); }
+{ return r->attrs->dest == RTD_UNICAST; }
/*
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)
{ 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);
void rta_init(void);
for (; x; x = x->next)
{
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);
}
{
if (!ipa_equal(x->gw, y->gw) || (x->iface != y->iface) || (x->weight != y->weight) || (x->labels != y->labels))
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])
return 0;
}
- return 1;
+ return x == y;
}
static int
if (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]);
if (r)
}
void
-nexthop_insert(struct nexthop *n, struct nexthop *x)
+nexthop_insert(struct nexthop **n, struct nexthop *x)
{
- struct nexthop tmp;
- memcpy(&tmp, n, sizeof(struct nexthop));
- if (nexthop_compare_node(n, x) > 0) /* Insert to the included nexthop */
- {
- memcpy(n, x, sizeof(struct nexthop));
- memcpy(x, &tmp, sizeof(struct nexthop));
- n->next = x;
- return;
- }
-
- for (struct nexthop **nn = &(n->next); *nn; nn = &((*nn)->next))
+ for (; *n; n = &((*n)->next))
{
- int cmp = nexthop_compare_node(*nn, x);
+ int cmp = nexthop_compare_node(*n, x);
if (cmp < 0)
continue;
-
- if (cmp > 0)
- {
- x->next = *nn;
- *nn = x;
- }
-
- return;
+ else if (cmp > 0)
+ break;
+ else
+ return;
}
+ x->next = *n;
+ *n = x;
}
int
static inline slab *
nexthop_slab(struct nexthop *nh)
{
- return nexthop_slab_[nh->labels > 2 ? 3 : nh->labels];
+ return nexthop_slab_[MIN(nh->labels, 3)];
}
static struct nexthop *
.source = RTS_DEVICE,
.scope = SCOPE_UNIVERSE,
.dest = RTD_UNICAST,
- .nh = {
- .iface = ad->iface
- }
+ .nh.iface = ad->iface,
};
a = rta_lookup(&a0);
rta_apply_hostentry(rta *a, struct hostentry *he)
{
a->hostentry = he;
-
a->dest = he->dest;
a->igp_metric = he->igp_metric;
static inline rte *
rt_next_hop_update_rte(rtable *tab UNUSED, rte *old)
{
- rta *ap = alloca(RTA_MAX_SIZE);
- memcpy(ap, old->attrs, rta_size(old->attrs));
- rta_apply_hostentry(ap, old->attrs->hostentry);
- ap->aflags = 0;
+ rta *a = alloca(RTA_MAX_SIZE);
+ memcpy(a, old->attrs, rta_size(old->attrs));
+ rta_apply_hostentry(a, old->attrs->hostentry);
+ a->aflags = 0;
rte *e = sl_alloc(rte_slab);
memcpy(e, old, sizeof(rte));
- e->attrs = rta_lookup(ap);
+ e->attrs = rta_lookup(a);
return e;
}
}
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))
{
/* The host address is a local address, this is not valid */
else
{
/* The host is reachable through some route entry */
- he->nh = (&a->nh);
+ he->nh = &(a->nh);
he->dest = a->dest;
}
static inline int
rte_resolvable(rte *rt)
{
- int rd = rt->attrs->dest;
- return (rd == RTD_UNICAST);
+ return rt->attrs->dest == RTD_UNICAST;
}
int
WITHDRAW(BAD_NEXT_HOP);
a->dest = RTD_UNICAST;
- a->nh.gw = nbr->addr;
- a->nh.iface = nbr->iface;
- a->nh.next = NULL;
+ a->nh = (struct nexthop){ .gw = nbr->addr, .iface = nbr->iface };
a->hostentry = NULL;
a->igp_metric = 0;
}
if (s->channel->cf->next_hop_self)
return 0;
- /* We need valid global gateway */
- if ((ra->dest != RTD_UNICAST) || (ra->nh.next) || ipa_zero(ra->nh.gw) || ipa_is_link_local(ra->nh.gw))
+ /* 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))
return 0;
/* Use it when exported to internal peers */
if (ea)
{
- a = alloca(sizeof(struct rta));
- memset(a, 0, sizeof(struct rta));
+ a = allocz(sizeof(struct rta));
a->source = RTS_BGP;
a->scope = SCOPE_UNIVERSE;
- a->dest = RTD_UNREACHABLE;
a->from = s->proto->cf->remote_ip;
a->eattrs = ea;
static inline struct nexthop *
new_nexthop(struct ospf_proto *p, ip_addr gw, struct iface *iface, byte weight)
{
- struct nexthop *nh = lp_alloc(p->nhpool, sizeof(struct nexthop));
- nh->labels = 0;
+ struct nexthop *nh = lp_allocz(p->nhpool, sizeof(struct nexthop));
nh->gw = gw;
nh->iface = iface;
- nh->next = NULL;
nh->weight = weight;
return nh;
}
(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->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));
}
.src = p->p.main_source,
.source = nf->n.type,
.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))
{
rta *a = rta_lookup(&a0);
#include "pipe.h"
-#include <alloca.h>
-
static void
pipe_rt_notify(struct proto *P, struct channel *src_ch, net *n, rte *new, rte *old, ea_list *attrs)
{
.src = p->p.main_source,
.source = RTS_RIP,
.scope = SCOPE_UNIVERSE,
+ .dest = RTD_UNICAST,
};
u8 rt_metric = rt->metric;
u16 rt_tag = rt->tag;
- struct rip_rte *rt2 = rt->next;
- /* Find second valid rte */
- while (rt2 && !rip_valid_rte(rt2))
- rt2 = rt2->next;
-
- a0.dest = RTD_UNICAST;
- if (p->ecmp && rt2)
+ if (p->ecmp)
{
/* ECMP route */
+ struct nexthop *nhs = NULL;
int num = 0;
for (rt = en->routes; rt && (num < p->ecmp); rt = rt->next)
if (!rip_valid_rte(rt))
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->iface = rt->from->nbr->iface;
nh->weight = rt->from->ifa->cf->ecmp_weight;
- if (a0.nh.next)
- nexthop_insert(&(a0.nh), nh);
-
+ nexthop_insert(&nhs, nh);
num++;
if (rt->tag != rt_tag)
rt_tag = 0;
}
+
+ a0.nh = *nhs;
}
else
{
/* Unipath route */
- a0.nh.next = NULL;
+ a0.from = rt->from->nbr->addr;
a0.nh.gw = rt->next_hop;
a0.nh.iface = rt->from->nbr->iface;
- a0.from = rt->from->nbr->addr;
}
rta *a = rta_lookup(&a0);
.src = p->p.main_source,
.source = RTS_RPKI,
.scope = SCOPE_UNIVERSE,
- .dest = RTD_BLACKHOLE,
+ .dest = RTD_NONE,
};
rta *a = rta_lookup(&a0);
CF_DEFINES
#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 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_route_finish(void)
{ }
| static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
;
-stat_nexthop_via: VIA
-{
- if (last_srt)
- {
- last_srt = (last_srt->mp_next = cfg_allocz(sizeof(struct static_route)));
- last_srt->net = this_srt->net;
- }
- 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 ipa ipa_scope {
+ this_snh = static_nexthop_new();
+ this_snh->via = $2;
+ this_snh->iface = $3;
+ add_tail(&STATIC_CFG->neigh_routes, &this_snh->n);
}
- | stat_nexthop_via TEXT {
- last_srt->via = IPA_NONE;
- last_srt->if_name = $2;
- add_tail(&STATIC_CFG->iface_routes, &last_srt->n);
+ | VIA TEXT {
+ this_snh = static_nexthop_new();
+ this_snh->via = IPA_NONE;
+ this_snh->if_name = $2;
+ add_tail(&STATIC_CFG->iface_routes, &this_snh->n);
}
- | stat_nexthop_ident MPLS label_stack {
- last_srt->label_count = $3[0];
- last_srt->label_stack = &($3[1]);
+ | stat_nexthop MPLS label_stack {
+ this_snh->label_count = $3[0];
+ this_snh->label_stack = &($3[1]);
}
- | stat_nexthop_ident WEIGHT expr {
- last_srt->weight = $3 - 1;
+ | stat_nexthop WEIGHT expr {
+ this_snh->weight = $3 - 1;
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_nexthop_ident
- | stat_nexthop stat_nexthop_ident
+stat_nexthops:
+ stat_nexthop
+ | stat_nexthops stat_nexthop
;
stat_route0: ROUTE net_any {
this_srt->net = $2;
this_srt_last_cmd = &(this_srt->cmds);
this_srt->mp_next = NULL;
- last_srt = NULL;
+ this_snh = NULL;
}
;
stat_route:
- stat_route0 stat_nexthop
+ stat_route0 stat_nexthops
| stat_route0 RECURSIVE ipa {
this_srt->dest = RTDX_RECURSIVE;
this_srt->via = $3;
static void
static_install(struct proto *p, struct static_route *r)
{
- rta *ap = alloca(RTA_MAX_SIZE);
+ rta *ap = allocz(RTA_MAX_SIZE);
rte *e;
if (!(r->state & STS_WANT) && (r->state & (STS_INSTALLED | STS_FORCE)) && r->dest != RTD_UNICAST)
goto drop;
DBG("Installing static route %N, rtd=%d\n", r->net, r->dest);
- bzero(ap, RTA_MAX_SIZE);
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->dest = r->dest;
if (r->dest == RTD_UNICAST)
{
+ struct nexthop *nhs = NULL;
struct static_route *r2;
- int num = 0, update = 0;
+ int update = 0;
+ r = r->mp_head;
for (r2 = r; r2; r2 = r2->mp_next)
{
-
if ((r2->state & STS_FORCE) ||
(!!(r2->state & STS_INSTALLED) != !!(r2->state & STS_WANT)))
update++;
if (r2->state & STS_WANT)
- {
- struct nexthop *nh = (ap->nh.next) ? alloca(NEXTHOP_MAX_SIZE) : &(ap->nh);
- 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)
- nexthop_insert(&(ap->nh), nh);
- r2->state |= STS_INSTALLED;
- num++;
- }
+ {
+ struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE);
+
+ nh->gw = r2->via;
+ nh->iface = r2->neigh ? r2->neigh->iface : r2->iface;
+ nh->weight = r2->weight;
+ 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
r2->state = 0;
}
if (!update) // Nothing changed
return;
- r = r->mp_head;
-
- if (!num) // No nexthop to install
+ if (!nhs) // No nexthop to install
{
drop:
rte_update(p, r->net, NULL);
return;
}
+
+ ap->dest = RTD_UNICAST;
+ nexthop_link(ap, nhs);
}
else
r->state |= STS_INSTALLED;
-
+
if (r->dest == RTDX_RECURSIVE)
{
ap->nh.labels_append = ap->nh.labels = r->label_count;
struct ks_msg msg;
char *body = (char *)msg.buf;
sockaddr gate, mask, dst;
- ip_addr gw;
DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
msg.rtm.rtm_flags |= RTF_BLACKHOLE;
#endif
- /* This is really very nasty, but I'm not able
- * to add "(reject|blackhole)" route without
- * gateway set
+ /*
+ * This is really very nasty, but I'm not able to add reject/blackhole route
+ * without gateway address.
*/
- if(!i)
+ if (!i)
{
- i = HEAD(iface_list);
-
WALK_LIST(j, iface_list)
{
if (j->flags & IF_LOOPBACK)
break;
}
}
- }
- gw = a->nh.gw;
-
- /* Embed interface ID to link-local address */
- if (ipa_is_link_local(gw))
- _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
+ if (!i)
+ {
+ log(L_ERR "KRT: Cannot find loopback iface");
+ return -1;
+ }
+ }
int af = AF_UNSPEC;
return -1;
}
-
sockaddr_fill(&dst, af, net_prefix(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)
{
- case RTD_UNICAST:
- if (ipa_zero(gw))
- {
- if(i)
- {
-#ifdef RTF_CLONING
- if (cmd == RTM_ADD && (i->flags & IF_MULTIACCESS) != IF_MULTIACCESS) /* PTP */
- msg.rtm.rtm_flags |= RTF_CLONING;
-#endif
+ case RTD_UNICAST:
+ if (ipa_nonzero(a->nh.gw))
+ {
+ ip_addr gw = a->nh.gw;
- if(!i->addr) {
- log(L_ERR "KRT: interface %s has no IP addess", i->name);
- return -1;
- }
-
- sockaddr_fill(&gate, ipa_is_ip4(i->addr->ip) ? AF_INET : AF_INET6, i->addr->ip, NULL, 0);
- msg.rtm.rtm_addrs |= RTA_GATEWAY;
- }
- } else {
- msg.rtm.rtm_flags |= RTF_GATEWAY;
- msg.rtm.rtm_addrs |= RTA_GATEWAY;
- }
+ /* Embed interface ID to link-local address */
+ if (ipa_is_link_local(gw))
+ _I0(gw) = 0xfe800000 | (i->index & 0x0000ffff);
+
+ sockaddr_fill(&gate, af, gw, NULL, 0);
+ msg.rtm.rtm_flags |= RTF_GATEWAY;
+ msg.rtm.rtm_addrs |= RTA_GATEWAY;
break;
+ }
#ifdef RTF_REJECT
- case RTD_UNREACHABLE:
+ case RTD_UNREACHABLE:
#endif
#ifdef RTF_BLACKHOLE
- case RTD_BLACKHOLE:
+ case RTD_BLACKHOLE:
#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;
}
a.dest = RTD_UNICAST;
- a.nh.next = NULL;
if (flags & RTF_GATEWAY)
{
neighbor *ng;
return;
}
}
- else
- a.nh.gw = IPA_NONE;
done:
e = rte_get_temp(&a);
[IFA_ADDRESS] = { 1, 1, sizeof(ip4_addr) },
[IFA_LOCAL] = { 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] = {
h->nlmsg_len += sizeof(*via);
- if (ipa_is_ip4(ipa)) {
- ip4_addr ip4 = ipa_to_ip4(ipa);
- ip4 = ip4_hton(ip4);
+ if (ipa_is_ip4(ipa))
+ {
via->rtvia_family = AF_INET;
- memcpy(via->rtvia_addr, &ip4, sizeof(ip4));
- h->nlmsg_len += sizeof(ip4);
- } else {
- ip6_addr ip6 = ipa_to_ip6(ipa);
- ip6 = ip6_hton(ip6);
+ put_ip4(via->rtvia_addr, ipa_to_ip4(ipa));
+ h->nlmsg_len += sizeof(ip4_addr);
+ }
+ else
+ {
via->rtvia_family = AF_INET6;
- memcpy(via->rtvia_addr, &ip6, sizeof(ip6));
- h->nlmsg_len += sizeof(ip6);
+ put_ip6(via->rtvia_addr, ipa_to_ip6(ipa));
+ h->nlmsg_len += sizeof(ip6_addr);
}
nl_close_attr(h, nest);
}
else
rv->gw = IPA_NONE;
+
if (a[RTA_ENCAP_TYPE])
{
if (rta_get_u16(a[RTA_ENCAP_TYPE]) != LWTUNNEL_ENCAP_MPLS) {
rta *a = e->attrs;
switch (a->dest)
- {
+ {
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_UNREACHABLE:
case RTD_PROHIBIT:
- break;
+ return 1;
+
default:
return 0;
- }
- return 1;
+ }
}
static inline int
dest:
- /* a->iface != NULL checked in krt_capable() for router and device routes */
switch (dest)
{
case RTD_UNICAST:
switch (i->rtm_type)
{
case RTN_UNICAST:
+ ra->dest = RTD_UNICAST;
if (a[RTA_MULTIPATH] && (i->rtm_family == AF_INET))
{
return;
}
- nexthop_link(ra, nh);
+ ra->nh = *nh;
break;
}
else
{
/* 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;
+ }
}
}
static int
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;
if (e->attrs->src->proto == P)
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))
return -1;