From 732a0a257d180a95a02587203555b8552b6128ac Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Mon, 23 Jan 2012 01:26:40 +0100 Subject: [PATCH] Fixes problems with creating/removing/renaming ifaces on BSD. --- nest/iface.c | 20 +++++++++++++++++++- nest/iface.h | 1 + sysdep/bsd/krt-sock.c | 34 +++++++++++++++++++++++----------- sysdep/linux/netlink/netlink.c | 27 +++++++++++---------------- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/nest/iface.c b/nest/iface.c index 2b14d3f0..d871ff33 100644 --- a/nest/iface.c +++ b/nest/iface.c @@ -252,6 +252,24 @@ if_change_flags(struct iface *i, unsigned flags) if_notify_change((i->flags & IF_UP) ? IF_CHANGE_UP : IF_CHANGE_DOWN, i); } +/** + * if_delete - remove interface + * @old: interface + * + * This function is called by the low-level platform dependent code + * whenever it notices an interface disappears. It is just a shorthand + * for if_update(). + */ + +void +if_delete(struct iface *old) +{ + struct iface f = {}; + strncpy(f.name, old->name, sizeof(f.name)-1); + f.flags = IF_SHUTDOWN; + if_update(&f); +} + /** * if_update - update interface status * @new: new interface status @@ -400,7 +418,7 @@ if_find_by_index(unsigned idx) struct iface *i; WALK_LIST(i, iface_list) - if (i->index == idx) + if (i->index == idx && !(i->flags & IF_SHUTDOWN)) return i; return NULL; } diff --git a/nest/iface.h b/nest/iface.h index d6d58ff9..2416f82f 100644 --- a/nest/iface.h +++ b/nest/iface.h @@ -88,6 +88,7 @@ void ifa_dump(struct ifa *); void if_show(void); void if_show_summary(void); struct iface *if_update(struct iface *); +void if_delete(struct iface *old); struct ifa *ifa_update(struct ifa *); void ifa_delete(struct ifa *); void if_start_update(void); diff --git a/sysdep/bsd/krt-sock.c b/sysdep/bsd/krt-sock.c index 4a91e85a..f831327b 100644 --- a/sysdep/bsd/krt-sock.c +++ b/sysdep/bsd/krt-sock.c @@ -416,8 +416,9 @@ krt_read_ifinfo(struct ks_msg *msg) void *body = (void *)(ifm + 1); struct sockaddr_dl *dl = NULL; unsigned int i; - struct iface *iface = NULL, f; + struct iface *iface = NULL, f = {}; int fl = ifm->ifm_flags; + int nlen = 0; for (i = 1; i<=RTA_IFP; i <<= 1) { @@ -432,31 +433,42 @@ krt_read_ifinfo(struct ks_msg *msg) } } - if(dl && (dl->sdl_family != AF_LINK)) + if (dl && (dl->sdl_family != AF_LINK)) { log("Ignoring strange IFINFO"); return; } - iface = if_find_by_index(ifm->ifm_index); + if (dl) + nlen = MIN(sizeof(f.name)-1, dl->sdl_nlen); - if(!iface) + /* Note that asynchronous IFINFO messages do not contain iface + name, so we have to found an existing iface by iface index */ + + iface = if_find_by_index(ifm->ifm_index); + if (!iface) { /* New interface */ - if(!dl) return; /* No interface name, ignoring */ + if (!dl) + return; /* No interface name, ignoring */ - 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); + memcpy(f.name, dl->sdl_data, nlen); + DBG("New interface '%s' found\n", f.name); + } + else if (dl && memcmp(iface->name, dl->sdl_data, nlen)) + { + /* Interface renamed */ + if_delete(iface); + memcpy(f.name, dl->sdl_data, nlen); } else { - memcpy(&f, iface, sizeof(struct iface)); + /* Old interface */ + memcpy(f.name, iface->name, sizeof(f.name)); } + f.index = ifm->ifm_index; f.mtu = ifm->ifm_data.ifi_mtu; - f.flags = 0; if (fl & IFF_UP) f.flags |= IF_ADMIN_UP; diff --git a/sysdep/linux/netlink/netlink.c b/sysdep/linux/netlink/netlink.c index cf808231..17c369ea 100644 --- a/sysdep/linux/netlink/netlink.c +++ b/sysdep/linux/netlink/netlink.c @@ -386,7 +386,7 @@ nl_parse_link(struct nlmsghdr *h, int scan) struct ifinfomsg *i; struct rtattr *a[IFLA_WIRELESS+1]; int new = h->nlmsg_type == RTM_NEWLINK; - struct iface f; + struct iface f = {}; struct iface *ifi; char *name; u32 mtu; @@ -408,26 +408,21 @@ nl_parse_link(struct nlmsghdr *h, int scan) if (!new) { DBG("KIF: IF%d(%s) goes down\n", i->ifi_index, name); - if (ifi && !scan) - { - memcpy(&f, ifi, sizeof(struct iface)); - f.flags |= IF_SHUTDOWN; - if_update(&f); - } + if (!ifi) + return; + + if_delete(ifi); } else { DBG("KIF: IF%d(%s) goes up (mtu=%d,flg=%x)\n", i->ifi_index, name, mtu, i->ifi_flags); - if (ifi) - memcpy(&f, ifi, sizeof(f)); - else - { - bzero(&f, sizeof(f)); - f.index = i->ifi_index; - } - strncpy(f.name, RTA_DATA(a[IFLA_IFNAME]), sizeof(f.name)-1); + if (ifi && strncmp(ifi->name, name, sizeof(ifi->name)-1)) + if_delete(ifi); + + strncpy(f.name, name, sizeof(f.name)-1); + f.index = i->ifi_index; f.mtu = mtu; - f.flags = 0; + fl = i->ifi_flags; if (fl & IFF_UP) f.flags |= IF_ADMIN_UP;