]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Implements router advertisements activated by received routes.
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 8 Feb 2013 22:58:27 +0000 (23:58 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 8 Feb 2013 22:58:27 +0000 (23:58 +0100)
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.

doc/bird.sgml
filter/filter.c
nest/route.h
nest/rt-table.c
proto/radv/config.Y
proto/radv/packets.c
proto/radv/radv.c
proto/radv/radv.h

index f6f9aad7b236985da823f438fc49c9254597f63f..762834e349700b30bddfe1b038b6dd0dc2090b93 100644 (file)
@@ -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>
 
 
index 44fcf2932be9fa380642a3c88cc47545c2d3451e..c35d0425ed106cd3d3de0010f497bf1fb22811e5 100644 (file)
@@ -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 );
 
index 177baa3858e293b71dfda41aaff727f53e16c15d..8fd01a6678e5f7a0247db6c1bdae4d2f30e7ea24 100644 (file)
@@ -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 *);
index 99175448c61359fd5820b0d873da973a88f9799d..75bfa6ba96c143f89f1dc8429f4de70adcbb9edc 100644 (file)
@@ -213,7 +213,8 @@ export_filter(struct announce_hook *ah, rte *rt0, rte **rt_free, ea_list **tmpa,
        goto reject;
 
       stats->exp_updates_rejected++;
-      rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
+      if (v == RIC_REJECT)
+       rte_trace_out(D_FILTERS, p, rt, "rejected by protocol");
       goto reject;
     }
   if (v > 0)
@@ -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;
            }
        }
index abccd2c7d3a03c63c948e4633e62652b64379ef2..fbec5a0aa758552c74d26db857fcd66c35091277 100644 (file)
@@ -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
index 6fdfcaa38b092430fb18eb5e47beec87ae51342c..dd839536de2ba65083b6635407d8809e8b3835e2 100644 (file)
@@ -240,6 +240,7 @@ radv_prepare_ra(struct radv_iface *ifa)
 {
   struct proto_radv *ra = ifa->ra;
   struct radv_config *cf = (struct radv_config *) (ra->p.cf);
+  struct radv_iface_config *ic = ifa->cf;
 
   char *buf = ifa->sk->tbuf;
   char *bufstart = buf;
@@ -249,21 +250,22 @@ radv_prepare_ra(struct radv_iface *ifa)
   pkt->type = ICMPV6_RA;
   pkt->code = 0;
   pkt->checksum = 0;
-  pkt->current_hop_limit = ifa->cf->current_hop_limit;
-  pkt->flags = (ifa->cf->managed ? OPT_RA_MANAGED : 0) |
-    (ifa->cf->other_config ? OPT_RA_OTHER_CFG : 0);
-  pkt->router_lifetime = htons(ifa->cf->default_lifetime);
-  pkt->reachable_time = htonl(ifa->cf->reachable_time);
-  pkt->retrans_timer = htonl(ifa->cf->retrans_timer);
+  pkt->current_hop_limit = ic->current_hop_limit;
+  pkt->flags = (ic->managed ? OPT_RA_MANAGED : 0) |
+    (ic->other_config ? OPT_RA_OTHER_CFG : 0);
+  pkt->router_lifetime = (ra->active || !ic->default_lifetime_sensitive) ?
+    htons(ic->default_lifetime) : 0;
+  pkt->reachable_time = htonl(ic->reachable_time);
+  pkt->retrans_timer = htonl(ic->retrans_timer);
   buf += sizeof(*pkt);
 
-  if (ifa->cf->link_mtu)
+  if (ic->link_mtu)
   {
     struct radv_opt_mtu *om = (void *) buf;
     om->type = OPT_MTU;
     om->length = 1;
     om->reserved = 0;
-    om->mtu = htonl(ifa->cf->link_mtu);
+    om->mtu = htonl(ic->link_mtu);
     buf += sizeof (*om);
   }
 
@@ -288,26 +290,28 @@ radv_prepare_ra(struct radv_iface *ifa)
     op->pxlen = addr->pxlen;
     op->flags = (pc->onlink ? OPT_PX_ONLINK : 0) |
       (pc->autonomous ? OPT_PX_AUTONOMOUS : 0);
-    op->valid_lifetime = htonl(pc->valid_lifetime);
-    op->preferred_lifetime = htonl(pc->preferred_lifetime);
+    op->valid_lifetime = (ra->active || !pc->valid_lifetime_sensitive) ?
+      htonl(pc->valid_lifetime) : 0;
+    op->preferred_lifetime = (ra->active || !pc->preferred_lifetime_sensitive) ?
+      htonl(pc->preferred_lifetime) : 0;
     op->reserved = 0;
     op->prefix = addr->prefix;
     ipa_hton(op->prefix);
     buf += sizeof(*op);
   }
 
-  if (! ifa->cf->rdnss_local)
+  if (! ic->rdnss_local)
     if (radv_prepare_rdnss(ifa, &cf->rdnss_list, &buf, bufend) < 0)
       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;
 
-  if (! ifa->cf->dnssl_local)
+  if (! ic->dnssl_local)
     if (radv_prepare_dnssl(ifa, &cf->dnssl_list, &buf, bufend) < 0)
       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;
 
  done:
index 5e7296a3188b23ca16561d492a821e6548e310e9..a6b9b16c8f8ea6ea0164d3dfc1afbace9d710808 100644 (file)
  * by RA_EV_* codes), and radv_timer(), which triggers sending RAs and
  * 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:
  * - RFC 4861 - main RA standard
  * - RFC 6106 - DNS extensions (RDDNS, DNSSL)
@@ -93,6 +100,16 @@ radv_iface_notify(struct radv_iface *ifa, int event)
   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 *
 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);
 }
 
+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 *
 radv_init(struct proto_config *c)
 {
   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->ifa_notify = radv_ifa_notify;
   return p;
@@ -252,9 +326,10 @@ static int
 radv_start(struct proto *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));
+  ra->active = !cf->trigger_valid;
 
   return PS_UP;
 }
@@ -293,6 +368,9 @@ radv_reconfigure(struct proto *p, struct proto_config *c)
    * 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;
   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));
 }
 
+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 = {
   .name =              "RAdv",
@@ -343,5 +429,6 @@ struct protocol proto_radv = {
   .start =             radv_start,
   .shutdown =          radv_shutdown,
   .reconfigure =       radv_reconfigure,
-  .copy_config =       radv_copy_config
+  .copy_config =       radv_copy_config,
+  .get_status =                radv_get_status
 };
index 48af8c004f75bc56c92176198d296f218b68670b..f80e4530162e402ada67eede44255012acce0535 100644 (file)
@@ -52,6 +52,10 @@ struct radv_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 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
@@ -75,6 +79,7 @@ struct radv_iface_config
   u32 retrans_timer;
   u32 current_hop_limit;
   u32 default_lifetime;
+  u8 default_lifetime_sensitive; /* Whether default_lifetime depends on trigger */
 };
 
 struct radv_prefix_config
@@ -88,6 +93,8 @@ struct radv_prefix_config
   u8 autonomous;
   u32 valid_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
@@ -113,6 +120,7 @@ struct proto_radv
 {
   struct proto p;
   list iface_list;             /* List of active ifaces */
+  u8 active;                   /* Whether radv is active w.r.t. triggers */
 };
 
 struct radv_iface