From fd4870613e667c40cbd0191d637e70f4db033c3e Mon Sep 17 00:00:00 2001 From: Anthony Dempsey Date: Fri, 4 Dec 2015 10:20:54 +0000 Subject: Dynamic addition of interfaces from netlink msg When a tracked interface is deleted then recreated with the same config VRRP groups tracking this interface will remain down. This is due to tracking of stale information. This patch listens for netlink messages for the creation of interfaces and does one of two things. i) If the interface doesn't exist in the vrrp interface list a new interface structure is created and the information from the message is used to fill the structure. This new interface is then added to the interface queue. ii) If the interface already exists in the queue we zero it and then use the information in the message to fill the structure. Signed-off-by: Anthony Dempsey (cherry picked from commit 4a5b9b98202e57db5375287f8fd8e2ee24dafb42) --- keepalived/include/vrrp_netlink.h | 2 + keepalived/vrrp/vrrp_netlink.c | 112 +++++++++++++++++++++++++------------- 2 files changed, 75 insertions(+), 39 deletions(-) diff --git a/keepalived/include/vrrp_netlink.h b/keepalived/include/vrrp_netlink.h index cc606bf..77787c9 100644 --- a/keepalived/include/vrrp_netlink.h +++ b/keepalived/include/vrrp_netlink.h @@ -42,6 +42,7 @@ /* local includes */ #include "timer.h" +#include "vrrp_if.h" /* types definitions */ typedef struct _nl_handle { @@ -80,5 +81,6 @@ extern int netlink_interface_lookup(void); extern int netlink_interface_refresh(void); extern void kernel_netlink_init(void); extern void kernel_netlink_close(void); +extern int netlink_populate_intf_struct(interface_t *, struct rtattr*[], struct ifinfomsg *); #endif diff --git a/keepalived/vrrp/vrrp_netlink.c b/keepalived/vrrp/vrrp_netlink.c index 913f793..67bf792 100644 --- a/keepalived/vrrp/vrrp_netlink.c +++ b/keepalived/vrrp/vrrp_netlink.c @@ -38,7 +38,6 @@ /* local include */ #include "check_api.h" #include "vrrp_netlink.h" -#include "vrrp_if.h" #include "logger.h" #include "memory.h" #include "scheduler.h" @@ -514,6 +513,48 @@ netlink_request(nl_handle_t *nl, int family, int type) return 0; } +int +netlink_populate_intf_struct(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg *ifi) { + char *name; + int i; + + name = (char *) RTA_DATA(tb[IFLA_IFNAME]); + /* Fill the interface structure */ + memcpy(ifp->ifname, name, strlen(name)); + ifp->ifindex = ifi->ifi_index; + ifp->mtu = *(int *) RTA_DATA(tb[IFLA_MTU]); + ifp->hw_type = ifi->ifi_type; + + if (!ifp->vmac) { + if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags); + ifp->flags = ifi->ifi_flags; + ifp->base_ifindex = ifi->ifi_index; + } + + if (tb[IFLA_ADDRESS]) { + int hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); + + if (hw_addr_len > IF_HWADDR_MAX) { + log_message(LOG_ERR, "MAC address for %s is too large: %d", + name, hw_addr_len); + return -1; + } + else { + ifp->hw_addr_len = hw_addr_len; + memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), + hw_addr_len); + for (i = 0; i < hw_addr_len; i++) + if (ifp->hw_addr[i] != 0) + break; + if (i == hw_addr_len) + ifp->hw_addr_len = 0; + else + ifp->hw_addr_len = hw_addr_len; + } + } + return 1; +} + /* Netlink interface link lookup filter */ static int netlink_if_link_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) @@ -521,7 +562,7 @@ netlink_if_link_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; - int i, len; + int len, status; char *name; ifi = NLMSG_DATA(h); @@ -556,38 +597,10 @@ netlink_if_link_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) /* Fill the interface structure */ ifp = (interface_t *) MALLOC(sizeof(interface_t)); - memcpy(ifp->ifname, name, strlen(name)); - ifp->ifindex = ifi->ifi_index; - ifp->mtu = *(int *) RTA_DATA(tb[IFLA_MTU]); - ifp->hw_type = ifi->ifi_type; - ifp->reset_arp_config = 0; - - if (!ifp->vmac) { - if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags); - ifp->flags = ifi->ifi_flags; - ifp->base_ifindex = ifi->ifi_index; - } - - if (tb[IFLA_ADDRESS]) { - int hw_addr_len = RTA_PAYLOAD(tb[IFLA_ADDRESS]); - - if (hw_addr_len > IF_HWADDR_MAX) - log_message(LOG_ERR, "MAC address for %s is too large: %d", - name, hw_addr_len); - else { - ifp->hw_addr_len = hw_addr_len; - memcpy(ifp->hw_addr, RTA_DATA(tb[IFLA_ADDRESS]), - hw_addr_len); - for (i = 0; i < hw_addr_len; i++) - if (ifp->hw_addr[i] != 0) - break; - if (i == hw_addr_len) - ifp->hw_addr_len = 0; - else - ifp->hw_addr_len = hw_addr_len; - } - } + status = netlink_populate_intf_struct(ifp, tb, ifi); + if (status < 0) + return -1; /* Queue this new interface_t */ if_add_queue(ifp); return 0; @@ -713,7 +726,7 @@ netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; - int len; + int len, status; ifi = NLMSG_DATA(h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) @@ -733,13 +746,34 @@ netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; - /* find the interface_t. Ignore it if we don't know about the interface */ + /* find the interface_t. If the interface doesn't exist in the interface + * list and this is a new interface add it to the interface list. + * If an interface with the same name exists overwrite the older + * structure and fill it with the new interface information. + */ ifp = if_get_by_ifindex(ifi->ifi_index); if (!ifp) { - if (__test_bit(LOG_DETAIL_BIT, &debug)) - log_message(LOG_INFO, "Unknown interface %s %s", (char *)tb[IFLA_IFNAME], - (h->nlmsg_type == RTM_NEWLINK ) ? "added" : "deleted" ); - return 0; + if (h->nlmsg_type == RTM_NEWLINK) { + char *name; + if (tb[IFLA_IFNAME] == NULL) + return -1; + name = (char *) RTA_DATA(tb[IFLA_IFNAME]); + ifp = if_get_by_ifname(name); + if (!ifp) { + ifp = (interface_t *) MALLOC(sizeof(interface_t)); + if_add_queue(ifp); + } else { + memset(ifp, 0, sizeof(interface_t)); + } + status = netlink_populate_intf_struct(ifp, tb, ifi); + if (status < 0) + return -1; + + } else { + if (__test_bit(LOG_DETAIL_BIT, &debug)) + log_message(LOG_INFO, "Unknown interface %s deleted", (char *)tb[IFLA_IFNAME]); + return 0; + } } /* -- 1.7.12.1