{
case SA_FROM: res.val.ip = rta->from; break;
case SA_GW: res.val.ip = rta->nh.gw; break;
- case SA_NET: res.val.net = (*f_rte)->net->n.addr; break;
+ case SA_NET: res.val.net = (*f_rte)->netA; break;
case SA_PROTO: res.val.s = rta->src->proto->name; break;
case SA_SOURCE: res.val.i = rta->source; break;
case SA_SCOPE: res.val.i = rta->scope; break;
{
ACCESS_RTE;
ACCESS_EATTRS;
- v1.val.net = (*f_rte)->net->n.addr;
+ v1.val.net = (*f_rte)->netA;
/* We ignore temporary attributes, probably not a problem here */
/* 0x02 is a value of BA_AS_PATH, we don't want to include BGP headers */
typedef struct rte {
struct rte *next;
- net *net; /* Network this RTE belongs to */
+ const net_addr *netA; /* Network this RTE belongs to */
struct channel *sender; /* Channel used to send the route to the routing table */
struct rta *attrs; /* Attributes of this route */
byte flags; /* Flags (REF_...) */
#define REF_DISCARD 8 /* Route is scheduled for discard */
#define REF_MODIFY 16 /* Route is scheduled for modify */
+#define RTE_NET(e) (((e)->flags & REF_COW) ? SKIP_BACK(struct network, n, SKIP_BACK(struct fib_node, addr, (e)->netA)) : NULL)
+
/* Route is valid for propagation (may depend on other flags in the future), accepts NULL */
static inline int rte_is_valid(rte *r) { return r && !(r->flags & REF_FILTERED); }
byte from[IPA_MAX_TEXT_LENGTH+8];
byte tm[TM_DATETIME_BUFFER_SIZE], info[256];
rta *a = e->attrs;
- int primary = (e->net->routes == e);
- int sync_error = (e->net->n.flags & KRF_SYNC_ERROR);
+ net *nn = RTE_NET(e);
+ int primary = nn && (nn->routes == e);
+ int sync_error = nn && (nn->n.flags & KRF_SYNC_ERROR);
void (*get_route_info)(struct rte *, byte *buf);
struct nexthop *nh;
static void
rte_trace(struct proto *p, rte *e, int dir, char *msg)
{
- log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->net->n.addr, rta_dest_name(e->attrs->dest));
+ log(L_TRACE "%s %c %s %N %s", p->name, dir, msg, e->netA, rta_dest_name(e->attrs->dest));
}
static inline void
rte_validate(rte *e)
{
int c;
- net *n = e->net;
+ const net_addr *n = e->netA;
- if (!net_validate(n->n.addr))
+ if (!net_validate(n))
{
log(L_WARN "Ignoring bogus prefix %N received via %s",
- n->n.addr, e->sender->proto->name);
+ n, e->sender->proto->name);
return 0;
}
/* FIXME: better handling different nettypes */
- c = !net_is_flow(n->n.addr) ?
- net_classify(n->n.addr): (IADDR_HOST | SCOPE_UNIVERSE);
+ c = !net_is_flow(n) ?
+ net_classify(n): (IADDR_HOST | SCOPE_UNIVERSE);
if ((c < 0) || !(c & IADDR_HOST) || ((c & IADDR_SCOPE_MASK) <= SCOPE_LINK))
{
log(L_WARN "Ignoring bogus route %N received via %s",
- n->n.addr, e->sender->proto->name);
+ n, e->sender->proto->name);
return 0;
}
- if (net_type_match(n->n.addr, NB_DEST) == !e->attrs->dest)
+ if (net_type_match(n, NB_DEST) == !e->attrs->dest)
{
log(L_WARN "Ignoring route %N with invalid dest %d received via %s",
- n->n.addr, e->attrs->dest, e->sender->proto->name);
+ n, e->attrs->dest, e->sender->proto->name);
return 0;
}
if ((e->attrs->dest == RTD_UNICAST) && !nexthop_is_sorted(&(e->attrs->nh)))
{
log(L_WARN "Ignoring unsorted multipath route %N received via %s",
- n->n.addr, e->sender->proto->name);
+ n, e->sender->proto->name);
return 0;
}
rte_update_lock();
if (new)
{
- nn = net_get(c->table, n);
-
- new->net = nn;
+ new->netA = n;
new->sender = c;
if (!new->pref)
if (!rta_is_cached(new->attrs)) /* Need to copy attributes */
new->attrs = rta_lookup(new->attrs);
new->flags |= REF_COW;
+
+ new->netA = (nn = net_get(c->table, n))->n.addr;
}
else
{
drop:
rte_free(new);
new = NULL;
- goto recalc;
+
+ if ((nn = net_find(c->table, n)) && src)
+ goto recalc;
+
+ rte_update_unlock();
+ return;
}
/* Independent call to rte_announce(), used from next hop
}
static inline void
-rte_discard(rte *old) /* Non-filtered route deletion, used during garbage collection */
+rte_discard(net *n, rte *old) /* Non-filtered route deletion, used during garbage collection */
{
rte_update_lock();
- rte_recalculate(old->sender, old->net, NULL, old->attrs->src);
+ rte_recalculate(old->sender, n, NULL, old->attrs->src);
rte_update_unlock();
}
/* Modify existing route by protocol hook, used for long-lived graceful restart */
static inline void
-rte_modify(rte *old)
+rte_modify(net *n, rte *old)
{
rte_update_lock();
new->flags = (old->flags & ~REF_MODIFY) | REF_COW;
}
- rte_recalculate(old->sender, old->net, new, old->attrs->src);
+ rte_recalculate(old->sender, n, new, old->attrs->src);
}
rte_update_unlock();
void
rte_dump(rte *e)
{
- net *n = e->net;
- debug("%-1N ", n->n.addr);
- debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
+ debug("%-1N ", e->netA);
+ net *n = RTE_NET(e);
+ if (n)
+ debug("KF=%02x PF=%02x pref=%d ", n->n.flags, e->pflags, e->pref);
+ else
+ debug("outside fib, PF=%02x pref=%d ", e->pflags, e->pref);
+
rta_dump(e->attrs);
if (e->attrs->src->proto->proto->dump_attrs)
e->attrs->src->proto->proto->dump_attrs(e);
return;
}
- rte_discard(e);
+ rte_discard(n, e);
limit--;
goto rescan;
return;
}
- rte_modify(e);
+ rte_modify(n, e);
limit--;
goto rescan;
/* Insert the new rte */
rte *e = rte_do_cow(new);
e->flags |= REF_COW;
- e->net = net;
+ e->netA = net->n.addr;
e->sender = c;
e->lastmod = current_time();
e->next = *pos;
static void
bgp_export_mpls_label_stack(struct bgp_export_state *s, eattr *a)
{
- net_addr *n = s->route->net->n.addr;
+ const net_addr *n = s->route->netA;
u32 *labels = (u32 *) a->u.ptr->data;
uint lnum = a->u.ptr->length / 4;
if (alen < 0)
{
- mrt_log(s, "Attribute list too long for %N", r->net->n.addr);
+ mrt_log(s, "Attribute list too long for %N", r->netA);
alen = 0;
}
}
static inline int
-radv_net_match_trigger(struct radv_config *cf, net *n)
+radv_net_match_trigger(struct radv_config *cf, const net_addr *n)
{
- return radv_trigger_valid(cf) && net_equal(n->n.addr, &cf->trigger);
+ return radv_trigger_valid(cf) && net_equal(n, &cf->trigger);
}
int
// struct radv_proto *p = (struct radv_proto *) P;
struct radv_config *cf = (struct radv_config *) (P->cf);
- if (radv_net_match_trigger(cf, (*new)->net))
+ if (radv_net_match_trigger(cf, (*new)->netA))
return RIC_PROCESS;
if (cf->propagate_routes)
struct radv_route *rt;
eattr *ea;
- if (radv_net_match_trigger(cf, n))
+ if (radv_net_match_trigger(cf, n->n.addr))
{
u8 old_active = p->active;
p->active = !!new;
static int
krt_send_route(struct krt_proto *p, int cmd, rte *e)
{
- net *net = e->net;
+ const net_addr *n = e->netA;
rta *a = e->attrs;
static int msg_seq;
struct iface *j, *i = a->nh.iface;
char *body = (char *)msg.buf;
sockaddr gate, mask, dst;
- DBG("krt-sock: send %I/%d via %I\n", net->n.prefix, net->n.pxlen, a->gw);
+ DBG("krt-sock: send %N via %I\n", n, a->gw);
bzero(&msg,sizeof (struct rt_msghdr));
msg.rtm.rtm_version = RTM_VERSION;
msg.rtm.rtm_flags = RTF_UP | RTF_PROTO1;
/* XXXX */
- if (net_pxlen(net->n.addr) == net_max_prefix_length[net->n.addr->type])
+ if (net_pxlen(n) == net_max_prefix_length[n->type])
msg.rtm.rtm_flags |= RTF_HOST;
else
msg.rtm.rtm_addrs |= RTA_NETMASK;
int af = AF_UNSPEC;
- switch (net->n.addr->type) {
+ switch (n->type) {
case NET_IP4:
af = AF_INET;
break;
af = AF_INET6;
break;
default:
- log(L_ERR "KRT: Not sending route %N to kernel", net->n.addr);
+ log(L_ERR "KRT: Not sending route %N to kernel", n);
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(&dst, af, net_prefix(n), NULL, 0);
+ sockaddr_fill(&mask, af, net_pxmask(n), NULL, 0);
switch (a->dest)
{
#if __OpenBSD__
/* Keeping temporarily old code for OpenBSD */
- struct ifa *addr = (net->n.addr->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
+ struct ifa *addr = (n->type == NET_IP4) ? i->addr4 : (i->addr6 ?: i->llv6);
if (!addr)
{
msg.rtm.rtm_msglen = l;
if ((l = write(p->sys.sk->fd, (char *)&msg, l)) < 0) {
- log(L_ERR "KRT: Error sending route %N to kernel: %m", net->n.addr);
+ log(L_ERR "KRT: Error sending route %N to kernel: %m", n);
return -1;
}
return 0;
}
-void
-krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
+int
+krt_replace_rte(struct krt_proto *p, rte *new, rte *old)
{
int err = 0;
if (new)
err = krt_send_route(p, RTM_ADD, new);
- if (err < 0)
- n->n.flags |= KRF_SYNC_ERROR;
- else
- n->n.flags &= ~KRF_SYNC_ERROR;
+ return (err >= 0);
}
#define SKIP(ARG...) do { DBG("KRT: Ignoring route - " ARG); return; } while(0)
int ipv6;
rte *e;
- net *net;
sockaddr dst, gate, mask;
ip_addr idst, igate, imask;
net_addr ndst;
else
src = KRT_SRC_KERNEL;
- net = net_get(p->p.main_channel->table, &ndst);
-
rta a = {
.src = p->p.main_source,
.source = RTS_INHERIT,
if (!a.nh.iface)
{
log(L_ERR "KRT: Received route %N with unknown ifindex %u",
- net->n.addr, msg->rtm.rtm_index);
+ &ndst, msg->rtm.rtm_index);
return;
}
return;
log(L_ERR "KRT: Received route %N with strange next-hop %I",
- net->n.addr, a.nh.gw);
+ &ndst, a.nh.gw);
return;
}
}
done:
e = rte_get_temp(&a);
- e->net = net;
+ e->netA = &ndst;
e->u.krt.src = src;
e->u.krt.proto = src2;
e->u.krt.seen = 0;
int scan;
int merge;
- net *net;
+ const net_addr *netA;
rta *attrs;
struct krt_proto *proto;
s8 new;
nl_send_route(struct krt_proto *p, rte *e, int op, int dest, struct nexthop *nh)
{
eattr *ea;
- net *net = e->net;
+ const net_addr *n = e->netA;
rta *a = e->attrs;
ea_list *eattrs = a->eattrs;
int bufsize = 128 + KRT_METRICS_MAX*8 + nh_bufsize(&(a->nh));
int rsize = sizeof(*r) + bufsize;
r = alloca(rsize);
- DBG("nl_send_route(%N,op=%x)\n", net->n.addr, op);
+ DBG("nl_send_route(%N,op=%x)\n", n, op);
bzero(&r->h, sizeof(r->h));
bzero(&r->r, sizeof(r->r));
r->h.nlmsg_flags = op | NLM_F_REQUEST | NLM_F_ACK;
r->r.rtm_family = p->af;
- r->r.rtm_dst_len = net_pxlen(net->n.addr);
+ r->r.rtm_dst_len = net_pxlen(n);
r->r.rtm_protocol = RTPROT_BIRD;
r->r.rtm_scope = RT_SCOPE_NOWHERE;
#ifdef HAVE_MPLS_KERNEL
* 2) Never use RTA_PRIORITY
*/
- u32 label = net_mpls(net->n.addr);
+ u32 label = net_mpls(n);
nl_add_attr_mpls(&r->h, rsize, RTA_DST, 1, &label);
r->r.rtm_scope = RT_SCOPE_UNIVERSE;
r->r.rtm_type = RTN_UNICAST;
else
#endif
{
- nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(net->n.addr));
+ nl_add_attr_ipa(&r->h, rsize, RTA_DST, net_prefix(n));
/* Add source address for IPv6 SADR routes */
- if (net->n.addr->type == NET_IP6_SADR)
+ if (n->type == NET_IP6_SADR)
{
- net_addr_ip6_sadr *a = (void *) &net->n.addr;
+ net_addr_ip6_sadr *a = (void *) n;
nl_add_attr_ip6(&r->h, rsize, RTA_SRC, a->src_prefix);
r->r.rtm_src_len = a->src_pxlen;
}
return err;
}
-void
-krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old)
+int
+krt_replace_rte(struct krt_proto *p, rte *new, rte *old)
{
int err = 0;
if (new)
err = nl_add_rte(p, new);
- if (err < 0)
- n->n.flags |= KRF_SYNC_ERROR;
- else
- n->n.flags &= ~KRF_SYNC_ERROR;
+ return (err >= 0);
}
static int
-nl_mergable_route(struct nl_parse_state *s, net *net, struct krt_proto *p, uint priority, uint krt_type)
+nl_mergable_route(struct nl_parse_state *s, const net_addr *netA, struct krt_proto *p, uint priority, uint krt_type)
{
/* Route merging must be active */
if (!s->merge)
return 0;
/* Saved and new route must have same network, proto/table, and priority */
- if ((s->net != net) || (s->proto != p) || (s->krt_metric != priority))
+ if (!net_equal(s->netA, netA) || (s->proto != p) || (s->krt_metric != priority))
return 0;
/* Both must be regular unicast routes */
nl_announce_route(struct nl_parse_state *s)
{
rte *e = rte_get_temp(s->attrs);
- e->net = s->net;
+ e->netA = s->netA;
e->u.krt.src = s->krt_src;
e->u.krt.proto = s->krt_proto;
e->u.krt.seen = 0;
else
krt_got_route_async(s->proto, e, s->new);
- s->net = NULL;
+ s->netA = NULL;
s->attrs = NULL;
s->proto = NULL;
lp_flush(s->pool);
static inline void
nl_parse_end(struct nl_parse_state *s)
{
- if (s->net)
+ if (s->netA)
nl_announce_route(s);
}
krt_src = KRT_SRC_ALIEN;
}
- net_addr *n = &dst;
+ net_addr *nloc;
if (p->p.net_type == NET_IP6_SADR)
- {
- n = alloca(sizeof(net_addr_ip6_sadr));
- net_fill_ip6_sadr(n, net6_prefix(&dst), net6_pxlen(&dst),
- net6_prefix(&src), net6_pxlen(&src));
- }
+ {
+ nloc = alloca(sizeof(net_addr_ip6_sadr));
+ net_fill_ip6_sadr(nloc, net6_prefix(&dst), net6_pxlen(&dst),
+ net6_prefix(&src), net6_pxlen(&src));
+ }
+ else
+ nloc = &dst;
- net *net = net_get(p->p.main_channel->table, n);
+ if (s->netA && !nl_mergable_route(s, nloc, p, priority, i->rtm_type))
+ nl_announce_route(s); /* Here is the s->pool flushed! */
- if (s->net && !nl_mergable_route(s, net, p, priority, i->rtm_type))
- nl_announce_route(s);
+ net_addr *n = lp_alloc(s->pool, dst.length);
+ net_copy(n, nloc);
rta *ra = lp_allocz(s->pool, RTA_MAX_SIZE);
ra->src = p->p.main_source;
struct nexthop *nh = nl_parse_multipath(s, p, a[RTA_MULTIPATH], i->rtm_family);
if (!nh)
{
- log(L_ERR "KRT: Received strange multipath route %N", net->n.addr);
+ log(L_ERR "KRT: Received strange multipath route %N", n);
return;
}
ra->nh.iface = if_find_by_index(oif);
if (!ra->nh.iface)
{
- log(L_ERR "KRT: Received route %N with unknown ifindex %u", net->n.addr, oif);
+ log(L_ERR "KRT: Received route %N with unknown ifindex %u", n, oif);
return;
}
(ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST))
{
- log(L_ERR "KRT: Received route %N with strange next-hop %I", net->n.addr,
+ log(L_ERR "KRT: Received route %N with strange next-hop %I", n,
ra->nh.gw);
return;
}
if (nl_parse_metrics(a[RTA_METRICS], metrics, ARRAY_SIZE(metrics)) < 0)
{
- log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", net->n.addr);
+ log(L_ERR "KRT: Received route %N with strange RTA_METRICS attribute", n);
return;
}
* Otherwise, we ignore additional next hops in nexthop_insert().
*/
- if (!s->net)
+ if (!s->netA)
{
/* Store the new route */
- s->net = net;
+ s->netA = n;
s->attrs = ra;
s->proto = p;
s->new = new;
krt_trace_in(struct krt_proto *p, rte *e, char *msg)
{
if (p->p.debug & D_PACKETS)
- log(L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
+ log(L_TRACE "%s: %N: %s", p->p.name, e->netA, msg);
}
static inline void
krt_trace_in_rl(struct tbf *f, struct krt_proto *p, rte *e, char *msg)
{
if (p->p.debug & D_PACKETS)
- log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->net->n.addr, msg);
+ log_rl(f, L_TRACE "%s: %N: %s", p->p.name, e->netA, msg);
}
/*
static void
krt_learn_announce_update(struct krt_proto *p, rte *e)
{
- net *n = e->net;
rta *aa = rta_clone(e->attrs);
rte *ee = rte_get_temp(aa);
ee->pflags = 0;
ee->u.krt = e->u.krt;
- rte_update(&p->p, n->n.addr, ee);
+ rte_update(&p->p, e->netA, ee);
}
static void
-krt_learn_announce_delete(struct krt_proto *p, net *n)
+krt_learn_announce_delete(struct krt_proto *p, net_addr *n)
{
- rte_update(&p->p, n->n.addr, NULL);
+ rte_update(&p->p, n, NULL);
}
/* Called when alien route is discovered during scan */
static void
krt_learn_scan(struct krt_proto *p, rte *e)
{
- net *n0 = e->net;
- net *n = net_get(&p->krt_table, n0->n.addr);
+ net *n = net_get(&p->krt_table, e->netA);
rte *m, **mm;
e->attrs = rta_lookup(e->attrs);
if (!m)
{
e->next = n->routes;
+ e->netA = n->n.addr;
n->routes = e;
e->u.krt.seen = 1;
}
{
DBG("%I/%d: deleting\n", n->n.prefix, n->n.pxlen);
if (old_best)
- krt_learn_announce_delete(p, n);
+ krt_learn_announce_delete(p, n->n.addr);
FIB_ITERATE_PUT(&fit);
fib_delete(fib, n);
static void
krt_learn_async(struct krt_proto *p, rte *e, int new)
{
- net *n0 = e->net;
- net *n = net_get(&p->krt_table, n0->n.addr);
+ net *n = net_get(&p->krt_table, e->netA);
rte *g, **gg, *best, **bestp, *old_best;
e->attrs = rta_lookup(e->attrs);
e->next = n->routes;
n->routes = e;
+ e->netA = n->n.addr;
}
else if (!g)
{
if (best)
krt_learn_announce_update(p, best);
else
- krt_learn_announce_delete(p, n);
+ krt_learn_announce_delete(p, n->n.addr);
}
}
* Routes
*/
+static void
+krt_replace_net_rte(struct krt_proto *p, net *net, rte *new, rte *old)
+{
+ if (krt_replace_rte(p, new, old))
+ net->n.flags &= ~KRF_SYNC_ERROR;
+ else
+ net->n.flags |= KRF_SYNC_ERROR;
+}
+
static void
krt_flush_routes(struct krt_proto *p)
{
if (rte_is_valid(e) && (n->n.flags & KRF_INSTALLED))
{
/* FIXME: this does not work if gw is changed in export filter */
- krt_replace_rte(p, e->net, NULL, e);
+ krt_replace_net_rte(p, n, NULL, e);
n->n.flags &= ~KRF_INSTALLED;
}
}
void
krt_got_route(struct krt_proto *p, rte *e)
{
- net *net = e->net;
int verdict;
+ net *net = net_get(p->p.main_channel->table, e->netA);
#ifdef KRT_ALLOW_LEARN
switch (e->u.krt.src)
verdict = KRF_DELETE;
goto sentenced;
- case KRT_SRC_ALIEN:
+ case KRT_SRC_ALIEN:
if (KRT_CF->learn)
krt_learn_scan(p, e);
else
e->attrs = rta_lookup(a);
e->next = net->routes;
net->routes = e;
+ e->netA = net->n.addr;
}
else
rte_free(e);
if (new && (n->n.flags & KRF_INSTALLED))
{
krt_trace_in(p, new, "reinstalling");
- krt_replace_rte(p, n, new, NULL);
+ krt_replace_net_rte(p, n, new, NULL);
}
break;
case KRF_SEEN:
break;
case KRF_UPDATE:
krt_trace_in(p, new, "updating");
- krt_replace_rte(p, n, new, old);
+ krt_replace_net_rte(p, n, new, old);
break;
case KRF_DELETE:
krt_trace_in(p, old, "deleting");
- krt_replace_rte(p, n, NULL, old);
+ krt_replace_net_rte(p, n, NULL, old);
break;
default:
bug("krt_prune: invalid route status");
void
krt_got_route_async(struct krt_proto *p, rte *e, int new)
{
- net *net = e->net;
-
switch (e->u.krt.src)
{
case KRT_SRC_BIRD:
if (new)
{
krt_trace_in(p, e, "[redirect] deleting");
- krt_replace_rte(p, net, NULL, e);
+ krt_replace_rte(p, NULL, e);
}
/* If !new, it is probably echo of our deletion */
break;
* We will remove KRT_INSTALLED flag, which stops such withdraw to be
* processed in krt_rt_notify() and krt_replace_rte().
*/
- if (e == e->net->routes)
- e->net->n.flags &= ~KRF_INSTALLED;
+ struct network *n = RTE_NET(e);
+ if (e == n->routes)
+ n->n.flags &= ~KRF_INSTALLED;
#endif
return -1;
}
else
net->n.flags &= ~KRF_INSTALLED;
if (p->initialized) /* Before first scan we don't touch the routes */
- krt_replace_rte(p, net, new, old);
+ krt_replace_net_rte(p, net, new, old);
}
static void
int krt_capable(rte *e);
void krt_do_scan(struct krt_proto *);
-void krt_replace_rte(struct krt_proto *p, net *n, rte *new, rte *old);
+int krt_replace_rte(struct krt_proto *p, rte *new, rte *old);
int krt_sys_get_attr(eattr *a, byte *buf, int buflen);