diff mbox series

[ovs-dev,v2,6/6] route-table: Support network namespaces.

Message ID ae0e6bfd8de70097c3333ec6885bdf57875e807a.1732630344.git.felix.huettner@stackit.cloud
State Changes Requested
Delegated to: Eelco Chaudron
Headers show
Series OVS Patches for OVN Fabric Integration | expand

Checks

Context Check Description
ovsrobot/apply-robot warning apply and check: warning

Commit Message

Felix Huettner Nov. 26, 2024, 2:37 p.m. UTC
When dumping a routing table from a network namespace we can not lookup
interface names using if_indextoname. In these cases we switch to using a
netlink request.

Signed-off-by: Felix Huettner <felix.huettner@stackit.cloud>
---
v1->v2: complete rework to now translate ifindex also to ifname in
        network namespaces

 lib/route-table.c        | 75 +++++++++++++++++++++++++++++++++-------
 tests/automake.mk        |  1 +
 tests/system-library.at  | 13 +++++++
 tests/test-route-table.c | 43 +++++++++++++++++++++++
 4 files changed, 119 insertions(+), 13 deletions(-)
 create mode 100644 tests/test-route-table.c
diff mbox series

Patch

diff --git a/lib/route-table.c b/lib/route-table.c
index 06e391184..f28e08995 100644
--- a/lib/route-table.c
+++ b/lib/route-table.c
@@ -203,12 +203,57 @@  route_table_reset(void)
     }
 }
 
