2 * net/tipc/ib_media.c: Infiniband bearer support for TIPC
4 * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
6 * Based on eth_media.c, which carries the following copyright notice:
8 * Copyright (c) 2001-2007, Ericsson AB
9 * Copyright (c) 2005-2008, 2011, Wind River Systems
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions are met:
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.
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.
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.
41 #include <linux/if_infiniband.h>
45 #define MAX_IB_BEARERS MAX_BEARERS
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
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
;
63 static struct tipc_media ib_media_info
;
64 static struct ib_bearer ib_bearers
[MAX_IB_BEARERS
];
65 static int ib_started
;
68 * ib_media_addr_set - initialize Infiniband media address structure
70 * Media-dependent "value" field stores MAC address in first 6 bytes
71 * and zeroes out the remaining bytes.
73 static void ib_media_addr_set(const struct tipc_bearer
*tb_ptr
,
74 struct tipc_media_addr
*a
, char *mac
)
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
);
83 * send_msg - send a TIPC message out over an InfiniBand interface
85 static int send_msg(struct sk_buff
*buf
, struct tipc_bearer
*tb_ptr
,
86 struct tipc_media_addr
*dest
)
88 struct sk_buff
*clone
;
89 struct net_device
*dev
;
92 clone
= skb_clone(buf
, GFP_ATOMIC
);
96 dev
= ((struct ib_bearer
*)(tb_ptr
->usr_handle
))->dev
;
97 delta
= dev
->hard_header_len
- skb_headroom(buf
);
100 pskb_expand_head(clone
, SKB_DATA_ALIGN(delta
), 0, GFP_ATOMIC
)) {
105 skb_reset_network_header(clone
);
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
);
115 * recv_msg - handle incoming TIPC message from an InfiniBand interface
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).
121 static int recv_msg(struct sk_buff
*buf
, struct net_device
*dev
,
122 struct packet_type
*pt
, struct net_device
*orig_dev
)
124 struct ib_bearer
*ib_ptr
= (struct ib_bearer
*)pt
->af_packet_priv
;
126 if (!net_eq(dev_net(dev
), &init_net
)) {
131 if (likely(ib_ptr
->bearer
)) {
132 if (likely(buf
->pkt_type
<= PACKET_BROADCAST
)) {
134 tipc_recv_msg(buf
, ib_ptr
->bearer
);
143 * setup_bearer - setup association between InfiniBand bearer and interface
145 static void setup_bearer(struct work_struct
*work
)
147 struct ib_bearer
*ib_ptr
=
148 container_of(work
, struct ib_bearer
, setup
);
150 dev_add_pack(&ib_ptr
->tipc_packet_type
);
154 * enable_bearer - attach TIPC bearer to an InfiniBand interface
156 static int enable_bearer(struct tipc_bearer
*tb_ptr
)
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;
165 /* Find unused InfiniBand bearer structure */
166 while (ib_ptr
->dev
) {
169 if (++ib_ptr
== stop
)
170 return pending_dev
? -EAGAIN
: -EDQUOT
;
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
)) {
182 read_unlock(&dev_base_lock
);
186 /* Create InfiniBand bearer for device */
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
);
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
;
205 ib_media_addr_set(tb_ptr
, &tb_ptr
->addr
, (char *)dev
->dev_addr
);
210 * cleanup_bearer - break association between InfiniBand bearer and interface
212 * This routine must be invoked from a work queue because it can sleep.
214 static void cleanup_bearer(struct work_struct
*work
)
216 struct ib_bearer
*ib_ptr
=
217 container_of(work
, struct ib_bearer
, cleanup
);
219 dev_remove_pack(&ib_ptr
->tipc_packet_type
);
220 dev_put(ib_ptr
->dev
);
225 * disable_bearer - detach TIPC bearer from an InfiniBand interface
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.)
231 static void disable_bearer(struct tipc_bearer
*tb_ptr
)
233 struct ib_bearer
*ib_ptr
= (struct ib_bearer
*)tb_ptr
->usr_handle
;
235 ib_ptr
->bearer
= NULL
;
236 INIT_WORK(&ib_ptr
->cleanup
, cleanup_bearer
);
237 schedule_work(&ib_ptr
->cleanup
);
241 * recv_notification - handle device updates from OS
243 * Change the state of the InfiniBand bearer (if any) associated with the
246 static int recv_notification(struct notifier_block
*nb
, unsigned long evt
,
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
];
253 if (!net_eq(dev_net(dev
), &init_net
))
256 while ((ib_ptr
->dev
!= dev
)) {
257 if (++ib_ptr
== stop
)
258 return NOTIFY_DONE
; /* couldn't find device */
261 return NOTIFY_DONE
; /* bearer had been disabled */
263 ib_ptr
->bearer
->mtu
= dev
->mtu
;
267 if (netif_carrier_ok(dev
))
268 tipc_continue(ib_ptr
->bearer
);
270 tipc_block_bearer(ib_ptr
->bearer
->name
);
273 tipc_continue(ib_ptr
->bearer
);
276 tipc_block_bearer(ib_ptr
->bearer
->name
);
278 case NETDEV_CHANGEMTU
:
279 case NETDEV_CHANGEADDR
:
280 tipc_block_bearer(ib_ptr
->bearer
->name
);
281 tipc_continue(ib_ptr
->bearer
);
283 case NETDEV_UNREGISTER
:
284 case NETDEV_CHANGENAME
:
285 tipc_disable_bearer(ib_ptr
->bearer
->name
);
291 static struct notifier_block notifier
= {
292 .notifier_call
= recv_notification
,
297 * ib_addr2str - convert InfiniBand address to string
299 static int ib_addr2str(struct tipc_media_addr
*a
, char *str_buf
, int str_size
)
301 if (str_size
< 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
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]);
316 * ib_addr2msg - convert InfiniBand address format to message header format
318 static int ib_addr2msg(struct tipc_media_addr
*a
, char *msg_area
)
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
);
327 * ib_msg2addr - convert message header address format to InfiniBand format
329 static int ib_msg2addr(const struct tipc_bearer
*tb_ptr
,
330 struct tipc_media_addr
*a
, char *msg_area
)
332 ib_media_addr_set(tb_ptr
, a
, msg_area
);
337 * InfiniBand media registration info
339 static 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
,
354 * tipc_ib_media_start - activate InfiniBand bearer support
356 * Register InfiniBand media type with TIPC bearer code. Also register
357 * with OS for notifications about device state changes.
359 int tipc_ib_media_start(void)
366 res
= tipc_register_media(&ib_media_info
);
370 res
= register_netdevice_notifier(¬ifier
);
377 * tipc_ib_media_stop - deactivate InfiniBand bearer support
379 void tipc_ib_media_stop(void)
384 flush_scheduled_work();
385 unregister_netdevice_notifier(¬ifier
);