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

Reply via email to