[PATCH 1/1] * Handle interface removal and renaming correctly on BSD

Alexander V. Chernikov melifaro at ipfw.ru
Thu Jan 19 16:28:06 CET 2012


---
 nest/iface.c            |   44 ++++++++++++++++++++++++++++++++++
 nest/iface.h            |    1 +
 proto/ospf/iface.c      |    9 +++++++
 sysdep/bsd/krt-sock.c   |   60 +++++++++++++++++++++++++++++++++++++++++++++-
 sysdep/unix/krt-iface.c |   13 +++++++---
 5 files changed, 121 insertions(+), 6 deletions(-)

diff --git a/nest/iface.c b/nest/iface.c
index b8b214e..4dae928 100644
--- a/nest/iface.c
+++ b/nest/iface.c
@@ -127,6 +127,10 @@ if_what_changed(struct iface *i, struct iface *j)
     c |= IF_CHANGE_LINK;
   if (i->mtu != j->mtu)
     c |= IF_CHANGE_MTU;
+  if (strcmp(i->name, j->name))
+    c |= IF_CHANGE_NAME;
+
+  log(L_ERR "Interface %s changed: %X", i->name, c);
   return c;
 }
 
@@ -179,6 +183,7 @@ if_send_notify(struct proto *p, unsigned c, struct iface *i)
 	    (c & IF_CHANGE_UP) ? "goes up" :
 	    (c & IF_CHANGE_DOWN) ? "goes down" :
 	    (c & IF_CHANGE_MTU) ? "changes MTU" :
+	    (c & IF_CHANGE_NAME) ? "changes name" :
 	    (c & IF_CHANGE_LINK) ? "changes link" :
 	    (c & IF_CHANGE_CREATE) ? "created" :
 	    "sends unknown event");
