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_MEDIA MAX_BEARERS
48 * struct ib_media - Infiniband media 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_media ib_media_array
[MAX_IB_MEDIA
];
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_media
*)(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_media
*ib_ptr
= (struct ib_media
*)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
);
135 return NET_RX_SUCCESS
;
143 * setup_bearer - setup association between InfiniBand bearer and interface
145 static void setup_media(struct work_struct
*work
)
147 struct ib_media
*ib_ptr
=
148 container_of(work
, struct ib_media
, setup
);
150 dev_add_pack(&ib_ptr
->tipc_packet_type
);
154 * enable_media - attach TIPC bearer to an InfiniBand interface
156 static int enable_media(struct tipc_bearer
*tb_ptr
)
158 struct net_device
*dev
;
159 struct ib_media
*ib_ptr
= &ib_media_array
[0];
160 struct ib_media
*stop
= &ib_media_array
[MAX_IB_MEDIA
];
161 char *driver_name
= strchr((const char *)tb_ptr
->name
, ':') + 1;
164 /* Find unused InfiniBand bearer structure */
165 while (ib_ptr
->dev
) {
168 if (++ib_ptr
== stop
)
169 return pending_dev
? -EAGAIN
: -EDQUOT
;
172 /* Find device with specified name */
173 dev
= dev_get_by_name(&init_net
, driver_name
);
177 /* Create InfiniBand bearer for device */
179 ib_ptr
->tipc_packet_type
.type
= htons(ETH_P_TIPC
);
180 ib_ptr
->tipc_packet_type
.dev
= dev
;
181 ib_ptr
->tipc_packet_type
.func
= recv_msg
;
182 ib_ptr
->tipc_packet_type
.af_packet_priv
= ib_ptr
;
183 INIT_LIST_HEAD(&(ib_ptr
->tipc_packet_type
.list
));
184 INIT_WORK(&ib_ptr
->setup
, setup_media
);
185 schedule_work(&ib_ptr
->setup
);
187 /* Associate TIPC bearer with InfiniBand bearer */
188 ib_ptr
->bearer
= tb_ptr
;
189 tb_ptr
->usr_handle
= (void *)ib_ptr
;
190 memset(tb_ptr
->bcast_addr
.value
, 0, sizeof(tb_ptr
->bcast_addr
.value
));
191 memcpy(tb_ptr
->bcast_addr
.value
, dev
->broadcast
, INFINIBAND_ALEN
);
192 tb_ptr
->bcast_addr
.media_id
= TIPC_MEDIA_TYPE_IB
;
193 tb_ptr
->bcast_addr
.broadcast
= 1;
194 tb_ptr
->mtu
= dev
->mtu
;
196 ib_media_addr_set(tb_ptr
, &tb_ptr
->addr
, (char *)dev
->dev_addr
);
201 * cleanup_bearer - break association between InfiniBand bearer and interface
203 * This routine must be invoked from a work queue because it can sleep.
205 static void cleanup_bearer(struct work_struct
*work
)
207 struct ib_media
*ib_ptr
=
208 container_of(work
, struct ib_media
, cleanup
);
210 dev_remove_pack(&ib_ptr
->tipc_packet_type
);
211 dev_put(ib_ptr
->dev
);
216 * disable_media - detach TIPC bearer from an InfiniBand interface
218 * Mark InfiniBand bearer as inactive so that incoming buffers are thrown away,
219 * then get worker thread to complete bearer cleanup. (Can't do cleanup
220 * here because cleanup code needs to sleep and caller holds spinlocks.)
222 static void disable_media(struct tipc_bearer
*tb_ptr
)
224 struct ib_media
*ib_ptr
= (struct ib_media
*)tb_ptr
->usr_handle
;
226 ib_ptr
->bearer
= NULL
;
227 INIT_WORK(&ib_ptr
->cleanup
, cleanup_bearer
);
228 schedule_work(&ib_ptr
->cleanup
);
232 * recv_notification - handle device updates from OS
234 * Change the state of the InfiniBand bearer (if any) associated with the
237 static int recv_notification(struct notifier_block
*nb
, unsigned long evt
,
240 struct net_device
*dev
= netdev_notifier_info_to_dev(ptr
);
241 struct ib_media
*ib_ptr
= &ib_media_array
[0];
242 struct ib_media
*stop
= &ib_media_array
[MAX_IB_MEDIA
];
244 if (!net_eq(dev_net(dev
), &init_net
))
247 while ((ib_ptr
->dev
!= dev
)) {
248 if (++ib_ptr
== stop
)
249 return NOTIFY_DONE
; /* couldn't find device */
252 return NOTIFY_DONE
; /* bearer had been disabled */
254 ib_ptr
->bearer
->mtu
= dev
->mtu
;
258 if (netif_carrier_ok(dev
))
259 tipc_continue(ib_ptr
->bearer
);
261 tipc_block_bearer(ib_ptr
->bearer
);
264 tipc_continue(ib_ptr
->bearer
);
267 tipc_block_bearer(ib_ptr
->bearer
);
269 case NETDEV_CHANGEMTU
:
270 case NETDEV_CHANGEADDR
:
271 tipc_block_bearer(ib_ptr
->bearer
);
272 tipc_continue(ib_ptr
->bearer
);
274 case NETDEV_UNREGISTER
:
275 case NETDEV_CHANGENAME
:
276 tipc_disable_bearer(ib_ptr
->bearer
->name
);
282 static struct notifier_block notifier
= {
283 .notifier_call
= recv_notification
,
288 * ib_addr2str - convert InfiniBand address to string
290 static int ib_addr2str(struct tipc_media_addr
*a
, char *str_buf
, int str_size
)
292 if (str_size
< 60) /* 60 = 19 * strlen("xx:") + strlen("xx\0") */
295 sprintf(str_buf
, "%20phC", a
->value
);
301 * ib_addr2msg - convert InfiniBand address format to message header format
303 static int ib_addr2msg(struct tipc_media_addr
*a
, char *msg_area
)
305 memset(msg_area
, 0, TIPC_MEDIA_ADDR_SIZE
);
306 msg_area
[TIPC_MEDIA_TYPE_OFFSET
] = TIPC_MEDIA_TYPE_IB
;
307 memcpy(msg_area
, a
->value
, INFINIBAND_ALEN
);
312 * ib_msg2addr - convert message header address format to InfiniBand format
314 static int ib_msg2addr(const struct tipc_bearer
*tb_ptr
,
315 struct tipc_media_addr
*a
, char *msg_area
)
317 ib_media_addr_set(tb_ptr
, a
, msg_area
);
322 * InfiniBand media registration info
324 static struct tipc_media ib_media_info
= {
325 .send_msg
= send_msg
,
326 .enable_media
= enable_media
,
327 .disable_media
= disable_media
,
328 .addr2str
= ib_addr2str
,
329 .addr2msg
= ib_addr2msg
,
330 .msg2addr
= ib_msg2addr
,
331 .priority
= TIPC_DEF_LINK_PRI
,
332 .tolerance
= TIPC_DEF_LINK_TOL
,
333 .window
= TIPC_DEF_LINK_WIN
,
334 .type_id
= TIPC_MEDIA_TYPE_IB
,
339 * tipc_ib_media_start - activate InfiniBand bearer support
341 * Register InfiniBand media type with TIPC bearer code. Also register
342 * with OS for notifications about device state changes.
344 int tipc_ib_media_start(void)
351 res
= tipc_register_media(&ib_media_info
);
355 res
= register_netdevice_notifier(¬ifier
);
362 * tipc_ib_media_stop - deactivate InfiniBand bearer support
364 void tipc_ib_media_stop(void)
369 flush_scheduled_work();
370 unregister_netdevice_notifier(¬ifier
);