aboutgitcodebugslistschat
path: root/netlink.c
diff options
context:
space:
mode:
authorStefano Brivio <sbrivio@redhat.com>2024-02-02 00:09:37 +0100
committerStefano Brivio <sbrivio@redhat.com>2024-02-09 13:24:33 +0100
commit6c7623d07bbd44d81beb4aa60b0a1de12b622630 (patch)
tree918337ec32c47da14a6a869355b4d7493385332d /netlink.c
parent322660b0b931e5fc1873659182559284e7a0946a (diff)
downloadpasst-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar.gz
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar.bz2
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar.lz
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar.xz
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.tar.zst
passt-6c7623d07bbd44d81beb4aa60b0a1de12b622630.zip
netlink: Add support to fetch default gateway from multipath routes
If the default route for a given IP version is a multipath one, instead of refusing to start because there's no RTA_GATEWAY attribute in the set returned by the kernel, we can just pick one of the paths. To make this somewhat less arbitrary, pick the path with the highest weight, if weights differ. Reported-by: Ed Santiago <santiago@redhat.com> Link: https://github.com/containers/podman/issues/20927 Signed-off-by: Stefano Brivio <sbrivio@redhat.com> Reviewed-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'netlink.c')
-rw-r--r--netlink.c51
1 files changed, 48 insertions, 3 deletions
diff --git a/netlink.c b/netlink.c
index bf79dd4..f0b04cb 100644
--- a/netlink.c
+++ b/netlink.c
@@ -271,12 +271,17 @@ unsigned int nl_get_ext_if(int s, sa_family_t af)
for (rta = RTM_RTA(rtm), na = RTM_PAYLOAD(nh); RTA_OK(rta, na);
rta = RTA_NEXT(rta, na)) {
- if (rta->rta_type != RTA_OIF)
- continue;
+ if (rta->rta_type == RTA_OIF) {
+ ifi = *(unsigned int *)RTA_DATA(rta);
+ } else if (rta->rta_type == RTA_MULTIPATH) {
+ struct rtnexthop *rtnh;
- ifi = *(unsigned int *)RTA_DATA(rta);
+ rtnh = (struct rtnexthop *)RTA_DATA(rta);
+ ifi = rtnh->rtnh_ifindex;
+ }
}
}
+
if (status < 0)
warn("netlink: RTM_GETROUTE failed: %s", strerror(-status));
@@ -284,6 +289,43 @@ unsigned int nl_get_ext_if(int s, sa_family_t af)
}
/**
+ * nl_route_get_def_multipath() - Get lowest-weight route from nexthop list
+ * @rta: Routing netlink attribute with type RTA_MULTIPATH
+ * @gw: Default gateway to fill
+ *
+ * Return: true if a gateway was found, false otherwise
+ */
+bool nl_route_get_def_multipath(struct rtattr *rta, void *gw)
+{
+ struct rtnexthop *rtnh;
+ bool found = false;
+ int hops = -1;
+
+ for (rtnh = (struct rtnexthop *)RTA_DATA(rta);
+ RTNH_OK(rtnh, RTA_PAYLOAD(rta)); rtnh = RTNH_NEXT(rtnh)) {
+ size_t len = rtnh->rtnh_len - sizeof(*rtnh);
+ struct rtattr *rta_inner;
+
+ if (rtnh->rtnh_hops < hops)
+ continue;
+
+ hops = rtnh->rtnh_hops;
+
+ for (rta_inner = RTNH_DATA(rtnh); RTA_OK(rta_inner, len);
+ rta_inner = RTA_NEXT(rta_inner, len)) {
+
+ if (rta_inner->rta_type != RTA_GATEWAY)
+ continue;
+
+ memcpy(gw, RTA_DATA(rta_inner), RTA_PAYLOAD(rta_inner));
+ found = true;
+ }
+ }
+
+ return found;
+}
+
+/**
* nl_route_get_def() - Get default route for given interface and address family
* @s: Netlink socket
* @ifi: Interface index
@@ -326,6 +368,9 @@ int nl_route_get_def(int s, unsigned int ifi, sa_family_t af, void *gw)
for (rta = RTM_RTA(rtm), na = RTM_PAYLOAD(nh); RTA_OK(rta, na);
rta = RTA_NEXT(rta, na)) {
+ if (rta->rta_type == RTA_MULTIPATH)
+ found = nl_route_get_def_multipath(rta, gw);
+
if (rta->rta_type != RTA_GATEWAY)
continue;