]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Allows sticky link-local neighbors.
authorOndrej Zajicek <santiago@crfreenet.org>
Sun, 1 Jan 2012 11:02:20 +0000 (12:02 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Sun, 1 Jan 2012 11:14:42 +0000 (12:14 +0100)
Allows using NEF_STICKY neighbors with link-local addresses. This is
used for static route nexthops, they can be specified like fe80::1%eth0
.

conf/confbase.Y
nest/iface.c
nest/iface.h
nest/neighbor.c
proto/bgp/bgp.c
proto/static/config.Y
proto/static/static.c
proto/static/static.h

index 499a770e66d7c4651efd5b289b488a811826c022..14893f47e9d90abc51e786685cd37a4140bd4834 100644 (file)
@@ -50,6 +50,7 @@ CF_DECLS
   struct f_path_mask *h;
   struct password_item *p;
   struct rt_show_data *ra;
+  struct iface *iface;
   void *g;
   bird_clock_t time;
   struct prefix px;
@@ -65,6 +66,7 @@ CF_DECLS
 %token <a> IPA
 %token <s> SYM
 %token <t> TEXT
+%type <iface> ipa_scope
 
 %type <i> expr bool pxlen
 %type <time> datetime
@@ -140,6 +142,11 @@ ipa:
    }
  ;
 
+ipa_scope:
+   /* empty */ { $$ = NULL; }
+ | '%' SYM { $$ = if_get_by_name($2->name); }
+ ;
+
 prefix:
    ipa pxlen {
      if (!ip_is_prefix($1, $2)) cf_error("Invalid prefix");
index bf57a9b11ac2118294704172df9489b97bb950a9..b8b214e5a869fa54c6956f1e257c84a6f927629e 100644 (file)
@@ -424,6 +424,24 @@ if_find_by_name(char *name)
   return NULL;
 }
 
+struct iface *
+if_get_by_name(char *name)
+{
+  struct iface *i;
+
+  if (i = if_find_by_name(name))
+    return i;
+
+  /* No active iface, create a dummy */
+  i = mb_allocz(if_pool, sizeof(struct iface));
+  strncpy(i->name, name, sizeof(i->name)-1);
+  i->flags = IF_SHUTDOWN;
+  init_list(&i->addrs);
+  init_list(&i->neighbors);
+  add_tail(&iface_list, &i->n);
+  return i;
+}
+
 struct ifa *kif_choose_primary(struct iface *i);
 
 static int
index 7307844e0c90f62e1d62481b69cb299ec6f76972..d6d58ff9c96c19531c2d997659b478f47f9000ed 100644 (file)
@@ -97,6 +97,7 @@ void if_flush_ifaces(struct proto *p);
 void if_feed_baby(struct proto *);
 struct iface *if_find_by_index(unsigned);
 struct iface *if_find_by_name(char *);
+struct iface *if_get_by_name(char *);
 void ifa_recalc_all_primary_addresses(void);
 
 /* The Neighbor Cache */
@@ -110,11 +111,13 @@ typedef struct neighbor {
   void *data;                          /* Protocol-specific data */
   unsigned aux;                                /* Protocol-specific data */
   unsigned flags;
-  unsigned scope;                      /* Address scope, SCOPE_HOST when it's our own address */
+  int scope;                           /* Address scope, -1 for unreachable sticky neighbors,
+                                          SCOPE_HOST when it's our own address */
 } neighbor;
 
 #define NEF_STICKY 1
 #define NEF_ONLINK 2
+#define NEF_BIND 4                     /* Used internally for neighbors bound to an iface */
 
 neighbor *neigh_find(struct proto *, ip_addr *, unsigned flags);
 neighbor *neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags);
index 67bd32b339e607dd78398eb9b938ed7835a1fb11..506d9bdee4618b76d2171c4dbeb54bc50ffb2072 100644 (file)
@@ -133,6 +133,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
   if (ifa)
     {
       scope = if_connected(a, ifa);
+      flags |= NEF_BIND;
 
       if ((scope < 0) && (flags & NEF_ONLINK))
        scope = class & IADDR_SCOPE_MASK;
@@ -160,10 +161,7 @@ neigh_find2(struct proto *p, ip_addr *a, struct iface *ifa, unsigned flags)
     }
   else
     {
-      /* sticky flag does not work for link-local neighbors;
-        fortunately, we don't use this combination */
       add_tail(&sticky_neigh_list, &n->n);
-      ifa = NULL;
       scope = -1;
     }
   n->iface = ifa;
@@ -235,7 +233,9 @@ neigh_down(neighbor *n)
 {
   DBG("Flushing neighbor %I on %s\n", n->addr, i->name);
   rem_node(&n->if_n);
-  n->iface = NULL;
+  if (! (n->flags & NEF_BIND))
+    n->iface = NULL;
+  n->scope = -1;
   if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
     n->proto->neigh_notify(n);
   rem_node(&n->n);
@@ -262,7 +262,8 @@ neigh_if_up(struct iface *i)
   int scope;
 
   WALK_LIST_DELSAFE(n, next, sticky_neigh_list)
-    if ((scope = if_connected(&n->addr, i)) >= 0)
+    if ((!n->iface || n->iface == i) &&
+       ((scope = if_connected(&n->addr, i)) >= 0))
       neigh_up(n, i, scope);
 }
 
@@ -339,7 +340,7 @@ neigh_prune_one(neighbor *n)
   if (n->proto->proto_state != PS_DOWN)
     return;
   rem_node(&n->n);
-  if (n->iface)
+  if (n->scope >= 0)
     rem_node(&n->if_n);
   sl_free(neigh_slab, n);
 }
index 28396a52015a5b8fc84101f4e529b332326f202e..6bd18f0952d166d23db3a46f2a3f6ff601ea95b3 100644 (file)
@@ -804,7 +804,7 @@ bgp_start_locked(struct object_lock *lock)
       return;
     }
   
-  if (p->neigh->iface)
+  if (p->neigh->scope > 0)
     bgp_start_neighbor(p);
   else
     BGP_TRACE(D_EVENTS, "Waiting for %I to become my neighbor", cf->remote_ip);
index 621fdf9b95df1f0f586435a6f14a46ece4d8cc52..f8e84f92fb2668b3e1d8abb5ed33ec0bafdc5343 100644 (file)
@@ -48,11 +48,12 @@ stat_route0: ROUTE prefix {
  ;
 
 stat_multipath1:
-   VIA ipa {
+   VIA ipa ipa_scope {
      last_srt_nh = this_srt_nh;
      this_srt_nh = cfg_allocz(sizeof(struct static_route));
      this_srt_nh->dest = RTD_NONE;
      this_srt_nh->via = $2;
+     this_srt_nh->via_if = $3;
      this_srt_nh->if_name = (void *) this_srt; /* really */
    }
  | stat_multipath1 WEIGHT expr {
@@ -67,9 +68,10 @@ stat_multipath:
  ;
 
 stat_route:
-   stat_route0 VIA ipa {
+   stat_route0 VIA ipa ipa_scope {
       this_srt->dest = RTD_ROUTER;
       this_srt->via = $3;
+      this_srt->via_if = $4;
    }
  | stat_route0 VIA TEXT {
       this_srt->dest = RTD_DEVICE;
index e5b293c07ce5d8cf9bfd5218f6b87ead22597c7f..3323c7ee003c0d904fec62cce73e36329756e679 100644 (file)
@@ -138,12 +138,10 @@ static_decide(struct static_config *cf, struct static_route *r)
   /* r->dest != RTD_MULTIPATH, but may be RTD_NONE (part of multipath route)
      the route also have to be valid (r->neigh != NULL) */
 
-  struct iface *ifa = r->neigh->iface;
-
-  if (!ifa)
+  if (r->neigh->scope < 0)
     return 0;
 
-  if (cf->check_link && !(ifa->flags & IF_LINK_UP))
+  if (cf->check_link && !(r->neigh->iface->flags & IF_LINK_UP))
     return 0;
 
   return 1;
@@ -158,7 +156,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
     {
     case RTD_ROUTER:
       {
-       struct neighbor *n = neigh_find(p, &r->via, NEF_STICKY);
+       struct neighbor *n = neigh_find2(p, &r->via, r->via_if, NEF_STICKY);
        if (n)
          {
            r->chain = n->data;
@@ -187,7 +185,7 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
 
        for (r2 = r->mp_next; r2; r2 = r2->mp_next)
          {
-           struct neighbor *n = neigh_find(p, &r2->via, NEF_STICKY);
+           struct neighbor *n = neigh_find2(p, &r2->via, r2->via_if, NEF_STICKY);
            if (n)
              {
                r2->chain = n->data;
@@ -385,7 +383,7 @@ static_same_dest(struct static_route *x, struct static_route *y)
   switch (x->dest)
     {
     case RTD_ROUTER:
-      return ipa_equal(x->via, y->via);
+      return ipa_equal(x->via, y->via) && (x->via_if == y->via_if);
 
     case RTD_DEVICE:
       return !strcmp(x->if_name, y->if_name);
@@ -394,7 +392,7 @@ static_same_dest(struct static_route *x, struct static_route *y)
       for (x = x->mp_next, y = y->mp_next;
           x && y;
           x = x->mp_next, y = y->mp_next)
-       if (!ipa_equal(x->via, y->via))
+       if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if))
          return 0;
       return !x && !y;
 
index 775743cf97b838468ba8a069473f777010a14ab2..eb87ddec7dadfe77d9e38054c1ebc83cb32ac486 100644 (file)
@@ -27,6 +27,7 @@ struct static_route {
   int masklen;                         /* Mask length */
   int dest;                            /* Destination type (RTD_*) */
   ip_addr via;                         /* Destination router */
+  struct iface *via_if;                        /* Destination iface, for link-local vias */
   struct neighbor *neigh;
   byte *if_name;                       /* Name for RTD_DEVICE routes */
   struct static_route *mp_next;                /* Nexthops for RTD_MULTIPATH routes */