Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

vmac: fix creation / deletion VMAC issue due to race conditions #2388

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 22 additions & 18 deletions keepalived/core/keepalived_netlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -1813,12 +1813,12 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
bool is_vrf = false;
uint32_t new_vrf_master_index;
bool is_vrf_master = false;
#endif
#endif
#endif /* _HAVE_VRF_ */
#endif /* _HAVE_VRRP_VMAC_ */

#ifdef _HAVE_VRRP_VMAC_
was_vlan = IS_MAC_IP_VLAN(ifp);
#endif
#endif /* _HAVE_VRRP_VMAC_ */

name = (char *)RTA_DATA(tb[IFLA_IFNAME]);

Expand All @@ -1827,10 +1827,10 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
ifp->ifindex = (ifindex_t)ifi->ifi_index;
#ifdef _HAVE_VRRP_VMAC_
ifp->if_type = IF_TYPE_STANDARD;
#endif
#endif /* _HAVE_VRRP_VMAC_ */
#ifdef HAVE_IFLA_LINK_NETNSID /* from Linux v4.0 */
ifp->base_netns_id = -1;
#endif
#endif /* HAVE_IFLA_LINK_NETNSID */

#ifdef _HAVE_VRRP_VMAC_
if (tb[IFLA_LINKINFO]) {
Expand All @@ -1848,7 +1848,7 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
ifp->if_type = IF_TYPE_IPVLAN;
parse_rtattr_nested(linkattr, IFLA_IPVLAN_MAX, linkinfo[IFLA_INFO_DATA]);
}
#endif
#endif /* _HAVE_VRRP_IPVLAN_ */
#ifdef _HAVE_VRF_
else if (!strcmp((char *)RTA_DATA(linkinfo[IFLA_INFO_KIND]), "vrf") ) {
is_vrf = true;
Expand All @@ -1857,14 +1857,14 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
if (vrf_attr[IFLA_VRF_TABLE])
ifp->vrf_tb_id = *PTR_CAST(uint32_t, RTA_DATA(vrf_attr[IFLA_VRF_TABLE]));
}
#endif
#endif /* _HAVE_VRF_ */
}
}

#ifdef _HAVE_IPV4_DEVCONF_
if (tb[IFLA_AF_SPEC])
parse_af_spec(tb[IFLA_AF_SPEC], ifp);
#endif
#endif /* _HAVE_IPV4_DEVCONF_ */

/* Check there hasn't been an unsupported interface type change */
if (!global_data->allow_if_changes && ifp->seen_interface) {
Expand All @@ -1875,10 +1875,12 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg

/* If a macvlan, check the underlying interface hasn't changed */
if (IS_MAC_IP_VLAN(ifp) &&
(!tb[IFLA_LINK] || ifp->base_ifp->ifindex != *PTR_CAST(uint32_t, RTA_DATA(tb[IFLA_LINK]))))
(!tb[IFLA_LINK] ||
(ifp->ifindex != ifp->base_ifp->ifindex &&
ifp->base_ifp->ifindex != *PTR_CAST(uint32_t, RTA_DATA(tb[IFLA_LINK])))))
return false;
}
#endif
#endif /* _HAVE_VRRP_VMAC_ */

