Implements router advertisements activated by received routes.
The RAdv protocol could be configured to change its behavior based on availability of routes, e.g., do not announce router lifetime when a default route is not available.
This commit is contained in:
parent
d214ae4fdc
commit
36da2857bc
8 changed files with 225 additions and 35 deletions
|
@ -691,8 +691,8 @@ This argument can be omitted if there exists only a single instance.
|
||||||
<p>You can also select just routes added by a specific protocol.
|
<p>You can also select just routes added by a specific protocol.
|
||||||
<cf>protocol <m/p/</cf>.
|
<cf>protocol <m/p/</cf>.
|
||||||
|
|
||||||
<p>If BIRD is configured to keep filtered routes (see </cf/import keep filtered/
|
<p>If BIRD is configured to keep filtered routes (see <cf/import keep filtered/
|
||||||
option), you can show them instead of routes by using </cf/filtered/ switch.
|
option), you can show them instead of routes by using <cf/filtered/ switch.
|
||||||
|
|
||||||
<p>The <cf/stats/ switch requests showing of route statistics (the
|
<p>The <cf/stats/ switch requests showing of route statistics (the
|
||||||
number of networks, number of routes before and after filtering). If
|
number of networks, number of routes before and after filtering). If
|
||||||
|
@ -2479,6 +2479,26 @@ interface definitions, prefix definitions and DNS definitions:
|
||||||
also as interface-specific options and there is a short
|
also as interface-specific options and there is a short
|
||||||
variant <cf>dnssl <m/domain/</cf> that just specifies one DNS
|
variant <cf>dnssl <m/domain/</cf> that just specifies one DNS
|
||||||
search domain.
|
search domain.
|
||||||
|
|
||||||
|
<label id="dsc-trigger"> <tag>trigger <m/prefix/</tag>
|
||||||
|
RAdv protocol could be configured to change its behavior based
|
||||||
|
on availability of routes. When this option is used, the
|
||||||
|
protocol waits in suppressed state until a <it/trigger route/
|
||||||
|
(for the specified network) is exported to the protocol, the
|
||||||
|
protocol also returnsd to suppressed state if the
|
||||||
|
<it/trigger route/ disappears. Note that route export depends
|
||||||
|
on specified export filter, as usual. This option could be
|
||||||
|
used, e.g., for handling failover in multihoming scenarios.
|
||||||
|
|
||||||
|
During suppressed state, router advertisements are generated,
|
||||||
|
but with some fields zeroed. Exact behavior depends on which
|
||||||
|
fields are zeroed, this can be configured by
|
||||||
|
<cf/sensitive/ option for appropriate fields. By default, just
|
||||||
|
<cf/default lifetime/ (also called <cf/router lifetime/) is
|
||||||
|
zeroed, which means hosts cannot use the router as a default
|
||||||
|
router. <cf/preferred lifetime/ and <cf/valid lifetime/ could
|
||||||
|
also be configured as <cf/sensitive/ for a prefix, which would
|
||||||
|
cause autoconfigured IPs to be deprecated or even removed.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
<p>Interface specific options:
|
<p>Interface specific options:
|
||||||
|
@ -2525,11 +2545,12 @@ interface definitions, prefix definitions and DNS definitions:
|
||||||
This option specifies which value of Hop Limit should be used
|
This option specifies which value of Hop Limit should be used
|
||||||
by hosts. Valid values are 0-255, 0 means unspecified. Default: 64
|
by hosts. Valid values are 0-255, 0 means unspecified. Default: 64
|
||||||
|
|
||||||
<tag>default lifetime <m/expr/</tag>
|
<tag>default lifetime <m/expr/ [sensitive <m/switch/]</tag>
|
||||||
This option specifies the time (in seconds) how long (after
|
This option specifies the time (in seconds) how long (after
|
||||||
the receipt of RA) hosts may use the router as a default
|
the receipt of RA) hosts may use the router as a default
|
||||||
router. 0 means do not use as a default router. Default: 3 *
|
router. 0 means do not use as a default router. For
|
||||||
<cf/max ra interval/.
|
<cf/sensitive/ option, see <ref id="dsc-trigger" name="trigger">.
|
||||||
|
Default: 3 * <cf/max ra interval/, <cf/sensitive/ yes.
|
||||||
|
|
||||||
<tag>rdnss local <m/switch/</tag>
|
<tag>rdnss local <m/switch/</tag>
|
||||||
Use only local (interface-specific) RDNSS definitions for this
|
Use only local (interface-specific) RDNSS definitions for this
|
||||||
|
@ -2561,18 +2582,20 @@ interface definitions, prefix definitions and DNS definitions:
|
||||||
This option specifies whether hosts may use the advertised
|
This option specifies whether hosts may use the advertised
|
||||||
prefix for stateless autoconfiguration. Default: yes
|
prefix for stateless autoconfiguration. Default: yes
|
||||||
|
|
||||||
<tag>valid lifetime <m/expr/</tag>
|
<tag>valid lifetime <m/expr/ [sensitive <m/switch/]</tag>
|
||||||
This option specifies the time (in seconds) how long (after
|
This option specifies the time (in seconds) how long (after
|
||||||
the receipt of RA) the prefix information is valid, i.e.,
|
the receipt of RA) the prefix information is valid, i.e.,
|
||||||
autoconfigured IP addresses can be assigned and hosts with
|
autoconfigured IP addresses can be assigned and hosts with
|
||||||
that IP addresses are considered directly reachable. 0 means
|
that IP addresses are considered directly reachable. 0 means
|
||||||
the prefix is no longer valid. Default: 86400 (1 day)
|
the prefix is no longer valid. For <cf/sensitive/ option, see
|
||||||
|
<ref id="dsc-trigger" name="trigger">. Default: 86400 (1 day), <cf/sensitive/ no.
|
||||||
|
|
||||||
<tag>preferred lifetime <m/expr/</tag>
|
<tag>preferred lifetime <m/expr/ [sensitive <m/switch/]</tag>
|
||||||
This option specifies the time (in seconds) how long (after
|
This option specifies the time (in seconds) how long (after
|
||||||
the receipt of RA) IP addresses generated from the prefix
|
the receipt of RA) IP addresses generated from the prefix
|
||||||
using stateless autoconfiguration remain preferred. Default:
|
using stateless autoconfiguration remain preferred. For
|
||||||
14400 (4 hours)
|
<cf/sensitive/ option, see <ref id="dsc-trigger" name="trigger">.
|
||||||
|
Default: 14400 (4 hours), <cf/sensitive/ no.
|
||||||
</descrip>
|
</descrip>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1429,6 +1429,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
|
||||||
int
|
int
|
||||||
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
|
f_run(struct filter *filter, struct rte **rte, struct ea_list **tmp_attrs, struct linpool *tmp_pool, int flags)
|
||||||
{
|
{
|
||||||
|
if (filter == FILTER_ACCEPT)
|
||||||
|
return F_ACCEPT;
|
||||||
|
|
||||||
|
if (filter == FILTER_REJECT)
|
||||||
|
return F_REJECT;
|
||||||
|
|
||||||
int rte_cow = ((*rte)->flags & REF_COW);
|
int rte_cow = ((*rte)->flags & REF_COW);
|
||||||
DBG( "Running filter `%s'...", filter->name );
|
DBG( "Running filter `%s'...", filter->name );
|
||||||
|
|
||||||
|
|
|
@ -235,6 +235,12 @@ static inline int rte_is_filtered(rte *r) { return !!(r->flags & REF_FILTERED);
|
||||||
#define RA_ACCEPTED 2 /* Announcement of first accepted route */
|
#define RA_ACCEPTED 2 /* Announcement of first accepted route */
|
||||||
#define RA_ANY 3 /* Announcement of any route change */
|
#define RA_ANY 3 /* Announcement of any route change */
|
||||||
|
|
||||||
|
/* Return value of import_control() callback */
|
||||||
|
#define RIC_ACCEPT 1 /* Accepted by protocol */
|
||||||
|
#define RIC_PROCESS 0 /* Process it through import filter */
|
||||||
|
#define RIC_REJECT -1 /* Rejected by protocol */
|
||||||
|
#define RIC_DROP -2 /* Silently dropped by protocol */
|
||||||
|
|
||||||
struct config;
|
struct config;
|
||||||
|
|
||||||
void rt_init(void);
|
void rt_init(void);
|
||||||
|
@ -250,6 +256,7 @@ rte *rte_get_temp(struct rta *);
|
||||||
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src);
|
void rte_update2(struct announce_hook *ah, net *net, rte *new, struct proto *src);
|
||||||
static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); }
|
static inline void rte_update(rtable *tab, net *net, struct proto *p, struct proto *src, rte *new) { rte_update2(p->main_ahook, net, new, src); }
|
||||||
void rte_discard(rtable *tab, rte *old);
|
void rte_discard(rtable *tab, rte *old);
|
||||||
|
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
|
||||||
void rte_dump(rte *);
|
void rte_dump(rte *);
|
||||||
void rte_free(rte *);
|
void rte_free(rte *);
|
||||||
rte *rte_do_cow(rte *);
|
rte *rte_do_cow(rte *);
|
||||||
|
|
|
@ -213,6 +213,7 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
|
||||||
goto reject;
|
goto reject;
|
||||||
|
|
||||||
stats->exp_updates_rejected++;
|
stats->exp_updates_rejected++;
|
||||||
|
if (v == RIC_REJECT)
|
||||||
rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
|
rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
|
||||||
goto reject;
|
goto reject;
|
||||||
}
|
}
|
||||||
|
@ -1042,6 +1043,34 @@ rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during gar
|
||||||
rte_update_unlock();
|
rte_update_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check rtable for best route to given net whether it would be exported do p */
|
||||||
|
int
|
||||||
|
rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter)
|
||||||
|
{
|
||||||
|
net *n = net_find(t, prefix, pxlen);
|
||||||
|
rte *rt = n ? n->routes : NULL;
|
||||||
|
|
||||||
|
if (!rte_is_valid(rt))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
rte_update_lock();
|
||||||
|
|
||||||
|
/* Rest is stripped down export_filter() */
|
||||||
|
struct proto *src = rt->attrs->proto;
|
||||||
|
ea_list *tmpa = src->make_tmp_attrs ? src->make_tmp_attrs(rt, rte_update_pool) : NULL;
|
||||||
|
int v = p->import_control ? p->import_control(p, &rt, &tmpa, rte_update_pool) : 0;
|
||||||
|
if (v == RIC_PROCESS)
|
||||||
|
v = (f_run(filter, &rt, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
|
||||||
|
|
||||||
|
/* Discard temporary rte */
|
||||||
|
if (rt != n->routes)
|
||||||
|
rte_free(rt);
|
||||||
|
|
||||||
|
rte_update_unlock();
|
||||||
|
|
||||||
|
return v > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rte_dump - dump a route
|
* rte_dump - dump a route
|
||||||
* @e: &rte to be dumped
|
* @e: &rte to be dumped
|
||||||
|
@ -2081,7 +2110,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||||
ee = e;
|
ee = e;
|
||||||
rte_update_lock(); /* We use the update buffer for filtering */
|
rte_update_lock(); /* We use the update buffer for filtering */
|
||||||
tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
|
tmpa = p0->make_tmp_attrs ? p0->make_tmp_attrs(e, rte_update_pool) : NULL;
|
||||||
ok = (d->filter == FILTER_ACCEPT || f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT);
|
ok = f_run(d->filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) <= F_ACCEPT;
|
||||||
if (p2 && p2 != p0) ok = 0;
|
if (p2 && p2 != p0) ok = 0;
|
||||||
if (ok && d->export_mode)
|
if (ok && d->export_mode)
|
||||||
{
|
{
|
||||||
|
@ -2095,8 +2124,8 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
|
||||||
'configure soft' command may change the export filter
|
'configure soft' command may change the export filter
|
||||||
and do not update routes */
|
and do not update routes */
|
||||||
|
|
||||||
if ((a = proto_find_announce_hook(p1, d->table)) && ((a->out_filter == FILTER_REJECT) ||
|
if ((a = proto_find_announce_hook(p1, d->table)) &&
|
||||||
(a->out_filter && f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)))
|
(f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
|
||||||
ok = 0;
|
ok = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,9 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
|
||||||
MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS,
|
MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS,
|
||||||
TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
|
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)
|
||||||
|
|
||||||
%type<i> radv_mult
|
%type<i> radv_mult radv_sensitive
|
||||||
|
|
||||||
CF_GRAMMAR
|
CF_GRAMMAR
|
||||||
|
|
||||||
|
@ -53,6 +53,11 @@ radv_proto_item:
|
||||||
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
|
| PREFIX radv_prefix { add_tail(&RADV_CFG->pref_list, NODE this_radv_prefix); }
|
||||||
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
|
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_CFG->rdnss_list, &radv_dns_list); }
|
||||||
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
|
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_CFG->dnssl_list, &radv_dns_list); }
|
||||||
|
| TRIGGER prefix {
|
||||||
|
RADV_CFG->trigger_prefix = $2.addr;
|
||||||
|
RADV_CFG->trigger_pxlen = $2.len;
|
||||||
|
RADV_CFG->trigger_valid = 1;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
radv_proto_opts:
|
radv_proto_opts:
|
||||||
|
@ -78,6 +83,7 @@ radv_iface_start:
|
||||||
RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
|
RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
|
||||||
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
|
RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
|
||||||
RADV_IFACE->default_lifetime = -1;
|
RADV_IFACE->default_lifetime = -1;
|
||||||
|
RADV_IFACE->default_lifetime_sensitive = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
radv_iface_item:
|
radv_iface_item:
|
||||||
|
@ -90,7 +96,11 @@ radv_iface_item:
|
||||||
| REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if (($3 < 0) || ($3 > 3600000)) cf_error("Reachable time must be in range 0-3600000"); }
|
| REACHABLE TIME expr { RADV_IFACE->reachable_time = $3; if (($3 < 0) || ($3 > 3600000)) cf_error("Reachable time must be in range 0-3600000"); }
|
||||||
| RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; if ($3 < 0) cf_error("Retrans timer must be 0 or positive"); }
|
| RETRANS TIMER expr { RADV_IFACE->retrans_timer = $3; if ($3 < 0) cf_error("Retrans timer must be 0 or positive"); }
|
||||||
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); }
|
| CURRENT HOP LIMIT expr { RADV_IFACE->current_hop_limit = $4; if (($4 < 0) || ($4 > 255)) cf_error("Current hop limit must be in range 0-255"); }
|
||||||
| DEFAULT LIFETIME expr { RADV_IFACE->default_lifetime = $3; if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000"); }
|
| DEFAULT LIFETIME expr radv_sensitive {
|
||||||
|
RADV_IFACE->default_lifetime = $3;
|
||||||
|
if (($3 < 0) || ($3 > 9000)) cf_error("Default lifetime must be in range 0-9000");
|
||||||
|
if ($4 != -1) RADV_IFACE->default_lifetime_sensitive = $4;
|
||||||
|
}
|
||||||
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
|
| PREFIX radv_prefix { add_tail(&RADV_IFACE->pref_list, NODE this_radv_prefix); }
|
||||||
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
|
| RDNSS { init_list(&radv_dns_list); } radv_rdnss { add_tail_list(&RADV_IFACE->rdnss_list, &radv_dns_list); }
|
||||||
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
|
| DNSSL { init_list(&radv_dns_list); } radv_dnssl { add_tail_list(&RADV_IFACE->dnssl_list, &radv_dns_list); }
|
||||||
|
@ -147,14 +157,25 @@ radv_prefix_item:
|
||||||
SKIP bool { RADV_PREFIX->skip = $2; }
|
SKIP bool { RADV_PREFIX->skip = $2; }
|
||||||
| ONLINK bool { RADV_PREFIX->onlink = $2; }
|
| ONLINK bool { RADV_PREFIX->onlink = $2; }
|
||||||
| AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; }
|
| AUTONOMOUS bool { RADV_PREFIX->autonomous = $2; }
|
||||||
| VALID LIFETIME expr { RADV_PREFIX->valid_lifetime = $3; if ($3 < 0) cf_error("Valid lifetime must be 0 or positive"); }
|
| VALID LIFETIME expr radv_sensitive {
|
||||||
| PREFERRED LIFETIME expr { RADV_PREFIX->preferred_lifetime = $3; if ($3 < 0) cf_error("Preferred lifetime must be 0 or positive"); }
|
RADV_PREFIX->valid_lifetime = $3;
|
||||||
|
if ($3 < 0) cf_error("Valid lifetime must be 0 or positive");
|
||||||
|
if ($4 != -1) RADV_PREFIX->valid_lifetime_sensitive = $4;
|
||||||
|
}
|
||||||
|
| PREFERRED LIFETIME expr radv_sensitive {
|
||||||
|
RADV_PREFIX->preferred_lifetime = $3;
|
||||||
|
if ($3 < 0) cf_error("Preferred lifetime must be 0 or positive");
|
||||||
|
if ($4 != -1) RADV_PREFIX->preferred_lifetime_sensitive = $4;
|
||||||
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
radv_prefix_finish:
|
radv_prefix_finish:
|
||||||
{
|
{
|
||||||
if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime)
|
if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->valid_lifetime)
|
||||||
cf_error("Preferred lifetime must be at most Valid lifetime");
|
cf_error("Preferred lifetime must be at most Valid lifetime");
|
||||||
|
|
||||||
|
if (RADV_PREFIX->valid_lifetime_sensitive > RADV_PREFIX->preferred_lifetime_sensitive)
|
||||||
|
cf_error("Valid lifetime sensitive requires that Preferred lifetime is sensitive too");
|
||||||
};
|
};
|
||||||
|
|
||||||
radv_prefix_opts:
|
radv_prefix_opts:
|
||||||
|
@ -268,6 +289,11 @@ radv_mult:
|
||||||
| MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); }
|
| MULT expr { $$ = 0; radv_mult_val = $2; if (($2 < 1) || ($2 > 254)) cf_error("Multiplier must be in range 1-254"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
radv_sensitive:
|
||||||
|
/* empty */ { $$ = -1 }
|
||||||
|
| SENSITIVE bool { $$ = $2 }
|
||||||
|
;
|
||||||
|
|
||||||
CF_CODE
|
CF_CODE
|
||||||
|
|
||||||
CF_END
|
CF_END
|
||||||
|
|
|
@ -240,6 +240,7 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||||
{
|
{
|
||||||
struct proto_radv *ra = ifa->ra;
|
struct proto_radv *ra = ifa->ra;
|
||||||
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
|
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
|
||||||
|
struct radv_iface_config *ic = ifa->cf;
|
||||||
|
|
||||||
char *buf = ifa->sk->tbuf;
|
char *buf = ifa->sk->tbuf;
|
||||||
char *bufstart = buf;
|
char *bufstart = buf;
|
||||||
|
@ -249,21 +250,22 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||||
pkt->type = ICMPV6_RA;
|
pkt->type = ICMPV6_RA;
|
||||||
pkt->code = 0;
|
pkt->code = 0;
|
||||||
pkt->checksum = 0;
|
pkt->checksum = 0;
|
||||||
pkt->current_hop_limit = ifa->cf->current_hop_limit;
|
pkt->current_hop_limit = ic->current_hop_limit;
|
||||||
pkt->flags = (ifa->cf->managed ? OPT_RA_MANAGED : 0) |
|
pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
|
||||||
(ifa->cf->other_config ? OPT_RA_OTHER_CFG : 0);
|
(ic->other_config ? OPT_RA_OTHER_CFG : 0);
|
||||||
pkt->router_lifetime = htons(ifa->cf->default_lifetime);
|
pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ?
|
||||||
pkt->reachable_time = htonl(ifa->cf->reachable_time);
|
htons(ic->default_lifetime) : 0;
|
||||||
pkt->retrans_timer = htonl(ifa->cf->retrans_timer);
|
pkt->reachable_time = htonl(ic->reachable_time);
|
||||||
|
pkt->retrans_timer = htonl(ic->retrans_timer);
|
||||||
buf += sizeof(*pkt);
|
buf += sizeof(*pkt);
|
||||||
|
|
||||||
if (ifa->cf->link_mtu)
|
if (ic->link_mtu)
|
||||||
{
|
{
|
||||||
struct radv_opt_mtu *om = (void *) buf;
|
struct radv_opt_mtu *om = (void *) buf;
|
||||||
om->type = OPT_MTU;
|
om->type = OPT_MTU;
|
||||||
om->length = 1;
|
om->length = 1;
|
||||||
om->reserved = 0;
|
om->reserved = 0;
|
||||||
om->mtu = htonl(ifa->cf->link_mtu);
|
om->mtu = htonl(ic->link_mtu);
|
||||||
buf += sizeof (*om);
|
buf += sizeof (*om);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,26 +290,28 @@ radv_prepare_ra(struct radv_iface *ifa)
|
||||||
op->pxlen = addr->pxlen;
|
op->pxlen = addr->pxlen;
|
||||||
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
|
op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
|
||||||
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
|
(pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
|
||||||
op->valid_lifetime = htonl(pc->valid_lifetime);
|
op->valid_lifetime = (ra->active || !pc->valid_lifetime_sensitive) ?
|
||||||
op->preferred_lifetime = htonl(pc->preferred_lifetime);
|
htonl(pc->valid_lifetime) : 0;
|
||||||
|
op->preferred_lifetime = (ra->active || !pc->preferred_lifetime_sensitive) ?
|
||||||
|
htonl(pc->preferred_lifetime) : 0;
|
||||||
op->reserved = 0;
|
op->reserved = 0;
|
||||||
op->prefix = addr->prefix;
|
op->prefix = addr->prefix;
|
||||||
ipa_hton(op->prefix);
|
ipa_hton(op->prefix);
|
||||||
buf += sizeof(*op);
|
buf += sizeof(*op);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! ifa->cf->rdnss_local)
|
if (! ic->rdnss_local)
|
||||||
if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0)
|
if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (radv_prepare_rdnss(ifa, &ifa->cf->rdnss_list, &buf, bufend) < 0)
|
if (radv_prepare_rdnss(ifa, &ic->rdnss_list, &buf, bufend) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (! ifa->cf->dnssl_local)
|
if (! ic->dnssl_local)
|
||||||
if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0)
|
if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (radv_prepare_dnssl(ifa, &ifa->cf->dnssl_list, &buf, bufend) < 0)
|
if (radv_prepare_dnssl(ifa, &ic->dnssl_list, &buf, bufend) < 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
* by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
|
* by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
|
||||||
* computes the next timeout.
|
* computes the next timeout.
|
||||||
*
|
*
|
||||||
|
* The RAdv protocol could receive routes (through
|
||||||
|
* radv_import_control() and radv_rt_notify()), but only the
|
||||||
|
* configured trigger route is tracked (in &active var). When a radv
|
||||||
|
* protocol is reconfigured, the connected routing table is examined
|
||||||
|
* (in radv_check_active()) to have proper &active value in case of
|
||||||
|
* the specified trigger prefix was changed.
|
||||||
|
*
|
||||||
* Supported standards:
|
* Supported standards:
|
||||||
* - RFC 4861 - main RA standard
|
* - RFC 4861 - main RA standard
|
||||||
* - RFC 6106 - DNS extensions (RDDNS, DNSSL)
|
* - RFC 6106 - DNS extensions (RDDNS, DNSSL)
|
||||||
|
@ -93,6 +100,16 @@ radv_iface_notify(struct radv_iface *ifa, int event)
|
||||||
tm_start(ifa->timer, after);
|
tm_start(ifa->timer, after);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
radv_iface_notify_all(struct proto_radv *ra, int event)
|
||||||
|
{
|
||||||
|
struct radv_iface *ifa;
|
||||||
|
|
||||||
|
WALK_LIST(ifa, ra->iface_list)
|
||||||
|
radv_iface_notify(ifa, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct radv_iface *
|
static struct radv_iface *
|
||||||
radv_iface_find(struct proto_radv *ra, struct iface *what)
|
radv_iface_find(struct proto_radv *ra, struct iface *what)
|
||||||
{
|
{
|
||||||
|
@ -238,11 +255,68 @@ radv_ifa_notify(struct proto *p, unsigned flags, struct ifa *a)
|
||||||
radv_iface_notify(ifa, RA_EV_CHANGE);
|
radv_iface_notify(ifa, RA_EV_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int radv_net_match_trigger(struct radv_config *cf, net *n)
|
||||||
|
{
|
||||||
|
return cf->trigger_valid &&
|
||||||
|
(n->n.pxlen == cf->trigger_pxlen) &&
|
||||||
|
ipa_equal(n->n.prefix, cf->trigger_prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
radv_import_control(struct proto *p, rte **new, ea_list **attrs UNUSED, struct linpool *pool UNUSED)
|
||||||
|
{
|
||||||
|
// struct proto_radv *ra = (struct proto_radv *) p;
|
||||||
|
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||||
|
|
||||||
|
if (radv_net_match_trigger(cf, (*new)->net))
|
||||||
|
return RIC_PROCESS;
|
||||||
|
|
||||||
|
return RIC_DROP;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
radv_rt_notify(struct proto *p, rtable *tbl UNUSED, net *n, rte *new, rte *old UNUSED, ea_list *attrs UNUSED)
|
||||||
|
{
|
||||||
|
struct proto_radv *ra = (struct proto_radv *) p;
|
||||||
|
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||||
|
|
||||||
|
if (radv_net_match_trigger(cf, n))
|
||||||
|
{
|
||||||
|
u8 old_active = ra->active;
|
||||||
|
ra->active = !!new;
|
||||||
|
|
||||||
|
if (ra->active == old_active)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ra->active)
|
||||||
|
RADV_TRACE(D_EVENTS, "Triggered");
|
||||||
|
else
|
||||||
|
RADV_TRACE(D_EVENTS, "Suppressed");
|
||||||
|
|
||||||
|
radv_iface_notify_all(ra, RA_EV_CHANGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
radv_check_active(struct proto_radv *ra)
|
||||||
|
{
|
||||||
|
struct radv_config *cf = (struct radv_config *) (ra->p.cf);
|
||||||
|
|
||||||
|
if (! cf->trigger_valid)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return rt_examine(ra->p.table, cf->trigger_prefix, cf->trigger_pxlen,
|
||||||
|
&(ra->p), ra->p.cf->out_filter);
|
||||||
|
}
|
||||||
|
|
||||||
static struct proto *
|
static struct proto *
|
||||||
radv_init(struct proto_config *c)
|
radv_init(struct proto_config *c)
|
||||||
{
|
{
|
||||||
struct proto *p = proto_new(c, sizeof(struct proto_radv));
|
struct proto *p = proto_new(c, sizeof(struct proto_radv));
|
||||||
|
|
||||||
|
p->accept_ra_types = RA_OPTIMAL;
|
||||||
|
p->import_control = radv_import_control;
|
||||||
|
p->rt_notify = radv_rt_notify;
|
||||||
p->if_notify = radv_if_notify;
|
p->if_notify = radv_if_notify;
|
||||||
p->ifa_notify = radv_ifa_notify;
|
p->ifa_notify = radv_ifa_notify;
|
||||||
return p;
|
return p;
|
||||||
|
@ -252,9 +326,10 @@ static int
|
||||||
radv_start(struct proto *p)
|
radv_start(struct proto *p)
|
||||||
{
|
{
|
||||||
struct proto_radv *ra = (struct proto_radv *) p;
|
struct proto_radv *ra = (struct proto_radv *) p;
|
||||||
// struct radv_config *cf = (struct radv_config *) (p->cf);
|
struct radv_config *cf = (struct radv_config *) (p->cf);
|
||||||
|
|
||||||
init_list(&(ra->iface_list));
|
init_list(&(ra->iface_list));
|
||||||
|
ra->active = !cf->trigger_valid;
|
||||||
|
|
||||||
return PS_UP;
|
return PS_UP;
|
||||||
}
|
}
|
||||||
|
@ -293,6 +368,9 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
|
||||||
* causing nodes to temporary remove their default routes.
|
* causing nodes to temporary remove their default routes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
p->cf = c; /* radv_check_active() requires proper p->cf */
|
||||||
|
ra->active = radv_check_active(ra);
|
||||||
|
|
||||||
struct iface *iface;
|
struct iface *iface;
|
||||||
WALK_LIST(iface, iface_list)
|
WALK_LIST(iface, iface_list)
|
||||||
{
|
{
|
||||||
|
@ -335,6 +413,14 @@ radv_copy_config(struct proto_config *dest, struct proto_config *src)
|
||||||
cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
|
cfg_copy_list(&d->pref_list, &s->pref_list, sizeof(struct radv_prefix_config));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
radv_get_status(struct proto *p, byte *buf)
|
||||||
|
{
|
||||||
|
struct proto_radv *ra = (struct proto_radv *) p;
|
||||||
|
|
||||||
|
if (!ra->active)
|
||||||
|
strcpy(buf, "Suppressed");
|
||||||
|
}
|
||||||
|
|
||||||
struct protocol proto_radv = {
|
struct protocol proto_radv = {
|
||||||
.name = "RAdv",
|
.name = "RAdv",
|
||||||
|
@ -343,5 +429,6 @@ struct protocol proto_radv = {
|
||||||
.start = radv_start,
|
.start = radv_start,
|
||||||
.shutdown = radv_shutdown,
|
.shutdown = radv_shutdown,
|
||||||
.reconfigure = radv_reconfigure,
|
.reconfigure = radv_reconfigure,
|
||||||
.copy_config = radv_copy_config
|
.copy_config = radv_copy_config,
|
||||||
|
.get_status = radv_get_status
|
||||||
};
|
};
|
||||||
|
|
|
@ -52,6 +52,10 @@ struct radv_config
|
||||||
list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
|
list pref_list; /* Global list of prefix configs (struct radv_prefix_config) */
|
||||||
list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
|
list rdnss_list; /* Global list of RDNSS configs (struct radv_rdnss_config) */
|
||||||
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
|
list dnssl_list; /* Global list of DNSSL configs (struct radv_dnssl_config) */
|
||||||
|
|
||||||
|
ip_addr trigger_prefix; /* Prefix of a trigger route, if defined */
|
||||||
|
u8 trigger_pxlen; /* Pxlen of a trigger route, if defined */
|
||||||
|
u8 trigger_valid; /* Whether a trigger route is defined */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radv_iface_config
|
struct radv_iface_config
|
||||||
|
@ -75,6 +79,7 @@ struct radv_iface_config
|
||||||
u32 retrans_timer;
|
u32 retrans_timer;
|
||||||
u32 current_hop_limit;
|
u32 current_hop_limit;
|
||||||
u32 default_lifetime;
|
u32 default_lifetime;
|
||||||
|
u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radv_prefix_config
|
struct radv_prefix_config
|
||||||
|
@ -88,6 +93,8 @@ struct radv_prefix_config
|
||||||
u8 autonomous;
|
u8 autonomous;
|
||||||
u32 valid_lifetime;
|
u32 valid_lifetime;
|
||||||
u32 preferred_lifetime;
|
u32 preferred_lifetime;
|
||||||
|
u8 valid_lifetime_sensitive; /* Whether valid_lifetime depends on trigger */
|
||||||
|
u8 preferred_lifetime_sensitive; /* Whether preferred_lifetime depends on trigger */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radv_rdnss_config
|
struct radv_rdnss_config
|
||||||
|
@ -113,6 +120,7 @@ struct proto_radv
|
||||||
{
|
{
|
||||||
struct proto p;
|
struct proto p;
|
||||||
list iface_list; /* List of active ifaces */
|
list iface_list; /* List of active ifaces */
|
||||||
|
u8 active; /* Whether radv is active w.r.t. triggers */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct radv_iface
|
struct radv_iface
|
||||||
|
|
Loading…
Reference in a new issue