From f7f6c54b160d9623730d6c7f7dcfebc3e775b633 Mon Sep 17 00:00:00 2001 From: zhangzujian Date: Tue, 30 Jan 2024 02:08:43 +0000 Subject: [PATCH] wip Signed-off-by: zhangzujian --- lib/netdev-linux.c | 2 +- lib/netdev.c | 175 ++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 167 insertions(+), 10 deletions(-) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index b7841fefb9f..403be12316c 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)) { + 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 c797783782f..b2b6663d279 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -2166,15 +2166,174 @@ netdev_get_change_seq(const struct netdev *netdev) #ifndef _WIN32 /* This implementation is shared by Linux and BSD. */ +struct addr_list { + struct in6_addr addr, mask; + struct addr_list *addr_next; +}; + +struct netdev_addr_list { + int if_index; + int 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 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) +{ + struct netdev_addr_list *l; + HMAP_FOR_EACH_IN_BUCKET (l, hmap_node, hash, if_addr_list) { + if (l->if_index == if_index) { + return l; + } + } + return NULL; +} + +static int +netdev_linux_get_addr_list() +{ + struct nl_dump dump; + struct ifaddrmsg *ifa; + uint64_t reply_stub[NL_DUMP_BUFSIZE / 8]; + struct ofpbuf request, reply, buf; + int error = 0; + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, sizeof(struct ifaddrmsg), + RTM_GETADDR, NLM_F_REQUEST); + ifa = ofpbuf_put_zeros(&request, sizeof(struct ifaddrmsg)); + ifa->ifa_family = AF_UNSPEC; + + nl_dump_start(&dump, NETLINK_ROUTE, &request); + ofpbuf_uninit(&request); + + if_addr_list = xmalloc(sizeof *if_addr_list); + hmap_init(if_addr_list); + + struct addr_list *all_addrs = NULL; + struct addr_list **p = &all_addrs; + + ofpbuf_use_stub(&buf, reply_stub, sizeof reply_stub); + while (nl_dump_next(&dump, &reply, &buf)) { + bool parsed, ipv4 = false; + + // IFA_ADDRESS raw protocol address interface address + // IFA_LOCAL raw protocol address local address + // IFA_LABEL asciiz string name of the interface + // IFA_BROADCAST raw protocol address broadcast address + // IFA_ANYCAST raw protocol address anycast address + // IFA_CACHEINFO struct ifa_cacheinfo Address information + + static const struct nl_policy policy[] = { + [IFA_ADDRESS] = { .type = NL_A_U32, .optional = false }, + [IFA_LOCAL] = { .type = NL_A_U32, .optional = true }, + [IFA_LABEL] = { .type = NL_A_STRING, .optional = true }, + [IFA_BROADCAST] = { .type = NL_A_U32, .optional = true }, + [IFA_ANYCAST] = { .type = NL_A_U32, .optional = true }, + [IFA_CACHEINFO] = { .type = NL_A_U128, .optional = true }, + }; + + static const struct nl_policy policy6[] = { + [IFA_ADDRESS] = { .type = NL_A_IPV6, .optional = false }, + [IFA_LOCAL] = { .type = NL_A_IPV6, .optional = true }, + [IFA_LABEL] = { .type = NL_A_STRING, .optional = true }, + [IFA_BROADCAST] = { .type = NL_A_IPV6, .optional = true }, + [IFA_ANYCAST] = { .type = NL_A_IPV6, .optional = true }, + [IFA_CACHEINFO] = { .type = NL_A_U128, .optional = true }, + }; + + struct nlattr *attrs[ARRAY_SIZE(policy)]; + const struct ifaddrmsg *msg; + + msg = ofpbuf_at(buf, NLMSG_HDRLEN, sizeof *msg); + + if (msg->ifa_family == AF_INET) { + parsed = nl_policy_parse(buf, + NLMSG_HDRLEN + sizeof(struct ifaddrmsg), + policy, attrs, ARRAY_SIZE(policy)); + ipv4 = true; + } else if (msg->ifa_family == AF_INET6) { + parsed = nl_policy_parse(buf, + NLMSG_HDRLEN + sizeof(struct ifaddrmsg), + policy6, attrs, ARRAY_SIZE(policy6)); + } else { + VLOG_DBG_RL(&rl, + "received non AF_INET/AF_INET6" + "rtnetlink address message"); + goto out; + } + + if (parsed) { + *p = xzalloc(sizeof struct addr_list); + p = &((*p)->next); + if (ipv4) { + ovs_be32 addr = nl_attr_get_be32(attrs[IFA_ADDRESS]); + (*p)->addr = in6_addr_mapped_ipv4(addr); + (*p)->mask = ibe32_prefix_mask(int(msg->ifa_prefixlen)); + } else { + (*p)->addr = nl_attr_get_in6_addr(attrs[IFA_ADDRESS]); + (*p)->mask =ipv6_create_mask(int(msg->ifa_prefixlen)); + } + + struct netdev_addr_list *list; + hash = hash_int(msg->ifa_index, 0); + list = find_if_addr_list(if_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); + } else { + list->count += 1; + } + } else { + VLOG_DBG_RL(&rl, "received unparseable rtnetlink address message"); + goto out; + } + } + ofpbuf_uninit(&buf); + + 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); + 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->count = 0; + } + list->addr_array[list->count] = addr->addr; + list->mask_array[list->count] = addr->mask; + list->count += 1; + free(addr); + } + + return error; +} + void netdev_get_addrs_list_flush(void) { ovs_mutex_lock(&if_addr_list_lock); if (if_addr_list) { - freeifaddrs(if_addr_list); + struct netdev_addr_list *list; + HMAP_FOR_EACH_SAFE (list, hmap_node, &if_addr_list) { + free(list->addr_array); + free(list->mask_array); + free(list); + } + hmap_destroy(if_addr_list); + free(if_addr_list); if_addr_list = NULL; } ovs_mutex_unlock(&if_addr_list_lock); @@ -2219,10 +2378,7 @@ netdev_get_addrs(const char dev[], struct in6_addr **paddr, } } if (ifa->ifa_addr && ifa->ifa_name && ifa->ifa_netmask) { - int family; - - family = ifa->ifa_addr->sa_family; - if (family == AF_INET || family == AF_INET6) { + if (sa_is_ip(ifa->ifa_addr)) { if (!strncmp(ifa->ifa_name, dev, IFNAMSIZ)) { cnt++; } @@ -2240,11 +2396,12 @@ netdev_get_addrs(const char dev[], struct in6_addr **paddr, if (ifa->ifa_name && ifa->ifa_addr && ifa->ifa_netmask - && !strncmp(ifa->ifa_name, dev, IFNAMSIZ) && sa_is_ip(ifa->ifa_addr)) { - addr_array[i] = sa_get_address(ifa->ifa_addr); - mask_array[i] = sa_get_address(ifa->ifa_netmask); - i++; + 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++; + } } } ovs_mutex_unlock(&if_addr_list_lock);