/* Return base interface from interface index incase of VMAC */ interface_t * base_if_get_by_ifindex(const int ifindex) { interface_t *ifp = if_get_by_ifindex(ifindex); return (ifp && ifp->vmac) ? if_get_by_ifindex(ifp->base_ifindex) : ifp; }
/* Return base interface from interface index incase of VMAC */ interface_t * base_if_get_by_ifindex(const int ifindex) { interface_t *ifp = if_get_by_ifindex(ifindex); #ifdef _HAVE_VRRP_VMAC_ return (ifp && ifp->vmac) ? if_get_by_ifindex(ifp->base_ifindex) : ifp; #else return ifp; #endif }
void dump_iproute(void *rt_data) { ip_route_t *route = rt_data; char *log_msg = MALLOC(1024); char *op = log_msg; if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) op += snprintf(op, log_msg + 1024 - op, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask); if (route->gw) op += snprintf(op, log_msg + 1024 - op, " gw %s", ipaddresstos(NULL, route->gw)); if (route->gw2) op += snprintf(op, log_msg + 1024 - op, " or gw %s", ipaddresstos(NULL, route->gw2)); if (route->src) op += snprintf(op, log_msg + 1024 - op, " src %s", ipaddresstos(NULL, route->src)); if (route->index) op += snprintf(op, log_msg + 1024 - op, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); if (route->table) op += snprintf(op, log_msg + 1024 - op, " table %d", route->table); if (route->scope) op += snprintf(op, log_msg + 1024 - op, " scope %s", netlink_scope_n2a(route->scope)); if (route->metric) op += snprintf(op, log_msg + 1024 - op, " metric %d", route->metric); log_message(LOG_INFO, " %s", log_msg); FREE(log_msg); }
static void route_print(FILE *file, void *data) { ip_route_t *route = data; fprintf(file, " "); if (route->blackhole) fprintf(file, "blackhole "); if (route->dst) fprintf(file, "%s/%d", ipaddresstos(NULL, route->dst), route->dmask); if (route->gw) fprintf(file, " gw %s", ipaddresstos(NULL, route->gw)); if (route->gw2) fprintf(file, " or gw %s", ipaddresstos(NULL, route->gw2)); if (route->src) fprintf(file, " src %s", ipaddresstos(NULL, route->src)); if (route->index) fprintf(file, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); if (route->table) fprintf(file, " table %d", route->table); if (route->scope) fprintf(file, " scope %s", netlink_scope_n2a(route->scope)); if (route->metric) fprintf(file, " metric %d", route->metric); fprintf(file, "\n"); }
void dump_iproute(void *rt_data) { ip_route_t *route = rt_data; char *log_msg = MALLOC(1024); char *tmp = MALLOC(INET6_ADDRSTRLEN + 30); char *tmp_str; if (route->blackhole) { strncat(log_msg, "blackhole ", 30); } if (route->dst) { tmp_str = ipaddresstos(route->dst); snprintf(tmp, INET6_ADDRSTRLEN + 30, "%s/%d", tmp_str, route->dmask); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw) { tmp_str = ipaddresstos(route->gw); snprintf(tmp, INET6_ADDRSTRLEN + 30, " gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->gw2) { tmp_str = ipaddresstos(route->gw2); snprintf(tmp, INET6_ADDRSTRLEN + 30, " or gw %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->src) { tmp_str = ipaddresstos(route->src); snprintf(tmp, INET6_ADDRSTRLEN + 30, " src %s", tmp_str); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); FREE(tmp_str); } if (route->index) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->table) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " table %d", route->table); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->scope) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } if (route->metric) { snprintf(tmp, INET6_ADDRSTRLEN + 30, " metric %d", route->metric); strncat(log_msg, tmp, INET6_ADDRSTRLEN + 30); } log_message(LOG_INFO, " %s", log_msg); FREE(tmp); FREE(log_msg); }
/* * Netlink interface address lookup filter * We need to handle multiple primary address and * multiple secondary address to the same interface. */ static int netlink_if_address_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifaddrmsg *ifa; struct rtattr *tb[IFA_MAX + 1]; interface_t *ifp; int len; void *addr; ifa = NLMSG_DATA(h); /* Only IPV4 are valid us */ if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) return 0; if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifaddrmsg)); if (len < 0) return -1; memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); /* Fetch interface_t */ ifp = if_get_by_ifindex(ifa->ifa_index); if (!ifp) return 0; if (tb[IFA_LOCAL] == NULL) tb[IFA_LOCAL] = tb[IFA_ADDRESS]; if (tb[IFA_ADDRESS] == NULL) tb[IFA_ADDRESS] = tb[IFA_LOCAL]; /* local interface address */ addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); if (addr == NULL) return -1; /* If no address is set on interface then set the first time */ if (ifa->ifa_family == AF_INET) { if (!ifp->sin_addr.s_addr) ifp->sin_addr = *(struct in_addr *) addr; } else { if (!ifp->sin6_addr.s6_addr16[0] && ifa->ifa_scope == RT_SCOPE_LINK) ifp->sin6_addr = *(struct in6_addr *) addr; } #ifdef _WITH_LVS_ /* Refresh checkers state */ update_checker_activity(ifa->ifa_family, addr, (h->nlmsg_type == RTM_NEWADDR) ? 1 : 0); #endif return 0; }
void route_print(FILE *file, void *data) { ip_route_t *route = data; char *msg = MALLOC(150); char *tmp = MALLOC(30); if (route->blackhole) { strncat(msg, "blackhole ", 30); } if (route->dst) { snprintf(tmp, 30, "%s/%d", ipaddresstos(route->dst), route->dmask); strncat(msg, tmp, 30); } if (route->gw) { snprintf(tmp, 30, " gw %s", ipaddresstos(route->gw)); strncat(msg, tmp, 30); } if (route->gw2) { snprintf(tmp, 30, " or gw %s", ipaddresstos(route->gw2)); strncat(msg, tmp, 30); } if (route->src) { snprintf(tmp, 30, " src %s", ipaddresstos(route->src)); strncat(msg, tmp, 30); } if (route->index) { snprintf(tmp, 30, " dev %s", IF_NAME(if_get_by_ifindex(route->index))); strncat(msg, tmp, 30); } if (route->table) { snprintf(tmp, 30, " table %d", route->table); strncat(msg, tmp, 30); } if (route->scope) { snprintf(tmp, 30, " scope %s", netlink_scope_n2a(route->scope)); strncat(msg, tmp, 30); } if (route->metric) { snprintf(tmp, 30, " metric %d", route->metric); strncat(msg, tmp, 30); } fprintf(file, " %s\n", msg); FREE(tmp); FREE(msg); }
/* Netlink flag Link update */ static int netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; int len; ifi = NLMSG_DATA(h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Interface name lookup */ memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; /* ignore loopback device */ if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; /* find the VMAC interface (if any) */ ifp = if_get_by_vmac_base_ifindex(ifi->ifi_index); /* if found, reflect base interface flags on VMAC interface */ if (ifp) ifp->flags = ifi->ifi_flags; /* find the interface_t */ ifp = if_get_by_ifindex(ifi->ifi_index); if (!ifp) return -1; /* * Update flags. * VMAC interfaces should never update it own flags, only be reflected * by the base interface flags, see above. */ if (!ifp->vmac) ifp->flags = ifi->ifi_flags; return 0; }
int netlink_link_del_vmac(vrrp_t *vrrp) { int status = 1; interface_t *base_ifp ; struct { struct nlmsghdr n; struct ifinfomsg ifi; char buf[256]; } req; if (!vrrp->ifp) return -1; /* Reset arp_ignore and arp_filter on the base interface if necessary */ if (vrrp->family == AF_INET) { base_ifp = if_get_by_ifindex(vrrp->ifp->base_ifindex); if (base_ifp) reset_interface_parameters(base_ifp); else log_message(LOG_INFO, "Unable to find base interface for vrrp instance %s", vrrp->iname); } memset(&req, 0, sizeof (req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof (struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_DELLINK; req.ifi.ifi_family = AF_INET; req.ifi.ifi_index = vrrp->vmac_ifindex; if (netlink_talk(&nl_cmd, &req.n) < 0) { log_message(LOG_INFO, "vmac: Error removing VMAC interface %s for vrrp_instance %s!!!" , vrrp->vmac_ifname, vrrp->iname); return -1; } log_message(LOG_INFO, "vmac: Success removing VMAC interface %s for vrrp_instance %s" , vrrp->vmac_ifname, vrrp->iname); return status; }
/* Netlink flag Link update */ static int netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface *ifp; int len; ifi = NLMSG_DATA(h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Interface name lookup */ memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; /* ignore loopback device */ if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; /* find the interface */ ifp = if_get_by_ifindex(ifi->ifi_index); if (!ifp) return -1; /* Update flags */ ifp->flags = ifi->ifi_flags; return 0; }
static void dump_if(void *data) { interface_t *ifp = data; #ifdef _HAVE_VRRP_VMAC_ interface_t *ifp_u; #endif char addr_str[INET6_ADDRSTRLEN]; log_message(LOG_INFO, "------< NIC >------"); log_message(LOG_INFO, " Name = %s", ifp->ifname); log_message(LOG_INFO, " index = %d", ifp->ifindex); log_message(LOG_INFO, " IPv4 address = %s", inet_ntop2(ifp->sin_addr.s_addr)); inet_ntop(AF_INET6, &ifp->sin6_addr, addr_str, sizeof(addr_str)); log_message(LOG_INFO, " IPv6 address = %s", addr_str); /* FIXME: Hardcoded for ethernet */ if (ifp->hw_type == ARPHRD_ETHER) log_message(LOG_INFO, " MAC = %.2x:%.2x:%.2x:%.2x:%.2x:%.2x", ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2] , ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5]); if (ifp->flags & IFF_UP) log_message(LOG_INFO, " is UP"); if (ifp->flags & IFF_RUNNING) log_message(LOG_INFO, " is RUNNING"); if (!(ifp->flags & IFF_UP) && !(ifp->flags & IFF_RUNNING)) log_message(LOG_INFO, " is DOWN"); log_message(LOG_INFO, " MTU = %d", ifp->mtu); switch (ifp->hw_type) { case ARPHRD_LOOPBACK: log_message(LOG_INFO, " HW Type = LOOPBACK"); break; case ARPHRD_ETHER: log_message(LOG_INFO, " HW Type = ETHERNET"); break; default: log_message(LOG_INFO, " HW Type = UNKNOWN"); break; } #ifdef _HAVE_VRRP_VMAC_ if (ifp->vmac && (ifp_u = if_get_by_ifindex(ifp->base_ifindex))) log_message(LOG_INFO, " VMAC underlying interface = %s", ifp_u->ifname); #endif /* MII channel supported ? */ if (IF_MII_SUPPORTED(ifp)) log_message(LOG_INFO, " NIC support MII regs"); else if (IF_ETHTOOL_SUPPORTED(ifp)) log_message(LOG_INFO, " NIC support EHTTOOL GLINK interface"); else log_message(LOG_INFO, " Enabling NIC ioctl refresh polling"); if (ifp->garp_delay) { if (ifp->garp_delay->have_garp_interval) log_message(LOG_INFO, " Gratuitous ARP interval %ldms", ifp->garp_delay->garp_interval.tv_sec * 100 + ifp->garp_delay->garp_interval.tv_usec / (TIMER_HZ / 100)); if (ifp->garp_delay->have_gna_interval) log_message(LOG_INFO, " Gratuitous NA interval %ldms", ifp->garp_delay->gna_interval.tv_sec * 100 + ifp->garp_delay->gna_interval.tv_usec / (TIMER_HZ / 100)); if (ifp->garp_delay->aggregation_group) log_message(LOG_INFO, " Gratuitous ARP aggregation group %d", ifp->garp_delay->aggregation_group); } }
/* Netlink flag Link update */ static int netlink_reflect_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { struct ifinfomsg *ifi; struct rtattr *tb[IFLA_MAX + 1]; interface_t *ifp; int len, status; ifi = NLMSG_DATA(h); if (!(h->nlmsg_type == RTM_NEWLINK || h->nlmsg_type == RTM_DELLINK)) return 0; len = h->nlmsg_len - NLMSG_LENGTH(sizeof (struct ifinfomsg)); if (len < 0) return -1; /* Interface name lookup */ memset(tb, 0, sizeof (tb)); parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len); if (tb[IFLA_IFNAME] == NULL) return -1; /* ignore loopback device */ if (ifi->ifi_type == ARPHRD_LOOPBACK) return 0; /* 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 (h->nlmsg_type == RTM_NEWLINK) { char *name; 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_if_link_populate(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; } } /* * Update flags. * VMAC interfaces should never update it own flags, only be reflected * by the base interface flags. */ #ifdef _HAVE_VRRP_VMAC_ if (!ifp->vmac) #endif { #ifdef _HAVE_VRRP_VMAC_ if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags); #endif ifp->flags = ifi->ifi_flags; } return 0; }
/* Our netlink parser */ static int netlink_parse_info(int (*filter) (struct sockaddr_nl *, struct nlmsghdr *), nl_handle_t *nl, struct nlmsghdr *n) { int status; int ret = 0; int error; while (1) { char buf[4096]; struct iovec iov = { .iov_base = buf, .iov_len = sizeof buf }; struct sockaddr_nl snl; struct msghdr msg = { .msg_name = &snl, .msg_namelen = sizeof(snl), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0 }; struct nlmsghdr *h; status = recvmsg(nl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK || errno == EAGAIN) break; log_message(LOG_INFO, "Netlink: Received message overrun (%m)"); continue; } if (status == 0) { log_message(LOG_INFO, "Netlink: EOF"); return -1; } if (msg.msg_namelen != sizeof snl) { log_message(LOG_INFO, "Netlink: Sender address length error: length %d", msg.msg_namelen); return -1; } for (h = (struct nlmsghdr *) buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) { /* Finish of reading. */ if (h->nlmsg_type == NLMSG_DONE) return ret; /* Error handling. */ if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA(h); /* * If error == 0 then this is a netlink ACK. * return if not related to multipart message. */ if (err->error == 0) { if (!(h->nlmsg_flags & NLM_F_MULTI)) return 0; continue; } if (h->nlmsg_len < NLMSG_LENGTH(sizeof (struct nlmsgerr))) { log_message(LOG_INFO, "Netlink: error: message truncated"); return -1; } if (n && (err->error == -EEXIST) && ((n->nlmsg_type == RTM_NEWROUTE) || (n->nlmsg_type == RTM_NEWADDR))) return 0; /* If have more than one IPv4 address in the same CIDR * and the "primary" address is removed, unless promote_secondaries * is configured on the interface, all the "secondary" addresses * in the same CIDR are deleted */ if (n && err->error == -EADDRNOTAVAIL && n->nlmsg_type == RTM_DELADDR) { netlink_if_address_filter(NULL, n); if (!(h->nlmsg_flags & NLM_F_MULTI)) return 0; continue; } if (netlink_error_ignore != -err->error) log_message(LOG_INFO, "Netlink: error: %s, type=(%u), seq=%u, pid=%d", strerror(-err->error), err->msg.nlmsg_type, err->msg.nlmsg_seq, err->msg.nlmsg_pid); return -1; } /* Skip unsolicited messages from cmd channel */ if (nl != &nl_cmd && h->nlmsg_pid == nl_cmd.nl_pid) continue; error = (*filter) (&snl, h); if (error < 0) { log_message(LOG_INFO, "Netlink: filter function error"); ret = error; } } /* After error care. */ if (msg.msg_flags & MSG_TRUNC) { log_message(LOG_INFO, "Netlink: error: message truncated"); continue; } if (status) { log_message(LOG_INFO, "Netlink: error: data remnant size %d", status); return -1; } } return ret; } /* Out talk filter */ static int netlink_talk_filter(struct sockaddr_nl *snl, struct nlmsghdr *h) { log_message(LOG_INFO, "Netlink: ignoring message type 0x%04x", h->nlmsg_type); return 0; } /* send message to netlink kernel socket, then receive response */ int netlink_talk(nl_handle_t *nl, struct nlmsghdr *n) { int status; int ret, flags; struct sockaddr_nl snl; struct iovec iov = { .iov_base = n, .iov_len = n->nlmsg_len }; struct msghdr msg = { .msg_name = &snl, .msg_namelen = sizeof(snl), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0 }; memset(&snl, 0, sizeof snl); snl.nl_family = AF_NETLINK; n->nlmsg_seq = ++nl->seq; /* Request Netlink acknowledgement */ n->nlmsg_flags |= NLM_F_ACK; /* Send message to netlink interface. */ status = sendmsg(nl->fd, &msg, 0); if (status < 0) { log_message(LOG_INFO, "Netlink: sendmsg() error: %s", strerror(errno)); return -1; } /* Set blocking flag */ ret = netlink_set_block(nl, &flags); if (ret < 0) log_message(LOG_INFO, "Netlink: Warning, couldn't set " "blocking flag to netlink socket..."); status = netlink_parse_info(netlink_talk_filter, nl, n); /* Restore previous flags */ if (ret == 0) netlink_set_nonblock(nl, &flags); return status; } /* Fetch a specific type information from netlink kernel */ static int netlink_request(nl_handle_t *nl, int family, int type) { int status; struct sockaddr_nl snl; struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; /* Cleanup the room */ memset(&snl, 0, sizeof (snl)); snl.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof (req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = ++nl->seq; req.g.rtgen_family = family; status = sendto(nl->fd, (void *) &req, sizeof (req) , 0, (struct sockaddr *) &snl, sizeof (snl)); if (status < 0) { log_message(LOG_INFO, "Netlink: sendto() failed: %s", strerror(errno)); return -1; } return 0; } static int netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg *ifi) { char *name; int i; #ifdef _HAVE_VRRP_VMAC_ struct rtattr* linkinfo[IFLA_INFO_MAX+1]; struct rtattr* linkattr[IFLA_MACVLAN_MAX+1]; interface_t *ifp_base; #endif 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 (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; } } #ifdef _HAVE_VRRP_VMAC_ /* See if this interface is a MACVLAN of ours */ if (tb[IFLA_LINKINFO] && tb[IFLA_LINK]){ /* If appears that the value of *(int*)RTA_DATA(tb[IFLA_LINKINFO]) is 0x1000c * for macvlan. 0x10000 for nested data, or'ed with 0x0c for macvlan; * other values are 0x09 for vlan, 0x0b for bridge, 0x08 for tun, -1 for no * underlying interface. * * I can't find where in the kernel these values are set or defined, so use * the string as below. */ parse_rtattr_nested(linkinfo, IFLA_INFO_MAX, tb[IFLA_LINKINFO]); if (linkinfo[IFLA_INFO_KIND] && RTA_PAYLOAD(linkinfo[IFLA_INFO_KIND]) >= strlen(macvlan_ll_kind) && !strncmp(macvlan_ll_kind, RTA_DATA(linkinfo[IFLA_INFO_KIND]), strlen(macvlan_ll_kind)) && linkinfo[IFLA_INFO_DATA]) { parse_rtattr_nested(linkattr, IFLA_MACVLAN_MAX, linkinfo[IFLA_INFO_DATA]); if (linkattr[IFLA_MACVLAN_MODE] && *(int*)RTA_DATA(linkattr[IFLA_MACVLAN_MODE]) == MACVLAN_MODE_PRIVATE) { ifp->base_ifindex = *(int*)RTA_DATA(tb[IFLA_LINK]); ifp->vmac = true; } } } if (!ifp->vmac) #endif { #ifdef _HAVE_VRRP_VMAC_ if_vmac_reflect_flags(ifi->ifi_index, ifi->ifi_flags); #endif ifp->flags = ifi->ifi_flags; #ifdef _HAVE_VRRP_VMAC_ log_message(LOG_INFO, "Setting base index for %s to ifi_index %d", name, ifi->ifi_index); ifp->base_ifindex = ifi->ifi_index; #endif } #ifdef _HAVE_VRRP_VMAC_ else { if ((ifp_base = if_get_by_ifindex(ifp->base_ifindex))) ifp->flags = ifp_base->flags; } #endif return 1; }