0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2025-01-07 01:21:54 +00:00

Merge branch 'int-new' into show-route

This commit is contained in:
Jan Moskyto Matejka 2017-07-12 14:25:55 +02:00
commit 2776cfafec
13 changed files with 493 additions and 91 deletions

View File

@ -1596,13 +1596,12 @@ networks. Babel is conceptually very simple in its operation and "just works"
in its default configuration, though some configuration is possible and in some in its default configuration, though some configuration is possible and in some
cases desirable. cases desirable.
<p>While the Babel protocol is dual stack (i.e., can carry both IPv4 and IPv6 <p>The Babel protocol is dual stack; i.e., it can carry both IPv4 and IPv6
routes over the same IPv6 transport), BIRD presently implements only the IPv6 routes over the same IPv6 transport. For sending and receiving Babel packets,
subset of the protocol. No Babel extensions are implemented, but the BIRD only a link-local IPv6 address is needed.
implementation can coexist with implementations using the extensions (and will
just ignore extension messages).
<p>The Babel protocol implementation in BIRD is currently in alpha stage. <p>BIRD does not implement any Babel extensions, but will coexist with
implementations using extensions (and will just ignore extension messages).
<sect1>Configuration <sect1>Configuration
<label id="babel-config"> <label id="babel-config">
@ -1623,6 +1622,8 @@ protocol babel [<name>] {
rx buffer <number>; rx buffer <number>;
tx length <number>; tx length <number>;
check link <switch>; check link <switch>;
next hop ipv4 <address>;
next hop ipv6 <address>;
}; };
} }
</code> </code>
@ -1680,6 +1681,18 @@ protocol babel [<name>] {
routes received from them are withdrawn. It is possible that some routes received from them are withdrawn. It is possible that some
hardware drivers or platforms do not implement this feature. Default: hardware drivers or platforms do not implement this feature. Default:
yes. yes.
<tag><label id="babel-next-hop-ipv4">next hop ipv4 <m/address/</tag>
Set the next hop address advertised for IPv4 routes advertised on this
interface. If not set, the first IPv4 address found on the interface will
be used, so it should only be necessary to set this option if this
auto-detection fails or finds the wrong address.
<tag><label id="babel-next-hop-ipv6">next hop ipv6 <m/address/</tag>
Set the next hop address advertised for IPv6 routes advertised on this
interface. If not set, the same link-local address that is used as the
source for Babel packets will be used. In normal operation, it should not
be necessary to set this option.
</descrip> </descrip>
<sect1>Attributes <sect1>Attributes
@ -1708,7 +1721,12 @@ protocol babel {
# configured on local interfaces, plus re-distribute all routes received # configured on local interfaces, plus re-distribute all routes received
# from other babel peers. # from other babel peers.
export where (source = RTS_DEVICE) || (source = RTS_BABEL); ipv4 {
export where (source = RTS_DEVICE) || (source = RTS_BABEL);
};
ipv6 {
export where (source = RTS_DEVICE) || (source = RTS_BABEL);
};
} }
</code> </code>

View File

