📄 ipoib_main.c
字号:
/* * Copyright (c) 2004 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_main.c 1377 2004-12-23 19:57:12Z roland $ */#include "ipoib.h"#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/kernel.h>#include <linux/if_arp.h> /* For ARPHRD_xxx */#include <linux/ip.h>#include <linux/in.h>#include <net/dst.h>MODULE_AUTHOR("Roland Dreier");MODULE_DESCRIPTION("IP-over-InfiniBand net driver");MODULE_LICENSE("Dual BSD/GPL");int ipoib_sendq_size __read_mostly = IPOIB_TX_RING_SIZE;int ipoib_recvq_size __read_mostly = IPOIB_RX_RING_SIZE;module_param_named(send_queue_size, ipoib_sendq_size, int, 0444);MODULE_PARM_DESC(send_queue_size, "Number of descriptors in send queue");module_param_named(recv_queue_size, ipoib_recvq_size, int, 0444);MODULE_PARM_DESC(recv_queue_size, "Number of descriptors in receive queue");#ifdef CONFIG_INFINIBAND_IPOIB_DEBUGint ipoib_debug_level;module_param_named(debug_level, ipoib_debug_level, int, 0644);MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0");#endifstruct ipoib_path_iter { struct net_device *dev; struct ipoib_path path;};static const u8 ipv4_bcast_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff};struct workqueue_struct *ipoib_workqueue;struct ib_sa_client ipoib_sa_client;static void ipoib_add_one(struct ib_device *device);static void ipoib_remove_one(struct ib_device *device);static struct ib_client ipoib_client = { .name = "ipoib", .add = ipoib_add_one, .remove = ipoib_remove_one};int ipoib_open(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_dbg(priv, "bringing up interface\n"); napi_enable(&priv->napi); set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); if (ipoib_pkey_dev_delay_open(dev)) return 0; if (ipoib_ib_dev_open(dev)) { napi_disable(&priv->napi); return -EINVAL; } if (ipoib_ib_dev_up(dev)) { ipoib_ib_dev_stop(dev, 1); napi_disable(&priv->napi); return -EINVAL; } if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { struct ipoib_dev_priv *cpriv; /* Bring up any child interfaces too */ mutex_lock(&priv->vlan_mutex); list_for_each_entry(cpriv, &priv->child_intfs, list) { int flags; flags = cpriv->dev->flags; if (flags & IFF_UP) continue; dev_change_flags(cpriv->dev, flags | IFF_UP); } mutex_unlock(&priv->vlan_mutex); } netif_start_queue(dev); return 0;}static int ipoib_stop(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); ipoib_dbg(priv, "stopping interface\n"); clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags); napi_disable(&priv->napi); netif_stop_queue(dev); /* * Now flush workqueue to make sure a scheduled task doesn't * bring our internal state back up. */ flush_workqueue(ipoib_workqueue); ipoib_ib_dev_down(dev, 1); ipoib_ib_dev_stop(dev, 1); if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) { struct ipoib_dev_priv *cpriv; /* Bring down any child interfaces too */ mutex_lock(&priv->vlan_mutex); list_for_each_entry(cpriv, &priv->child_intfs, list) { int flags; flags = cpriv->dev->flags; if (!(flags & IFF_UP)) continue; dev_change_flags(cpriv->dev, flags & ~IFF_UP); } mutex_unlock(&priv->vlan_mutex); } return 0;}static int ipoib_change_mtu(struct net_device *dev, int new_mtu){ struct ipoib_dev_priv *priv = netdev_priv(dev); /* dev->mtu > 2K ==> connected mode */ if (ipoib_cm_admin_enabled(dev) && new_mtu <= IPOIB_CM_MTU) { if (new_mtu > priv->mcast_mtu) ipoib_warn(priv, "mtu > %d will cause multicast packet drops.\n", priv->mcast_mtu); dev->mtu = new_mtu; return 0; } if (new_mtu > IPOIB_PACKET_SIZE - IPOIB_ENCAP_LEN) { return -EINVAL; } priv->admin_mtu = new_mtu; dev->mtu = min(priv->mcast_mtu, priv->admin_mtu); return 0;}static struct ipoib_path *__path_find(struct net_device *dev, void *gid){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct rb_node *n = priv->path_tree.rb_node; struct ipoib_path *path; int ret; while (n) { path = rb_entry(n, struct ipoib_path, rb_node); ret = memcmp(gid, path->pathrec.dgid.raw, sizeof (union ib_gid)); if (ret < 0) n = n->rb_left; else if (ret > 0) n = n->rb_right; else return path; } return NULL;}static int __path_add(struct net_device *dev, struct ipoib_path *path){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct rb_node **n = &priv->path_tree.rb_node; struct rb_node *pn = NULL; struct ipoib_path *tpath; int ret; while (*n) { pn = *n; tpath = rb_entry(pn, struct ipoib_path, rb_node); ret = memcmp(path->pathrec.dgid.raw, tpath->pathrec.dgid.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(&path->rb_node, pn, n); rb_insert_color(&path->rb_node, &priv->path_tree); list_add_tail(&path->list, &priv->path_list); return 0;}static void path_free(struct net_device *dev, struct ipoib_path *path){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_neigh *neigh, *tn; struct sk_buff *skb; unsigned long flags; while ((skb = __skb_dequeue(&path->queue))) dev_kfree_skb_irq(skb); spin_lock_irqsave(&priv->lock, flags); list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { /* * 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. */ if (neigh->ah) ipoib_put_ah(neigh->ah); ipoib_neigh_free(dev, neigh); } spin_unlock_irqrestore(&priv->lock, flags); if (path->ah) ipoib_put_ah(path->ah); kfree(path);}#ifdef CONFIG_INFINIBAND_IPOIB_DEBUGstruct ipoib_path_iter *ipoib_path_iter_init(struct net_device *dev){ struct ipoib_path_iter *iter; iter = kmalloc(sizeof *iter, GFP_KERNEL); if (!iter) return NULL; iter->dev = dev; memset(iter->path.pathrec.dgid.raw, 0, 16); if (ipoib_path_iter_next(iter)) { kfree(iter); return NULL; } return iter;}int ipoib_path_iter_next(struct ipoib_path_iter *iter){ struct ipoib_dev_priv *priv = netdev_priv(iter->dev); struct rb_node *n; struct ipoib_path *path; int ret = 1; spin_lock_irq(&priv->lock); n = rb_first(&priv->path_tree); while (n) { path = rb_entry(n, struct ipoib_path, rb_node); if (memcmp(iter->path.pathrec.dgid.raw, path->pathrec.dgid.raw, sizeof (union ib_gid)) < 0) { iter->path = *path; ret = 0; break; } n = rb_next(n); } spin_unlock_irq(&priv->lock); return ret;}void ipoib_path_iter_read(struct ipoib_path_iter *iter, struct ipoib_path *path){ *path = iter->path;}#endif /* CONFIG_INFINIBAND_IPOIB_DEBUG */void ipoib_flush_paths(struct net_device *dev){ struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_path *path, *tp; LIST_HEAD(remove_list); spin_lock_irq(&priv->tx_lock); spin_lock(&priv->lock); list_splice(&priv->path_list, &remove_list); INIT_LIST_HEAD(&priv->path_list); list_for_each_entry(path, &remove_list, list) rb_erase(&path->rb_node, &priv->path_tree); list_for_each_entry_safe(path, tp, &remove_list, list) { if (path->query) ib_sa_cancel_query(path->query_id, path->query); spin_unlock(&priv->lock); spin_unlock_irq(&priv->tx_lock); wait_for_completion(&path->done); path_free(dev, path); spin_lock_irq(&priv->tx_lock); spin_lock(&priv->lock); } spin_unlock(&priv->lock); spin_unlock_irq(&priv->tx_lock);}static void path_rec_completion(int status, struct ib_sa_path_rec *pathrec, void *path_ptr){ struct ipoib_path *path = path_ptr; struct net_device *dev = path->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); struct ipoib_ah *ah = NULL; struct ipoib_neigh *neigh, *tn; struct sk_buff_head skqueue; struct sk_buff *skb; unsigned long flags; if (!status) ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n", be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid)); else ipoib_dbg(priv, "PathRec status %d for GID " IPOIB_GID_FMT "\n", status, IPOIB_GID_ARG(path->pathrec.dgid)); skb_queue_head_init(&skqueue); if (!status) { struct ib_ah_attr av; if (!ib_init_ah_from_path(priv->ca, priv->port, pathrec, &av)) ah = ipoib_create_ah(dev, priv->pd, &av); } spin_lock_irqsave(&priv->lock, flags); path->ah = ah; if (ah) { path->pathrec = *pathrec; ipoib_dbg(priv, "created address handle %p for LID 0x%04x, SL %d\n", ah, be16_to_cpu(pathrec->dlid), pathrec->sl); while ((skb = __skb_dequeue(&path->queue))) __skb_queue_tail(&skqueue, skb); list_for_each_entry_safe(neigh, tn, &path->neigh_list, list) { 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); continue; } } while ((skb = __skb_dequeue(&neigh->queue)))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -