[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