u32 cqe_bcnt,
                                         struct sk_buff *skb)
 {
-       struct net_device *netdev = rq->netdev;
+       struct net_device *netdev;
        char *pseudo_header;
+       u32 qpn;
        u8 *dgid;
        u8 g;
 
+       qpn = be32_to_cpu(cqe->sop_drop_qpn) & 0xffffff;
+       netdev = mlx5i_pkey_get_netdev(rq->netdev, qpn);
+
+       /* No mapping present, cannot process SKB. This might happen if a child
+        * interface is going down while having unprocessed CQEs on parent RQ
+        */
+       if (unlikely(!netdev)) {
+               /* TODO: add drop counters support */
+               skb->dev = NULL;
+               pr_warn_once("Unable to map QPN %u to dev - dropping skb\n", qpn);
+               return;
+       }
+
        g = (be32_to_cpu(cqe->flags_rqpn) >> 28) & 3;
        dgid = skb->data + MLX5_IB_GRH_DGID_OFFSET;
        if ((!g) || dgid[0] != 0xff)
                goto wq_free_wqe;
 
        mlx5i_complete_rx_cqe(rq, cqe, cqe_bcnt, skb);
+       if (unlikely(!skb->dev)) {
+               dev_kfree_skb_any(skb);
+               goto wq_free_wqe;
+       }
        napi_gro_receive(rq->cq.napi, skb);
 
 wq_free_wqe:
 
        dev->dev_addr[2] = (ipriv->qp.qpn >>  8) & 0xff;
        dev->dev_addr[3] = (ipriv->qp.qpn) & 0xff;
 
+       /* Add QPN to net-device mapping to HT */
+       mlx5i_pkey_add_qpn(dev ,ipriv->qp.qpn);
+
        return 0;
 }
 
 static void mlx5i_dev_cleanup(struct net_device *dev)
 {
        struct mlx5e_priv    *priv   = mlx5i_epriv(dev);
+       struct mlx5i_priv    *ipriv = priv->ppriv;
 
        mlx5i_uninit_underlay_qp(priv);
+
+       /* Delete QPN to net-device mapping from HT */
+       mlx5i_pkey_del_qpn(dev, ipriv->qp.qpn);
 }
 
 static int mlx5i_open(struct net_device *netdev)
        if (!epriv->wq)
                goto err_free_netdev;
 
+       err = mlx5i_pkey_qpn_ht_init(netdev);
+       if (err) {
+               mlx5_core_warn(mdev, "allocate qpn_to_netdev ht failed\n");
+               goto destroy_wq;
+       }
+
        profile->init(mdev, netdev, profile, ipriv);
 
        mlx5e_attach_netdev(epriv);
 
        return netdev;
 
+destroy_wq:
+       destroy_workqueue(epriv->wq);
 err_free_netdev:
        free_netdev(netdev);
 free_mdev_resources:
        mlx5e_detach_netdev(priv);
        profile->cleanup(priv);
        destroy_workqueue(priv->wq);
+       mlx5i_pkey_qpn_ht_cleanup(netdev);
        free_netdev(netdev);
 
        mlx5e_destroy_mdev_resources(mdev);
 
--- /dev/null
+/*
+ * Copyright (c) 2017, Mellanox Technologies. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/hash.h>
+#include "ipoib.h"
+
+#define MLX5I_MAX_LOG_PKEY_SUP 7
+
+struct qpn_to_netdev {
+       struct net_device *netdev;
+       struct hlist_node hlist;
+       u32 underlay_qpn;
+};
+
+struct mlx5i_pkey_qpn_ht {
+       struct hlist_head buckets[1 << MLX5I_MAX_LOG_PKEY_SUP];
+       spinlock_t ht_lock; /* Synchronise with NAPI */
+};
+
+int mlx5i_pkey_qpn_ht_init(struct net_device *netdev)
+{
+       struct mlx5i_priv *ipriv = netdev_priv(netdev);
+       struct mlx5i_pkey_qpn_ht *qpn_htbl;
+
+       qpn_htbl = kzalloc(sizeof(*qpn_htbl), GFP_KERNEL);
+       if (!qpn_htbl)
+               return -ENOMEM;
+
+       ipriv->qpn_htbl = qpn_htbl;
+       spin_lock_init(&qpn_htbl->ht_lock);
+
+       return 0;
+}
+
+void mlx5i_pkey_qpn_ht_cleanup(struct net_device *netdev)
+{
+       struct mlx5i_priv *ipriv = netdev_priv(netdev);
+
+       kfree(ipriv->qpn_htbl);
+}
+
+static struct qpn_to_netdev *mlx5i_find_qpn_to_netdev_node(struct hlist_head *buckets,
+                                                          u32 qpn)
+{
+       struct hlist_head *h = &buckets[hash_32(qpn, MLX5I_MAX_LOG_PKEY_SUP)];
+       struct qpn_to_netdev *node;
+
+       hlist_for_each_entry(node, h, hlist) {
+               if (node->underlay_qpn == qpn)
+                       return node;
+       }
+
+       return NULL;
+}
+
+int mlx5i_pkey_add_qpn(struct net_device *netdev, u32 qpn)
+{
+       struct mlx5i_priv *ipriv = netdev_priv(netdev);
+       struct mlx5i_pkey_qpn_ht *ht = ipriv->qpn_htbl;
+       u8 key = hash_32(qpn, MLX5I_MAX_LOG_PKEY_SUP);
+       struct qpn_to_netdev *new_node;
+
+       new_node = kzalloc(sizeof(*new_node), GFP_KERNEL);
+       if (!new_node)
+               return -ENOMEM;
+
+       new_node->netdev = netdev;
+       new_node->underlay_qpn = qpn;
+       spin_lock_bh(&ht->ht_lock);
+       hlist_add_head(&new_node->hlist, &ht->buckets[key]);
+       spin_unlock_bh(&ht->ht_lock);
+
+       return 0;
+}
+
+int mlx5i_pkey_del_qpn(struct net_device *netdev, u32 qpn)
+{
+       struct mlx5e_priv *epriv = mlx5i_epriv(netdev);
+       struct mlx5i_priv *ipriv = epriv->ppriv;
+       struct mlx5i_pkey_qpn_ht *ht = ipriv->qpn_htbl;
+       struct qpn_to_netdev *node;
+
+       node = mlx5i_find_qpn_to_netdev_node(ht->buckets, qpn);
+       if (!node) {
+               mlx5_core_warn(epriv->mdev, "QPN to netdev delete from HT failed\n");
+               return -EINVAL;
+       }
+
+       spin_lock_bh(&ht->ht_lock);
+       hlist_del_init(&node->hlist);
+       spin_unlock_bh(&ht->ht_lock);
+       kfree(node);
+
+       return 0;
+}
+
+struct net_device *mlx5i_pkey_get_netdev(struct net_device *netdev, u32 qpn)
+{
+       struct mlx5i_priv *ipriv = netdev_priv(netdev);
+       struct qpn_to_netdev *node;
+
+       node = mlx5i_find_qpn_to_netdev_node(ipriv->qpn_htbl->buckets, qpn);
+       if (!node)
+               return NULL;
+
+       return node->netdev;
+}