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

📄 ipoib_multicast.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2004, 2005 Topspin Communications.  All rights reserved. * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. * Copyright (c) 2004 Voltaire, Inc. 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. * * $Id: ipoib_multicast.c 1362 2004-12-18 15:56:29Z roland $ */#include <linux/skbuff.h>#include <linux/rtnetlink.h>#include <linux/ip.h>#include <linux/in.h>#include <linux/igmp.h>#include <linux/inetdevice.h>#include <linux/delay.h>#include <linux/completion.h>#include "ipoib.h"#ifdef CONFIG_INFINIBAND_IPOIB_DEBUGstatic int mcast_debug_level;module_param(mcast_debug_level, int, 0644);MODULE_PARM_DESC(mcast_debug_level,		 "Enable multicast debug tracing if > 0");#endifstatic DECLARE_MUTEX(mcast_mutex);/* Used for all multicast joins (broadcast, IPv4 mcast and IPv6 mcast) */struct ipoib_mcast {	struct ib_sa_mcmember_rec mcmember;	struct ipoib_ah          *ah;	struct rb_node    rb_node;	struct list_head  list;	struct completion done;	int                 query_id;	struct ib_sa_query *query;	unsigned long created;	unsigned long backoff;	unsigned long flags;	unsigned char logcount;	struct list_head  neigh_list;	struct sk_buff_head pkt_queue;	struct net_device *dev;};struct ipoib_mcast_iter {	struct net_device *dev;	union ib_gid       mgid;	unsigned long      created;	unsigned int       queuelen;	unsigned int       complete;	unsigned int       send_only;};static void ipoib_mcast_free(struct ipoib_mcast *mcast){	struct net_device *dev = mcast->dev;	struct ipoib_dev_priv *priv = netdev_priv(dev);	struct ipoib_neigh *neigh, *tmp;	unsigned long flags;	LIST_HEAD(ah_list);	struct ipoib_ah *ah, *tah;	ipoib_dbg_mcast(netdev_priv(dev),			"deleting multicast group " IPOIB_GID_FMT "\n",			IPOIB_GID_ARG(mcast->mcmember.mgid));	spin_lock_irqsave(&priv->lock, flags);	list_for_each_entry_safe(neigh, tmp, &mcast->neigh_list, list) {		if (neigh->ah)			list_add_tail(&neigh->ah->list, &ah_list);		*to_ipoib_neigh(neigh->neighbour) = NULL;		neigh->neighbour->ops->destructor = NULL;		kfree(neigh);	}	spin_unlock_irqrestore(&priv->lock, flags);	list_for_each_entry_safe(ah, tah, &ah_list, list)		ipoib_put_ah(ah);	if (mcast->ah)		ipoib_put_ah(mcast->ah);	while (!skb_queue_empty(&mcast->pkt_queue))		dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));	kfree(mcast);}static struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev,					     int can_sleep){	struct ipoib_mcast *mcast;	mcast = kzalloc(sizeof *mcast, can_sleep ? GFP_KERNEL : GFP_ATOMIC);	if (!mcast)		return NULL;	mcast->dev = dev;	mcast->created = jiffies;	mcast->backoff = 1;	INIT_LIST_HEAD(&mcast->list);	INIT_LIST_HEAD(&mcast->neigh_list);	skb_queue_head_init(&mcast->pkt_queue);	return mcast;}static struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, union ib_gid *mgid){	struct ipoib_dev_priv *priv = netdev_priv(dev);	struct rb_node *n = priv->multicast_tree.rb_node;	while (n) {		struct ipoib_mcast *mcast;		int ret;		mcast = rb_entry(n, struct ipoib_mcast, rb_node);		ret = memcmp(mgid->raw, mcast->mcmember.mgid.raw,			     sizeof (union ib_gid));		if (ret < 0)			n = n->rb_left;		else if (ret > 0)			n = n->rb_right;		else			return mcast;	}	return NULL;}static int __ipoib_mcast_add(struct net_device *dev, struct ipoib_mcast *mcast){	struct ipoib_dev_priv *priv = netdev_priv(dev);	struct rb_node **n = &priv->multicast_tree.rb_node, *pn = NULL;	while (*n) {		struct ipoib_mcast *tmcast;		int ret;		pn = *n;		tmcast = rb_entry(pn, struct ipoib_mcast, rb_node);		ret = memcmp(mcast->mcmember.mgid.raw, tmcast->mcmember.mgid.raw,			     sizeof (union ib_gid));		if (ret < 0)			n = &pn->rb_left;		else if (ret > 0)			n = &pn->rb_right;		else			return -EEXIST;	}	rb_link_node(&mcast->rb_node, pn, n);	rb_insert_color(&mcast->rb_node, &priv->multicast_tree);	return 0;}static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,				   struct ib_sa_mcmember_rec *mcmember){	struct net_device *dev = mcast->dev;	struct ipoib_dev_priv *priv = netdev_priv(dev);	int ret;	mcast->mcmember = *mcmember;	/* Set the cached Q_Key before we attach if it's the broadcast group */	if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4,		    sizeof (union ib_gid))) {		priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey);		priv->tx_wr.wr.ud.remote_qkey = priv->qkey;	}	if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {		if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {			ipoib_warn(priv, "multicast group " IPOIB_GID_FMT				   " already attached\n",				   IPOIB_GID_ARG(mcast->mcmember.mgid));			return 0;		}		ret = ipoib_mcast_attach(dev, be16_to_cpu(mcast->mcmember.mlid),					 &mcast->mcmember.mgid);		if (ret < 0) {			ipoib_warn(priv, "couldn't attach QP to multicast group "				   IPOIB_GID_FMT "\n",				   IPOIB_GID_ARG(mcast->mcmember.mgid));			clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags);			return ret;		}	}	{		struct ib_ah_attr av = {			.dlid	       = be16_to_cpu(mcast->mcmember.mlid),			.port_num      = priv->port,			.sl	       = mcast->mcmember.sl,			.ah_flags      = IB_AH_GRH,			.grh	       = {				.flow_label    = be32_to_cpu(mcast->mcmember.flow_label),				.hop_limit     = mcast->mcmember.hop_limit,				.sgid_index    = 0,				.traffic_class = mcast->mcmember.traffic_class			}		};		int path_rate = ib_sa_rate_enum_to_int(mcast->mcmember.rate);		av.grh.dgid = mcast->mcmember.mgid;		if (path_rate > 0 && priv->local_rate > path_rate)			av.static_rate = (priv->local_rate - 1) / path_rate;		ipoib_dbg_mcast(priv, "static_rate %d for local port %dX, mcmember %dX\n",				av.static_rate, priv->local_rate,				ib_sa_rate_enum_to_int(mcast->mcmember.rate));		mcast->ah = ipoib_create_ah(dev, priv->pd, &av);		if (!mcast->ah) {			ipoib_warn(priv, "ib_address_create failed\n");		} else {			ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT					" AV %p, LID 0x%04x, SL %d\n",					IPOIB_GID_ARG(mcast->mcmember.mgid),					mcast->ah->ah,					be16_to_cpu(mcast->mcmember.mlid),					mcast->mcmember.sl);		}	}	/* actually send any queued packets */	while (!skb_queue_empty(&mcast->pkt_queue)) {		struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue);		skb->dev = dev;		if (!skb->dst || !skb->dst->neighbour) {			/* put pseudoheader back on for next time */			skb_push(skb, sizeof (struct ipoib_pseudoheader));		}		if (dev_queue_xmit(skb))			ipoib_warn(priv, "dev_queue_xmit failed to requeue packet\n");	}	return 0;}static voidipoib_mcast_sendonly_join_complete(int status,				   struct ib_sa_mcmember_rec *mcmember,				   void *mcast_ptr){	struct ipoib_mcast *mcast = mcast_ptr;	struct net_device *dev = mcast->dev;	if (!status)		ipoib_mcast_join_finish(mcast, mcmember);	else {		if (mcast->logcount++ < 20)			ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for "					IPOIB_GID_FMT ", status %d\n",					IPOIB_GID_ARG(mcast->mcmember.mgid), status);		/* Flush out any queued packets */		while (!skb_queue_empty(&mcast->pkt_queue))			dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));		/* Clear the busy flag so we try again */		clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);	}	complete(&mcast->done);}static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast){	struct net_device *dev = mcast->dev;	struct ipoib_dev_priv *priv = netdev_priv(dev);	struct ib_sa_mcmember_rec rec = {#if 0				/* Some SMs don't support send-only yet */		.join_state = 4#else		.join_state = 1#endif	};	int ret = 0;	if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) {		ipoib_dbg_mcast(priv, "device shutting down, no multicast joins\n");		return -ENODEV;	}	if (test_and_set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) {		ipoib_dbg_mcast(priv, "multicast entry busy, skipping\n");		return -EBUSY;	}	rec.mgid     = mcast->mcmember.mgid;	rec.port_gid = priv->local_gid;	rec.pkey     = cpu_to_be16(priv->pkey);	init_completion(&mcast->done);	ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec,				     IB_SA_MCMEMBER_REC_MGID		|				     IB_SA_MCMEMBER_REC_PORT_GID	|				     IB_SA_MCMEMBER_REC_PKEY		|				     IB_SA_MCMEMBER_REC_JOIN_STATE,				     1000, GFP_ATOMIC,				     ipoib_mcast_sendonly_join_complete,				     mcast, &mcast->query);	if (ret < 0) {		ipoib_warn(priv, "ib_sa_mcmember_rec_set failed (ret = %d)\n",			   ret);	} else {		ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT				", starting join\n",				IPOIB_GID_ARG(mcast->mcmember.mgid));		mcast->query_id = ret;	}	return ret;}static void ipoib_mcast_join_complete(int status,				      struct ib_sa_mcmember_rec *mcmember,				      void *mcast_ptr){	struct ipoib_mcast *mcast = mcast_ptr;	struct net_device *dev = mcast->dev;	struct ipoib_dev_priv *priv = netdev_priv(dev);	ipoib_dbg_mcast(priv, "join completion for " IPOIB_GID_FMT			" (status %d)\n",			IPOIB_GID_ARG(mcast->mcmember.mgid), status);	if (!status && !ipoib_mcast_join_finish(mcast, mcmember)) {		mcast->backoff = 1;		down(&mcast_mutex);		if (test_bit(IPOIB_MCAST_RUN, &priv->flags))			queue_work(ipoib_workqueue, &priv->mcast_task);		up(&mcast_mutex);		complete(&mcast->done);		return;	}	if (status == -EINTR) {		complete(&mcast->done);		return;	}	if (status && mcast->logcount++ < 20) {		if (status == -ETIMEDOUT || status == -EINTR) {			ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT					", status %d\n",					IPOIB_GID_ARG(mcast->mcmember.mgid),					status);		} else {			ipoib_warn(priv, "multicast join failed for "				   IPOIB_GID_FMT ", status %d\n",				   IPOIB_GID_ARG(mcast->mcmember.mgid),				   status);		}	}	mcast->backoff *= 2;	if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)		mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;	mcast->query = NULL;	down(&mcast_mutex);	if (test_bit(IPOIB_MCAST_RUN, &priv->flags)) {		if (status == -ETIMEDOUT)			queue_work(ipoib_workqueue, &priv->mcast_task);		else			queue_delayed_work(ipoib_workqueue, &priv->mcast_task,					   mcast->backoff * HZ);	} else		complete(&mcast->done);	up(&mcast_mutex);	return;}static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,			     int create){	struct ipoib_dev_priv *priv = netdev_priv(dev);	struct ib_sa_mcmember_rec rec = {		.join_state = 1	};	ib_sa_comp_mask comp_mask;	int ret = 0;	ipoib_dbg_mcast(priv, "joining MGID " IPOIB_GID_FMT "\n",			IPOIB_GID_ARG(mcast->mcmember.mgid));	rec.mgid     = mcast->mcmember.mgid;	rec.port_gid = priv->local_gid;	rec.pkey     = cpu_to_be16(priv->pkey);	comp_mask =		IB_SA_MCMEMBER_REC_MGID		|		IB_SA_MCMEMBER_REC_PORT_GID	|		IB_SA_MCMEMBER_REC_PKEY		|		IB_SA_MCMEMBER_REC_JOIN_STATE;	if (create) {		comp_mask |=			IB_SA_MCMEMBER_REC_QKEY		|			IB_SA_MCMEMBER_REC_SL		|			IB_SA_MCMEMBER_REC_FLOW_LABEL	|			IB_SA_MCMEMBER_REC_TRAFFIC_CLASS;		rec.qkey	  = priv->broadcast->mcmember.qkey;		rec.sl		  = priv->broadcast->mcmember.sl;		rec.flow_label	  = priv->broadcast->mcmember.flow_label;		rec.traffic_class = priv->broadcast->mcmember.traffic_class;	}	init_completion(&mcast->done);	ret = ib_sa_mcmember_rec_set(priv->ca, priv->port, &rec, comp_mask,				     mcast->backoff * 1000, GFP_ATOMIC,				     ipoib_mcast_join_complete,				     mcast, &mcast->query);	if (ret < 0) {		ipoib_warn(priv, "ib_sa_mcmember_rec_set failed, status %d\n", ret);		mcast->backoff *= 2;		if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)			mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;		down(&mcast_mutex);		if (test_bit(IPOIB_MCAST_RUN, &priv->flags))			queue_delayed_work(ipoib_workqueue,					   &priv->mcast_task,					   mcast->backoff * HZ);		up(&mcast_mutex);	} else		mcast->query_id = ret;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -