]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Adds support for iface link check to static protocol.
authorOndrej Zajicek <santiago@crfreenet.org>
Thu, 11 Nov 2010 11:24:27 +0000 (12:24 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Thu, 11 Nov 2010 11:24:27 +0000 (12:24 +0100)
nest/iface.c
nest/iface.h
nest/neighbor.c
proto/static/config.Y
proto/static/static.c
proto/static/static.h

index 8e4593637d44ecef8b4ab6d5dbfe6597dc848db1..c52367824e8d1845fecbd9b9ddc098dfcfec75f3 100644 (file)
@@ -117,7 +117,7 @@ if_what_changed(struct iface *i, struct iface *j)
 {
   unsigned c;
 
-  if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_TMP_DOWN | IF_JUST_CREATED))
+  if (((i->flags ^ j->flags) & ~(IF_UP | IF_SHUTDOWN | IF_UPDATED | IF_ADMIN_UP | IF_LINK_UP | IF_TMP_DOWN | IF_JUST_CREATED))
       || i->index != j->index)
     return IF_CHANGE_TOO_MUCH;
   c = 0;
@@ -213,6 +213,10 @@ if_notify_change(unsigned c, struct iface *i)
        a->flags = (i->flags & ~IA_FLAGS) | (a->flags & IA_FLAGS);
        ifa_notify_change(IF_CHANGE_UP, a);
       }
+
+  if ((c & (IF_CHANGE_UP | IF_CHANGE_DOWN | IF_CHANGE_LINK)) == IF_CHANGE_LINK)
+    neigh_if_link(i);
+
   if (c & IF_CHANGE_DOWN)
     neigh_if_down(i);
 }
index 471625f23edbdcde36a646bde112e03bc4424a71..1936885cbb53abeb5b74d022dc060bc61324f6f8 100644 (file)
@@ -125,6 +125,7 @@ void neigh_dump_all(void);
 void neigh_prune(void);
 void neigh_if_up(struct iface *);
 void neigh_if_down(struct iface *);
+void neigh_if_link(struct iface *);
 void neigh_init(struct pool *);
 
 /*
index 7e7cc491f41427b4dd23ac2dc366d7ce131d57c1..785b1d46743515c3250b0388d2175d9c144bb373 100644 (file)
@@ -278,6 +278,28 @@ neigh_if_down(struct iface *i)
     }
 }
 
+/**
+ * neigh_if_link - notify neighbor cache about interface link change
+ * @i: the interface in question
+ *
+ * Notify the neighbor cache that an interface changed link state.
+ * All owners of neighbor entries connected to this interface are
+ * notified.
+ */
+
+void
+neigh_if_link(struct iface *i)
+{
+  node *x, *y;
+
+  WALK_LIST_DELSAFE(x, y, i->neighbors)
+    {
+      neighbor *n = SKIP_BACK(neighbor, if_n, x);
+      if (n->proto->neigh_notify && n->proto->core_state != FS_FLUSHING)
+       n->proto->neigh_notify(n);
+    }
+}
+
 static inline void
 neigh_prune_one(neighbor *n)
 {
index a7e501640a6ba01b3a03e2ba1339a5bb120c20f1..9f4d7da6f6b5077473e743165b5439bcaf6239e0 100644 (file)
@@ -12,11 +12,12 @@ CF_HDR
 
 CF_DEFINES
 
+#define STATIC_CFG ((struct static_config *) this_proto)
 static struct static_route *this_srt;
 
 CF_DECLS
 
-CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE)
+CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
 
 CF_GRAMMAR
 
@@ -31,12 +32,13 @@ static_proto_start: proto_start STATIC {
 static_proto:
    static_proto_start proto_name '{'
  | static_proto proto_item ';'
+ | static_proto CHECK LINK ';' { STATIC_CFG->check = STATIC_CHECK_LINK; }
  | static_proto stat_route ';'
  ;
 
 stat_route0: ROUTE prefix {
      this_srt = cfg_allocz(sizeof(struct static_route));
-     add_tail(&((struct static_config *) this_proto)->other_routes, &this_srt->n);
+     add_tail(&STATIC_CFG->other_routes, &this_srt->n);
      this_srt->net = $2.addr;
      this_srt->masklen = $2.len;
   }
@@ -51,7 +53,7 @@ stat_route:
       this_srt->dest = RTD_DEVICE;
       this_srt->if_name = $3;
       rem_node(&this_srt->n);
-      add_tail(&((struct static_config *) this_proto)->iface_routes, &this_srt->n);
+      add_tail(&STATIC_CFG->iface_routes, &this_srt->n);
    }
  | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; }
  | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; }