@@ -253,6 +258,40 @@ if_change_flags(struct iface *i, unsigned flags)
 }
 
 /**
+ * if_destroy - destroy given interface
+ * @i: interface to be removed
+ */
+static void
+if_destroy(struct iface *i)
+{
+  struct ifa *a, *a_next;
+
+  i->flags &= ~IF_UP;
+  i->flags |= IF_TMP_DOWN;
+  if_notify_change(IF_CHANGE_DOWN, i);
+
+  /*
+   * all protocols are notified about ifa's going down (sockets became invalid)
+   * neighbor cache is cleared for this itnerface
+   */
+
+  /* Remove all addresses */
+  WALK_LIST_DELSAFE(a, a_next, i->addrs)
+      mb_free(a);
+
+  rem_node(&i->n);
+
+  if (!EMPTY_LIST(i->neighbors))
+    {
+      log(L_ERR "Error: neighbors cache for interface %s is not empty", i->name);
+      memset(i, 0, sizeof(struct iface));
+      return;
+    }
+
+  mb_free(i);
+}
+
+/**
  * if_update - update interface status
  * @new: new interface status
  *
@@ -282,6 +321,11 @@ if_update(struct iface *new)
 	c = if_what_changed(i, new);
 	if (c & IF_CHANGE_TOO_MUCH)	/* Changed a lot, convert it to down/up */
 	  {
+	    if (new->flags & IF_SHUTDOWN)
+	      {
+		if_destroy(i);
+		return NULL;
+	      }
 	    DBG("Interface %s changed too much -- forcing down/up transition\n", i->name);
 	    if_change_flags(i, i->flags | IF_TMP_DOWN);
 	    rem_node(&i->n);
diff --git a/nest/iface.h b/nest/iface.h
index d6d58ff..cadf5c9 100644
--- a/nest/iface.h
+++ b/nest/iface.h
@@ -79,6 +79,7 @@ struct iface {
 #define IF_CHANGE_MTU 4
 #define IF_CHANGE_CREATE 8		/* Seen this interface for the first time */
 #define IF_CHANGE_LINK 0x10
+#define IF_CHANGE_NAME 0x20		/* Interface is renamed */
 #define IF_CHANGE_TOO_MUCH 0x40000000	/* Used internally */
 
 void if_init(void);
diff --git a/proto/ospf/iface.c b/proto/ospf/iface.c
index cced710..73f44c1 100644
--- a/proto/ospf/iface.c
+++ b/proto/ospf/iface.c
@@ -1025,6 +1025,12 @@ ospf_ifaces_reconfigure(struct ospf_area *oa, struct ospf_area_config *nac)
 #endif
 
 static void
+ospf_iface_rename(struct proto_ospf *po, struct iface *iface)
+{
+}
+
+
+static void
 ospf_iface_change_mtu(struct proto_ospf *po, struct ospf_iface *ifa)
 {
   struct proto *p = &po->proto;
@@ -1081,6 +1087,9 @@ ospf_if_notify(struct proto *p, unsigned flags, struct iface *iface)
   if (flags & IF_CHANGE_UP)
     return;
 
+  if (flags & IF_CHANGE_NAME)
+    ospf_iface_rename(po, iface);
+
   struct ospf_iface *ifa, *ifx;
   WALK_LIST_DELSAFE(ifa, ifx, po->iface_list)
     if ((ifa->type != OSPF_IT_VLINK) && (ifa->iface == iface))
diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c
index 4bf6600..9371e21 100644
--- a/sysdep/bsd/krt-sock.c
+++ b/sysdep/bsd/krt-sock.c
@@ -276,7 +276,7 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
   if (sa_family_check(&dst))
     get_sockaddr(&dst, &idst, NULL, NULL, 0);
   else
-    SKIP("invalid DST");
+    SKIP("invalid DST\n");
 
   /* We will check later whether we have valid gateway addr */
   if (sa_family_check(&gate))
@@ -410,6 +410,60 @@ krt_read_rt(struct ks_msg *msg, struct krt_proto *p, int scan)
 }
 
 static void
+krt_read_ifannounce(struct ks_msg *msg)
+{
+  struct iface *iface, f;
+  struct if_announcemsghdr *ifam = (struct if_announcemsghdr *)&msg->rtm;
+
+  iface = if_find_by_index(ifam->ifan_index);
+
+  if (ifam->ifan_what == IFAN_DEPARTURE)
+  {
+    /* Interface is destroyed  */
+    if (!iface)
+    {
+      DBG("KRT: unknown interface (%s, #%d) going down. Ignoring\n", ifam->ifan_name, ifam->ifan_index);
+      return;
+    }
+
+    /*
+     * If interface is still up this means interface is renamed. Do nothing
+     * and update interface name on interface arrival event
+     */
+    if (iface->flags & IF_UP)
+      return;
+
+    /* Prepare fake structure without IF_UP flag */
+    bzero(&f, sizeof(f));
+    f.index = ifam->ifan_index;
+    f.flags = IF_SHUTDOWN;
+    memcpy(f.name, ifam->ifan_name, sizeof(f.name) - 1);
+
+    if_update(&f);
+    return;
+  }
+
+  if (ifam->ifan_what == IFAN_ARRIVAL)
+  {
+    /* New interface. Check if it already exists */
+    if (!iface)
+      return;
+
+    /* Interface is renamed. */
+    if (strcmp(iface->name, ifam->ifan_name))
+    {
+      DBG("KRT: Interface %s renamed to %s\n", iface->name, ifam->ifan_name);
+      memcpy(&f, iface, sizeof(struct iface));
+      /* Assume both strings are IFNAMSIZ length */
+      memcpy(f.name, ifam->ifan_name, IFNAMSIZ);
+      if_update(&f);
+    }
+  }
+
+  DBG("KRT: IFANNOUNCE what: %d index %d name %s\n", ifam->ifan_what, ifam->ifan_index, ifam->ifan_name);
+}
+
+static void
 krt_read_ifinfo(struct ks_msg *msg)
 {
   struct if_msghdr *ifm = (struct if_msghdr *)&msg->rtm;
@@ -448,7 +502,7 @@ krt_read_ifinfo(struct ks_msg *msg)
     bzero(&f, sizeof(f));
     f.index = ifm->ifm_index;
     memcpy(f.name, dl->sdl_data, MIN(sizeof(f.name)-1, dl->sdl_nlen));
-    DBG("New interface '%s' found", f.name);
+    DBG("New interface '%s' found\n", f.name);
   }
   else
   {
@@ -588,6 +642,8 @@ krt_read_msg(struct proto *p, struct ks_msg *msg, int scan)
     case RTM_DELETE:
       krt_read_rt(msg, (struct krt_proto *)p, scan);
       break;
+    case RTM_IFANNOUNCE:
+      krt_read_ifannounce(msg);
     case RTM_IFINFO:
       krt_read_ifinfo(msg);
       break;
diff --git a/sysdep/unix/krt-iface.c b/sysdep/unix/krt-iface.c
index 69048ae..0866e08 100644
--- a/sysdep/unix/krt-iface.c
+++ b/sysdep/unix/krt-iface.c
@@ -177,10 +177,15 @@ scan_ifs(struct ifreq *r, int cnt)
 	  a.flags |= IA_SECONDARY;
 	  pi = if_find_by_index(i.index);
 	}
-      if (!pi)
-	pi = if_update(&i);
-      a.iface = pi;
-      ifa_update(&a);
+      if ((!pi) && (pi = if_update(&i)))
+        {
+	  /*
+	   * if_update() CAN return NULL for updates
+	   * with IF_SHUTDOWN flag
+	   */
+	  a.iface = pi;
+	  ifa_update(&a);
+	}
     }
   if_end_update();
 }
-- 
1.7.3.2


--------------050303070709040602030009--



More information about the Bird-users mailing list