diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index 403be12316c..1dd2f16516d 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -843,7 +843,7 @@ netdev_linux_changed(struct netdev_linux *dev, dev->ifi_flags = ifi_flags; dev->cache_valid &= mask; - if (!(mask & VALID_IN) && !strncmp(netdev_get_name(dev->up), "kube-ipvs0", IFNAMSIZ)) { + if (!(mask & VALID_IN) && !strncmp(netdev_get_name(&dev->up), "kube-ipvs0", IFNAMSIZ)) { netdev_get_addrs_list_flush(); } } diff --git a/lib/netdev.c b/lib/netdev.c index b2b6663d279..b14530530b0 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -29,6 +29,10 @@ #include #include #include +#include +#include +#include +#include #endif #include "cmap.h" @@ -2166,28 +2170,26 @@ netdev_get_change_seq(const struct netdev *netdev) #ifndef _WIN32 /* This implementation is shared by Linux and BSD. */ -struct addr_list { +struct linux_addr_list { + int if_index; struct in6_addr addr, mask; - struct addr_list *addr_next; + struct linux_addr_list *next; }; -struct netdev_addr_list { - int if_index; - int count; +struct netdev_linux_addr_list { + int if_index, count; struct in6_addr *addr_array, *mask_array; struct hmap_node hmap_node; }; -static hmap *if_addr_list = NULL; - -static struct ifaddrs *if_addr_list; +static struct hmap *if_addr_list = NULL; static struct ovs_mutex if_addr_list_lock = OVS_MUTEX_INITIALIZER; -static struct conjunctive_match * -find_if_addr_list(struct hmap *if_addr_list, int if_index, uint32_t hash) +static struct netdev_linux_addr_list * +find_if_addr_list(struct hmap *addr_list, int if_index, uint32_t hash) { - struct netdev_addr_list *l; - HMAP_FOR_EACH_IN_BUCKET (l, hmap_node, hash, if_addr_list) { + struct netdev_linux_addr_list *l; + HMAP_FOR_EACH_IN_BUCKET (l, hmap_node, hash, addr_list) { if (l->if_index == if_index) { return l; } @@ -2196,12 +2198,13 @@ find_if_addr_list(struct hmap *if_addr_list, int if_index, uint32_t hash) } static int -netdev_linux_get_addr_list() +netdev_linux_get_addr_list(struct hmap **addr_list) { struct nl_dump dump; struct ifaddrmsg *ifa; uint64_t reply_stub[NL_DUMP_BUFSIZE / 8]; struct ofpbuf request, reply, buf; + uint32_t hash; int error = 0; ofpbuf_init(&request, 0); @@ -2213,11 +2216,11 @@ netdev_linux_get_addr_list() nl_dump_start(&dump, NETLINK_ROUTE, &request); ofpbuf_uninit(&request); - if_addr_list = xmalloc(sizeof *if_addr_list); - hmap_init(if_addr_list); + *addr_list = xmalloc(sizeof(struct hmap)); + hmap_init(*addr_list); - struct addr_list *all_addrs = NULL; - struct addr_list **p = &all_addrs; + struct linux_addr_list *all_addrs = NULL; + struct linux_addr_list **p = &all_addrs; ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub); while (nl_dump_next(&dump, &reply, &buf)) { @@ -2251,15 +2254,14 @@ netdev_linux_get_addr_list() struct nlattr *attrs[ARRAY_SIZE(policy)]; const struct ifaddrmsg *msg; - msg = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *msg); - + msg = ofpbuf_at(&reply, NLMSG_HDRLEN, sizeof *msg); if (msg->ifa_family == AF_INET) { - parsed = nl_policy_parse(buf, + parsed = nl_policy_parse(&reply, NLMSG_HDRLEN + sizeof(struct ifaddrmsg), policy, attrs, ARRAY_SIZE(policy)); ipv4 = true; } else if (msg->ifa_family == AF_INET6) { - parsed = nl_policy_parse(buf, + parsed = nl_policy_parse(&reply, NLMSG_HDRLEN + sizeof(struct ifaddrmsg), policy6, attrs, ARRAY_SIZE(policy6)); } else { @@ -2270,25 +2272,27 @@ netdev_linux_get_addr_list() } if (parsed) { - *p = xzalloc(sizeof struct addr_list); - p = &((*p)->next); + *p = xzalloc(sizeof(struct linux_addr_list)); + (*p)->if_index = msg->ifa_index; if (ipv4) { ovs_be32 addr = nl_attr_get_be32(attrs[IFA_ADDRESS]); + ovs_be32 mask = be32_prefix_mask(msg->ifa_prefixlen); (*p)->addr = in6_addr_mapped_ipv4(addr); - (*p)->mask = ibe32_prefix_mask(int(msg->ifa_prefixlen)); + (*p)->mask = in6_addr_mapped_ipv4(mask); } else { (*p)->addr = nl_attr_get_in6_addr(attrs[IFA_ADDRESS]); - (*p)->mask =ipv6_create_mask(int(msg->ifa_prefixlen)); + (*p)->mask = ipv6_create_mask(msg->ifa_prefixlen); } + p = &((*p)->next); - struct netdev_addr_list *list; + struct netdev_linux_addr_list *list; hash = hash_int(msg->ifa_index, 0); - list = find_if_addr_list(if_addr_list, msg->ifa_index, hash); + list = find_if_addr_list(addr_list, msg->ifa_index, hash); if (!list) { list = xzalloc(sizeof *list); list->if_index = msg->ifa_index; list->count = 1; - hmap_insert(if_addr_list, &list->hmap_node, hash); + hmap_insert(addr_list, &list->hmap_node, hash); } else { list->count += 1; } @@ -2302,14 +2306,15 @@ netdev_linux_get_addr_list() error = nl_dump_done(&dump); out: - struct addr_list *addr, *p; - for (addr = all_addrs; addr; addr = p) { - p = addr->next; - struct netdev_addr_list *list; - list = find_if_addr_list(if_addr_list, msg->ifa_index, hash); + struct linux_addr_list *addr, *next; + for (addr = all_addrs; addr; addr = next) { + next = addr->next; + struct netdev_linux_addr_list *list; + hash_int(addr->if_index, 0); + list = find_if_addr_list(addr_list, addr->if_index, hash); if (!list->addr_array) { - list->addr_array = xzalloc(sizeof struct in6_addr * list->count); - list->mask_array = xzalloc(sizeof struct in6_addr * list->count); + list->addr_array = xzalloc(sizeof(struct in6_addr) * list->count); + list->mask_array = xzalloc(sizeof(struct in6_addr) * list->count); list->count = 0; } list->addr_array[list->count] = addr->addr; @@ -2326,8 +2331,8 @@ netdev_get_addrs_list_flush(void) { ovs_mutex_lock(&if_addr_list_lock); if (if_addr_list) { - struct netdev_addr_list *list; - HMAP_FOR_EACH_SAFE (list, hmap_node, &if_addr_list) { + struct netdev_linux_addr_list *list; + HMAP_FOR_EACH_SAFE (list, hmap_node, if_addr_list) { free(list->addr_array); free(list->mask_array); free(list); @@ -2343,9 +2348,6 @@ int netdev_get_addrs(const char dev[], struct in6_addr **paddr, struct in6_addr **pmask, int *n_in) { - struct in6_addr *addr_array, *mask_array; - const struct ifaddrs *ifa; - int cnt = 0, i = 0; int retries = 3; ovs_mutex_lock(&if_addr_list_lock); @@ -2353,7 +2355,7 @@ netdev_get_addrs(const char dev[], struct in6_addr **paddr, int err; retry: - err = getifaddrs(&if_addr_list); + err = netdev_linux_get_addr_list(&if_addr_list); if (err) { ovs_mutex_unlock(&if_addr_list_lock); return -err; @@ -2361,48 +2363,16 @@ netdev_get_addrs(const char dev[], struct in6_addr **paddr, retries--; } - for (ifa = if_addr_list; ifa; ifa = ifa->ifa_next) { - if (!ifa->ifa_name) { - if (retries) { - /* Older versions of glibc have a bug on race condition with - * address addition which may cause one of the returned - * ifa_name values to be NULL. In such case, we know that we've - * got an inconsistent dump. Retry but beware of an endless - * loop. From glibc 2.28 and beyond, this workaround is not - * needed and should be eventually removed. */ - freeifaddrs(if_addr_list); - goto retry; - } else { - VLOG_WARN("Proceeding with an inconsistent dump of " - "interfaces from the kernel. Some may be missing"); - } - } - if (ifa->ifa_addr && ifa->ifa_name && ifa->ifa_netmask) { - if (sa_is_ip(ifa->ifa_addr)) { - if (!strncmp(ifa->ifa_name, dev, IFNAMSIZ)) { - cnt++; - } - } - } - } - - if (!cnt) { - ovs_mutex_unlock(&if_addr_list_lock); - return EADDRNOTAVAIL; - } - addr_array = xzalloc(sizeof *addr_array * cnt); - mask_array = xzalloc(sizeof *mask_array * cnt); - for (ifa = if_addr_list; ifa; ifa = ifa->ifa_next) { - if (ifa->ifa_name - && ifa->ifa_addr - && ifa->ifa_netmask - && sa_is_ip(ifa->ifa_addr)) { - if (!strncmp(ifa->ifa_name, dev, IFNAMSIZ)) { - addr_array[i] = sa_get_address(ifa->ifa_addr); - mask_array[i] = sa_get_address(ifa->ifa_netmask); - i++; - } - } + struct netdev_linux_addr_list *list; + uint32_t hash = hash_int(msg->ifa_index, 0); + list = find_if_addr_list(addr_list, msg->ifa_index, hash); + if (!list) { + list = xzalloc(sizeof *list); + list->if_index = msg->ifa_index; + list->count = 1; + hmap_insert(addr_list, &list->hmap_node, hash); + } else { + list->count += 1; } ovs_mutex_unlock(&if_addr_list_lock); if (paddr) {