aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-04-17 02:18:28 -0400
committerDavid S. Miller <davem@davemloft.net>2013-04-17 14:18:33 -0400
commita29a194a15df9840b24c6c383a9a9a1236979db5 (patch)
tree2ac0866f749d572aaeacc44765c25f3c3c521fb8 /net
parent76f5c6f359a18abd3359ad8523cb23fbf58602b7 (diff)
tipc: add InfiniBand media type
Add InfiniBand media type based on the ethernet media type. The only real difference is that in case of InfiniBand, we need the entire 20 bytes of space reserved for media addresses, so the TIPC media type ID is not explicitly stored in the packet payload. Sample output of tipc-config: # tipc-config -v -addr -netid -nt=all -p -m -b -n -ls node address: <10.1.4> current network id: 4711 Type Lower Upper Port Identity Publication Scope 0 167776257 167776257 <10.1.1:1855512577> 1855512578 cluster 167776260 167776260 <10.1.4:1216454657> 1216454658 zone 1 1 1 <10.1.4:1216479235> 1216479236 node Ports: 1216479235: bound to {1,1} 1216454657: bound to {0,167776260} Media: eth ib Bearers: ib:ib0 Nodes known: <10.1.1>: up Link <broadcast-link> Window:20 packets RX packets:0 fragments:0/0 bundles:0/0 TX packets:0 fragments:0/0 bundles:0/0 RX naks:0 defs:0 dups:0 TX naks:0 acks:0 dups:0 Congestion bearer:0 link:0 Send queue max:0 avg:0 Link <10.1.4:ib0-10.1.1:ib0> ACTIVE MTU:2044 Priority:10 Tolerance:1500 ms Window:50 packets RX packets:80 fragments:0/0 bundles:0/0 TX packets:40 fragments:0/0 bundles:0/0 TX profile sample:22 packets average:54 octets 0-64:100% -256:0% -1024:0% -4096:0% -16384:0% -32768:0% -66000:0% RX states:410 probes:213 naks:0 defs:0 dups:0 TX states:410 probes:197 naks:0 acks:0 dups:0 Congestion bearer:0 link:0 Send queue max:1 avg:0 Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/tipc/Kconfig7
-rw-r--r--net/tipc/Makefile2
-rw-r--r--net/tipc/bearer.c2
-rw-r--r--net/tipc/bearer.h9
-rw-r--r--net/tipc/core.c12
-rw-r--r--net/tipc/ib_media.c387
6 files changed, 416 insertions, 3 deletions
diff --git a/net/tipc/Kconfig b/net/tipc/Kconfig
index 4f99600a5fed..c890848f9d56 100644
--- a/net/tipc/Kconfig
+++ b/net/tipc/Kconfig
@@ -31,3 +31,10 @@ config TIPC_PORTS
31 31
32 Setting this to a smaller value saves some memory, 32 Setting this to a smaller value saves some memory,
33 setting it to higher allows for more ports. 33 setting it to higher allows for more ports.
34
35config TIPC_MEDIA_IB
36 bool "InfiniBand media type support"
37 depends on TIPC && INFINIBAND_IPOIB
38 help
39 Saying Y here will enable support for running TIPC on
40 IP-over-InfiniBand devices.
diff --git a/net/tipc/Makefile b/net/tipc/Makefile
index 6cd55d671d3a..4df8e02d9008 100644
--- a/net/tipc/Makefile
+++ b/net/tipc/Makefile
@@ -9,3 +9,5 @@ tipc-y += addr.o bcast.o bearer.o config.o \
9 name_distr.o subscr.o name_table.o net.o \ 9 name_distr.o subscr.o name_table.o net.o \
10 netlink.o node.o node_subscr.o port.o ref.o \ 10 netlink.o node.o node_subscr.o port.o ref.o \
11 socket.o log.o eth_media.o 11 socket.o log.o eth_media.o
12
13tipc-$(CONFIG_TIPC_MEDIA_IB) += ib_media.o
diff --git a/net/tipc/bearer.c b/net/tipc/bearer.c
index 45d5398cd957..cb29ef7ba2f0 100644
--- a/net/tipc/bearer.c
+++ b/net/tipc/bearer.c
@@ -39,7 +39,7 @@
39#include "bearer.h" 39#include "bearer.h"
40#include "discover.h" 40#include "discover.h"
41 41
42#define MAX_ADDR_STR 32 42#define MAX_ADDR_STR 60
43 43
44static struct tipc_media *media_list[MAX_MEDIA]; 44static struct tipc_media *media_list[MAX_MEDIA];
45static u32 media_count; 45static u32 media_count;
diff --git a/net/tipc/bearer.h b/net/tipc/bearer.h
index 3b3fa26cb3dd..09c869adcfcf 100644
--- a/net/tipc/bearer.h
+++ b/net/tipc/bearer.h
@@ -56,6 +56,7 @@
56 * Identifiers of supported TIPC media types 56 * Identifiers of supported TIPC media types
57 */ 57 */
58#define TIPC_MEDIA_TYPE_ETH 1 58#define TIPC_MEDIA_TYPE_ETH 1
59#define TIPC_MEDIA_TYPE_IB 2
59 60
60/** 61/**
61 * struct tipc_media_addr - destination address used by TIPC bearers 62 * struct tipc_media_addr - destination address used by TIPC bearers
@@ -174,6 +175,14 @@ int tipc_disable_bearer(const char *name);
174int tipc_eth_media_start(void); 175int tipc_eth_media_start(void);
175void tipc_eth_media_stop(void); 176void tipc_eth_media_stop(void);
176 177
178#ifdef CONFIG_TIPC_MEDIA_IB
179int tipc_ib_media_start(void);
180void tipc_ib_media_stop(void);
181#else
182static inline int tipc_ib_media_start(void) { return 0; }
183static inline void tipc_ib_media_stop(void) { return; }
184#endif
185
177int tipc_media_set_priority(const char *name, u32 new_value); 186int tipc_media_set_priority(const char *name, u32 new_value);
178int tipc_media_set_window(const char *name, u32 new_value); 187int tipc_media_set_window(const char *name, u32 new_value);
179void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a); 188void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
diff --git a/net/tipc/core.c b/net/tipc/core.c
index fc05cecd7481..7ec2c1eb94f1 100644
--- a/net/tipc/core.c
+++ b/net/tipc/core.c
@@ -82,6 +82,7 @@ static void tipc_core_stop_net(void)
82{ 82{
83 tipc_net_stop(); 83 tipc_net_stop();
84 tipc_eth_media_stop(); 84 tipc_eth_media_stop();
85 tipc_ib_media_stop();
85} 86}
86 87
87/** 88/**
@@ -93,8 +94,15 @@ int tipc_core_start_net(unsigned long addr)
93 94
94 tipc_net_start(addr); 95 tipc_net_start(addr);
95 res = tipc_eth_media_start(); 96 res = tipc_eth_media_start();
96 if (res) 97 if (res < 0)
97 tipc_core_stop_net(); 98 goto err;
99 res = tipc_ib_media_start();
100 if (res < 0)
101 goto err;
102 return res;
103
104err:
105 tipc_core_stop_net();
98 return res; 106 return res;
99} 107}
100 108
diff --git a/net/tipc/ib_media.c b/net/tipc/ib_media.c
new file mode 100644
index 000000000000..2a2864c25e15
--- /dev/null
+++ b/net/tipc/ib_media.c
@@ -0,0 +1,387 @@
1/*
2 * net/tipc/ib_media.c: Infiniband bearer support for TIPC
3 *
4 * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
5 *
6 * Based on eth_media.c, which carries the following copyright notice:
7 *
8 * Copyright (c) 2001-2007, Ericsson AB
9 * Copyright (c) 2005-2008, 2011, Wind River Systems
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the names of the copyright holders nor the names of its
21 * contributors may be used to endorse or promote products derived from
22 * this software without specific prior written permission.
23 *
24 * Alternatively, this software may be distributed under the terms of the
25 * GNU General Public License ("GPL") version 2 as published by the Free
26 * Software Foundation.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
32 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41#include <linux/if_infiniband.h>
42#include "core.h"
43#include "bearer.h"
44
45#define MAX_IB_BEARERS MAX_BEARERS
46
47/**
48 * struct ib_bearer - Infiniband bearer data structure
49 * @bearer: ptr to associated "generic" bearer structure
50 * @dev: ptr to associated Infiniband network device
51 * @tipc_packet_type: used in binding TIPC to Infiniband driver
52 * @cleanup: work item used when disabling bearer
53 */
54
55struct ib_bearer {
56 struct tipc_bearer *bearer;
57 struct net_device *dev;
58 struct packet_type tipc_packet_type;
59 struct work_struct setup;
60 struct work_struct cleanup;
61};
62
63static struct tipc_media ib_media_info;
64static struct ib_bearer ib_bearers[MAX_IB_BEARERS];
65static int ib_started;
66
67/**
68 * ib_media_addr_set - initialize Infiniband media address structure
69 *
70 * Media-dependent "value" field stores MAC address in first 6 bytes
71 * and zeroes out the remaining bytes.
72 */
73static void ib_media_addr_set(const struct tipc_bearer *tb_ptr,
74 struct tipc_media_addr *a, char *mac)
75{
76 BUILD_BUG_ON(sizeof(a->value) < INFINIBAND_ALEN);
77 memcpy(a->value, mac, INFINIBAND_ALEN);
78 a->media_id = TIPC_MEDIA_TYPE_IB;
79 a->broadcast = !memcmp(mac, tb_ptr->bcast_addr.value, INFINIBAND_ALEN);
80}
81
82/**
83 * send_msg - send a TIPC message out over an InfiniBand interface
84 */
85static int send_msg(struct sk_buff *buf, struct tipc_bearer *tb_ptr,
86 struct tipc_media_addr *dest)
87{
88 struct sk_buff *clone;
89 struct net_device *dev;
90 int delta;
91
92 clone = skb_clone(buf, GFP_ATOMIC);
93 if (!clone)
94 return 0;
95
96 dev = ((struct ib_bearer *)(tb_ptr->usr_handle))->dev;
97 delta = dev->hard_header_len - skb_headroom(buf);
98
99 if ((delta > 0) &&
100 pskb_expand_head(clone, SKB_DATA_ALIGN(delta), 0, GFP_ATOMIC)) {
101 kfree_skb(clone);
102 return 0;
103 }
104
105 skb_reset_network_header(clone);
106 clone->dev = dev;
107 clone->protocol = htons(ETH_P_TIPC);
108 dev_hard_header(clone, dev, ETH_P_TIPC, dest->value,
109 dev->dev_addr, clone->len);
110 dev_queue_xmit(clone);
111 return 0;
112}
113
114/**
115 * recv_msg - handle incoming TIPC message from an InfiniBand interface
116 *
117 * Accept only packets explicitly sent to this node, or broadcast packets;
118 * ignores packets sent using InfiniBand multicast, and traffic sent to other
119 * nodes (which can happen if interface is running in promiscuous mode).
120 */
121static int recv_msg(struct sk_buff *buf, struct net_device *dev,
122 struct packet_type *pt, struct net_device *orig_dev)
123{
124 struct ib_bearer *ib_ptr = (struct ib_bearer *)pt->af_packet_priv;
125
126 if (!net_eq(dev_net(dev), &init_net)) {
127 kfree_skb(buf);
128 return 0;
129 }
130
131 if (likely(ib_ptr->bearer)) {
132 if (likely(buf->pkt_type <= PACKET_BROADCAST)) {
133 buf->next = NULL;
134 tipc_recv_msg(buf, ib_ptr->bearer);
135 return 0;
136 }
137 }
138 kfree_skb(buf);
139 return 0;
140}
141
142/**
143 * setup_bearer - setup association between InfiniBand bearer and interface
144 */
145static void setup_bearer(struct work_struct *work)
146{
147 struct ib_bearer *ib_ptr =
148 container_of(work, struct ib_bearer, setup);
149
150 dev_add_pack(&ib_ptr->tipc_packet_type);
151}
152
153/**
154 * enable_bearer - attach TIPC bearer to an InfiniBand interface
155 */
156static int enable_bearer(struct tipc_bearer *tb_ptr)
157{
158 struct net_device *dev = NULL;
159 struct net_device *pdev = NULL;
160 struct ib_bearer *ib_ptr = &ib_bearers[0];
161 struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
162 char *driver_name = strchr((const char *)tb_ptr->name, ':') + 1;
163 int pending_dev = 0;
164
165 /* Find unused InfiniBand bearer structure */
166 while (ib_ptr->dev) {
167 if (!ib_ptr->bearer)
168 pending_dev++;
169 if (++ib_ptr == stop)
170 return pending_dev ? -EAGAIN : -EDQUOT;
171 }
172
173 /* Find device with specified name */
174 read_lock(&dev_base_lock);
175 for_each_netdev(&init_net, pdev) {
176 if (!strncmp(pdev->name, driver_name, IFNAMSIZ)) {
177 dev = pdev;
178 dev_hold(dev);
179 break;
180 }
181 }
182 read_unlock(&dev_base_lock);
183 if (!dev)
184 return -ENODEV;
185
186 /* Create InfiniBand bearer for device */
187 ib_ptr->dev = dev;
188 ib_ptr->tipc_packet_type.type = htons(ETH_P_TIPC);
189 ib_ptr->tipc_packet_type.dev = dev;
190 ib_ptr->tipc_packet_type.func = recv_msg;
191 ib_ptr->tipc_packet_type.af_packet_priv = ib_ptr;
192 INIT_LIST_HEAD(&(ib_ptr->tipc_packet_type.list));
193 INIT_WORK(&ib_ptr->setup, setup_bearer);
194 schedule_work(&ib_ptr->setup);
195
196 /* Associate TIPC bearer with InfiniBand bearer */
197 ib_ptr->bearer = tb_ptr;
198 tb_ptr->usr_handle = (void *)ib_ptr;
199 memset(tb_ptr->bcast_addr.value, 0, sizeof(tb_ptr->bcast_addr.value));
200 memcpy(tb_ptr->bcast_addr.value, dev->broadcast, INFINIBAND_ALEN);
201 tb_ptr->bcast_addr.media_id = TIPC_MEDIA_TYPE_IB;
202 tb_ptr->bcast_addr.broadcast = 1;
203 tb_ptr->mtu = dev->mtu;
204 tb_ptr->blocked = 0;
205 ib_media_addr_set(tb_ptr, &tb_ptr->addr, (char *)dev->dev_addr);
206 return 0;
207}
208
209/**
210 * cleanup_bearer - break association between InfiniBand bearer and interface
211 *
212 * This routine must be invoked from a work queue because it can sleep.
213 */
214static void cleanup_bearer(struct work_struct *work)
215{
216 struct ib_bearer *ib_ptr =
217 container_of(work, struct ib_bearer, cleanup);
218
219 dev_remove_pack(&ib_ptr->tipc_packet_type);
220 dev_put(ib_ptr->dev);
221 ib_ptr->dev = NULL;
222}
223
224/**
225 * disable_bearer - detach TIPC bearer from an InfiniBand interface
226 *
227 * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away,
228 * then get worker thread to complete bearer cleanup. (Can't do cleanup
229 * here because cleanup code needs to sleep and caller holds spinlocks.)
230 */
231static void disable_bearer(struct tipc_bearer *tb_ptr)
232{
233 struct ib_bearer *ib_ptr = (struct ib_bearer *)tb_ptr->usr_handle;
234
235 ib_ptr->bearer = NULL;
236 INIT_WORK(&ib_ptr->cleanup, cleanup_bearer);
237 schedule_work(&ib_ptr->cleanup);
238}
239
240/**
241 * recv_notification - handle device updates from OS
242 *
243 * Change the state of the InfiniBand bearer (if any) associated with the
244 * specified device.
245 */
246static int recv_notification(struct notifier_block *nb, unsigned long evt,
247 void *dv)
248{
249 struct net_device *dev = (struct net_device *)dv;
250 struct ib_bearer *ib_ptr = &ib_bearers[0];
251 struct ib_bearer *stop = &ib_bearers[MAX_IB_BEARERS];
252
253 if (!net_eq(dev_net(dev), &init_net))
254 return NOTIFY_DONE;
255
256 while ((ib_ptr->dev != dev)) {
257 if (++ib_ptr == stop)
258 return NOTIFY_DONE; /* couldn't find device */
259 }
260 if (!ib_ptr->bearer)
261 return NOTIFY_DONE; /* bearer had been disabled */
262
263 ib_ptr->bearer->mtu = dev->mtu;
264
265 switch (evt) {
266 case NETDEV_CHANGE:
267 if (netif_carrier_ok(dev))
268 tipc_continue(ib_ptr->bearer);
269 else
270 tipc_block_bearer(ib_ptr->bearer->name);
271 break;
272 case NETDEV_UP:
273 tipc_continue(ib_ptr->bearer);
274 break;
275 case NETDEV_DOWN:
276 tipc_block_bearer(ib_ptr->bearer->name);
277 break;
278 case NETDEV_CHANGEMTU:
279 case NETDEV_CHANGEADDR:
280 tipc_block_bearer(ib_ptr->bearer->name);
281 tipc_continue(ib_ptr->bearer);
282 break;
283 case NETDEV_UNREGISTER:
284 case NETDEV_CHANGENAME:
285 tipc_disable_bearer(ib_ptr->bearer->name);
286 break;
287 }
288 return NOTIFY_OK;
289}
290
291static struct notifier_block notifier = {
292 .notifier_call = recv_notification,
293 .priority = 0,
294};
295
296/**
297 * ib_addr2str - convert InfiniBand address to string
298 */
299static int ib_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size)
300{
301 if (str_size < 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
302 return 1;
303
304 sprintf(str_buf, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:"
305 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
306 a->value[0], a->value[1], a->value[2], a->value[3],
307 a->value[4], a->value[5], a->value[6], a->value[7],
308 a->value[8], a->value[9], a->value[10], a->value[11],
309 a->value[12], a->value[13], a->value[14], a->value[15],
310 a->value[16], a->value[17], a->value[18], a->value[19]);
311
312 return 0;
313}
314
315/**
316 * ib_addr2msg - convert InfiniBand address format to message header format
317 */
318static int ib_addr2msg(struct tipc_media_addr *a, char *msg_area)
319{
320 memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE);
321 msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB;
322 memcpy(msg_area, a->value, INFINIBAND_ALEN);
323 return 0;
324}
325
326/**
327 * ib_msg2addr - convert message header address format to InfiniBand format
328 */
329static int ib_msg2addr(const struct tipc_bearer *tb_ptr,
330 struct tipc_media_addr *a, char *msg_area)
331{
332 ib_media_addr_set(tb_ptr, a, msg_area);
333 return 0;
334}
335
336/*
337 * InfiniBand media registration info
338 */
339static struct tipc_media ib_media_info = {
340 .send_msg = send_msg,
341 .enable_bearer = enable_bearer,
342 .disable_bearer = disable_bearer,
343 .addr2str = ib_addr2str,
344 .addr2msg = ib_addr2msg,
345 .msg2addr = ib_msg2addr,
346 .priority = TIPC_DEF_LINK_PRI,
347 .tolerance = TIPC_DEF_LINK_TOL,
348 .window = TIPC_DEF_LINK_WIN,
349 .type_id = TIPC_MEDIA_TYPE_IB,
350 .name = "ib"
351};
352
353/**
354 * tipc_ib_media_start - activate InfiniBand bearer support
355 *
356 * Register InfiniBand media type with TIPC bearer code. Also register
357 * with OS for notifications about device state changes.
358 */
359int tipc_ib_media_start(void)
360{
361 int res;
362
363 if (ib_started)
364 return -EINVAL;
365
366 res = tipc_register_media(&ib_media_info);
367 if (res)
368 return res;
369
370 res = register_netdevice_notifier(&notifier);
371 if (!res)
372 ib_started = 1;
373 return res;
374}
375
376/**
377 * tipc_ib_media_stop - deactivate InfiniBand bearer support
378 */
379void tipc_ib_media_stop(void)
380{
381 if (!ib_started)
382 return;
383
384 flush_scheduled_work();
385 unregister_netdevice_notifier(&notifier);
386 ib_started = 0;
387}