⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ipoib_main.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 3 页
字号:
				__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 + -