RAdv: Allow solicited RAs to be sent as unicast
Add option to send solicited router advertisements as unicast directly to soliciting nodes instead of as multicast to all-nodes group.
This commit is contained in:
parent
9f3e098320
commit
70a4320bdd
6 changed files with 72 additions and 27 deletions
|
@ -4121,6 +4121,12 @@ definitions, prefix definitions and DNS definitions:
|
||||||
The minimum delay between two consecutive router advertisements, in
|
The minimum delay between two consecutive router advertisements, in
|
||||||
seconds. Default: 3
|
seconds. Default: 3
|
||||||
|
|
||||||
|
<tag><label id="radv-solicited-ra-unicast">solicited ra unicast <m/switch/</tag>
|
||||||
|
Solicited router advertisements are usually sent to all-nodes multicast
|
||||||
|
group like unsolicited ones, but the router can be configured to send
|
||||||
|
them as unicast directly to soliciting nodes instead. This is especially
|
||||||
|
useful on wireless networks (see <rfc id="7772">). Default: no
|
||||||
|
|
||||||
<tag><label id="radv-iface-managed">managed <m/switch/</tag>
|
<tag><label id="radv-iface-managed">managed <m/switch/</tag>
|
||||||
This option specifies whether hosts should use DHCPv6 for IP address
|
This option specifies whether hosts should use DHCPv6 for IP address
|
||||||
configuration. Default: no
|
configuration. Default: no
|
||||||
|
|
|
@ -97,7 +97,7 @@ void sk_dump_all(void);
|
||||||
int sk_is_ipv4(sock *s); /* True if socket is IPv4 */
|
int sk_is_ipv4(sock *s); /* True if socket is IPv4 */
|
||||||
int sk_is_ipv6(sock *s); /* True if socket is IPv6 */
|
int sk_is_ipv6(sock *s); /* True if socket is IPv6 */
|
||||||
|
|
||||||
static inline int sk_send_buffer_empty(sock *sk)
|
static inline int sk_tx_buffer_empty(sock *sk)
|
||||||
{ return sk->tbuf == sk->tpos; }
|
{ return sk->tbuf == sk->tpos; }
|
||||||
|
|
||||||
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
|
int sk_setup_multicast(sock *s); /* Prepare UDP or IP socket for multicasting */
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Router Advertisement Configuration
|
* BIRD -- Router Advertisement Configuration
|
||||||
*
|
*
|
||||||
|
* (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* (c) 2011--2019 CZ.NIC z.s.p.o.
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -26,12 +28,12 @@ static u8 radv_mult_val; /* Used by radv_mult for second return value */
|
||||||
|
|
||||||
CF_DECLS
|
CF_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
|
CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED,
|
||||||
MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, RETRANS,
|
UNICAST, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME,
|
||||||
TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
|
RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
|
||||||
LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
|
LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL,
|
||||||
LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE,
|
TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE,
|
||||||
ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME)
|
ROUTES, RA_PREFERENCE, RA_LIFETIME)
|
||||||
|
|
||||||
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
|
CF_ENUM(T_ENUM_RA_PREFERENCE, RA_PREF_, LOW, MEDIUM, HIGH)
|
||||||
|
|
||||||
|
@ -98,6 +100,7 @@ radv_iface_item:
|
||||||
MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
|
MIN RA INTERVAL expr { RADV_IFACE->min_ra_int = $4; if ($4 < 3) cf_error("Min RA interval must be at least 3"); }
|
||||||
| MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); }
|
| MAX RA INTERVAL expr { RADV_IFACE->max_ra_int = $4; if (($4 < 4) || ($4 > 1800)) cf_error("Max RA interval must be in range 4-1800"); }
|
||||||
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
|
| MIN DELAY expr { RADV_IFACE->min_delay = $3; if ($3 <= 0) cf_error("Min delay must be positive"); }
|
||||||
|
| SOLICITED RA UNICAST bool { RADV_IFACE->solicited_ra_unicast = $4; }
|
||||||
| MANAGED bool { RADV_IFACE->managed = $2; }
|
| MANAGED bool { RADV_IFACE->managed = $2; }
|
||||||
| OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
|
| OTHER CONFIG bool { RADV_IFACE->other_config = $3; }
|
||||||
| LINK MTU expr { RADV_IFACE->link_mtu = $3; }
|
| LINK MTU expr { RADV_IFACE->link_mtu = $3; }
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- RAdv Packet Processing
|
* BIRD -- RAdv Packet Processing
|
||||||
*
|
*
|
||||||
|
* (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* (c) 2011--2019 CZ.NIC z.s.p.o.
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -370,18 +372,48 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
radv_send_ra(struct radv_iface *ifa)
|
radv_send_ra(struct radv_iface *ifa, ip_addr to)
|
||||||
{
|
{
|
||||||
struct radv_proto *p = ifa->ra;
|
struct radv_proto *p = ifa->ra;
|
||||||
|
|
||||||
|
/* TX queue is already full */
|
||||||
|
if (!sk_tx_buffer_empty(ifa->sk))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ifa->valid_time <= current_time())
|
||||||
|
radv_invalidate(ifa);
|
||||||
|
|
||||||
/* We store prepared RA in tbuf */
|
/* We store prepared RA in tbuf */
|
||||||
if (!ifa->plen)
|
if (!ifa->plen)
|
||||||
radv_prepare_ra(ifa);
|
radv_prepare_ra(ifa);
|
||||||
|
|
||||||
|
if (ipa_zero(to))
|
||||||
|
{
|
||||||
|
to = IP6_ALL_NODES;
|
||||||
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name);
|
||||||
sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RADV_TRACE(D_PACKETS, "Sending RA to %I via %s", to, ifa->iface->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int done = sk_send_to(ifa->sk, ifa->plen, to, 0);
|
||||||
|
if (!done)
|
||||||
|
log(L_WARN "%s: TX queue full on %s", p->p.name, ifa->iface->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
radv_receive_rs(struct radv_proto *p, struct radv_iface *ifa, ip_addr from)
|
||||||
|
{
|
||||||
|
RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
|
||||||
|
from, ifa->iface->name);
|
||||||
|
|
||||||
|
if (ifa->cf->solicited_ra_unicast && ipa_nonzero(from))
|
||||||
|
radv_send_ra(ifa, from);
|
||||||
|
else
|
||||||
|
radv_iface_notify(ifa, RA_EV_RS);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
radv_rx_hook(sock *sk, uint size)
|
radv_rx_hook(sock *sk, uint size)
|
||||||
|
@ -410,9 +442,7 @@ radv_rx_hook(sock *sk, uint size)
|
||||||
switch (buf[0])
|
switch (buf[0])
|
||||||
{
|
{
|
||||||
case ICMPV6_RS:
|
case ICMPV6_RS:
|
||||||
RADV_TRACE(D_PACKETS, "Received RS from %I via %s",
|
radv_receive_rs(p, ifa, sk->faddr);
|
||||||
sk->faddr, ifa->iface->name);
|
|
||||||
radv_iface_notify(ifa, RA_EV_RS);
|
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
case ICMPV6_RA:
|
case ICMPV6_RA:
|
||||||
|
@ -430,7 +460,10 @@ static void
|
||||||
radv_tx_hook(sock *sk)
|
radv_tx_hook(sock *sk)
|
||||||
{
|
{
|
||||||
struct radv_iface *ifa = sk->data;
|
struct radv_iface *ifa = sk->data;
|
||||||
log(L_WARN "%s: TX hook called", ifa->ra->p.name);
|
log(L_INFO "%s: TX queue ready on %s", ifa->ra->p.name, ifa->iface->name);
|
||||||
|
|
||||||
|
/* Some RAs may be missed due to full TX queue */
|
||||||
|
radv_iface_notify(ifa, RA_EV_RS);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Router Advertisement
|
* BIRD -- Router Advertisement
|
||||||
*
|
*
|
||||||
|
* (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* (c) 2011--2019 CZ.NIC z.s.p.o.
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -35,18 +37,14 @@
|
||||||
* case of the specified trigger prefix was changed.
|
* case of the specified trigger prefix was changed.
|
||||||
*
|
*
|
||||||
* Supported standards:
|
* Supported standards:
|
||||||
* - RFC 4861 - main RA standard
|
* RFC 4861 - main RA standard
|
||||||
* - RFC 4191 - Default Router Preferences and More-Specific Routes
|
* RFC 4191 - Default Router Preferences and More-Specific Routes
|
||||||
* - RFC 6106 - DNS extensions (RDDNS, DNSSL)
|
* RFC 6106 - DNS extensions (RDDNS, DNSSL)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void radv_prune_prefixes(struct radv_iface *ifa);
|
static void radv_prune_prefixes(struct radv_iface *ifa);
|
||||||
static void radv_prune_routes(struct radv_proto *p);
|
static void radv_prune_routes(struct radv_proto *p);
|
||||||
|
|
||||||
/* Invalidate cached RA packet */
|
|
||||||
static inline void radv_invalidate(struct radv_iface *ifa)
|
|
||||||
{ ifa->plen = 0; }
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
radv_timer(timer *tm)
|
radv_timer(timer *tm)
|
||||||
{
|
{
|
||||||
|
@ -56,16 +54,13 @@ radv_timer(timer *tm)
|
||||||
|
|
||||||
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
|
RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name);
|
||||||
|
|
||||||
if (ifa->valid_time <= now)
|
|
||||||
radv_invalidate(ifa);
|
|
||||||
|
|
||||||
if (ifa->prune_time <= now)
|
if (ifa->prune_time <= now)
|
||||||
radv_prune_prefixes(ifa);
|
radv_prune_prefixes(ifa);
|
||||||
|
|
||||||
if (p->prune_time <= now)
|
if (p->prune_time <= now)
|
||||||
radv_prune_routes(p);
|
radv_prune_routes(p);
|
||||||
|
|
||||||
radv_send_ra(ifa);
|
radv_send_ra(ifa, IPA_NONE);
|
||||||
|
|
||||||
/* Update timer */
|
/* Update timer */
|
||||||
ifa->last = now;
|
ifa->last = now;
|
||||||
|
@ -627,7 +622,7 @@ radv_iface_shutdown(struct radv_iface *ifa)
|
||||||
if (ifa->sk)
|
if (ifa->sk)
|
||||||
{
|
{
|
||||||
radv_invalidate(ifa);
|
radv_invalidate(ifa);
|
||||||
radv_send_ra(ifa);
|
radv_send_ra(ifa, IPA_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
/*
|
/*
|
||||||
* BIRD -- Router Advertisement
|
* BIRD -- Router Advertisement
|
||||||
*
|
*
|
||||||
|
* (c) 2011--2019 Ondrej Zajicek <santiago@crfreenet.org>
|
||||||
|
* (c) 2011--2019 CZ.NIC z.s.p.o.
|
||||||
*
|
*
|
||||||
* Can be freely distributed and used under the terms of the GNU GPL.
|
* Can be freely distributed and used under the terms of the GNU GPL.
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +68,8 @@ struct radv_iface_config
|
||||||
u32 max_ra_int;
|
u32 max_ra_int;
|
||||||
u32 min_delay;
|
u32 min_delay;
|
||||||
|
|
||||||
|
u8 solicited_ra_unicast; /* Send solicited RAs as unicast */
|
||||||
|
|
||||||
u32 prefix_linger_time; /* How long we advertise dead prefixes with lifetime 0 */
|
u32 prefix_linger_time; /* How long we advertise dead prefixes with lifetime 0 */
|
||||||
u32 route_linger_time; /* How long we advertise dead routes with lifetime 0 */
|
u32 route_linger_time; /* How long we advertise dead routes with lifetime 0 */
|
||||||
|
|
||||||
|
@ -204,12 +208,16 @@ struct radv_iface
|
||||||
log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
|
log(L_TRACE "%s: " msg, p->p.name , ## args ); } while(0)
|
||||||
|
|
||||||
|
|
||||||
|
/* Invalidate cached RA packet */
|
||||||
|
static inline void radv_invalidate(struct radv_iface *ifa)
|
||||||
|
{ ifa->plen = 0; }
|
||||||
|
|
||||||
/* radv.c */
|
/* radv.c */
|
||||||
void radv_iface_notify(struct radv_iface *ifa, int event);
|
void radv_iface_notify(struct radv_iface *ifa, int event);
|
||||||
|
|
||||||
/* packets.c */
|
/* packets.c */
|
||||||
int radv_process_domain(struct radv_dnssl_config *cf);
|
int radv_process_domain(struct radv_dnssl_config *cf);
|
||||||
void radv_send_ra(struct radv_iface *ifa);
|
void radv_send_ra(struct radv_iface *ifa, ip_addr to);
|
||||||
int radv_sk_open(struct radv_iface *ifa);
|
int radv_sk_open(struct radv_iface *ifa);
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue