This commit adds the ability for a netdev that has namespace details to provide the namespace IDs to a caller. These netns identifiers are relative, but are useful in the context of the inet diag interfaces when attempting to retrieve the sock inode details.
Signed-off-by: Aaron Conole <[email protected]> --- lib/netdev-linux.c | 83 +++++++++++++++++++++++++++++++++++ lib/netdev-provider.h | 9 ++++ lib/netdev.c | 12 +++++ lib/netdev.h | 2 + utilities/checkpatch_dict.txt | 3 ++ 5 files changed, 109 insertions(+) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index a63d03d484..8e96041814 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -96,6 +96,10 @@ COVERAGE_DEFINE(netdev_linux_unknown_l4_csum); #ifndef IFLA_IF_NETNSID #define IFLA_IF_NETNSID 0x45 #endif + +#ifndef IFLA_NET_NS_ID +#define IFLA_NET_NS_ID 46 +#endif /* These were introduced in Linux 2.6.14, so they might be missing if we have * old headers. */ #ifndef ADVERTISED_Pause @@ -3761,6 +3765,84 @@ netdev_linux_arp_lookup(const struct netdev *netdev, return retval; } +static int +netdev_linux_get_netns_id_by_ifindex(int ifindex, int *netns_id, + int *link_netns_id) +{ + static const struct nl_policy policy[IFLA_MAX + 1] = { + [IFLA_NET_NS_ID] = { .type = NL_A_U32, .optional = true }, + [IFLA_LINK_NETNSID] = { .type = NL_A_U32, .optional = true }, + }; + struct ofpbuf request, *reply = NULL; + struct nlattr *attrs[IFLA_MAX + 1]; + struct ifinfomsg *ifi; + int error; + + /* Build RTM_GETLINK request for the specific ifindex */ + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, 0, RTM_GETLINK, NLM_F_REQUEST); + ifi = ofpbuf_put_zeros(&request, sizeof *ifi); + ifi->ifi_family = AF_UNSPEC; + ifi->ifi_index = ifindex; + + error = nl_transact(NETLINK_ROUTE, &request, &reply); + ofpbuf_uninit(&request); + + if (error) { + return error; + } + + if (netns_id) { + /* Assume it is the current namespace. */ + *netns_id = NETNSID_LOCAL; + } + + if (link_netns_id) { + /* Assume it is the current namespace. */ + *link_netns_id = NETNSID_LOCAL; + } + + /* Parse the response */ + if (!nl_policy_parse(reply, NLMSG_HDRLEN + sizeof(struct ifinfomsg), + policy, attrs, IFLA_MAX)) { + VLOG_WARN_RL(&rl, "Failed to parse rtnl class."); + error = EPROTO; + goto out; + } + + if (attrs[IFLA_NET_NS_ID] && netns_id) { + *netns_id = (int) nl_attr_get_u32(attrs[IFLA_NET_NS_ID]); + } + if (attrs[IFLA_LINK_NETNSID] && link_netns_id) { + *link_netns_id = (int) nl_attr_get_u32(attrs[IFLA_LINK_NETNSID]); + } + +out: + ofpbuf_delete(reply); + return error; +} + +static int +netdev_linux_get_target_ns(const struct netdev *netdev, int *target_ns) +{ + int contained_ns, linked_ns; + int ifindex; + int error; + + error = get_ifindex(netdev, &ifindex); + + if (error) { + return EOPNOTSUPP; + } + + error = netdev_linux_get_netns_id_by_ifindex(ifindex, &contained_ns, + &linked_ns); + if (!error) { + *target_ns = linked_ns; + } + return error; +} + static unsigned int nd_to_iff_flags(enum netdev_flags nd) { @@ -3874,6 +3956,7 @@ exit: .add_router = netdev_linux_add_router, \ .get_next_hop = netdev_linux_get_next_hop, \ .arp_lookup = netdev_linux_arp_lookup, \ + .get_target_ns = netdev_linux_get_target_ns, \ .update_flags = netdev_linux_update_flags, \ .rxq_alloc = netdev_linux_rxq_alloc, \ .rxq_dealloc = netdev_linux_rxq_dealloc, \ diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h index 5ae3794699..589c53842f 100644 --- a/lib/netdev-provider.h +++ b/lib/netdev-provider.h @@ -775,6 +775,15 @@ struct netdev_class { int (*arp_lookup)(const struct netdev *netdev, ovs_be32 ip, struct eth_addr *mac); + /* Retrieves the target network namespace ID for 'netdev'. On success, + * stores the namespace ID in '*target_ns' and returns 0. The namespace + * ID follows the same semantics as netnsid.h (NETNSID_LOCAL for local + * namespace, positive values for remote namespaces). + * + * This function may be set to null if it would always return EOPNOTSUPP + * anyhow. */ + int (*get_target_ns)(const struct netdev *netdev, int *target_ns); + /* Retrieves the current set of flags on 'netdev' into '*old_flags'. Then, * turns off the flags that are set to 1 in 'off' and turns on the flags * that are set to 1 in 'on'. (No bit will be set to 1 in both 'off' and diff --git a/lib/netdev.c b/lib/netdev.c index df5b35232d..501c48bb36 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -1659,6 +1659,18 @@ netdev_arp_lookup(const struct netdev *netdev, return error; } +/* Retrieves the target network namespace ID for 'netdev'. On success, stores + * the namespace ID in '*target_ns' and returns 0. The namespace ID follows + * the same semantics as netnsid.h (NETNSID_LOCAL for local namespace, + * positive values for remote namespaces). */ +int +netdev_get_target_ns(const struct netdev *netdev, int *target_ns) +{ + return (netdev->netdev_class->get_target_ns + ? netdev->netdev_class->get_target_ns(netdev, target_ns) + : EOPNOTSUPP); +} + /* Returns true if carrier is active (link light is on) on 'netdev'. */ bool netdev_get_carrier(const struct netdev *netdev) diff --git a/lib/netdev.h b/lib/netdev.h index 63e03d72db..e2c5630cc6 100644 --- a/lib/netdev.h +++ b/lib/netdev.h @@ -300,6 +300,8 @@ int netdev_get_status(const struct netdev *, struct smap *); int netdev_arp_lookup(const struct netdev *, ovs_be32 ip, struct eth_addr *mac); +int netdev_get_target_ns(const struct netdev *, int *target_ns); + struct netdev *netdev_find_dev_by_in4(const struct in_addr *); /* Statistics. */ diff --git a/utilities/checkpatch_dict.txt b/utilities/checkpatch_dict.txt index 13f107246b..b131290adc 100644 --- a/utilities/checkpatch_dict.txt +++ b/utilities/checkpatch_dict.txt @@ -51,6 +51,7 @@ dest dhcp dhcpv4 dhcpv6 +diag dnat dns dpcls @@ -107,6 +108,7 @@ icmpv6 idl ifdef ifindex +inet initializer inlined int @@ -177,6 +179,7 @@ netdev netdevs netflow netlink +netns networkmanager nic nicira -- 2.51.0 _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
