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:
commit
2776cfafec
@ -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>
|
||||||
|
|
||||||
|
@ -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 */
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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:
|
||||||
|
@ -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))
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user