@ -366,12 +366,16 @@ struct nexthop {
ip_addr gw; /* Next hop */ ip_addr gw; /* Next hop */
struct iface *iface; /* Outgoing interface */ struct iface *iface; /* Outgoing interface */
struct nexthop *next; struct nexthop *next;
byte flags;
byte weight; byte weight;
byte labels_orig; /* Number of labels before hostentry was applied */ byte labels_orig; /* Number of labels before hostentry was applied */
byte labels; /* Number of all labels */ byte labels; /* Number of all labels */
u32 label[0]; u32 label[0];
}; };
#define RNF_ONLINK 0x1 /* Gateway is onlink regardless of IP ranges */
struct rte_src { struct rte_src {
struct rte_src *next; /* Hash chain */ struct rte_src *next; /* Hash chain */
struct proto *proto; /* Protocol the source is based on */ struct proto *proto; /* Protocol the source is based on */

View File

@ -171,7 +171,9 @@ nexthop__same(struct nexthop *x, struct nexthop *y)
{ {
for (; x && y; x = x->next, y = y->next) for (; x && y; x = x->next, y = y->next)
{ {
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->flags != y->flags) || (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++)
@ -193,6 +195,8 @@ nexthop_compare_node(struct nexthop *x, struct nexthop *y)
if (!y) if (!y)
return -1; return -1;
/* Should we also compare flags ? */
r = ((int) y->weight) - ((int) x->weight); r = ((int) y->weight) - ((int) x->weight);
if (r) if (r)
return r; return r;

View File

@ -120,6 +120,7 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
for (nh = &(a->nh); nh; nh = nh->next) for (nh = &(a->nh); nh; nh = nh->next)
{ {
char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls; char mpls[MPLS_MAX_LABEL_STACK*12 + 5], *lsp = mpls;
char *onlink = (nh->flags & RNF_ONLINK) ? " onlink" : "";
if (nh->labels) if (nh->labels)
{ {
@ -130,9 +131,11 @@ rt_show_rte(struct cli *c, byte *ia, rte *e, struct rt_show_data *d, ea_list *tm
*lsp = '\0'; *lsp = '\0';
if (a->nh.next) if (a->nh.next)
cli_printf(c, -1007, "\tvia %I%s on %s weight %d", nh->gw, mpls, nh->iface->name, nh->weight + 1); cli_printf(c, -1007, "\tvia %I%s on %s%s weight %d",
nh->gw, mpls, nh->iface->name, onlink, nh->weight + 1);
else else
cli_printf(c, -1007, "\tvia %I%s on %s", nh->gw, mpls, nh->iface->name); cli_printf(c, -1007, "\tvia %I%s on %s%s",
nh->gw, mpls, nh->iface->name, onlink);
} }
if (d->verbose) if (d->verbose)

View File

@ -1819,7 +1819,10 @@ no_nexthop:
} }
} }
if (ipa_nonzero(nh->gw)) if (ipa_nonzero(nh->gw))
nhp->gw = nh->gw; /* Router nexthop */ {
nhp->gw = nh->gw; /* Router nexthop */
nhp->flags |= (nh->flags & RNF_ONLINK);
}
else if (ipa_nonzero(he->link)) else if (ipa_nonzero(he->link))
nhp->gw = he->link; /* Device nexthop with link-local address known */ nhp->gw = he->link; /* Device nexthop with link-local address known */
else else

View File

@ -78,13 +78,15 @@ babel_init_entry(void *E)
static inline struct babel_entry * static inline struct babel_entry *
babel_find_entry(struct babel_proto *p, const net_addr *n) babel_find_entry(struct babel_proto *p, const net_addr *n)
{ {
return fib_find(&p->rtable, n); struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable;
return fib_find(rtable, n);
} }
static struct babel_entry * static struct babel_entry *
babel_get_entry(struct babel_proto *p, const net_addr *n) babel_get_entry(struct babel_proto *p, const net_addr *n)
{ {
struct babel_entry *e = fib_get(&p->rtable, n); struct fib *rtable = (n->type == NET_IP4) ? &p->ip4_rtable : &p->ip6_rtable;
struct babel_entry *e = fib_get(rtable, n);
e->proto = p; e->proto = p;
return e; return e;
} }
@ -224,15 +226,15 @@ babel_refresh_route(struct babel_route *r)
} }
static void static void
babel_expire_routes(struct babel_proto *p) babel_expire_routes_(struct babel_proto *p UNUSED, struct fib *rtable)
{ {
struct babel_route *r, *rx; struct babel_route *r, *rx;
struct fib_iterator fit; struct fib_iterator fit;
FIB_ITERATE_INIT(&fit, &p->rtable); FIB_ITERATE_INIT(&fit, rtable);
loop: loop:
FIB_ITERATE_START(&p->rtable, &fit, struct babel_entry, e) FIB_ITERATE_START(rtable, &fit, struct babel_entry, e)
{ {
int changed = 0; int changed = 0;
@ -253,7 +255,7 @@ loop:
/* /*
* We have to restart the iteration because there may be a cascade of * We have to restart the iteration because there may be a cascade of
* synchronous events babel_select_route() -> nest table change -> * synchronous events babel_select_route() -> nest table change ->
* babel_rt_notify() -> p->rtable change, invalidating hidden variables. * babel_rt_notify() -> rtable change, invalidating hidden variables.
*/ */
FIB_ITERATE_PUT(&fit); FIB_ITERATE_PUT(&fit);
@ -267,13 +269,20 @@ loop:
if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes)) if (EMPTY_LIST(e->sources) && EMPTY_LIST(e->routes))
{ {
FIB_ITERATE_PUT(&fit); FIB_ITERATE_PUT(&fit);
fib_delete(&p->rtable, e); fib_delete(rtable, e);
goto loop; goto loop;
} }
} }
FIB_ITERATE_END; FIB_ITERATE_END;
} }
static void
babel_expire_routes(struct babel_proto *p)
{
babel_expire_routes_(p, &p->ip4_rtable);
babel_expire_routes_(p, &p->ip6_rtable);
}
static struct babel_neighbor * static struct babel_neighbor *
babel_find_neighbor(struct babel_iface *ifa, ip_addr addr) babel_find_neighbor(struct babel_iface *ifa, ip_addr addr)
{ {
@ -468,6 +477,7 @@ static void
babel_announce_rte(struct babel_proto *p, struct babel_entry *e) babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
{ {
struct babel_route *r = e->selected_in; struct babel_route *r = e->selected_in;
struct channel *c = (e->n.addr->type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
if (r) if (r)
{ {
@ -490,12 +500,12 @@ babel_announce_rte(struct babel_proto *p, struct babel_entry *e)
rte->u.babel.router_id = r->router_id; rte->u.babel.router_id = r->router_id;
rte->pflags = 0; rte->pflags = 0;
rte_update(&p->p, e->n.addr, rte); rte_update2(c, e->n.addr, rte, p->p.main_source);
} }
else else
{ {
/* Retraction */ /* Retraction */
rte_update(&p->p, e->n.addr, NULL); rte_update2(c, e->n.addr, NULL, p->p.main_source);
} }
} }
@ -740,11 +750,11 @@ babel_unicast_seqno_request(struct babel_route *r)
* transmitted entry is updated. * transmitted entry is updated.
*/ */
static void static void
babel_send_update(struct babel_iface *ifa, bird_clock_t changed) babel_send_update_(struct babel_iface *ifa, bird_clock_t changed, struct fib *rtable)
{ {
struct babel_proto *p = ifa->proto; struct babel_proto *p = ifa->proto;
FIB_WALK(&p->rtable, struct babel_entry, e) FIB_WALK(rtable, struct babel_entry, e)
{ {
struct babel_route *r = e->selected_out; struct babel_route *r = e->selected_out;
@ -774,6 +784,9 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
msg.update.router_id = r->router_id; msg.update.router_id = r->router_id;
net_copy(&msg.update.net, e->n.addr); net_copy(&msg.update.net, e->n.addr);
msg.update.next_hop = ((e->n.addr->type == NET_IP4) ?
ifa->next_hop_ip4 : ifa->next_hop_ip6);
babel_enqueue(&msg, ifa); babel_enqueue(&msg, ifa);
/* Update feasibility distance for redistributed routes */ /* Update feasibility distance for redistributed routes */
@ -793,6 +806,15 @@ babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
FIB_WALK_END; FIB_WALK_END;
} }
static void
babel_send_update(struct babel_iface *ifa, bird_clock_t changed)
{
struct babel_proto *p = ifa->proto;
babel_send_update_(ifa, changed, &p->ip4_rtable);
babel_send_update_(ifa, changed, &p->ip6_rtable);
}
static void static void
babel_trigger_iface_update(struct babel_iface *ifa) babel_trigger_iface_update(struct babel_iface *ifa)
{ {
@ -1073,6 +1095,13 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
return; return;
} }
struct channel *c = (msg->net.type == NET_IP4) ? p->ip4_channel : p->ip6_channel;
if (!c || (c->channel_state != CS_UP))
{
DBG("Babel: Ignoring update for inactive address family.\n");
return;
}
/* /*
* RFC section 3.5.4: * RFC section 3.5.4:
* *
@ -1475,14 +1504,26 @@ babel_add_iface(struct babel_proto *p, struct iface *new, struct babel_iface_con
add_tail(&p->interfaces, NODE ifa); add_tail(&p->interfaces, NODE ifa);
ip_addr addr4 = IPA_NONE;
struct ifa *addr; struct ifa *addr;
WALK_LIST(addr, new->addrs) WALK_LIST(addr, new->addrs)
{
if (ipa_is_link_local(addr->ip)) if (ipa_is_link_local(addr->ip))
ifa->addr = addr->ip; ifa->addr = addr->ip;
if (ipa_zero(addr4) && ipa_is_ip4(addr->ip))
addr4 = addr->ip;
}
ifa->next_hop_ip4 = ipa_nonzero(ic->next_hop_ip4) ? ic->next_hop_ip4 : addr4;
ifa->next_hop_ip6 = ipa_nonzero(ic->next_hop_ip6) ? ic->next_hop_ip6 : ifa->addr;
if (ipa_zero(ifa->addr)) if (ipa_zero(ifa->addr))
log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name); log(L_WARN "%s: Cannot find link-local addr on %s", p->p.name, new->name);
if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, new->name);
init_list(&ifa->neigh_list); init_list(&ifa->neigh_list);
ifa->hello_seqno = 1; ifa->hello_seqno = 1;
@ -1574,6 +1615,26 @@ babel_reconfigure_iface(struct babel_proto *p, struct babel_iface *ifa, struct b
ifa->cf = new; ifa->cf = new;
if (ipa_nonzero(new->next_hop_ip4))
ifa->next_hop_ip4 = new->next_hop_ip4;
else
{
ifa->next_hop_ip4 = IPA_NONE;
struct ifa *addr;
WALK_LIST(addr, ifa->iface->addrs)
if (ipa_is_ip4(addr->ip))
{
ifa->next_hop_ip4 = addr->ip;
break;
}
}
ifa->next_hop_ip6 = ipa_nonzero(new->next_hop_ip6) ? new->next_hop_ip6 : ifa->addr;
if (ipa_zero(ifa->next_hop_ip4) && p->ip4_channel)
log(L_WARN "%s: Cannot find IPv4 next hop addr on %s", p->p.name, ifa->ifname);
if (ifa->next_hello > (now + new->hello_interval)) if (ifa->next_hello > (now + new->hello_interval))
ifa->next_hello = now + (random() % new->hello_interval) + 1; ifa->next_hello = now + (random() % new->hello_interval) + 1;
@ -1680,9 +1741,10 @@ babel_dump_iface(struct babel_iface *ifa)
{ {
struct babel_neighbor *n; struct babel_neighbor *n;
debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d\n", debug("Babel: Interface %s addr %I rxcost %d type %d hello seqno %d intervals %d %d",
ifa->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno, ifa->ifname, ifa->addr, ifa->cf->rxcost, ifa->cf->type, ifa->hello_seqno,
ifa->cf->hello_interval, ifa->cf->update_interval); ifa->cf->hello_interval, ifa->cf->update_interval);
debug(" next hop v4 %I next hop v6 %I\n", ifa->next_hop_ip4, ifa->next_hop_ip6);
WALK_LIST(n, ifa->neigh_list) WALK_LIST(n, ifa->neigh_list)
{ debug(" "); babel_dump_neighbor(n); } { debug(" "); babel_dump_neighbor(n); }
@ -1699,7 +1761,12 @@ babel_dump(struct proto *P)
WALK_LIST(ifa, p->interfaces) WALK_LIST(ifa, p->interfaces)
babel_dump_iface(ifa); babel_dump_iface(ifa);
FIB_WALK(&p->rtable, struct babel_entry, e) FIB_WALK(&p->ip4_rtable, struct babel_entry, e)
{
babel_dump_entry(e);
}
FIB_WALK_END;
FIB_WALK(&p->ip6_rtable, struct babel_entry, e)
{ {
babel_dump_entry(e); babel_dump_entry(e);
} }
@ -1749,8 +1816,9 @@ babel_show_interfaces(struct proto *P, char *iff)
} }
cli_msg(-1023, "%s:", p->p.name); cli_msg(-1023, "%s:", p->p.name);
cli_msg(-1023, "%-10s %-6s %7s %6s %6s", cli_msg(-1023, "%-10s %-6s %7s %6s %6s %-15s %s",
"Interface", "State", "RX cost", "Nbrs", "Timer"); "Interface", "State", "RX cost", "Nbrs", "Timer",
"Next hop (v4)", "Next hop (v6)");
WALK_LIST(ifa, p->interfaces) WALK_LIST(ifa, p->interfaces)
{ {
@ -1762,8 +1830,10 @@ babel_show_interfaces(struct proto *P, char *iff)
nbrs++; nbrs++;
int timer = MIN(ifa->next_regular, ifa->next_hello) - now; int timer = MIN(ifa->next_regular, ifa->next_hello) - now;
cli_msg(-1023, "%-10s %-6s %7u %6u %6u", cli_msg(-1023, "%-10s %-6s %7u %6u %6u %-15I %I",
ifa->iface->name, (ifa->up ? "Up" : "Down"), ifa->cf->rxcost, nbrs, MAX(timer, 0)); ifa->iface->name, (ifa->up ? "Up" : "Down"),
ifa->cf->rxcost, nbrs, MAX(timer, 0),
ifa->next_hop_ip4, ifa->next_hop_ip6);
} }
cli_msg(0, ""); cli_msg(0, "");
@ -1808,27 +1878,15 @@ babel_show_neighbors(struct proto *P, char *iff)
cli_msg(0, ""); cli_msg(0, "");
} }
void static void
babel_show_entries(struct proto *P) babel_show_entries_(struct babel_proto *p, struct fib *rtable)
{ {
struct babel_proto *p = (void *) P;
struct babel_source *s = NULL; struct babel_source *s = NULL;
struct babel_route *r = NULL; struct babel_route *r = NULL;
char ridbuf[ROUTER_ID_64_LENGTH+1]; char ridbuf[ROUTER_ID_64_LENGTH+1];
if (p->p.proto_state != PS_UP) FIB_WALK(rtable, struct babel_entry, e)
{
cli_msg(-1025, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
cli_msg(-1025, "%s:", p->p.name);
cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
"Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
FIB_WALK(&p->rtable, struct babel_entry, e)
{ {
r = e->selected_in ? e->selected_in : e->selected_out; r = e->selected_in ? e->selected_in : e->selected_out;
@ -1853,6 +1911,26 @@ babel_show_entries(struct proto *P)
} }
} }
FIB_WALK_END; FIB_WALK_END;
}
void
babel_show_entries(struct proto *P)
{
struct babel_proto *p = (void *) P;
if (p->p.proto_state != PS_UP)
{
cli_msg(-1025, "%s: is not up", p->p.name);
cli_msg(0, "");
return;
}
cli_msg(-1025, "%s:", p->p.name);
cli_msg(-1025, "%-29s %-23s %6s %5s %7s %7s",
"Prefix", "Router ID", "Metric", "Seqno", "Expires", "Sources");
babel_show_entries_(p, &p->ip4_rtable);
babel_show_entries_(p, &p->ip6_rtable);
cli_msg(0, ""); cli_msg(0, "");
} }
@ -2028,8 +2106,10 @@ static struct proto *
babel_init(struct proto_config *CF) babel_init(struct proto_config *CF)
{ {
struct proto *P = proto_new(CF); struct proto *P = proto_new(CF);
struct babel_proto *p = (void *) P;
P->main_channel = proto_add_channel(P, proto_cf_main_channel(CF)); proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4));
proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6));
P->if_notify = babel_if_notify; P->if_notify = babel_if_notify;
P->rt_notify = babel_rt_notify; P->rt_notify = babel_rt_notify;
@ -2048,8 +2128,11 @@ babel_start(struct proto *P)
struct babel_proto *p = (void *) P; struct babel_proto *p = (void *) P;
struct babel_config *cf = (void *) P->cf; struct babel_config *cf = (void *) P->cf;
fib_init(&p->rtable, P->pool, NET_IP6, sizeof(struct babel_entry), fib_init(&p->ip4_rtable, P->pool, NET_IP4, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry); OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
fib_init(&p->ip6_rtable, P->pool, NET_IP6, sizeof(struct babel_entry),
OFFSETOF(struct babel_entry, n), 0, babel_init_entry);
init_list(&p->interfaces); init_list(&p->interfaces);
p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1); p->timer = tm_new_set(P->pool, babel_timer, p, 0, 1);
tm_start(p->timer, 2); tm_start(p->timer, 2);
@ -2099,7 +2182,8 @@ babel_reconfigure(struct proto *P, struct proto_config *CF)
TRACE(D_EVENTS, "Reconfiguring"); TRACE(D_EVENTS, "Reconfiguring");
if (!proto_configure_channel(P, &P->main_channel, proto_cf_main_channel(CF))) if (!proto_configure_channel(P, &p->ip4_channel, proto_cf_find_channel(CF, NET_IP4)) ||
!proto_configure_channel(P, &p->ip6_channel, proto_cf_find_channel(CF, NET_IP6)))
return 0; return 0;
p->p.cf = CF; p->p.cf = CF;
@ -2117,7 +2201,7 @@ struct protocol proto_babel = {
.template = "babel%d", .template = "babel%d",
.attr_class = EAP_BABEL, .attr_class = EAP_BABEL,
.preference = DEF_PREF_BABEL, .preference = DEF_PREF_BABEL,
.channel_mask = NB_IP6, .channel_mask = NB_IP,
.proto_size = sizeof(struct babel_proto), .proto_size = sizeof(struct babel_proto),
.config_size = sizeof(struct babel_config), .config_size = sizeof(struct babel_config),
.init = babel_init, .init = babel_init,

View File

@ -78,6 +78,11 @@ enum babel_tlv_type {
BABEL_TLV_MAX BABEL_TLV_MAX
}; };
enum babel_subtlv_type {
BABEL_SUBTLV_PAD1 = 0,
BABEL_SUBTLV_PADN = 1
};
enum babel_iface_type { enum babel_iface_type {
/* In practice, UNDEF and WIRED give equivalent behaviour */ /* In practice, UNDEF and WIRED give equivalent behaviour */
BABEL_IFACE_TYPE_UNDEF = 0, BABEL_IFACE_TYPE_UNDEF = 0,
@ -116,12 +121,20 @@ struct babel_iface_config {
u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */ u16 tx_length; /* TX packet length limit (including headers), 0 for MTU */
int tx_tos; int tx_tos;
int tx_priority; int tx_priority;
ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
}; };
struct babel_proto { struct babel_proto {
struct proto p; struct proto p;
timer *timer; timer *timer;
struct fib rtable; struct fib ip4_rtable;
struct fib ip6_rtable;
struct channel *ip4_channel;
struct channel *ip6_channel;
list interfaces; /* Interfaces we really know about (struct babel_iface) */ list interfaces; /* Interfaces we really know about (struct babel_iface) */
u64 router_id; u64 router_id;
u16 update_seqno; /* To be increased on request */ u16 update_seqno; /* To be increased on request */
@ -151,6 +164,8 @@ struct babel_iface {
char *ifname; char *ifname;
sock *sk; sock *sk;
ip_addr addr; ip_addr addr;
ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
int tx_length; int tx_length;
list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */ list neigh_list; /* List of neighbors seen on this iface (struct babel_neighbor) */
list msg_queue; list msg_queue;

View File

@ -21,7 +21,8 @@ CF_DEFINES
CF_DECLS CF_DECLS
CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED, CF_KEYWORDS(BABEL, METRIC, RXCOST, HELLO, UPDATE, INTERVAL, PORT, WIRED,
WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC) WIRELESS, RX, TX, BUFFER, LENGTH, CHECK, LINK, BABEL_METRIC, NEXT, HOP,
IPV4, IPV6)
CF_GRAMMAR CF_GRAMMAR
@ -30,7 +31,6 @@ CF_ADDTO(proto, babel_proto)
babel_proto_start: proto_start BABEL babel_proto_start: proto_start BABEL
{ {
this_proto = proto_config_new(&proto_babel, $1); this_proto = proto_config_new(&proto_babel, $1);
this_proto->net_type = NET_IP6;
init_list(&BABEL_CFG->iface_list); init_list(&BABEL_CFG->iface_list);
}; };
@ -98,6 +98,8 @@ babel_iface_item:
| TX tos { BABEL_IFACE->tx_tos = $2; } | TX tos { BABEL_IFACE->tx_tos = $2; }
| TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; } | TX PRIORITY expr { BABEL_IFACE->tx_priority = $3; }
| CHECK LINK bool { BABEL_IFACE->check_link = $3; } | CHECK LINK bool { BABEL_IFACE->check_link = $3; }
| NEXT HOP IPV4 ipa { BABEL_IFACE->next_hop_ip4 = $4; if (!ipa_is_ip4($4)) cf_error("Must be an IPv4 address"); }
| NEXT HOP IPV6 ipa { BABEL_IFACE->next_hop_ip6 = $4; if (!ipa_is_ip6($4)) cf_error("Must be an IPv6 address"); }
; ;
babel_iface_opts: babel_iface_opts:

View File

@ -112,13 +112,15 @@ struct babel_parse_state {
struct babel_proto *proto; struct babel_proto *proto;
struct babel_iface *ifa; struct babel_iface *ifa;
ip_addr saddr; ip_addr saddr;
ip_addr next_hop; ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
u64 router_id; /* Router ID used in subsequent updates */ u64 router_id; /* Router ID used in subsequent updates */
u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */ u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */
u8 def_ip4_prefix[4]; /* Implicit IPv4 prefix in network order */ u8 def_ip4_prefix[4]; /* Implicit IPv4 prefix in network order */
u8 router_id_seen; /* router_id field is valid */ u8 router_id_seen; /* router_id field is valid */
u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */ u8 def_ip6_prefix_seen; /* def_ip6_prefix is valid */
u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */ u8 def_ip4_prefix_seen; /* def_ip4_prefix is valid */
u8 current_tlv_endpos; /* End of self-terminating TLVs (offset from start) */
}; };
enum parse_result { enum parse_result {
@ -130,7 +132,10 @@ enum parse_result {
struct babel_write_state { struct babel_write_state {
u64 router_id; u64 router_id;
u8 router_id_seen; u8 router_id_seen;
// ip_addr next_hop; ip_addr next_hop_ip4;
ip_addr next_hop_ip6;
u8 def_ip6_prefix[16]; /* Implicit IPv6 prefix in network order */
u8 def_ip6_pxlen;
}; };
@ -148,6 +153,14 @@ struct babel_write_state {
#define NET_SIZE(n) BYTES(net_pxlen(n)) #define NET_SIZE(n) BYTES(net_pxlen(n))
static inline uint
bytes_equal(u8 *b1, u8 *b2, uint maxlen)
{
uint i;
for (i = 0; (i < maxlen) && (*b1 == *b2); i++, b1++, b2++)
;
return i;
}
static inline u16 static inline u16
get_time16(const void *p) get_time16(const void *p)
@ -162,6 +175,21 @@ put_time16(void *p, u16 v)
put_u16(p, v * BABEL_TIME_UNITS); put_u16(p, v * BABEL_TIME_UNITS);
} }
static inline void
read_ip4_px(net_addr *n, const void *p, uint plen)
{
ip4_addr addr = {0};
memcpy(&addr, p, BYTES(plen));
net_fill_ip4(n, ip4_ntoh(addr), plen);
}
static inline void
put_ip4_px(void *p, net_addr *n)
{
ip4_addr addr = ip4_hton(net4_prefix(n));
memcpy(p, &addr, NET_SIZE(n));
}
static inline void static inline void
read_ip6_px(net_addr *n, const void *p, uint plen) read_ip6_px(net_addr *n, const void *p, uint plen)
{ {
@ -352,14 +380,33 @@ babel_read_ihu(struct babel_tlv *hdr, union babel_msg *m,
if (msg->ae >= BABEL_AE_MAX) if (msg->ae >= BABEL_AE_MAX)
return PARSE_IGNORE; return PARSE_IGNORE;
// We handle link-local IPs. In every other case, the addr field will be 0 but /*
// validation will succeed. The handler takes care of these cases. * We only actually read link-local IPs. In every other case, the addr field
if (msg->ae == BABEL_AE_IP6_LL) * will be 0 but validation will succeed. The handler takes care of these
* cases. We handle them here anyway because we need the length for parsing
* subtlvs.
*/
switch (msg->ae)
{ {
case BABEL_AE_IP4:
if (TLV_OPT_LENGTH(tlv) < 4)
return PARSE_ERROR;
state->current_tlv_endpos += 4;
break;
case BABEL_AE_IP6:
if (TLV_OPT_LENGTH(tlv) < 16)
return PARSE_ERROR;
state->current_tlv_endpos += 16;
break;
case BABEL_AE_IP6_LL:
if (TLV_OPT_LENGTH(tlv) < 8) if (TLV_OPT_LENGTH(tlv) < 8)
return PARSE_ERROR; return PARSE_ERROR;
msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr)); msg->addr = ipa_from_ip6(get_ip6_ll(&tlv->addr));
state->current_tlv_endpos += 8;
break;
} }
return PARSE_SUCCESS; return PARSE_SUCCESS;
@ -432,21 +479,27 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_ERROR; return PARSE_ERROR;
case BABEL_AE_IP4: case BABEL_AE_IP4:
/* TODO */ if (TLV_OPT_LENGTH(tlv) < sizeof(ip4_addr))
return PARSE_ERROR;
state->next_hop_ip4 = ipa_from_ip4(get_ip4(&tlv->addr));
state->current_tlv_endpos += sizeof(ip4_addr);
return PARSE_IGNORE; return PARSE_IGNORE;
case BABEL_AE_IP6: case BABEL_AE_IP6:
if (TLV_OPT_LENGTH(tlv) < sizeof(ip6_addr)) if (TLV_OPT_LENGTH(tlv) < sizeof(ip6_addr))
return PARSE_ERROR; return PARSE_ERROR;
state->next_hop = ipa_from_ip6(get_ip6(&tlv->addr)); state->next_hop_ip6 = ipa_from_ip6(get_ip6(&tlv->addr));
state->current_tlv_endpos += sizeof(ip6_addr);
return PARSE_IGNORE; return PARSE_IGNORE;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
if (TLV_OPT_LENGTH(tlv) < 8) if (TLV_OPT_LENGTH(tlv) < 8)
return PARSE_ERROR; return PARSE_ERROR;
state->next_hop = ipa_from_ip6(get_ip6_ll(&tlv->addr)); state->next_hop_ip6 = ipa_from_ip6(get_ip6_ll(&tlv->addr));
state->current_tlv_endpos += 8;
return PARSE_IGNORE; return PARSE_IGNORE;
default: default:
@ -456,6 +509,51 @@ babel_read_next_hop(struct babel_tlv *hdr, union babel_msg *m UNUSED,
return PARSE_IGNORE; return PARSE_IGNORE;
} }
/* This is called directly from babel_write_update() and returns -1 if a next
hop should be written but there is not enough space. */
static int
babel_write_next_hop(struct babel_tlv *hdr, ip_addr addr,
struct babel_write_state *state, uint max_len)
{
struct babel_tlv_next_hop *tlv = (void *) hdr;
if (ipa_zero(addr))
{
/* Should not happen */
return 0;
}
else if (ipa_is_ip4(addr) && !ipa_equal(addr, state->next_hop_ip4))
{
uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip4_addr);
if (len > max_len)
return -1;
TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len);
tlv->ae = BABEL_AE_IP4;
put_ip4(&tlv->addr, ipa_to_ip4(addr));
state->next_hop_ip4 = addr;
return len;
}
else if (ipa_is_ip6(addr) && !ipa_equal(addr, state->next_hop_ip6))
{
uint len = sizeof(struct babel_tlv_next_hop) + sizeof(ip6_addr);
if (len > max_len)
return -1;
TLV_HDR(tlv, BABEL_TLV_NEXT_HOP, len);
tlv->ae = BABEL_AE_IP6;
put_ip6(&tlv->addr, ipa_to_ip6(addr));
state->next_hop_ip6 = addr;
return len;
}
return 0;
}
static int static int
babel_read_update(struct babel_tlv *hdr, union babel_msg *m, babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
struct babel_parse_state *state) struct babel_parse_state *state)
@ -488,8 +586,33 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
break; break;
case BABEL_AE_IP4: case BABEL_AE_IP4:
/* TODO */ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
return PARSE_IGNORE; return PARSE_ERROR;
/* Cannot omit data if there is no saved prefix */
if (tlv->omitted && !state->def_ip4_prefix_seen)
return PARSE_ERROR;
/* Need next hop for v4 routes */
if (ipa_zero(state->next_hop_ip4))
return PARSE_ERROR;
/* Merge saved prefix and received prefix parts */
memcpy(buf, state->def_ip4_prefix, tlv->omitted);
memcpy(buf + tlv->omitted, tlv->addr, len);
ip4_addr prefix4 = get_ip4(buf);
net_fill_ip4(&msg->net, prefix4, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
{
put_ip4(state->def_ip4_prefix, prefix4);
state->def_ip4_prefix_seen = 1;
}
msg->next_hop = state->next_hop_ip4;
break;
case BABEL_AE_IP6: case BABEL_AE_IP6:
if (tlv->plen > IP6_MAX_PREFIX_LENGTH) if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
@ -503,20 +626,23 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
memcpy(buf, state->def_ip6_prefix, tlv->omitted); memcpy(buf, state->def_ip6_prefix, tlv->omitted);
memcpy(buf + tlv->omitted, tlv->addr, len); memcpy(buf + tlv->omitted, tlv->addr, len);
ip6_addr prefix = get_ip6(buf); ip6_addr prefix6 = get_ip6(buf);
net_fill_ip6(&msg->net, prefix, tlv->plen); net_fill_ip6(&msg->net, prefix6, tlv->plen);
if (tlv->flags & BABEL_FLAG_DEF_PREFIX) if (tlv->flags & BABEL_FLAG_DEF_PREFIX)
{ {
put_ip6(state->def_ip6_prefix, prefix); put_ip6(state->def_ip6_prefix, prefix6);
state->def_ip6_prefix_seen = 1; state->def_ip6_prefix_seen = 1;
} }
if (tlv->flags & BABEL_FLAG_ROUTER_ID) if (tlv->flags & BABEL_FLAG_ROUTER_ID)
{ {
state->router_id = ((u64) _I2(prefix)) << 32 | _I3(prefix); state->router_id = ((u64) _I2(prefix6)) << 32 | _I3(prefix6);
state->router_id_seen = 1; state->router_id_seen = 1;
} }
msg->next_hop = state->next_hop_ip6;
break; break;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
@ -535,8 +661,8 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
} }
msg->router_id = state->router_id; msg->router_id = state->router_id;
msg->next_hop = state->next_hop;
msg->sender = state->saddr; msg->sender = state->saddr;
state->current_tlv_endpos += len;
return PARSE_SUCCESS; return PARSE_SUCCESS;
} }
@ -545,7 +671,6 @@ static uint
babel_write_update(struct babel_tlv *hdr, union babel_msg *m, babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
struct babel_write_state *state, uint max_len) struct babel_write_state *state, uint max_len)
{ {
struct babel_tlv_update *tlv = (void *) hdr;
struct babel_msg_update *msg = &m->update; struct babel_msg_update *msg = &m->update;
uint len0 = 0; uint len0 = 0;
@ -554,15 +679,34 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
* both of them. There is enough space for the Router-ID TLV, because * both of them. There is enough space for the Router-ID TLV, because
* sizeof(struct babel_tlv_router_id) == sizeof(struct babel_tlv_update). * sizeof(struct babel_tlv_router_id) == sizeof(struct babel_tlv_update).
* *
* Router ID is not used for retractions, so do not us it in such case. * Router ID is not used for retractions, so do not use it in such case.
*/ */
if ((msg->metric < BABEL_INFINITY) && if ((msg->metric < BABEL_INFINITY) &&
(!state->router_id_seen || (msg->router_id != state->router_id))) (!state->router_id_seen || (msg->router_id != state->router_id)))
{ {
len0 = babel_write_router_id(hdr, msg->router_id, state, max_len); len0 = babel_write_router_id(hdr, msg->router_id, state, max_len);
tlv = (struct babel_tlv_update *) NEXT_TLV(tlv); hdr = NEXT_TLV(hdr);
} }
/*
* We also may add Next Hop TLV for regular updates. It may fail for not
* enough space or it may be unnecessary as the next hop is the same as the
* last one already announced. So we handle all three cases.
*/
if (msg->metric < BABEL_INFINITY)
{
int l = babel_write_next_hop(hdr, msg->next_hop, state, max_len - len0);
if (l < 0)
return 0;
if (l)
{
len0 += l;
hdr = NEXT_TLV(hdr);
}
}
struct babel_tlv_update *tlv = (void *) hdr;
uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net); uint len = sizeof(struct babel_tlv_update) + NET_SIZE(&msg->net);
if (len0 + len > max_len) if (len0 + len > max_len)
@ -576,11 +720,39 @@ babel_write_update(struct babel_tlv *hdr, union babel_msg *m,
tlv->ae = BABEL_AE_WILDCARD; tlv->ae = BABEL_AE_WILDCARD;
tlv->plen = 0; tlv->plen = 0;
} }
else if (msg->net.type == NET_IP4)
{
tlv->ae = BABEL_AE_IP4;
tlv->plen = net4_pxlen(&msg->net);
put_ip4_px(tlv->addr, &msg->net);
}
else else
{ {
tlv->ae = BABEL_AE_IP6; tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net); tlv->plen = net6_pxlen(&msg->net);
put_ip6_px(tlv->addr, &msg->net);
/* Address compression - omit initial matching bytes */
u8 buf[16], omit;
put_ip6(buf, net6_prefix(&msg->net));
omit = bytes_equal(buf, state->def_ip6_prefix,
MIN(tlv->plen, state->def_ip6_pxlen) / 8);
if (omit > 0)
{
memcpy(tlv->addr, buf + omit, NET_SIZE(&msg->net) - omit);
tlv->omitted = omit;
tlv->length -= omit;
len -= omit;
}
else
{
put_ip6_px(tlv->addr, &msg->net);
tlv->flags |= BABEL_FLAG_DEF_PREFIX;
put_ip6(state->def_ip6_prefix, net6_prefix(&msg->net));
state->def_ip6_pxlen = tlv->plen;
}
} }
put_time16(&tlv->interval, msg->interval); put_time16(&tlv->interval, msg->interval);
@ -610,8 +782,15 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_SUCCESS; return PARSE_SUCCESS;
case BABEL_AE_IP4: case BABEL_AE_IP4:
/* TODO */ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
return PARSE_IGNORE; return PARSE_ERROR;
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
return PARSE_ERROR;
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6: case BABEL_AE_IP6:
if (tlv->plen > IP6_MAX_PREFIX_LENGTH) if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
@ -621,6 +800,7 @@ babel_read_route_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR; return PARSE_ERROR;
read_ip6_px(&msg->net, tlv->addr, tlv->plen); read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS; return PARSE_SUCCESS;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
@ -652,6 +832,12 @@ babel_write_route_request(struct babel_tlv *hdr, union babel_msg *m,
tlv->ae = BABEL_AE_WILDCARD; tlv->ae = BABEL_AE_WILDCARD;
tlv->plen = 0; tlv->plen = 0;
} }
else if (msg->net.type == NET_IP4)
{
tlv->ae = BABEL_AE_IP4;
tlv->plen = net4_pxlen(&msg->net);
put_ip4_px(tlv->addr, &msg->net);
}
else else
{ {
tlv->ae = BABEL_AE_IP6; tlv->ae = BABEL_AE_IP6;
@ -684,8 +870,15 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR; return PARSE_ERROR;
case BABEL_AE_IP4: case BABEL_AE_IP4:
/* TODO */ if (tlv->plen > IP4_MAX_PREFIX_LENGTH)
return PARSE_IGNORE; return PARSE_ERROR;
if (TLV_OPT_LENGTH(tlv) < BYTES(tlv->plen))
return PARSE_ERROR;
read_ip4_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS;
case BABEL_AE_IP6: case BABEL_AE_IP6:
if (tlv->plen > IP6_MAX_PREFIX_LENGTH) if (tlv->plen > IP6_MAX_PREFIX_LENGTH)
@ -695,6 +888,7 @@ babel_read_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return PARSE_ERROR; return PARSE_ERROR;
read_ip6_px(&msg->net, tlv->addr, tlv->plen); read_ip6_px(&msg->net, tlv->addr, tlv->plen);
state->current_tlv_endpos += BYTES(tlv->plen);
return PARSE_SUCCESS; return PARSE_SUCCESS;
case BABEL_AE_IP6_LL: case BABEL_AE_IP6_LL:
@ -720,16 +914,63 @@ babel_write_seqno_request(struct babel_tlv *hdr, union babel_msg *m,
return 0; return 0;
TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len); TLV_HDR(tlv, BABEL_TLV_SEQNO_REQUEST, len);
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net); if (msg->net.type == NET_IP4)
{
tlv->ae = BABEL_AE_IP4;
tlv->plen = net4_pxlen(&msg->net);
put_ip4_px(tlv->addr, &msg->net);
}
else
{
tlv->ae = BABEL_AE_IP6;
tlv->plen = net6_pxlen(&msg->net);
put_ip6_px(tlv->addr, &msg->net);
}
put_u16(&tlv->seqno, msg->seqno); put_u16(&tlv->seqno, msg->seqno);
tlv->hop_count = msg->hop_count; tlv->hop_count = msg->hop_count;
put_u64(&tlv->router_id, msg->router_id); put_u64(&tlv->router_id, msg->router_id);
put_ip6_px(tlv->addr, &msg->net);
return len; return len;
} }
static inline int
babel_read_subtlvs(struct babel_tlv *hdr,
union babel_msg *msg UNUSED,
struct babel_parse_state *state)
{
struct babel_tlv *tlv;
for (tlv = (void *) hdr + state->current_tlv_endpos;
(void *) tlv < (void *) hdr + TLV_LENGTH(hdr);
tlv = NEXT_TLV(tlv))
{
/*
* The subtlv type space is non-contiguous (due to the mandatory bit), so
* use a switch for dispatch instead of the mapping array we use for TLVs
*/
switch (tlv->type)
{
case BABEL_SUBTLV_PAD1:
case BABEL_SUBTLV_PADN:
/* FIXME: Framing errors in PADN are silently ignored, see babel_process_packet() */
break;
default:
/* Unknown mandatory subtlv; PARSE_IGNORE ignores the whole TLV */
if (tlv->type > 128)
{
DBG("Babel: Mandatory subtlv %d found; skipping TLV\n", tlv->type);
return PARSE_IGNORE;
}
break;
}
}
return PARSE_SUCCESS;
}
static inline int static inline int
babel_read_tlv(struct babel_tlv *hdr, babel_read_tlv(struct babel_tlv *hdr,
union babel_msg *msg, union babel_msg *msg,
@ -743,8 +984,14 @@ babel_read_tlv(struct babel_tlv *hdr,
if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length) if (TLV_LENGTH(hdr) < tlv_data[hdr->type].min_length)
return PARSE_ERROR; return PARSE_ERROR;
state->current_tlv_endpos = tlv_data[hdr->type].min_length;
memset(msg, 0, sizeof(*msg)); memset(msg, 0, sizeof(*msg));
return tlv_data[hdr->type].read_tlv(hdr, msg, state);
int res = tlv_data[hdr->type].read_tlv(hdr, msg, state);
if (res != PARSE_SUCCESS)
return res;
return babel_read_subtlvs(hdr, msg, state);
} }
static uint static uint
@ -799,7 +1046,7 @@ static uint
babel_write_queue(struct babel_iface *ifa, list *queue) babel_write_queue(struct babel_iface *ifa, list *queue)
{ {
struct babel_proto *p = ifa->proto; struct babel_proto *p = ifa->proto;
struct babel_write_state state = {}; struct babel_write_state state = { .next_hop_ip6 = ifa->addr };
if (EMPTY_LIST(*queue)) if (EMPTY_LIST(*queue))
return 0; return 0;
@ -935,10 +1182,10 @@ babel_process_packet(struct babel_pkt_header *pkt, int len,
byte *end = (byte *)pkt + plen; byte *end = (byte *)pkt + plen;
struct babel_parse_state state = { struct babel_parse_state state = {
.proto = p, .proto = p,
.ifa = ifa, .ifa = ifa,
.saddr = saddr, .saddr = saddr,
.next_hop = saddr, .next_hop_ip6 = saddr,
}; };
if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION)) if ((pkt->magic != BABEL_MAGIC) || (pkt->version != BABEL_VERSION))

View File

@ -73,7 +73,7 @@ CF_DECLS
%type <fl> float_rate %type <fl> float_rate
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
CF_KEYWORDS(WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS) CF_KEYWORDS(ONLINK, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD, MPLS)
CF_KEYWORDS(RATE, SAMPLE, LAST, DSCP) CF_KEYWORDS(RATE, SAMPLE, LAST, DSCP)
CF_KEYWORDS_CS(mBps, mbps, Bps, bps, kBps, kbps, MBps, Mbps, GBps, Gbps, TBps, Tbps) CF_KEYWORDS_CS(mBps, mbps, Bps, bps, kBps, kbps, MBps, Mbps, GBps, Gbps, TBps, Tbps)
@ -118,6 +118,9 @@ stat_nexthop:
| stat_nexthop MPLS label_stack { | stat_nexthop MPLS label_stack {
this_snh->mls = $3; this_snh->mls = $3;
} }
| stat_nexthop ONLINK bool {
this_snh->onlink = $3;
}
| stat_nexthop WEIGHT expr { | stat_nexthop WEIGHT expr {
this_snh->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");

View File

@ -71,6 +71,7 @@ static_announce_rte(struct static_proto *p, struct static_route *r)
struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE); struct nexthop *nh = allocz(NEXTHOP_MAX_SIZE);
nh->gw = r2->via; nh->gw = r2->via;
nh->iface = r2->neigh->iface; nh->iface = r2->neigh->iface;
nh->flags = r2->onlink ? RNF_ONLINK : 0;
nh->weight = r2->weight; nh->weight = r2->weight;
if (r2->mls) if (r2->mls)
{ {
@ -205,7 +206,8 @@ static_add_rte(struct static_proto *p, struct static_route *r)
for (r2 = r; r2; r2 = r2->mp_next) for (r2 = r; r2; r2 = r2->mp_next)
{ {
n = ipa_nonzero(r2->via) ? n = ipa_nonzero(r2->via) ?
neigh_find2(&p->p, &r2->via, r2->iface, NEF_STICKY) : neigh_find2(&p->p, &r2->via, r2->iface,
NEF_STICKY | (r2->onlink ? NEF_ONLINK : 0)) :
neigh_find_iface(&p->p, r2->iface); neigh_find_iface(&p->p, r2->iface);
if (!n) if (!n)
@ -267,8 +269,9 @@ static_same_dest(struct static_route *x, struct static_route *y)
{ {
if (!ipa_equal(x->via, y->via) || if (!ipa_equal(x->via, y->via) ||
(x->iface != y->iface) || (x->iface != y->iface) ||
(x->use_bfd != y->use_bfd) || (x->onlink != y->onlink) ||
(x->weight != y->weight) || (x->weight != y->weight) ||
(x->use_bfd != y->use_bfd) ||
(!x->mls != !y->mls) || (!x->mls != !y->mls) ||
((x->mls) && (y->mls) && (x->mls->len != y->mls->len))) ((x->mls) && (y->mls) && (x->mls->len != y->mls->len)))
return 0; return 0;
@ -614,11 +617,13 @@ static_show_rt(struct static_route *r)
for (r2 = r; r2; r2 = r2->mp_next) for (r2 = r; r2; r2 = r2->mp_next)
{ {
if (r2->iface && ipa_zero(r2->via)) if (r2->iface && ipa_zero(r2->via))
cli_msg(-1009, "\tdev %s%s%s", r2->iface->name, cli_msg(-1009, "\tdev %s%s", r2->iface->name,
r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)"); r2->active ? "" : " (dormant)");
else else
cli_msg(-1009, "\tvia %I%J%s%s", r2->via, r2->iface, cli_msg(-1009, "\tvia %I%J%s%s%s", r2->via, r2->iface,
r2->bfd_req ? " (bfd)" : "", r2->active ? "" : " (dormant)"); r2->onlink ? " onlink" : "",
r2->bfd_req ? " (bfd)" : "",
r2->active ? "" : " (dormant)");
} }
break; break;
} }

View File

@ -43,6 +43,7 @@ struct static_route {
byte dest; /* Destination type (RTD_*) */ byte dest; /* Destination type (RTD_*) */
byte state; /* State of route announcement (SRS_*) */ byte state; /* State of route announcement (SRS_*) */
byte active; /* Next hop is active (nbr/iface/BFD available) */ byte active; /* Next hop is active (nbr/iface/BFD available) */
byte onlink; /* Gateway is onlink regardless of IP ranges */
byte weight; /* Multipath next hop weight */ byte weight; /* Multipath next hop weight */
byte use_bfd; /* Configured to use BFD */ byte use_bfd; /* Configured to use BFD */
struct bfd_request *bfd_req; /* BFD request, if BFD is used */ struct bfd_request *bfd_req; /* BFD request, if BFD is used */

View File

@ -622,6 +622,9 @@ nl_add_multipath(struct nlmsghdr *h, uint bufsize, struct nexthop *nh, int af)
nl_add_nexthop(h, bufsize, nh, af); nl_add_nexthop(h, bufsize, nh, af);
if (nh->flags & RNF_ONLINK)
rtnh->rtnh_flags |= RTNH_F_ONLINK;
nl_close_nexthop(h, rtnh); nl_close_nexthop(h, rtnh);
} }
@ -660,6 +663,7 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
rv->next = NULL; rv->next = NULL;
last = &(rv->next); last = &(rv->next);
rv->flags = 0;
rv->weight = nh->rtnh_hops; rv->weight = nh->rtnh_hops;
rv->iface = if_find_by_index(nh->rtnh_ifindex); rv->iface = if_find_by_index(nh->rtnh_ifindex);
if (!rv->iface) if (!rv->iface)
@ -672,9 +676,12 @@ nl_parse_multipath(struct krt_proto *p, struct rtattr *ra)
{ {
rv->gw = rta_get_ipa(a[RTA_GATEWAY]); rv->gw = rta_get_ipa(a[RTA_GATEWAY]);
if (nh->rtnh_flags & RTNH_F_ONLINK)
rv->flags |= RNF_ONLINK;
neighbor *nbr; neighbor *nbr;
nbr = neigh_find2(&p->p, &rv->gw, rv->iface, nbr = neigh_find2(&p->p, &rv->gw, rv->iface,
(nh->rtnh_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); (rv->flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST)) if (!nbr || (nbr->scope == SCOPE_HOST))
return NULL; return NULL;
} }
@ -1228,6 +1235,9 @@ dest:
{ {
nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index); nl_add_attr_u32(&r->h, rsize, RTA_OIF, nh->iface->index);
nl_add_nexthop(&r->h, rsize, nh, p->af); nl_add_nexthop(&r->h, rsize, nh, p->af);
if (nh->flags & RNF_ONLINK)
r->r.rtm_flags |= RTNH_F_ONLINK;
} }
break; break;
case RTD_BLACKHOLE: case RTD_BLACKHOLE:
@ -1543,9 +1553,12 @@ nl_parse_route(struct nl_parse_state *s, struct nlmsghdr *h)
if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit)) if ((i->rtm_family == AF_INET6) && ipa_in_netX(ra->nh.gw, (net_addr *) &sit))
return; return;
if (i->rtm_flags & RTNH_F_ONLINK)
ra->nh.flags |= RNF_ONLINK;
neighbor *nbr; neighbor *nbr;
nbr = neigh_find2(&p->p, &(ra->nh.gw), ra->nh.iface, nbr = neigh_find2(&p->p, &(ra->nh.gw), ra->nh.iface,
(i->rtm_flags & RTNH_F_ONLINK) ? NEF_ONLINK : 0); (ra->nh.flags & RNF_ONLINK) ? NEF_ONLINK : 0);
if (!nbr || (nbr->scope == SCOPE_HOST)) 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", net->n.addr,