index 6b42a379be7c41d884769fc403798184548cd2f0..4f879bd3e2ef84360ddddd00e538fae70a359151 100644 (file)
@@ -64,6 +64,20 @@ static_install(struct proto *p, struct static_route *r, struct iface *ifa)
   r->installed = 1;
 }
 
+static int
+static_decide(struct static_config *cf, struct static_route *r)
+{
+  struct iface *ifa = r->neigh->iface;
+
+  if (!ifa)
+    return 0;
+
+  if ((cf->check == STATIC_CHECK_LINK) && !(ifa->flags & IF_LINK_UP))
+    return 0;
+
+  return 1;
+}
+
 static void
 static_remove(struct proto *p, struct static_route *r)
 {
@@ -80,7 +94,7 @@ static_remove(struct proto *p, struct static_route *r)
 }
 
 static void
-static_add(struct proto *p, struct static_route *r)
+static_add(struct proto *p, struct static_config *cf, struct static_route *r)
 {
   DBG("static_add(%I/%d,%d)\n", r->net, r->masklen, r->dest);
   switch (r->dest)
@@ -93,8 +107,10 @@ static_add(struct proto *p, struct static_route *r)
            r->chain = n->data;
            n->data = r;
            r->neigh = n;
-           if (n->iface)
+           if (static_decide(cf, r))
              static_install(p, r, n->iface);
+           else
+             static_remove(p, r);
          }
        else
          log(L_ERR "Static route destination %I is invalid. Ignoring.", r->via);
@@ -115,7 +131,7 @@ static_start(struct proto *p)
 
   DBG("Static: take off!\n");
   WALK_LIST(r, c->other_routes)
-    static_add(p, r);
+    static_add(p, c, r);
   return PS_UP;
 }
 
@@ -142,7 +158,7 @@ static_neigh_notify(struct neighbor *n)
 
   DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface);
   for(r=n->data; r; r=r->chain)
-    if (n->iface)
+    if (static_decide((struct static_config *) p->cf, r))
       static_install(p, r, n->iface);
     else
       static_remove(p, r);
@@ -249,13 +265,13 @@ static_match(struct proto *p, struct static_route *r, struct static_config *n)
   WALK_LIST(t, n->iface_routes)
     if (static_same_net(r, t))
       {
-       t->installed = static_same_dest(r, t);
+       t->installed = r->installed && static_same_dest(r, t);
        return;
       }
   WALK_LIST(t, n->other_routes)
     if (static_same_net(r, t))
       {
-       t->installed = static_same_dest(r, t);
+       t->installed = r->installed && static_same_dest(r, t);
        return;
       }
   static_remove(p, r);
@@ -282,7 +298,7 @@ static_reconfigure(struct proto *p, struct proto_config *new)
        static_install(p, r, ifa);
     }
   WALK_LIST(r, n->other_routes)
-    static_add(p, r);
+    static_add(p, n, r);
 
   return 1;
 }
index 5d2bd21897cb249eaa26ba27abe4fff007cacfc7..40da74c9a2d5dbd83dfdc4fcdf790de18cfd02ea 100644 (file)
 
 struct static_config {
   struct proto_config c;
-  list iface_routes;                   /* Routes to search on interface events */
-  list other_routes;                   /* Routes hooked to neighbor cache and reject routes */
+  list iface_routes;           /* Routes to search on interface events */
+  list other_routes;           /* Routes hooked to neighbor cache and reject routes */
+  int check;                   /* Condition for route install */
 };
 
+#define STATIC_CHECK_NONE 0
+#define STATIC_CHECK_LINK 1
+
 void static_init_config(struct static_config *);
 
 struct static_route {