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 <[email protected]> --- 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 --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); -- 2.47.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
