Add two new NLAs to support configuration of Infiniband node or port
GUIDs. New applications can choose to use this interface to configure
GUIDs with iproute2 with commands such as:

ip link set dev ib0 vf 0 node_guid 00:02:c9:03:00:21:6e:70
ip link set dev ib0 vf 0 port_guid 00:02:c9:03:00:21:6e:78

For backwards compatibility, old applications which set the MAC of a VF
may set the VF's port GUID for an infiniband port also via set MAC. The
GUID will be generated from the 6-byte MAC per IETF RFC 7042. Note that
when using set MAC to set a port GUID, the node GUID is set as well (to
the port guid value).

A new ndo, ndo_sef_vf_guid is introduced to notify the net device of the
request to change the GUID.

Signed-off-by: Eli Cohen <e...@mellanox.com>
---
 include/linux/netdevice.h    |  3 ++
 include/uapi/linux/if_link.h |  7 ++++
 net/core/rtnetlink.c         | 79 ++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 5440b7b705eb..7b4ae218b90b 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1147,6 +1147,9 @@ struct net_device_ops {
                                                   struct nlattr *port[]);
        int                     (*ndo_get_vf_port)(struct net_device *dev,
                                                   int vf, struct sk_buff *skb);
+       int                     (*ndo_set_vf_guid)(struct net_device *dev,
+                                                  int vf, u64 guid,
+                                                  int guid_type);
        int                     (*ndo_set_vf_rss_query_en)(
                                                   struct net_device *dev,
                                                   int vf, bool setting);
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index a30b78090594..1d01e8a4e5dd 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -556,6 +556,8 @@ enum {
                                 */
        IFLA_VF_STATS,          /* network device statistics */
        IFLA_VF_TRUST,          /* Trust VF */
+       IFLA_VF_IB_NODE_GUID,   /* VF Infiniband node GUID */
+       IFLA_VF_IB_PORT_GUID,   /* VF Infiniband port GUID */
        __IFLA_VF_MAX,
 };
 
@@ -588,6 +590,11 @@ struct ifla_vf_spoofchk {
        __u32 setting;
 };
 
+struct ifla_vf_guid {
+       __u32 vf;
+       __u64 guid;
+};
+
 enum {
        IFLA_VF_LINK_STATE_AUTO,        /* link state of the uplink */
        IFLA_VF_LINK_STATE_ENABLE,      /* link always up */
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index d735e854f916..9db6e5bde786 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -1387,6 +1387,8 @@ static const struct nla_policy 
ifla_vf_policy[IFLA_VF_MAX+1] = {
        [IFLA_VF_RSS_QUERY_EN]  = { .len = sizeof(struct ifla_vf_rss_query_en) 
},
        [IFLA_VF_STATS]         = { .type = NLA_NESTED },
        [IFLA_VF_TRUST]         = { .len = sizeof(struct ifla_vf_trust) },
+       [IFLA_VF_IB_NODE_GUID]  = { .len = sizeof(struct ifla_vf_guid) },
+       [IFLA_VF_IB_PORT_GUID]  = { .len = sizeof(struct ifla_vf_guid) },
 };
 
 static const struct nla_policy ifla_vf_stats_policy[IFLA_VF_STATS_MAX + 1] = {
@@ -1534,6 +1536,58 @@ static int validate_linkmsg(struct net_device *dev, 
struct nlattr *tb[])
        return 0;
 }
 
+static int handle_infiniband_guid(struct net_device *dev, struct ifla_vf_guid 
*ivt,
+                                 int guid_type)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       return ops->ndo_set_vf_guid(dev, ivt->vf, ivt->guid, guid_type);
+}
+
+static int handle_vf_guid(struct net_device *dev, struct ifla_vf_guid *ivt, 
int guid_type)
+{
+       if (dev->type != ARPHRD_INFINIBAND)
+               return -EOPNOTSUPP;
+
+       return handle_infiniband_guid(dev, ivt, guid_type);
+}
+
+static int handle_vf_mac(struct net_device *dev, struct ifla_vf_mac *ivm)
+{
+       const struct net_device_ops *ops = dev->netdev_ops;
+       struct ifla_vf_guid ivt;
+       u8 *s = ivm->mac;
+       u8 d[8];
+       int err;
+
+       if (dev->type != ARPHRD_INFINIBAND) {
+               if (!ops->ndo_set_vf_mac)
+                       return -EOPNOTSUPP;
+
+               return ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac);
+       }
+
+       if (!ops->ndo_set_vf_guid)
+               return -EOPNOTSUPP;
+
+       d[0] = s[0];
+       d[1] = s[1];
+       d[2] = s[2];
+       d[3] = 0xff;
+       d[4] = 0xfe;
+       d[5] = s[3];
+       d[6] = s[4];
+       d[7] = s[5];
+
+       ivt.vf = ivm->vf;
+       ivt.guid = be64_to_cpu(*(__be64 *)d);
+       err = handle_infiniband_guid(dev, &ivt, IFLA_VF_IB_NODE_GUID);
+       if (err)
+               return err;
+
+       return handle_infiniband_guid(dev, &ivt, IFLA_VF_IB_PORT_GUID);
+}
+
 static int do_setvfinfo(struct net_device *dev, struct nlattr **tb)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
@@ -1542,12 +1596,7 @@ static int do_setvfinfo(struct net_device *dev, struct 
nlattr **tb)
        if (tb[IFLA_VF_MAC]) {
                struct ifla_vf_mac *ivm = nla_data(tb[IFLA_VF_MAC]);
 
-               err = -EOPNOTSUPP;
-               if (ops->ndo_set_vf_mac)
-                       err = ops->ndo_set_vf_mac(dev, ivm->vf,
-                                                 ivm->mac);
-               if (err < 0)
-                       return err;
+               return handle_vf_mac(dev, ivm);
        }
 
        if (tb[IFLA_VF_VLAN]) {
@@ -1636,6 +1685,24 @@ static int do_setvfinfo(struct net_device *dev, struct 
nlattr **tb)
                        return err;
        }
 
+       if (tb[IFLA_VF_IB_NODE_GUID]) {
+               struct ifla_vf_guid *ivt = nla_data(tb[IFLA_VF_IB_NODE_GUID]);
+
+               if (!ops->ndo_set_vf_guid)
+                       return -EOPNOTSUPP;
+
+               return handle_vf_guid(dev, ivt, IFLA_VF_IB_NODE_GUID);
+       }
+
+       if (tb[IFLA_VF_IB_PORT_GUID]) {
+               struct ifla_vf_guid *ivt = nla_data(tb[IFLA_VF_IB_PORT_GUID]);
+
+               if (!ops->ndo_set_vf_guid)
+                       return -EOPNOTSUPP;
+
+               return handle_vf_guid(dev, ivt, IFLA_VF_IB_PORT_GUID);
+       }
+
        return err;
 }
 
-- 
Cc: netdev@vger.kernel.org
1.8.3.1

Reply via email to