ifp->mtu = *PTR_CAST(uint32_t, RTA_DATA(tb[IFLA_MTU]));
ifp->hw_type = ifi->ifi_type;
Expand All @@ -1901,7 +1903,7 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
if (((ifp->if_type == IF_TYPE_MACVLAN && linkattr[IFLA_MACVLAN_MODE])
#ifdef _HAVE_VRRP_IPVLAN_
|| (ifp->if_type == IF_TYPE_IPVLAN && linkattr[IFLA_IPVLAN_MODE])
#endif
#endif /* _HAVE_VRRP_IPVLAN_ */
) &&
tb[IFLA_LINK]) {
if (ifp->if_type == IF_TYPE_MACVLAN)
Expand All @@ -1911,15 +1913,15 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
ifp->vmac_type = *PTR_CAST(uint32_t, RTA_DATA(linkattr[IFLA_IPVLAN_MODE]));
#if HAVE_DECL_IFLA_IPVLAN_FLAGS
ifp->ipvlan_flags = *PTR_CAST(uint32_t, RTA_DATA(linkattr[IFLA_IPVLAN_FLAGS]));
#endif
#endif /* HAVE_DECL_IFLA_IPVLAN_FLAGS */
}
#endif
#endif /* _HAVE_VRRP_IPVLAN_ */
ifp->base_ifindex = *PTR_CAST(uint32_t, RTA_DATA(tb[IFLA_LINK]));
#ifdef HAVE_IFLA_LINK_NETNSID /* from Linux v4.0 */
if (tb[IFLA_LINK_NETNSID]) /* Only use link details if in same network namespace */
ifp->base_netns_id = *PTR_CAST(int32_t, RTA_DATA(tb[IFLA_LINK_NETNSID]));
else
#endif
#endif /* HAVE_IFLA_LINK_NETNSID */
{
ifp->base_ifp = if_get_by_ifindex(ifp->base_ifindex);
if (ifp->base_ifp)
Expand All @@ -1937,11 +1939,11 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
is_vrf_master = true;
}
}
#endif
#endif /* _HAVE_VRF_ */

#ifdef _FIXED_IF_TYPE_
if (strcmp(_FIXED_IF_TYPE_, (char *)RTA_DATA(linkinfo[IFLA_INFO_KIND])))
#endif
#endif /* _FIXED_IF_TYPE_ */
ifp->changeable_type = true;
}
}
Expand Down Expand Up @@ -1973,10 +1975,12 @@ netlink_if_link_populate(interface_t *ifp, struct rtattr *tb[], struct ifinfomsg
}
}
}
#endif
#endif /* _HAVE_VRF_ */

ifp->rp_filter = UINT_MAX; /* We have not read it yet */
#endif

ifp->cleaning = false;
#endif /* _HAVE_VRRP_VMAC_ */

ifp->ifi_flags = ifi->ifi_flags;
if (FLAGS_UP(ifi->ifi_flags))
Expand Down
1 change: 1 addition & 0 deletions keepalived/include/vrrp_if.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ typedef struct _interface {
otherwise the physical interface */
bool is_ours; /* keepalived created the interface */
bool deleting; /* Set when we are deleting the interface */
bool cleaning; /* Set when we are cleaning the interface */
bool seen_interface; /* The interface has existed at some point since we started */
bool changeable_type; /* The interface type or underlying interface can be changed */
#ifdef _HAVE_VRF_
Expand Down
12 changes: 12 additions & 0 deletions keepalived/vrrp/vrrp_if.c
Original file line number Diff line number Diff line change
Expand Up @@ -1394,6 +1394,11 @@ cleanup_lost_interface(interface_t *ifp)
tracking_obj_t *top;
vrrp_t *vrrp;

#ifdef _HAVE_VRRP_VMAC_
ifp->cleaning = true;
#endif /* _HAVE_VRRP_VMAC_ */


list_for_each_entry(top, &ifp->tracking_vrrp, e_list) {
vrrp = top->obj.vrrp;

Expand Down Expand Up @@ -1476,12 +1481,19 @@ cleanup_lost_interface(interface_t *ifp)

interface_down(ifp);

#ifdef _HAVE_VRRP_VMAC_
if (!ifp->cleaning)
/* interface has been refreshed. Do not clean */
return;
#endif /* _HAVE_VRRP_VMAC_ */

ifp->ifindex = 0;
ifp->ifi_flags = 0;
ifp->seen_up = false;
#ifdef _HAVE_VRRP_VMAC_
if (!ifp->is_ours)
ifp->base_ifp = ifp;
ifp->cleaning = false;
#endif
#ifdef _HAVE_VRF_
ifp->vrf_master_ifp = NULL;
Expand Down
Loading