162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Communications. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2004 Voltaire, Inc. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/skbuff.h> 3662306a36Sopenharmony_ci#include <linux/rtnetlink.h> 3762306a36Sopenharmony_ci#include <linux/moduleparam.h> 3862306a36Sopenharmony_ci#include <linux/ip.h> 3962306a36Sopenharmony_ci#include <linux/in.h> 4062306a36Sopenharmony_ci#include <linux/igmp.h> 4162306a36Sopenharmony_ci#include <linux/inetdevice.h> 4262306a36Sopenharmony_ci#include <linux/delay.h> 4362306a36Sopenharmony_ci#include <linux/completion.h> 4462306a36Sopenharmony_ci#include <linux/slab.h> 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#include <net/dst.h> 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#include "ipoib.h" 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 5162306a36Sopenharmony_cistatic int mcast_debug_level; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cimodule_param(mcast_debug_level, int, 0644); 5462306a36Sopenharmony_ciMODULE_PARM_DESC(mcast_debug_level, 5562306a36Sopenharmony_ci "Enable multicast debug tracing if > 0"); 5662306a36Sopenharmony_ci#endif 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistruct ipoib_mcast_iter { 5962306a36Sopenharmony_ci struct net_device *dev; 6062306a36Sopenharmony_ci union ib_gid mgid; 6162306a36Sopenharmony_ci unsigned long created; 6262306a36Sopenharmony_ci unsigned int queuelen; 6362306a36Sopenharmony_ci unsigned int complete; 6462306a36Sopenharmony_ci unsigned int send_only; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci/* join state that allows creating mcg with sendonly member request */ 6862306a36Sopenharmony_ci#define SENDONLY_FULLMEMBER_JOIN 8 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci/* 7162306a36Sopenharmony_ci * This should be called with the priv->lock held 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic void __ipoib_mcast_schedule_join_thread(struct ipoib_dev_priv *priv, 7462306a36Sopenharmony_ci struct ipoib_mcast *mcast, 7562306a36Sopenharmony_ci bool delay) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 7862306a36Sopenharmony_ci return; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci /* 8162306a36Sopenharmony_ci * We will be scheduling *something*, so cancel whatever is 8262306a36Sopenharmony_ci * currently scheduled first 8362306a36Sopenharmony_ci */ 8462306a36Sopenharmony_ci cancel_delayed_work(&priv->mcast_task); 8562306a36Sopenharmony_ci if (mcast && delay) { 8662306a36Sopenharmony_ci /* 8762306a36Sopenharmony_ci * We had a failure and want to schedule a retry later 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_ci mcast->backoff *= 2; 9062306a36Sopenharmony_ci if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS) 9162306a36Sopenharmony_ci mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS; 9262306a36Sopenharmony_ci mcast->delay_until = jiffies + (mcast->backoff * HZ); 9362306a36Sopenharmony_ci /* 9462306a36Sopenharmony_ci * Mark this mcast for its delay, but restart the 9562306a36Sopenharmony_ci * task immediately. The join task will make sure to 9662306a36Sopenharmony_ci * clear out all entries without delays, and then 9762306a36Sopenharmony_ci * schedule itself to run again when the earliest 9862306a36Sopenharmony_ci * delay expires 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->mcast_task, 0); 10162306a36Sopenharmony_ci } else if (delay) { 10262306a36Sopenharmony_ci /* 10362306a36Sopenharmony_ci * Special case of retrying after a failure to 10462306a36Sopenharmony_ci * allocate the broadcast multicast group, wait 10562306a36Sopenharmony_ci * 1 second and try again 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->mcast_task, HZ); 10862306a36Sopenharmony_ci } else 10962306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->mcast_task, 0); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic void ipoib_mcast_free(struct ipoib_mcast *mcast) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci struct net_device *dev = mcast->dev; 11562306a36Sopenharmony_ci int tx_dropped = 0; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci ipoib_dbg_mcast(ipoib_priv(dev), "deleting multicast group %pI6\n", 11862306a36Sopenharmony_ci mcast->mcmember.mgid.raw); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* remove all neigh connected to this mcast */ 12162306a36Sopenharmony_ci ipoib_del_neighs_by_gid(dev, mcast->mcmember.mgid.raw); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (mcast->ah) 12462306a36Sopenharmony_ci ipoib_put_ah(mcast->ah); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci while (!skb_queue_empty(&mcast->pkt_queue)) { 12762306a36Sopenharmony_ci ++tx_dropped; 12862306a36Sopenharmony_ci dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci netif_tx_lock_bh(dev); 13262306a36Sopenharmony_ci dev->stats.tx_dropped += tx_dropped; 13362306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci kfree(mcast); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic struct ipoib_mcast *ipoib_mcast_alloc(struct net_device *dev) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct ipoib_mcast *mcast; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci mcast = kzalloc(sizeof(*mcast), GFP_ATOMIC); 14362306a36Sopenharmony_ci if (!mcast) 14462306a36Sopenharmony_ci return NULL; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci mcast->dev = dev; 14762306a36Sopenharmony_ci mcast->created = jiffies; 14862306a36Sopenharmony_ci mcast->delay_until = jiffies; 14962306a36Sopenharmony_ci mcast->backoff = 1; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci INIT_LIST_HEAD(&mcast->list); 15262306a36Sopenharmony_ci INIT_LIST_HEAD(&mcast->neigh_list); 15362306a36Sopenharmony_ci skb_queue_head_init(&mcast->pkt_queue); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci return mcast; 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic struct ipoib_mcast *__ipoib_mcast_find(struct net_device *dev, void *mgid) 15962306a36Sopenharmony_ci{ 16062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 16162306a36Sopenharmony_ci struct rb_node *n = priv->multicast_tree.rb_node; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci while (n) { 16462306a36Sopenharmony_ci struct ipoib_mcast *mcast; 16562306a36Sopenharmony_ci int ret; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mcast = rb_entry(n, struct ipoib_mcast, rb_node); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci ret = memcmp(mgid, mcast->mcmember.mgid.raw, 17062306a36Sopenharmony_ci sizeof (union ib_gid)); 17162306a36Sopenharmony_ci if (ret < 0) 17262306a36Sopenharmony_ci n = n->rb_left; 17362306a36Sopenharmony_ci else if (ret > 0) 17462306a36Sopenharmony_ci n = n->rb_right; 17562306a36Sopenharmony_ci else 17662306a36Sopenharmony_ci return mcast; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return NULL; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_cistatic int __ipoib_mcast_add(struct net_device *dev, struct ipoib_mcast *mcast) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 18562306a36Sopenharmony_ci struct rb_node **n = &priv->multicast_tree.rb_node, *pn = NULL; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci while (*n) { 18862306a36Sopenharmony_ci struct ipoib_mcast *tmcast; 18962306a36Sopenharmony_ci int ret; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci pn = *n; 19262306a36Sopenharmony_ci tmcast = rb_entry(pn, struct ipoib_mcast, rb_node); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci ret = memcmp(mcast->mcmember.mgid.raw, tmcast->mcmember.mgid.raw, 19562306a36Sopenharmony_ci sizeof (union ib_gid)); 19662306a36Sopenharmony_ci if (ret < 0) 19762306a36Sopenharmony_ci n = &pn->rb_left; 19862306a36Sopenharmony_ci else if (ret > 0) 19962306a36Sopenharmony_ci n = &pn->rb_right; 20062306a36Sopenharmony_ci else 20162306a36Sopenharmony_ci return -EEXIST; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rb_link_node(&mcast->rb_node, pn, n); 20562306a36Sopenharmony_ci rb_insert_color(&mcast->rb_node, &priv->multicast_tree); 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci return 0; 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, 21162306a36Sopenharmony_ci struct ib_sa_mcmember_rec *mcmember) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct net_device *dev = mcast->dev; 21462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 21562306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 21662306a36Sopenharmony_ci struct ipoib_ah *ah; 21762306a36Sopenharmony_ci struct rdma_ah_attr av; 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci int set_qkey = 0; 22062306a36Sopenharmony_ci int mtu; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci mcast->mcmember = *mcmember; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Set the multicast MTU and cached Q_Key before we attach if it's 22562306a36Sopenharmony_ci * the broadcast group. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci if (!memcmp(mcast->mcmember.mgid.raw, priv->dev->broadcast + 4, 22862306a36Sopenharmony_ci sizeof (union ib_gid))) { 22962306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 23062306a36Sopenharmony_ci if (!priv->broadcast) { 23162306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 23262306a36Sopenharmony_ci return -EAGAIN; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci /*update priv member according to the new mcast*/ 23562306a36Sopenharmony_ci priv->broadcast->mcmember.qkey = mcmember->qkey; 23662306a36Sopenharmony_ci priv->broadcast->mcmember.mtu = mcmember->mtu; 23762306a36Sopenharmony_ci priv->broadcast->mcmember.traffic_class = mcmember->traffic_class; 23862306a36Sopenharmony_ci priv->broadcast->mcmember.rate = mcmember->rate; 23962306a36Sopenharmony_ci priv->broadcast->mcmember.sl = mcmember->sl; 24062306a36Sopenharmony_ci priv->broadcast->mcmember.flow_label = mcmember->flow_label; 24162306a36Sopenharmony_ci priv->broadcast->mcmember.hop_limit = mcmember->hop_limit; 24262306a36Sopenharmony_ci /* assume if the admin and the mcast are the same both can be changed */ 24362306a36Sopenharmony_ci mtu = rdma_mtu_enum_to_int(priv->ca, priv->port, 24462306a36Sopenharmony_ci priv->broadcast->mcmember.mtu); 24562306a36Sopenharmony_ci if (priv->mcast_mtu == priv->admin_mtu) 24662306a36Sopenharmony_ci priv->admin_mtu = IPOIB_UD_MTU(mtu); 24762306a36Sopenharmony_ci priv->mcast_mtu = IPOIB_UD_MTU(mtu); 24862306a36Sopenharmony_ci rn->mtu = priv->mcast_mtu; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci priv->qkey = be32_to_cpu(priv->broadcast->mcmember.qkey); 25162306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 25262306a36Sopenharmony_ci priv->tx_wr.remote_qkey = priv->qkey; 25362306a36Sopenharmony_ci set_qkey = 1; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { 25762306a36Sopenharmony_ci if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { 25862306a36Sopenharmony_ci ipoib_warn(priv, "multicast group %pI6 already attached\n", 25962306a36Sopenharmony_ci mcast->mcmember.mgid.raw); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci ret = rn->attach_mcast(dev, priv->ca, &mcast->mcmember.mgid, 26562306a36Sopenharmony_ci be16_to_cpu(mcast->mcmember.mlid), 26662306a36Sopenharmony_ci set_qkey, priv->qkey); 26762306a36Sopenharmony_ci if (ret < 0) { 26862306a36Sopenharmony_ci ipoib_warn(priv, "couldn't attach QP to multicast group %pI6\n", 26962306a36Sopenharmony_ci mcast->mcmember.mgid.raw); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags); 27262306a36Sopenharmony_ci return ret; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci memset(&av, 0, sizeof(av)); 27762306a36Sopenharmony_ci av.type = rdma_ah_find_type(priv->ca, priv->port); 27862306a36Sopenharmony_ci rdma_ah_set_dlid(&av, be16_to_cpu(mcast->mcmember.mlid)); 27962306a36Sopenharmony_ci rdma_ah_set_port_num(&av, priv->port); 28062306a36Sopenharmony_ci rdma_ah_set_sl(&av, mcast->mcmember.sl); 28162306a36Sopenharmony_ci rdma_ah_set_static_rate(&av, mcast->mcmember.rate); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci rdma_ah_set_grh(&av, &mcast->mcmember.mgid, 28462306a36Sopenharmony_ci be32_to_cpu(mcast->mcmember.flow_label), 28562306a36Sopenharmony_ci 0, mcast->mcmember.hop_limit, 28662306a36Sopenharmony_ci mcast->mcmember.traffic_class); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ah = ipoib_create_ah(dev, priv->pd, &av); 28962306a36Sopenharmony_ci if (IS_ERR(ah)) { 29062306a36Sopenharmony_ci ipoib_warn(priv, "ib_address_create failed %ld\n", 29162306a36Sopenharmony_ci -PTR_ERR(ah)); 29262306a36Sopenharmony_ci /* use original error */ 29362306a36Sopenharmony_ci return PTR_ERR(ah); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 29662306a36Sopenharmony_ci mcast->ah = ah; 29762306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "MGID %pI6 AV %p, LID 0x%04x, SL %d\n", 30062306a36Sopenharmony_ci mcast->mcmember.mgid.raw, 30162306a36Sopenharmony_ci mcast->ah->ah, 30262306a36Sopenharmony_ci be16_to_cpu(mcast->mcmember.mlid), 30362306a36Sopenharmony_ci mcast->mcmember.sl); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* actually send any queued packets */ 30662306a36Sopenharmony_ci netif_tx_lock_bh(dev); 30762306a36Sopenharmony_ci while (!skb_queue_empty(&mcast->pkt_queue)) { 30862306a36Sopenharmony_ci struct sk_buff *skb = skb_dequeue(&mcast->pkt_queue); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci skb->dev = dev; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci ret = dev_queue_xmit(skb); 31562306a36Sopenharmony_ci if (ret) 31662306a36Sopenharmony_ci ipoib_warn(priv, "%s:dev_queue_xmit failed to re-queue packet, ret:%d\n", 31762306a36Sopenharmony_ci __func__, ret); 31862306a36Sopenharmony_ci netif_tx_lock_bh(dev); 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci return 0; 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_civoid ipoib_mcast_carrier_on_task(struct work_struct *work) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = container_of(work, struct ipoib_dev_priv, 32862306a36Sopenharmony_ci carrier_on_task); 32962306a36Sopenharmony_ci struct ib_port_attr attr; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci if (ib_query_port(priv->ca, priv->port, &attr) || 33262306a36Sopenharmony_ci attr.state != IB_PORT_ACTIVE) { 33362306a36Sopenharmony_ci ipoib_dbg(priv, "Keeping carrier off until IB port is active\n"); 33462306a36Sopenharmony_ci return; 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Take rtnl_lock to avoid racing with ipoib_stop() and 33862306a36Sopenharmony_ci * turning the carrier back on while a device is being 33962306a36Sopenharmony_ci * removed. However, ipoib_stop() will attempt to flush 34062306a36Sopenharmony_ci * the workqueue while holding the rtnl lock, so loop 34162306a36Sopenharmony_ci * on trylock until either we get the lock or we see 34262306a36Sopenharmony_ci * FLAG_OPER_UP go away as that signals that we are bailing 34362306a36Sopenharmony_ci * and can safely ignore the carrier on work. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_ci while (!rtnl_trylock()) { 34662306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 34762306a36Sopenharmony_ci return; 34862306a36Sopenharmony_ci else 34962306a36Sopenharmony_ci msleep(20); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci if (!ipoib_cm_admin_enabled(priv->dev)) 35262306a36Sopenharmony_ci dev_set_mtu(priv->dev, min(priv->mcast_mtu, priv->admin_mtu)); 35362306a36Sopenharmony_ci netif_carrier_on(priv->dev); 35462306a36Sopenharmony_ci rtnl_unlock(); 35562306a36Sopenharmony_ci} 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_cistatic int ipoib_mcast_join_complete(int status, 35862306a36Sopenharmony_ci struct ib_sa_multicast *multicast) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct ipoib_mcast *mcast = multicast->context; 36162306a36Sopenharmony_ci struct net_device *dev = mcast->dev; 36262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "%sjoin completion for %pI6 (status %d)\n", 36562306a36Sopenharmony_ci test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) ? 36662306a36Sopenharmony_ci "sendonly " : "", 36762306a36Sopenharmony_ci mcast->mcmember.mgid.raw, status); 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci /* We trap for port events ourselves. */ 37062306a36Sopenharmony_ci if (status == -ENETRESET) { 37162306a36Sopenharmony_ci status = 0; 37262306a36Sopenharmony_ci goto out; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (!status) 37662306a36Sopenharmony_ci status = ipoib_mcast_join_finish(mcast, &multicast->rec); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci if (!status) { 37962306a36Sopenharmony_ci mcast->backoff = 1; 38062306a36Sopenharmony_ci mcast->delay_until = jiffies; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* 38362306a36Sopenharmony_ci * Defer carrier on work to priv->wq to avoid a 38462306a36Sopenharmony_ci * deadlock on rtnl_lock here. Requeue our multicast 38562306a36Sopenharmony_ci * work too, which will end up happening right after 38662306a36Sopenharmony_ci * our carrier on task work and will allow us to 38762306a36Sopenharmony_ci * send out all of the non-broadcast joins 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci if (mcast == priv->broadcast) { 39062306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 39162306a36Sopenharmony_ci queue_work(priv->wq, &priv->carrier_on_task); 39262306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, NULL, 0); 39362306a36Sopenharmony_ci goto out_locked; 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci } else { 39662306a36Sopenharmony_ci bool silent_fail = 39762306a36Sopenharmony_ci test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) && 39862306a36Sopenharmony_ci status == -EINVAL; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci if (mcast->logcount < 20) { 40162306a36Sopenharmony_ci if (status == -ETIMEDOUT || status == -EAGAIN || 40262306a36Sopenharmony_ci silent_fail) { 40362306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "%smulticast join failed for %pI6, status %d\n", 40462306a36Sopenharmony_ci test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) ? "sendonly " : "", 40562306a36Sopenharmony_ci mcast->mcmember.mgid.raw, status); 40662306a36Sopenharmony_ci } else { 40762306a36Sopenharmony_ci ipoib_warn(priv, "%smulticast join failed for %pI6, status %d\n", 40862306a36Sopenharmony_ci test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) ? "sendonly " : "", 40962306a36Sopenharmony_ci mcast->mcmember.mgid.raw, status); 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!silent_fail) 41362306a36Sopenharmony_ci mcast->logcount++; 41462306a36Sopenharmony_ci } 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) && 41762306a36Sopenharmony_ci mcast->backoff >= 2) { 41862306a36Sopenharmony_ci /* 41962306a36Sopenharmony_ci * We only retry sendonly joins once before we drop 42062306a36Sopenharmony_ci * the packet and quit trying to deal with the 42162306a36Sopenharmony_ci * group. However, we leave the group in the 42262306a36Sopenharmony_ci * mcast list as an unjoined group. If we want to 42362306a36Sopenharmony_ci * try joining again, we simply queue up a packet 42462306a36Sopenharmony_ci * and restart the join thread. The empty queue 42562306a36Sopenharmony_ci * is why the join thread ignores this group. 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci mcast->backoff = 1; 42862306a36Sopenharmony_ci netif_tx_lock_bh(dev); 42962306a36Sopenharmony_ci while (!skb_queue_empty(&mcast->pkt_queue)) { 43062306a36Sopenharmony_ci ++dev->stats.tx_dropped; 43162306a36Sopenharmony_ci dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue)); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci netif_tx_unlock_bh(dev); 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 43662306a36Sopenharmony_ci /* Requeue this join task with a backoff delay */ 43762306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, mcast, 1); 43862306a36Sopenharmony_ci goto out_locked; 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ciout: 44262306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 44362306a36Sopenharmony_ciout_locked: 44462306a36Sopenharmony_ci /* 44562306a36Sopenharmony_ci * Make sure to set mcast->mc before we clear the busy flag to avoid 44662306a36Sopenharmony_ci * racing with code that checks for BUSY before checking mcast->mc 44762306a36Sopenharmony_ci */ 44862306a36Sopenharmony_ci if (status) 44962306a36Sopenharmony_ci mcast->mc = NULL; 45062306a36Sopenharmony_ci else 45162306a36Sopenharmony_ci mcast->mc = multicast; 45262306a36Sopenharmony_ci clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); 45362306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 45462306a36Sopenharmony_ci complete(&mcast->done); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return status; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/* 46062306a36Sopenharmony_ci * Caller must hold 'priv->lock' 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_cistatic int ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 46562306a36Sopenharmony_ci struct ib_sa_multicast *multicast; 46662306a36Sopenharmony_ci struct ib_sa_mcmember_rec rec = { 46762306a36Sopenharmony_ci .join_state = 1 46862306a36Sopenharmony_ci }; 46962306a36Sopenharmony_ci ib_sa_comp_mask comp_mask; 47062306a36Sopenharmony_ci int ret = 0; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci if (!priv->broadcast || 47362306a36Sopenharmony_ci !test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 47462306a36Sopenharmony_ci return -EINVAL; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci init_completion(&mcast->done); 47762306a36Sopenharmony_ci set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci rec.mgid = mcast->mcmember.mgid; 48262306a36Sopenharmony_ci rec.port_gid = priv->local_gid; 48362306a36Sopenharmony_ci rec.pkey = cpu_to_be16(priv->pkey); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci comp_mask = 48662306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_MGID | 48762306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_PORT_GID | 48862306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_PKEY | 48962306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_JOIN_STATE; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (mcast != priv->broadcast) { 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * RFC 4391: 49462306a36Sopenharmony_ci * The MGID MUST use the same P_Key, Q_Key, SL, MTU, 49562306a36Sopenharmony_ci * and HopLimit as those used in the broadcast-GID. The rest 49662306a36Sopenharmony_ci * of attributes SHOULD follow the values used in the 49762306a36Sopenharmony_ci * broadcast-GID as well. 49862306a36Sopenharmony_ci */ 49962306a36Sopenharmony_ci comp_mask |= 50062306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_QKEY | 50162306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_MTU_SELECTOR | 50262306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_MTU | 50362306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_TRAFFIC_CLASS | 50462306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_RATE_SELECTOR | 50562306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_RATE | 50662306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_SL | 50762306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_FLOW_LABEL | 50862306a36Sopenharmony_ci IB_SA_MCMEMBER_REC_HOP_LIMIT; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci rec.qkey = priv->broadcast->mcmember.qkey; 51162306a36Sopenharmony_ci rec.mtu_selector = IB_SA_EQ; 51262306a36Sopenharmony_ci rec.mtu = priv->broadcast->mcmember.mtu; 51362306a36Sopenharmony_ci rec.traffic_class = priv->broadcast->mcmember.traffic_class; 51462306a36Sopenharmony_ci rec.rate_selector = IB_SA_EQ; 51562306a36Sopenharmony_ci rec.rate = priv->broadcast->mcmember.rate; 51662306a36Sopenharmony_ci rec.sl = priv->broadcast->mcmember.sl; 51762306a36Sopenharmony_ci rec.flow_label = priv->broadcast->mcmember.flow_label; 51862306a36Sopenharmony_ci rec.hop_limit = priv->broadcast->mcmember.hop_limit; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* 52162306a36Sopenharmony_ci * Send-only IB Multicast joins work at the core IB layer but 52262306a36Sopenharmony_ci * require specific SM support. 52362306a36Sopenharmony_ci * We can use such joins here only if the current SM supports that feature. 52462306a36Sopenharmony_ci * However, if not, we emulate an Ethernet multicast send, 52562306a36Sopenharmony_ci * which does not require a multicast subscription and will 52662306a36Sopenharmony_ci * still send properly. The most appropriate thing to 52762306a36Sopenharmony_ci * do is to create the group if it doesn't exist as that 52862306a36Sopenharmony_ci * most closely emulates the behavior, from a user space 52962306a36Sopenharmony_ci * application perspective, of Ethernet multicast operation. 53062306a36Sopenharmony_ci */ 53162306a36Sopenharmony_ci if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) 53262306a36Sopenharmony_ci rec.join_state = SENDONLY_FULLMEMBER_JOIN; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci multicast = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port, 53662306a36Sopenharmony_ci &rec, comp_mask, GFP_ATOMIC, 53762306a36Sopenharmony_ci ipoib_mcast_join_complete, mcast); 53862306a36Sopenharmony_ci if (IS_ERR(multicast)) { 53962306a36Sopenharmony_ci ret = PTR_ERR(multicast); 54062306a36Sopenharmony_ci ipoib_warn(priv, "ib_sa_join_multicast failed, status %d\n", ret); 54162306a36Sopenharmony_ci /* Requeue this join task with a backoff delay */ 54262306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, mcast, 1); 54362306a36Sopenharmony_ci clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags); 54462306a36Sopenharmony_ci complete(&mcast->done); 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci return 0; 54862306a36Sopenharmony_ci} 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_civoid ipoib_mcast_join_task(struct work_struct *work) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct ipoib_dev_priv *priv = 55362306a36Sopenharmony_ci container_of(work, struct ipoib_dev_priv, mcast_task.work); 55462306a36Sopenharmony_ci struct net_device *dev = priv->dev; 55562306a36Sopenharmony_ci struct ib_port_attr port_attr; 55662306a36Sopenharmony_ci unsigned long delay_until = 0; 55762306a36Sopenharmony_ci struct ipoib_mcast *mcast = NULL; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 56062306a36Sopenharmony_ci return; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (ib_query_port(priv->ca, priv->port, &port_attr)) { 56362306a36Sopenharmony_ci ipoib_dbg(priv, "ib_query_port() failed\n"); 56462306a36Sopenharmony_ci return; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci if (port_attr.state != IB_PORT_ACTIVE) { 56762306a36Sopenharmony_ci ipoib_dbg(priv, "port state is not ACTIVE (state = %d) suspending join task\n", 56862306a36Sopenharmony_ci port_attr.state); 56962306a36Sopenharmony_ci return; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci priv->local_lid = port_attr.lid; 57262306a36Sopenharmony_ci netif_addr_lock_bh(dev); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_DEV_ADDR_SET, &priv->flags)) { 57562306a36Sopenharmony_ci netif_addr_unlock_bh(dev); 57662306a36Sopenharmony_ci return; 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci netif_addr_unlock_bh(dev); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 58162306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 58262306a36Sopenharmony_ci goto out; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (!priv->broadcast) { 58562306a36Sopenharmony_ci struct ipoib_mcast *broadcast; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci broadcast = ipoib_mcast_alloc(dev); 58862306a36Sopenharmony_ci if (!broadcast) { 58962306a36Sopenharmony_ci ipoib_warn(priv, "failed to allocate broadcast group\n"); 59062306a36Sopenharmony_ci /* 59162306a36Sopenharmony_ci * Restart us after a 1 second delay to retry 59262306a36Sopenharmony_ci * creating our broadcast group and attaching to 59362306a36Sopenharmony_ci * it. Until this succeeds, this ipoib dev is 59462306a36Sopenharmony_ci * completely stalled (multicast wise). 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, NULL, 1); 59762306a36Sopenharmony_ci goto out; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci memcpy(broadcast->mcmember.mgid.raw, priv->dev->broadcast + 4, 60162306a36Sopenharmony_ci sizeof (union ib_gid)); 60262306a36Sopenharmony_ci priv->broadcast = broadcast; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci __ipoib_mcast_add(dev, priv->broadcast); 60562306a36Sopenharmony_ci } 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { 60862306a36Sopenharmony_ci if (IS_ERR_OR_NULL(priv->broadcast->mc) && 60962306a36Sopenharmony_ci !test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags)) { 61062306a36Sopenharmony_ci mcast = priv->broadcast; 61162306a36Sopenharmony_ci if (mcast->backoff > 1 && 61262306a36Sopenharmony_ci time_before(jiffies, mcast->delay_until)) { 61362306a36Sopenharmony_ci delay_until = mcast->delay_until; 61462306a36Sopenharmony_ci mcast = NULL; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci goto out; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * We'll never get here until the broadcast group is both allocated 62262306a36Sopenharmony_ci * and attached 62362306a36Sopenharmony_ci */ 62462306a36Sopenharmony_ci list_for_each_entry(mcast, &priv->multicast_list, list) { 62562306a36Sopenharmony_ci if (IS_ERR_OR_NULL(mcast->mc) && 62662306a36Sopenharmony_ci !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) && 62762306a36Sopenharmony_ci (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags) || 62862306a36Sopenharmony_ci !skb_queue_empty(&mcast->pkt_queue))) { 62962306a36Sopenharmony_ci if (mcast->backoff == 1 || 63062306a36Sopenharmony_ci time_after_eq(jiffies, mcast->delay_until)) { 63162306a36Sopenharmony_ci /* Found the next unjoined group */ 63262306a36Sopenharmony_ci if (ipoib_mcast_join(dev, mcast)) { 63362306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 63462306a36Sopenharmony_ci return; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } else if (!delay_until || 63762306a36Sopenharmony_ci time_before(mcast->delay_until, delay_until)) 63862306a36Sopenharmony_ci delay_until = mcast->delay_until; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci mcast = NULL; 64362306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "successfully started all multicast joins\n"); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ciout: 64662306a36Sopenharmony_ci if (delay_until) { 64762306a36Sopenharmony_ci cancel_delayed_work(&priv->mcast_task); 64862306a36Sopenharmony_ci queue_delayed_work(priv->wq, &priv->mcast_task, 64962306a36Sopenharmony_ci delay_until - jiffies); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci if (mcast) 65262306a36Sopenharmony_ci ipoib_mcast_join(dev, mcast); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_civoid ipoib_mcast_start_thread(struct net_device *dev) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 66062306a36Sopenharmony_ci unsigned long flags; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "starting multicast thread\n"); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 66562306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, NULL, 0); 66662306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 66762306a36Sopenharmony_ci} 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_civoid ipoib_mcast_stop_thread(struct net_device *dev) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "stopping multicast thread\n"); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci cancel_delayed_work_sync(&priv->mcast_task); 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 68162306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 68262306a36Sopenharmony_ci int ret = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) 68562306a36Sopenharmony_ci ipoib_warn(priv, "ipoib_mcast_leave on an in-flight join\n"); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!IS_ERR_OR_NULL(mcast->mc)) 68862306a36Sopenharmony_ci ib_sa_free_multicast(mcast->mc); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { 69162306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "leaving MGID %pI6\n", 69262306a36Sopenharmony_ci mcast->mcmember.mgid.raw); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci /* Remove ourselves from the multicast group */ 69562306a36Sopenharmony_ci ret = rn->detach_mcast(dev, priv->ca, &mcast->mcmember.mgid, 69662306a36Sopenharmony_ci be16_to_cpu(mcast->mcmember.mlid)); 69762306a36Sopenharmony_ci if (ret) 69862306a36Sopenharmony_ci ipoib_warn(priv, "ib_detach_mcast failed (result = %d)\n", ret); 69962306a36Sopenharmony_ci } else if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) 70062306a36Sopenharmony_ci ipoib_dbg(priv, "leaving with no mcmember but not a " 70162306a36Sopenharmony_ci "SENDONLY join\n"); 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci return 0; 70462306a36Sopenharmony_ci} 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci/* 70762306a36Sopenharmony_ci * Check if the multicast group is sendonly. If so remove it from the maps 70862306a36Sopenharmony_ci * and add to the remove list 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_civoid ipoib_check_and_add_mcast_sendonly(struct ipoib_dev_priv *priv, u8 *mgid, 71162306a36Sopenharmony_ci struct list_head *remove_list) 71262306a36Sopenharmony_ci{ 71362306a36Sopenharmony_ci /* Is this multicast ? */ 71462306a36Sopenharmony_ci if (*mgid == 0xff) { 71562306a36Sopenharmony_ci struct ipoib_mcast *mcast = __ipoib_mcast_find(priv->dev, mgid); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (mcast && test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { 71862306a36Sopenharmony_ci list_del(&mcast->list); 71962306a36Sopenharmony_ci rb_erase(&mcast->rb_node, &priv->multicast_tree); 72062306a36Sopenharmony_ci list_add_tail(&mcast->list, remove_list); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci} 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_civoid ipoib_mcast_remove_list(struct list_head *remove_list) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct ipoib_mcast *mcast, *tmcast; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* 73062306a36Sopenharmony_ci * make sure the in-flight joins have finished before we attempt 73162306a36Sopenharmony_ci * to leave 73262306a36Sopenharmony_ci */ 73362306a36Sopenharmony_ci list_for_each_entry_safe(mcast, tmcast, remove_list, list) 73462306a36Sopenharmony_ci if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) 73562306a36Sopenharmony_ci wait_for_completion(&mcast->done); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci list_for_each_entry_safe(mcast, tmcast, remove_list, list) { 73862306a36Sopenharmony_ci ipoib_mcast_leave(mcast->dev, mcast); 73962306a36Sopenharmony_ci ipoib_mcast_free(mcast); 74062306a36Sopenharmony_ci } 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_civoid ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 74662306a36Sopenharmony_ci struct rdma_netdev *rn = netdev_priv(dev); 74762306a36Sopenharmony_ci struct ipoib_mcast *mcast; 74862306a36Sopenharmony_ci unsigned long flags; 74962306a36Sopenharmony_ci void *mgid = daddr + 4; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags) || 75462306a36Sopenharmony_ci !priv->broadcast || 75562306a36Sopenharmony_ci !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) { 75662306a36Sopenharmony_ci ++dev->stats.tx_dropped; 75762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 75862306a36Sopenharmony_ci goto unlock; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci mcast = __ipoib_mcast_find(dev, mgid); 76262306a36Sopenharmony_ci if (!mcast || !mcast->ah) { 76362306a36Sopenharmony_ci if (!mcast) { 76462306a36Sopenharmony_ci /* Let's create a new send only group now */ 76562306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "setting up send only multicast group for %pI6\n", 76662306a36Sopenharmony_ci mgid); 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci mcast = ipoib_mcast_alloc(dev); 76962306a36Sopenharmony_ci if (!mcast) { 77062306a36Sopenharmony_ci ipoib_warn(priv, "unable to allocate memory " 77162306a36Sopenharmony_ci "for multicast structure\n"); 77262306a36Sopenharmony_ci ++dev->stats.tx_dropped; 77362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 77462306a36Sopenharmony_ci goto unlock; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci set_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags); 77862306a36Sopenharmony_ci memcpy(mcast->mcmember.mgid.raw, mgid, 77962306a36Sopenharmony_ci sizeof (union ib_gid)); 78062306a36Sopenharmony_ci __ipoib_mcast_add(dev, mcast); 78162306a36Sopenharmony_ci list_add_tail(&mcast->list, &priv->multicast_list); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci if (skb_queue_len(&mcast->pkt_queue) < IPOIB_MAX_MCAST_QUEUE) { 78462306a36Sopenharmony_ci /* put pseudoheader back on for next time */ 78562306a36Sopenharmony_ci skb_push(skb, sizeof(struct ipoib_pseudo_header)); 78662306a36Sopenharmony_ci skb_queue_tail(&mcast->pkt_queue, skb); 78762306a36Sopenharmony_ci } else { 78862306a36Sopenharmony_ci ++dev->stats.tx_dropped; 78962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 79062306a36Sopenharmony_ci } 79162306a36Sopenharmony_ci if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) { 79262306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, NULL, 0); 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci } else { 79562306a36Sopenharmony_ci struct ipoib_neigh *neigh; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 79862306a36Sopenharmony_ci neigh = ipoib_neigh_get(dev, daddr); 79962306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 80062306a36Sopenharmony_ci if (!neigh) { 80162306a36Sopenharmony_ci neigh = ipoib_neigh_alloc(daddr, dev); 80262306a36Sopenharmony_ci /* Make sure that the neigh will be added only 80362306a36Sopenharmony_ci * once to mcast list. 80462306a36Sopenharmony_ci */ 80562306a36Sopenharmony_ci if (neigh && list_empty(&neigh->list)) { 80662306a36Sopenharmony_ci kref_get(&mcast->ah->ref); 80762306a36Sopenharmony_ci neigh->ah = mcast->ah; 80862306a36Sopenharmony_ci neigh->ah->valid = 1; 80962306a36Sopenharmony_ci list_add_tail(&neigh->list, &mcast->neigh_list); 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 81362306a36Sopenharmony_ci mcast->ah->last_send = rn->send(dev, skb, mcast->ah->ah, 81462306a36Sopenharmony_ci IB_MULTICAST_QPN); 81562306a36Sopenharmony_ci if (neigh) 81662306a36Sopenharmony_ci ipoib_neigh_put(neigh); 81762306a36Sopenharmony_ci return; 81862306a36Sopenharmony_ci } 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ciunlock: 82162306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_civoid ipoib_mcast_dev_flush(struct net_device *dev) 82562306a36Sopenharmony_ci{ 82662306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(dev); 82762306a36Sopenharmony_ci LIST_HEAD(remove_list); 82862306a36Sopenharmony_ci struct ipoib_mcast *mcast, *tmcast; 82962306a36Sopenharmony_ci unsigned long flags; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci mutex_lock(&priv->mcast_mutex); 83262306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "flushing multicast list\n"); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { 83762306a36Sopenharmony_ci list_del(&mcast->list); 83862306a36Sopenharmony_ci rb_erase(&mcast->rb_node, &priv->multicast_tree); 83962306a36Sopenharmony_ci list_add_tail(&mcast->list, &remove_list); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (priv->broadcast) { 84362306a36Sopenharmony_ci rb_erase(&priv->broadcast->rb_node, &priv->multicast_tree); 84462306a36Sopenharmony_ci list_add_tail(&priv->broadcast->list, &remove_list); 84562306a36Sopenharmony_ci priv->broadcast = NULL; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci ipoib_mcast_remove_list(&remove_list); 85162306a36Sopenharmony_ci mutex_unlock(&priv->mcast_mutex); 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic int ipoib_mcast_addr_is_valid(const u8 *addr, const u8 *broadcast) 85562306a36Sopenharmony_ci{ 85662306a36Sopenharmony_ci /* reserved QPN, prefix, scope */ 85762306a36Sopenharmony_ci if (memcmp(addr, broadcast, 6)) 85862306a36Sopenharmony_ci return 0; 85962306a36Sopenharmony_ci /* signature lower, pkey */ 86062306a36Sopenharmony_ci if (memcmp(addr + 7, broadcast + 7, 3)) 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ci return 1; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_civoid ipoib_mcast_restart_task(struct work_struct *work) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct ipoib_dev_priv *priv = 86862306a36Sopenharmony_ci container_of(work, struct ipoib_dev_priv, restart_task); 86962306a36Sopenharmony_ci struct net_device *dev = priv->dev; 87062306a36Sopenharmony_ci struct netdev_hw_addr *ha; 87162306a36Sopenharmony_ci struct ipoib_mcast *mcast, *tmcast; 87262306a36Sopenharmony_ci LIST_HEAD(remove_list); 87362306a36Sopenharmony_ci struct ib_sa_mcmember_rec rec; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) 87662306a36Sopenharmony_ci /* 87762306a36Sopenharmony_ci * shortcut...on shutdown flush is called next, just 87862306a36Sopenharmony_ci * let it do all the work 87962306a36Sopenharmony_ci */ 88062306a36Sopenharmony_ci return; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "restarting multicast task\n"); 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci netif_addr_lock_bh(dev); 88562306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* 88862306a36Sopenharmony_ci * Unfortunately, the networking core only gives us a list of all of 88962306a36Sopenharmony_ci * the multicast hardware addresses. We need to figure out which ones 89062306a36Sopenharmony_ci * are new and which ones have been removed 89162306a36Sopenharmony_ci */ 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Clear out the found flag */ 89462306a36Sopenharmony_ci list_for_each_entry(mcast, &priv->multicast_list, list) 89562306a36Sopenharmony_ci clear_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci /* Mark all of the entries that are found or don't exist */ 89862306a36Sopenharmony_ci netdev_for_each_mc_addr(ha, dev) { 89962306a36Sopenharmony_ci union ib_gid mgid; 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (!ipoib_mcast_addr_is_valid(ha->addr, dev->broadcast)) 90262306a36Sopenharmony_ci continue; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci memcpy(mgid.raw, ha->addr + 4, sizeof(mgid)); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci mcast = __ipoib_mcast_find(dev, &mgid); 90762306a36Sopenharmony_ci if (!mcast || test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { 90862306a36Sopenharmony_ci struct ipoib_mcast *nmcast; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* ignore group which is directly joined by userspace */ 91162306a36Sopenharmony_ci if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && 91262306a36Sopenharmony_ci !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { 91362306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %pI6\n", 91462306a36Sopenharmony_ci mgid.raw); 91562306a36Sopenharmony_ci continue; 91662306a36Sopenharmony_ci } 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci /* Not found or send-only group, let's add a new entry */ 91962306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "adding multicast entry for mgid %pI6\n", 92062306a36Sopenharmony_ci mgid.raw); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci nmcast = ipoib_mcast_alloc(dev); 92362306a36Sopenharmony_ci if (!nmcast) { 92462306a36Sopenharmony_ci ipoib_warn(priv, "unable to allocate memory for multicast structure\n"); 92562306a36Sopenharmony_ci continue; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci set_bit(IPOIB_MCAST_FLAG_FOUND, &nmcast->flags); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci nmcast->mcmember.mgid = mgid; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (mcast) { 93362306a36Sopenharmony_ci /* Destroy the send only entry */ 93462306a36Sopenharmony_ci list_move_tail(&mcast->list, &remove_list); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci rb_replace_node(&mcast->rb_node, 93762306a36Sopenharmony_ci &nmcast->rb_node, 93862306a36Sopenharmony_ci &priv->multicast_tree); 93962306a36Sopenharmony_ci } else 94062306a36Sopenharmony_ci __ipoib_mcast_add(dev, nmcast); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci list_add_tail(&nmcast->list, &priv->multicast_list); 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (mcast) 94662306a36Sopenharmony_ci set_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags); 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* Remove all of the entries don't exist anymore */ 95062306a36Sopenharmony_ci list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { 95162306a36Sopenharmony_ci if (!test_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags) && 95262306a36Sopenharmony_ci !test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { 95362306a36Sopenharmony_ci ipoib_dbg_mcast(priv, "deleting multicast group %pI6\n", 95462306a36Sopenharmony_ci mcast->mcmember.mgid.raw); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci rb_erase(&mcast->rb_node, &priv->multicast_tree); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci /* Move to the remove list */ 95962306a36Sopenharmony_ci list_move_tail(&mcast->list, &remove_list); 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci } 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 96462306a36Sopenharmony_ci netif_addr_unlock_bh(dev); 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ipoib_mcast_remove_list(&remove_list); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci /* 96962306a36Sopenharmony_ci * Double check that we are still up 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci if (test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) { 97262306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 97362306a36Sopenharmony_ci __ipoib_mcast_schedule_join_thread(priv, NULL, 0); 97462306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 97562306a36Sopenharmony_ci } 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_cistruct ipoib_mcast_iter *ipoib_mcast_iter_init(struct net_device *dev) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct ipoib_mcast_iter *iter; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci iter = kmalloc(sizeof(*iter), GFP_KERNEL); 98562306a36Sopenharmony_ci if (!iter) 98662306a36Sopenharmony_ci return NULL; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci iter->dev = dev; 98962306a36Sopenharmony_ci memset(iter->mgid.raw, 0, 16); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci if (ipoib_mcast_iter_next(iter)) { 99262306a36Sopenharmony_ci kfree(iter); 99362306a36Sopenharmony_ci return NULL; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci return iter; 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ciint ipoib_mcast_iter_next(struct ipoib_mcast_iter *iter) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct ipoib_dev_priv *priv = ipoib_priv(iter->dev); 100262306a36Sopenharmony_ci struct rb_node *n; 100362306a36Sopenharmony_ci struct ipoib_mcast *mcast; 100462306a36Sopenharmony_ci int ret = 1; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci spin_lock_irq(&priv->lock); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci n = rb_first(&priv->multicast_tree); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci while (n) { 101162306a36Sopenharmony_ci mcast = rb_entry(n, struct ipoib_mcast, rb_node); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci if (memcmp(iter->mgid.raw, mcast->mcmember.mgid.raw, 101462306a36Sopenharmony_ci sizeof (union ib_gid)) < 0) { 101562306a36Sopenharmony_ci iter->mgid = mcast->mcmember.mgid; 101662306a36Sopenharmony_ci iter->created = mcast->created; 101762306a36Sopenharmony_ci iter->queuelen = skb_queue_len(&mcast->pkt_queue); 101862306a36Sopenharmony_ci iter->complete = !!mcast->ah; 101962306a36Sopenharmony_ci iter->send_only = !!(mcast->flags & (1 << IPOIB_MCAST_FLAG_SENDONLY)); 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci ret = 0; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci } 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci n = rb_next(n); 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci spin_unlock_irq(&priv->lock); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return ret; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_civoid ipoib_mcast_iter_read(struct ipoib_mcast_iter *iter, 103562306a36Sopenharmony_ci union ib_gid *mgid, 103662306a36Sopenharmony_ci unsigned long *created, 103762306a36Sopenharmony_ci unsigned int *queuelen, 103862306a36Sopenharmony_ci unsigned int *complete, 103962306a36Sopenharmony_ci unsigned int *send_only) 104062306a36Sopenharmony_ci{ 104162306a36Sopenharmony_ci *mgid = iter->mgid; 104262306a36Sopenharmony_ci *created = iter->created; 104362306a36Sopenharmony_ci *queuelen = iter->queuelen; 104462306a36Sopenharmony_ci *complete = iter->complete; 104562306a36Sopenharmony_ci *send_only = iter->send_only; 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */ 1049