Commit 36da2857 authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

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.
parent d214ae4f
Loading
Loading
Loading
Loading
+33 −10
Original line number Diff line number Diff line
@@ -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.
	<cf>protocol <m/p/</cf>.

	<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.
	<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.

	<p>The <cf/stats/ switch requests showing of route statistics (the
	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
	variant <cf>dnssl <m/domain/</cf> that just specifies one DNS
        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>

<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
	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
	the receipt of RA) hosts may use the router as a default
	router. 0 means do not use as a default router. Default: 3 *
	<cf/max ra interval/.
	router. 0 means do not use as a default router. For
	<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>
	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
	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
	the receipt of RA) the prefix information is valid, i.e.,
	autoconfigured IP addresses can be assigned and hosts with
	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
	the receipt of RA) IP addresses generated from the prefix
	using stateless autoconfiguration remain preferred. Default:
	14400 (4 hours)
	using stateless autoconfiguration remain preferred. For
	<cf/sensitive/ option, see <ref id="dsc-trigger" name="trigger">.
	Default: 14400 (4 hours), <cf/sensitive/ no.
</descrip>


+6 −0
Original line number Diff line number Diff line
@@ -1429,6 +1429,12 @@ i_same(struct f_inst *f1, struct f_inst *f2)
int
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);
  DBG( "Running filter `%s'...", filter->name );

+7 −0
Original line number Diff line number Diff line
@@ -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_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;

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);
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);
int rt_examine(rtable *t, ip_addr prefix, int pxlen, struct proto *p, struct filter *filter);
void rte_dump(rte *);
void rte_free(rte *);
rte *rte_do_cow(rte *);
+33 −4
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
	goto reject;

      stats->exp_updates_rejected++;
      if (v == RIC_REJECT)
	rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
      goto reject;
    }
@@ -1042,6 +1043,34 @@ rte_discard(rtable *t, rte *old) /* Non-filtered route deletion, used during gar
  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
 * @e: &rte to be dumped
@@ -2081,7 +2110,7 @@ rt_show_net(struct cli *c, net *n, struct rt_show_data *d)
      ee = e;
      rte_update_lock();		/* We use the update buffer for filtering */
      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 (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
		 and do not update routes */

	      if ((a = proto_find_announce_hook(p1, d->table)) && ((a->out_filter == FILTER_REJECT) ||
		  (a->out_filter && f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT)))
	      if ((a = proto_find_announce_hook(p1, d->table)) && 
		  (f_run(a->out_filter, &e, &tmpa, rte_update_pool, FF_FORCE_TMPATTR) > F_ACCEPT))
		ok = 0;
	    }
	}
+31 −5
Original line number Diff line number Diff line
@@ -30,9 +30,9 @@ CF_KEYWORDS(RADV, PREFIX, INTERFACE, MIN, MAX, RA, DELAY, INTERVAL,
	MANAGED, OTHER, CONFIG, LINK, MTU, REACHABLE, TIME, RETRANS,
	TIMER, CURRENT, HOP, LIMIT, DEFAULT, VALID, PREFERRED, MULT,
	LIFETIME, SKIP, ONLINK, AUTONOMOUS, RDNSS, DNSSL, NS, DOMAIN,
	LOCAL)
	LOCAL, TRIGGER, SENSITIVE)

%type<i> radv_mult
%type<i> radv_mult radv_sensitive

CF_GRAMMAR

@@ -53,6 +53,11 @@ radv_proto_item:
 | 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); }
 | 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:
@@ -78,6 +83,7 @@ radv_iface_start:
  RADV_IFACE->min_delay = DEFAULT_MIN_DELAY;
  RADV_IFACE->current_hop_limit = DEFAULT_CURRENT_HOP_LIMIT;
  RADV_IFACE->default_lifetime = -1;
  RADV_IFACE->default_lifetime_sensitive = 1;
};

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"); }
 | 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"); }
 | 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); }
 | 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); }
@@ -147,14 +157,25 @@ radv_prefix_item:
   SKIP bool { RADV_PREFIX->skip = $2; }
 | ONLINK bool { RADV_PREFIX->onlink = $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"); }
 | PREFERRED LIFETIME expr { RADV_PREFIX->preferred_lifetime = $3; if ($3 < 0) cf_error("Preferred lifetime must be 0 or positive"); }
 | VALID LIFETIME expr radv_sensitive {
     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:
{
  if (RADV_PREFIX->preferred_lifetime > RADV_PREFIX->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:
@@ -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"); }
 ;

radv_sensitive:
   /* empty */ { $$ = -1 }
 | SENSITIVE bool { $$ = $2 }
 ;

CF_CODE

CF_END
Loading