Author: hselasky
Date: Fri Sep  7 18:05:09 2018
New Revision: 338526
URL: https://svnweb.freebsd.org/changeset/base/338526

Log:
  Implement get network interface by params function in ipoib.
  
  Also fix the validate_ipv4_net_dev() and validate_ipv6_net_dev() functions
  which had source and destination addresses swapped, and didn't set the
  scope ID for IPv6 link-local addresses.
  
  This allows applications like krping to work using IPoIB devices.
  
  MFC after:            3 days
  Approved by:          re (gjb)
  Sponsored by:         Mellanox Technologies

Modified:
  head/sys/ofed/drivers/infiniband/core/ib_cma.c
  head/sys/ofed/drivers/infiniband/core/ib_roce_gid_mgmt.c
  head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c

Modified: head/sys/ofed/drivers/infiniband/core/ib_cma.c
==============================================================================
--- head/sys/ofed/drivers/infiniband/core/ib_cma.c      Fri Sep  7 15:52:20 
2018        (r338525)
+++ head/sys/ofed/drivers/infiniband/core/ib_cma.c      Fri Sep  7 18:05:09 
2018        (r338526)
@@ -1263,10 +1263,10 @@ static bool validate_ipv4_net_dev(struct net_device *n
                                  const struct sockaddr_in *src_addr)
 {
 #ifdef INET
-       struct sockaddr_in dst_tmp = *dst_addr;
+       struct sockaddr_in src_tmp = *src_addr;
        __be32 daddr = dst_addr->sin_addr.s_addr,
               saddr = src_addr->sin_addr.s_addr;
-       struct net_device *src_dev;
+       struct net_device *dst_dev;
        struct rtentry *rte;
        bool ret;
 
@@ -1276,29 +1276,29 @@ static bool validate_ipv4_net_dev(struct net_device *n
            ipv4_is_loopback(saddr))
                return false;
 
-       src_dev = ip_dev_find(net_dev->if_vnet, saddr);
-       if (src_dev != net_dev) {
-               if (src_dev != NULL)
-                       dev_put(src_dev);
+       dst_dev = ip_dev_find(net_dev->if_vnet, daddr);
+       if (dst_dev != net_dev) {
+               if (dst_dev != NULL)
+                       dev_put(dst_dev);
                return false;
        }
-       dev_put(src_dev);
+       dev_put(dst_dev);
 
        /*
         * Make sure the socket address length field
         * is set, else rtalloc1() will fail.
         */
-       dst_tmp.sin_len = sizeof(dst_tmp);
+       src_tmp.sin_len = sizeof(src_tmp);
 
        CURVNET_SET(net_dev->if_vnet);
-       rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
-       CURVNET_RESTORE();
+       rte = rtalloc1((struct sockaddr *)&src_tmp, 1, 0);
        if (rte != NULL) {
                ret = (rte->rt_ifp == net_dev);
                RTFREE_LOCKED(rte);
        } else {
                ret = false;
        }
+       CURVNET_RESTORE();
        return ret;
 #else
        return false;
@@ -1310,31 +1310,42 @@ static bool validate_ipv6_net_dev(struct net_device *n
                                  const struct sockaddr_in6 *src_addr)
 {
 #ifdef INET6
-       struct sockaddr_in6 dst_tmp = *dst_addr;
-       struct in6_addr in6_addr = src_addr->sin6_addr;
-       struct net_device *src_dev;
+       struct sockaddr_in6 src_tmp = *src_addr;
+       struct in6_addr in6_addr = dst_addr->sin6_addr;
+       struct net_device *dst_dev;
        struct rtentry *rte;
        bool ret;
 
-       src_dev = ip6_dev_find(net_dev->if_vnet, in6_addr);
-       if (src_dev != net_dev)
+       dst_dev = ip6_dev_find(net_dev->if_vnet, in6_addr);
+       if (dst_dev != net_dev) {
+               if (dst_dev != NULL)
+                       dev_put(dst_dev);
                return false;
+       }
 
+       CURVNET_SET(net_dev->if_vnet);
+
        /*
         * Make sure the socket address length field
         * is set, else rtalloc1() will fail.
         */
-       dst_tmp.sin6_len = sizeof(dst_tmp);
+       src_tmp.sin6_len = sizeof(src_tmp);
 
-       CURVNET_SET(net_dev->if_vnet);
-       rte = rtalloc1((struct sockaddr *)&dst_tmp, 1, 0);
-       CURVNET_RESTORE();
+       /*
+        * Make sure the scope ID gets embedded, else rtalloc1() will
+        * resolve to the loopback interface.
+        */
+       src_tmp.sin6_scope_id = net_dev->if_index;
+       sa6_embedscope(&src_tmp, 0);
+
+       rte = rtalloc1((struct sockaddr *)&src_tmp, 1, 0);
        if (rte != NULL) {
                ret = (rte->rt_ifp == net_dev);
                RTFREE_LOCKED(rte);
        } else {
                ret = false;
        }
+       CURVNET_RESTORE();
        return ret;
 #else
        return false;

Modified: head/sys/ofed/drivers/infiniband/core/ib_roce_gid_mgmt.c
==============================================================================
--- head/sys/ofed/drivers/infiniband/core/ib_roce_gid_mgmt.c    Fri Sep  7 
15:52:20 2018        (r338525)
+++ head/sys/ofed/drivers/infiniband/core/ib_roce_gid_mgmt.c    Fri Sep  7 
18:05:09 2018        (r338526)
@@ -149,16 +149,6 @@ roce_gid_enum_netdev_default(struct ib_device *ib_dev,
        return (hweight_long(gid_type_mask));
 }
 
-#define ETH_IPOIB_DRV_NAME     "ib"
-
-static inline int
-is_eth_ipoib_intf(struct net_device *dev)
-{
-       if (strcmp(dev->if_dname, ETH_IPOIB_DRV_NAME))
-               return 0;
-       return 1;
-}
-
 static void
 roce_gid_update_addr_callback(struct ib_device *device, u8 port,
     struct net_device *ndev, void *cookie)
@@ -322,15 +312,15 @@ roce_gid_queue_scan_event(struct net_device *ndev)
        struct roce_netdev_event_work *work;
 
 retry:
-       if (is_eth_ipoib_intf(ndev))
-               return;
-
-       if (ndev->if_type != IFT_ETHER) {
-               if (ndev->if_type == IFT_L2VLAN) {
-                       ndev = rdma_vlan_dev_real_dev(ndev);
-                       if (ndev != NULL)
-                               goto retry;
-               }
+       switch (ndev->if_type) {
+       case IFT_ETHER:
+               break;
+       case IFT_L2VLAN:
+               ndev = rdma_vlan_dev_real_dev(ndev);
+               if (ndev != NULL)
+                       goto retry;
+               /* FALLTHROUGH */
+       default:
                return;
        }
 

Modified: head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c
==============================================================================
--- head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c     Fri Sep  7 
15:52:20 2018        (r338525)
+++ head/sys/ofed/drivers/infiniband/ulp/ipoib/ipoib_main.c     Fri Sep  7 
18:05:09 2018        (r338526)
@@ -54,6 +54,8 @@ static        int ipoib_resolvemulti(struct ifnet *, struct s
 #include <net/ip.h>
 #include <net/ipv6.h>
 
+#include <rdma/ib_cache.h>
+
 MODULE_AUTHOR("Roland Dreier");
 MODULE_DESCRIPTION("IP-over-InfiniBand net driver");
 MODULE_LICENSE("Dual BSD/GPL");
@@ -90,6 +92,10 @@ struct ib_sa_client ipoib_sa_client;
 
 static void ipoib_add_one(struct ib_device *device);
 static void ipoib_remove_one(struct ib_device *device, void *client_data);
+static struct net_device *ipoib_get_net_dev_by_params(
+               struct ib_device *dev, u8 port, u16 pkey,
+               const union ib_gid *gid, const struct sockaddr *addr,
+               void *client_data);
 static void ipoib_start(struct ifnet *dev);
 static int ipoib_output(struct ifnet *ifp, struct mbuf *m,
            const struct sockaddr *dst, struct route *ro);
@@ -163,7 +169,8 @@ ipoib_mtap_proto(struct ifnet *ifp, struct mbuf *mb, u
 static struct ib_client ipoib_client = {
        .name   = "ipoib",
        .add    = ipoib_add_one,
-       .remove = ipoib_remove_one
+       .remove = ipoib_remove_one,
+       .get_net_dev_by_params = ipoib_get_net_dev_by_params,
 };
 
 int
@@ -1111,6 +1118,156 @@ ipoib_remove_one(struct ib_device *device, void *clien
        }
 
        kfree(dev_list);
+}
+
+static int
+ipoib_match_dev_addr(const struct sockaddr *addr, struct net_device *dev)
+{
+       struct ifaddr *ifa;
+       int retval = 0;
+
+       CURVNET_SET(dev->if_vnet);
+       IF_ADDR_RLOCK(dev);
+       CK_STAILQ_FOREACH(ifa, &dev->if_addrhead, ifa_link) {
+               if (ifa->ifa_addr == NULL ||
+                   ifa->ifa_addr->sa_family != addr->sa_family ||
+                   ifa->ifa_addr->sa_len != addr->sa_len) {
+                       continue;
+               }
+               if (memcmp(ifa->ifa_addr, addr, addr->sa_len) == 0) {
+                       retval = 1;
+                       break;
+               }
+       }
+       IF_ADDR_RUNLOCK(dev);
+       CURVNET_RESTORE();
+
+       return (retval);
+}
+
+/*
+ * ipoib_match_gid_pkey_addr - returns the number of IPoIB netdevs on
+ * top a given ipoib device matching a pkey_index and address, if one
+ * exists.
+ *
+ * @found_net_dev: contains a matching net_device if the return value
+ * >= 1, with a reference held.
+ */
+static int
+ipoib_match_gid_pkey_addr(struct ipoib_dev_priv *priv,
+    const union ib_gid *gid, u16 pkey_index, const struct sockaddr *addr,
+    struct net_device **found_net_dev)
+{
+       struct ipoib_dev_priv *child_priv;
+       int matches = 0;
+
+       if (priv->pkey_index == pkey_index &&
+           (!gid || !memcmp(gid, &priv->local_gid, sizeof(*gid)))) {
+               if (addr == NULL || ipoib_match_dev_addr(addr, priv->dev) != 0) 
{
+                       if (*found_net_dev == NULL) {
+                               struct net_device *net_dev;
+
+                               if (priv->parent != NULL)
+                                       net_dev = priv->parent;
+                               else
+                                       net_dev = priv->dev;
+                               *found_net_dev = net_dev;
+                               dev_hold(net_dev);
+                       }
+                       matches++;
+               }
+       }
+
+       /* Check child interfaces */
+       mutex_lock(&priv->vlan_mutex);
+       list_for_each_entry(child_priv, &priv->child_intfs, list) {
+               matches += ipoib_match_gid_pkey_addr(child_priv, gid,
+                   pkey_index, addr, found_net_dev);
+               if (matches > 1)
+                       break;
+       }
+       mutex_unlock(&priv->vlan_mutex);
+
+       return matches;
+}
+
+/*
+ * __ipoib_get_net_dev_by_params - returns the number of matching
+ * net_devs found (between 0 and 2). Also return the matching
+ * net_device in the @net_dev parameter, holding a reference to the
+ * net_device, if the number of matches >= 1
+ */
+static int
+__ipoib_get_net_dev_by_params(struct list_head *dev_list, u8 port,
+    u16 pkey_index, const union ib_gid *gid,
+    const struct sockaddr *addr, struct net_device **net_dev)
+{
+       struct ipoib_dev_priv *priv;
+       int matches = 0;
+
+       *net_dev = NULL;
+
+       list_for_each_entry(priv, dev_list, list) {
+               if (priv->port != port)
+                       continue;
+
+               matches += ipoib_match_gid_pkey_addr(priv, gid, pkey_index,
+                   addr, net_dev);
+
+               if (matches > 1)
+                       break;
+       }
+
+       return matches;
+}
+
+static struct net_device *
+ipoib_get_net_dev_by_params(struct ib_device *dev, u8 port, u16 pkey,
+    const union ib_gid *gid, const struct sockaddr *addr, void *client_data)
+{
+       struct net_device *net_dev;
+       struct list_head *dev_list = client_data;
+       u16 pkey_index;
+       int matches;
+       int ret;
+
+       if (!rdma_protocol_ib(dev, port))
+               return NULL;
+
+       ret = ib_find_cached_pkey(dev, port, pkey, &pkey_index);
+       if (ret)
+               return NULL;
+
+       if (!dev_list)
+               return NULL;
+
+       /* See if we can find a unique device matching the L2 parameters */
+       matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index,
+                                               gid, NULL, &net_dev);
+
+       switch (matches) {
+       case 0:
+               return NULL;
+       case 1:
+               return net_dev;
+       }
+
+       dev_put(net_dev);
+
+       /* Couldn't find a unique device with L2 parameters only. Use L3
+        * address to uniquely match the net device */
+       matches = __ipoib_get_net_dev_by_params(dev_list, port, pkey_index,
+                                               gid, addr, &net_dev);
+       switch (matches) {
+       case 0:
+               return NULL;
+       default:
+               dev_warn_ratelimited(&dev->dev,
+                                    "duplicate IP address detected\n");
+               /* Fall through */
+       case 1:
+               return net_dev;
+       }
 }
 
 static void
_______________________________________________
[email protected] mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[email protected]"

Reply via email to