diff options
author | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-12 00:41:36 +0200 |
---|---|---|
committer | Ondrej Zajicek (work) <santiago@crfreenet.org> | 2019-08-12 00:43:19 +0200 |
commit | 70a4320bdd44122d7a93bc71c77a9d684b3c9adc (patch) | |
tree | 01e1d376a979ca0e71ebd016f89439c1f3dbd68c /proto | |
parent | 9f3e09832081bc029dc98ae6dda49ee86d138fde (diff) |
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.
Diffstat (limited to 'proto')
-rw-r--r-- | proto/radv/config.Y | 15 | ||||
-rw-r--r-- | proto/radv/packets.c | 47 | ||||
-rw-r--r-- | proto/radv/radv.c | 19 | ||||
-rw-r--r-- | proto/radv/radv.h | 10 |
4 files changed, 65 insertions, 26 deletions
diff --git a/proto/radv/config.Y b/proto/radv/config.Y index 53715f77..dda9cfcd 100644 --- a/proto/radv/config.Y +++ b/proto/radv/config.Y @@ -1,6 +1,8 @@ /* * 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. */ @@ -26,12 +28,12 @@ static u8 radv_mult_val; /* Used by radv_mult for second return value */ CF_DECLS -CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, - MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, RETRANS, - TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, - LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, - LOCAL, TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, - ROUTE, ROUTES, RA_PREFERENCE, RA_LIFETIME) +CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL, SOLICITED, + UNICAST, MANAGED, OTHER, CONFIG, LINGER, LINK, MTU, REACHABLE, TIME, + RETRANS, TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT, + LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN, LOCAL, + TRIGGER, SENSITIVE, PREFERENCE, LOW, MEDIUM, HIGH, PROPAGATE, ROUTE, + ROUTES, RA_PREFERENCE, RA_LIFETIME) 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"); } | 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"); } + | SOLICITED RA UNICAST bool { RADV_IFACE->solicited_ra_unicast = $4; } | MANAGED bool { RADV_IFACE->managed = $2; } | OTHER CONFIG bool { RADV_IFACE->other_config = $3; } | LINK MTU expr { RADV_IFACE->link_mtu = $3; } diff --git a/proto/radv/packets.c b/proto/radv/packets.c index b12d3a12..3139d321 100644 --- a/proto/radv/packets.c +++ b/proto/radv/packets.c @@ -1,6 +1,8 @@ /* * 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. */ @@ -370,19 +372,49 @@ radv_prepare_ra(struct radv_iface *ifa) void -radv_send_ra(struct radv_iface *ifa) +radv_send_ra(struct radv_iface *ifa, ip_addr to) { 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 */ if (!ifa->plen) radv_prepare_ra(ifa); - RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); - sk_send_to(ifa->sk, ifa->plen, IP6_ALL_NODES, 0); + if (ipa_zero(to)) + { + to = IP6_ALL_NODES; + RADV_TRACE(D_PACKETS, "Sending RA via %s", ifa->iface->name); + } + 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 radv_rx_hook(sock *sk, uint size) { @@ -410,9 +442,7 @@ radv_rx_hook(sock *sk, uint size) switch (buf[0]) { case ICMPV6_RS: - RADV_TRACE(D_PACKETS, "Received RS from %I via %s", - sk->faddr, ifa->iface->name); - radv_iface_notify(ifa, RA_EV_RS); + radv_receive_rs(p, ifa, sk->faddr); return 1; case ICMPV6_RA: @@ -430,7 +460,10 @@ static void radv_tx_hook(sock *sk) { 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 diff --git a/proto/radv/radv.c b/proto/radv/radv.c index 990b6024..622b3c3c 100644 --- a/proto/radv/radv.c +++ b/proto/radv/radv.c @@ -1,6 +1,8 @@ /* * 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. */ @@ -35,18 +37,14 @@ * case of the specified trigger prefix was changed. * * Supported standards: - * - RFC 4861 - main RA standard - * - RFC 4191 - Default Router Preferences and More-Specific Routes - * - RFC 6106 - DNS extensions (RDDNS, DNSSL) + * RFC 4861 - main RA standard + * RFC 4191 - Default Router Preferences and More-Specific Routes + * RFC 6106 - DNS extensions (RDDNS, DNSSL) */ static void radv_prune_prefixes(struct radv_iface *ifa); 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 radv_timer(timer *tm) { @@ -56,16 +54,13 @@ radv_timer(timer *tm) RADV_TRACE(D_EVENTS, "Timer fired on %s", ifa->iface->name); - if (ifa->valid_time <= now) - radv_invalidate(ifa); - if (ifa->prune_time <= now) radv_prune_prefixes(ifa); if (p->prune_time <= now) radv_prune_routes(p); - radv_send_ra(ifa); + radv_send_ra(ifa, IPA_NONE); /* Update timer */ ifa->last = now; @@ -627,7 +622,7 @@ radv_iface_shutdown(struct radv_iface *ifa) if (ifa->sk) { radv_invalidate(ifa); - radv_send_ra(ifa); + radv_send_ra(ifa, IPA_NONE); } } diff --git a/proto/radv/radv.h b/proto/radv/radv.h index 719948d5..2c8ad7d4 100644 --- a/proto/radv/radv.h +++ b/proto/radv/radv.h @@ -1,6 +1,8 @@ /* * 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. */ @@ -66,6 +68,8 @@ struct radv_iface_config u32 max_ra_int; 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 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) +/* Invalidate cached RA packet */ +static inline void radv_invalidate(struct radv_iface *ifa) +{ ifa->plen = 0; } + /* radv.c */ void radv_iface_notify(struct radv_iface *ifa, int event); /* packets.c */ 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); |