+static int
+route_table_index_to_name(uint32_t ifindex, const char *netns,
+                          char ifname[IFNAMSIZ])
+{
+    if (!ifindex) {
+        return false;
+    }
+    if (netns) {
+        struct rtnetlink_change rtnl_change;
+        struct ifinfomsg *ifinfo;
+        struct ofpbuf request;
+        struct ofpbuf *reply;
+        int err;
+
+        ofpbuf_init(&request, 0);
+        nl_msg_put_nlmsghdr(&request,
+                            sizeof(struct ifinfomsg),
+                            RTM_GETLINK, NLM_F_REQUEST);
+        ifinfo = ofpbuf_put_zeros(&request, sizeof(struct ifinfomsg));
+        ifinfo->ifi_index = ifindex;
+
+        err = nl_ns_transact(netns, NETLINK_ROUTE, &request, &reply);
+        if (err != 0) {
+            ofpbuf_uninit(&request);
+            return err;
+        }
+        if (!rtnetlink_parse(reply, &rtnl_change)) {
+            ofpbuf_uninit(&request);
+            ofpbuf_delete(reply);
+            return -1;
+        }
+        ovs_strlcpy(ifname, rtnl_change.ifname, IFNAMSIZ);
+        ofpbuf_uninit(&request);
+        ofpbuf_delete(reply);
+    } else {
+        if (!if_indextoname(ifindex, ifname)) {
+            return errno;
+        }
+    }
+    return 0;
+}
+
 static bool
 route_table_add_nexthop(struct route_table_msg *change,
                         bool ipv4,
                         struct nlattr *nl_gw,
-                        uint32_t ifindex)
+                        uint32_t ifindex,
+                        const char *netns)
 {
+    int err;
+
     if (change->rd.n_nexthops >= MAX_ROUTE_DATA_NEXTHOP) {
         VLOG_DBG("tried to add more nexthops to a route than possible");
         return false;
@@ -227,12 +272,11 @@  route_table_add_nexthop(struct route_table_msg *change,
         }
     }
 
-    if (ifindex && !if_indextoname(ifindex, nh->ifname)) {
-        int error = errno;
-
+    err = route_table_index_to_name(ifindex, netns, nh->ifname);
+    if (err != 0) {
         VLOG_DBG_RL(&rl, "Could not find interface name[%u]: %s",
-                    ifindex, ovs_strerror(error));
-        if (error == ENXIO) {
+                    ifindex, ovs_strerror(err));
+        if (err == ENXIO) {
             change->relevant = false;
         } else {
             return false;
@@ -255,7 +299,7 @@  route_table_add_nexthop(struct route_table_msg *change,
 static bool
 route_table_parse_multipath(struct route_table_msg *change,
                             struct nlattr *multipath,
-                            bool ipv4)
+                            bool ipv4, const char *netns)
 {
     static const struct nl_policy policy[] = {
         [RTA_GATEWAY] = { .type = NL_A_U32, .optional = true },
@@ -287,12 +331,15 @@  route_table_parse_multipath(struct route_table_msg *change,
         }
 
         if (!parsed) {
-            VLOG_DBG_RL(&rl, "received unparseable rtnetlink route message");
+            VLOG_DBG_RL(&rl, "received unparseable rtnetlink multipath "
+                             "nexthop");
             return false;
         }
 
         if (!route_table_add_nexthop(change, ipv4, attrs[RTA_GATEWAY],
-                                     rtnh->rtnh_ifindex)) {
+                                     rtnh->rtnh_ifindex, netns)) {
+            VLOG_DBG_RL(&rl, "received unparseable rtnetlink multipath "
+                             "nexthop");
             return false;
         }
 
@@ -310,8 +357,7 @@  route_table_parse_multipath(struct route_table_msg *change,
 /* Return RTNLGRP_IPV4_ROUTE or RTNLGRP_IPV6_ROUTE on success, 0 on parse
  * error. */
 int
-route_table_parse_ns(struct ofpbuf *buf, void *change_,
-                     const char *netns OVS_UNUSED)
+route_table_parse_ns(struct ofpbuf *buf, void *change_, const char *netns)
 {
     struct route_table_msg *change = change_;
     bool parsed, ipv4 = false;
@@ -426,12 +472,15 @@  route_table_parse_ns(struct ofpbuf *buf, void *change_,
                 ifindex = nl_attr_get_u32(attrs[RTA_OIF]);
             }
             if (!route_table_add_nexthop(change, ipv4, attrs[RTA_GATEWAY],
-                                         ifindex)) {
+                                         ifindex, netns)) {
+                VLOG_DBG_RL(&rl, "received unparseable route nexthop");
                 return 0;
             }
         } else if (attrs[RTA_MULTIPATH]) {
             if (!route_table_parse_multipath(change,
-                                             attrs[RTA_MULTIPATH], ipv4)) {
+                                             attrs[RTA_MULTIPATH], ipv4,
+                                             netns)) {
+                VLOG_DBG_RL(&rl, "received unparseable route multipath");
                 return 0;
             }
         }
diff --git a/tests/automake.mk b/tests/automake.mk
index abb0d352c..f0756f98e 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -502,6 +502,7 @@  tests_ovstest_SOURCES += \
 	tests/test-netlink-conntrack.c \
 	tests/test-netlink-policy.c \
 	tests/test-netlink-socket.c \
+	tests/test-route-table.c \
 	tests/test-psample.c
 endif
 
diff --git a/tests/system-library.at b/tests/system-library.at
index de7f2178f..cc36efe94 100644
--- a/tests/system-library.at
+++ b/tests/system-library.at
@@ -8,3 +8,16 @@  NS_EXEC([ns1337], [ip link add vrf1337 type vrf table 1337])
 AT_CHECK([ovstest test-netlink-socket], [0])
 AT_CLEANUP
 
+AT_SETUP([route table])
+AT_SKIP_IF([test "$IS_WIN32" = "yes"])
+AT_SKIP_IF([test "$IS_BSD" = "yes"])
+ADD_NAMESPACES([ns1337])
+NS_EXEC([ns1337], [ip link set lo up])
+NS_EXEC([ns1337], [ip link add br-test type bridge])
+NS_EXEC([ns1337], [ip link set br-test up])
+NS_EXEC([ns1337], [ip addr add 192.168.0.10/24 dev br-test])
+NS_EXEC([ns1337], [ip route add 172.16.0.0/16 via 192.168.0.1])
+NS_EXEC([ns1337], [ip route add 172.17.0.0/16 nexthop via 192.168.0.1 nexthop via 127.0.0.1])
+AT_CHECK([ovstest test-route-table], [0])
+AT_CLEANUP
+
diff --git a/tests/test-route-table.c b/tests/test-route-table.c
new file mode 100644
index 000000000..1c72cc718
--- /dev/null
+++ b/tests/test-route-table.c
@@ -0,0 +1,43 @@ 
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+
+#include "route-table.h"
+#include "ovstest.h"
+
+static void
+count_br_test(const struct route_table_msg *msg, void *data)
+{
+    int *count = data;
+    if (msg->rd.plen != 16) {
+        return;
+    }
+
+    for (int i = 0; i < msg->rd.n_nexthops; i++) {
+        if (!strcmp(msg->rd.nexthops[i].ifname, "br-test")) {
+            *count = *count + 1;
+        }
+    }
+}
+
+static void
+test_route_table_main(int argc OVS_UNUSED, char *argv[] OVS_UNUSED)
+{
+    int count = 0;
+    route_table_dump_one_table("ns1337", 0, count_br_test, &count);
+    ovs_assert(count == 2);
+}
+
+OVSTEST_REGISTER("test-route-table", test_route_table_main);