📄 ipoib_main.c
字号:
__skb_queue_tail(&skqueue, skb); } } path->query = NULL; complete(&path->done); spin_unlock_irqrestore(&priv->lock, flags); while ((skb = __skb_dequeue(&skqueue))) { skb->dev = dev; if (dev_queue_xmit(skb)) ipoib_warn(priv, "dev_queue_xmit failed " "to requeue packet\n"); }}static struct ipoib_path *path_rec_create(struct net_device *dev, void *gid){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; if (!priv->broadcast) return NULL; path = kzalloc(sizeof *path, GFP_ATOMIC); if (!path) return NULL; path->dev = dev; skb_queue_head_init(&path->queue); INIT_LIST_HEAD(&path->neigh_list); memcpy(path->pathrec.dgid.raw, gid, sizeof (union ib_gid)); path->pathrec.sgid = priv->local_gid; path->pathrec.pkey = cpu_to_be16(priv->pkey); path->pathrec.numb_path = 1; path->pathrec.traffic_class = priv->broadcast->mcmember.traffic_class; return path;}static int path_rec_start(struct net_device *dev, struct ipoib_path *path){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n", IPOIB_GID_ARG(path->pathrec.dgid)); init_completion(&path->done); path->query_id = ib_sa_path_rec_get(&ipoib_sa_client, priv->ca, priv->port, &path->pathrec, IB_SA_PATH_REC_DGID | IB_SA_PATH_REC_SGID | IB_SA_PATH_REC_NUMB_PATH | IB_SA_PATH_REC_TRAFFIC_CLASS | IB_SA_PATH_REC_PKEY, 1000, GFP_ATOMIC, path_rec_completion, path, &path->query); if (path->query_id < 0) { ipoib_warn(priv, "ib_sa_path_rec_get failed\n"); path->query = NULL; return path->query_id; } return 0;}static void neigh_add_path(struct sk_buff *skb, struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; struct ipoib_neigh *neigh; neigh = ipoib_neigh_alloc(skb->dst->neighbour, skb->dev); if (!neigh) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); return; } /* * We can only be called from ipoib_start_xmit, so we're * inside tx_lock -- no need to save/restore flags. */ spin_lock(&priv->lock); path = __path_find(dev, skb->dst->neighbour->ha + 4); if (!path) { path = path_rec_create(dev, skb->dst->neighbour->ha + 4); if (!path) goto err_path; __path_add(dev, path); } list_add_tail(&neigh->list, &path->neigh_list); if (path->ah) { kref_get(&path->ah->ref); neigh->ah = path->ah; memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, sizeof(union ib_gid)); if (ipoib_cm_enabled(dev, neigh->neighbour)) { if (!ipoib_cm_get(neigh)) ipoib_cm_set(neigh, ipoib_cm_create_tx(dev, path, neigh)); if (!ipoib_cm_get(neigh)) { list_del(&neigh->list); if (neigh->ah) ipoib_put_ah(neigh->ah); ipoib_neigh_free(dev, neigh); goto err_drop; } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) __skb_queue_tail(&neigh->queue, skb); else { ipoib_warn(priv, "queue length limit %d. Packet drop.\n", skb_queue_len(&neigh->queue)); goto err_drop; } } else ipoib_send(dev, skb, path->ah, IPOIB_QPN(skb->dst->neighbour->ha)); } else { neigh->ah = NULL; if (!path->query && path_rec_start(dev, path)) goto err_list; __skb_queue_tail(&neigh->queue, skb); } spin_unlock(&priv->lock); return;err_list: list_del(&neigh->list);err_path: ipoib_neigh_free(dev, neigh);err_drop: ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); spin_unlock(&priv->lock);}static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(skb->dev); /* Look up path record for unicasts */ if (skb->dst->neighbour->ha[4] != 0xff) { neigh_add_path(skb, dev); return; } /* Add in the P_Key for multicasts */ skb->dst->neighbour->ha[8] = (priv->pkey >> 8) & 0xff; skb->dst->neighbour->ha[9] = priv->pkey & 0xff; ipoib_mcast_send(dev, skb->dst->neighbour->ha + 4, skb);}static void unicast_arp_send(struct sk_buff *skb, struct net_device *dev, struct ipoib_pseudoheader *phdr){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path; /* * We can only be called from ipoib_start_xmit, so we're * inside tx_lock -- no need to save/restore flags. */ spin_lock(&priv->lock); path = __path_find(dev, phdr->hwaddr + 4); if (!path) { path = path_rec_create(dev, phdr->hwaddr + 4); if (path) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); if (path_rec_start(dev, path)) { spin_unlock(&priv->lock); path_free(dev, path); return; } else __path_add(dev, path); } else { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } spin_unlock(&priv->lock); return; } if (path->ah) { ipoib_dbg(priv, "Send unicast ARP to %04x\n", be16_to_cpu(path->pathrec.dlid)); ipoib_send(dev, skb, path->ah, IPOIB_QPN(phdr->hwaddr)); } else if ((path->query || !path_rec_start(dev, path)) && skb_queue_len(&path->queue) < IPOIB_MAX_PATH_REC_QUEUE) { /* put pseudoheader back on for next time */ skb_push(skb, sizeof *phdr); __skb_queue_tail(&path->queue, skb); } else { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } spin_unlock(&priv->lock);}static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh; unsigned long flags; if (unlikely(!spin_trylock_irqsave(&priv->tx_lock, flags))) return NETDEV_TX_LOCKED; /* * Check if our queue is stopped. Since we have the LLTX bit * set, we can't rely on netif_stop_queue() preventing our * xmit function from being called with a full queue. */ if (unlikely(netif_queue_stopped(dev))) { spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_BUSY; } if (likely(skb->dst && skb->dst->neighbour)) { if (unlikely(!*to_ipoib_neigh(skb->dst->neighbour))) { ipoib_path_lookup(skb, dev); goto out; } neigh = *to_ipoib_neigh(skb->dst->neighbour); if (ipoib_cm_get(neigh)) { if (ipoib_cm_up(neigh)) { ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); goto out; } } else if (neigh->ah) { if (unlikely((memcmp(&neigh->dgid.raw, skb->dst->neighbour->ha + 4, sizeof(union ib_gid))) || (neigh->dev != dev))) { spin_lock(&priv->lock); /* * It's safe to call ipoib_put_ah() inside * priv->lock here, because we know that * path->ah will always hold one more reference, * so ipoib_put_ah() will never do more than * decrement the ref count. */ ipoib_put_ah(neigh->ah); list_del(&neigh->list); ipoib_neigh_free(dev, neigh); spin_unlock(&priv->lock); ipoib_path_lookup(skb, dev); goto out; } ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(skb->dst->neighbour->ha)); goto out; } if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { spin_lock(&priv->lock); __skb_queue_tail(&neigh->queue, skb); spin_unlock(&priv->lock); } else { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } } else { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb->data; skb_pull(skb, sizeof *phdr); if (phdr->hwaddr[4] == 0xff) { /* Add in the P_Key for multicast*/ phdr->hwaddr[8] = (priv->pkey >> 8) & 0xff; phdr->hwaddr[9] = priv->pkey & 0xff; ipoib_mcast_send(dev, phdr->hwaddr + 4, skb); } else { /* unicast GID -- should be ARP or RARP reply */ if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x " IPOIB_GID_FMT "\n", skb->dst ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; goto out; } unicast_arp_send(skb, dev, phdr); } }out: spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_OK;}static void ipoib_timeout(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_warn(priv, "transmit timeout: latency %d msecs\n", jiffies_to_msecs(jiffies - dev->trans_start)); ipoib_warn(priv, "queue stopped %d, tx_head %u, tx_tail %u\n", netif_queue_stopped(dev), priv->tx_head, priv->tx_tail); /* XXX reset QP, etc. */}static int ipoib_hard_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned len){ struct ipoib_header *header; header = (struct ipoib_header *) skb_push(skb, sizeof *header); header->proto = htons(type); header->reserved = 0; /* * If we don't have a neighbour structure, stuff the * destination address onto the front of the skb so we can * figure out where to send the packet later. */ if ((!skb->dst || !skb->dst->neighbour) && daddr) { struct ipoib_pseudoheader *phdr = (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); memcpy(phdr->hwaddr, daddr, INFINIBAND_ALEN); } return 0;}static void ipoib_set_mcast_list(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { ipoib_dbg(priv, "IPOIB_FLAG_OPER_UP not set"); return; } queue_work(ipoib_workqueue, &priv->restart_task);}static void ipoib_neigh_cleanup(struct neighbour *n){ struct ipoib_neigh *neigh; struct ipoib_dev_priv *priv = netdev_priv(n->dev); unsigned long flags; struct ipoib_ah *ah = NULL; neigh = *to_ipoib_neigh(n); if (neigh) { priv = netdev_priv(neigh->dev); ipoib_dbg(priv, "neigh_destructor for bonding device: %s\n", n->dev->name); } else return; ipoib_dbg(priv, "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", IPOIB_QPN(n->ha), IPOIB_GID_RAW_ARG(n->ha + 4)); spin_lock_irqsave(&priv->lock, flags); if (neigh->ah) ah = neigh->ah; list_del(&neigh->list); ipoib_neigh_free(n->dev, neigh); spin_unlock_irqrestore(&priv->lock, flags); if (ah) ipoib_put_ah(ah);}struct ipoib_neigh *ipoib_neigh_alloc(struct neighbour *neighbour, struct net_device *dev){ struct ipoib_neigh *neigh; neigh = kmalloc(sizeof *neigh, GFP_ATOMIC); if (!neigh) return NULL; neigh->neighbour = neighbour; neigh->dev = dev; *to_ipoib_neigh(neighbour) = neigh; skb_queue_head_init(&neigh->queue); ipoib_cm_set(neigh, NULL); return neigh;}void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh){ struct sk_buff *skb; *to_ipoib_neigh(neigh->neighbour) = NULL; while ((skb = __skb_dequeue(&neigh->queue))) { ++dev->stats.tx_dropped; dev_kfree_skb_any(skb); } if (ipoib_cm_get(neigh)) ipoib_cm_destroy_tx(ipoib_cm_get(neigh)); kfree(neigh);}static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms){ parms->neigh_cleanup = ipoib_neigh_cleanup;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -