1 | // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB |
2 | /* |
3 | * Copyright (c) 2016 Mellanox Technologies Ltd. All rights reserved. |
4 | * Copyright (c) 2015 System Fabric Works, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/skbuff.h> |
8 | #include <linux/if_arp.h> |
9 | #include <linux/netdevice.h> |
10 | #include <linux/if.h> |
11 | #include <linux/if_vlan.h> |
12 | #include <net/udp_tunnel.h> |
13 | #include <net/sch_generic.h> |
14 | #include <linux/netfilter.h> |
15 | #include <rdma/ib_addr.h> |
16 | |
17 | #include "rxe.h" |
18 | #include "rxe_net.h" |
19 | #include "rxe_loc.h" |
20 | |
21 | static struct rxe_recv_sockets recv_sockets; |
22 | |
23 | static struct dst_entry *rxe_find_route4(struct rxe_qp *qp, |
24 | struct net_device *ndev, |
25 | struct in_addr *saddr, |
26 | struct in_addr *daddr) |
27 | { |
28 | struct rtable *rt; |
29 | struct flowi4 fl = { { 0 } }; |
30 | |
31 | memset(&fl, 0, sizeof(fl)); |
32 | fl.flowi4_oif = ndev->ifindex; |
33 | memcpy(&fl.saddr, saddr, sizeof(*saddr)); |
34 | memcpy(&fl.daddr, daddr, sizeof(*daddr)); |
35 | fl.flowi4_proto = IPPROTO_UDP; |
36 | |
37 | rt = ip_route_output_key(net: &init_net, flp: &fl); |
38 | if (IS_ERR(ptr: rt)) { |
39 | rxe_dbg_qp(qp, "no route to %pI4\n" , &daddr->s_addr); |
40 | return NULL; |
41 | } |
42 | |
43 | return &rt->dst; |
44 | } |
45 | |
46 | #if IS_ENABLED(CONFIG_IPV6) |
47 | static struct dst_entry *rxe_find_route6(struct rxe_qp *qp, |
48 | struct net_device *ndev, |
49 | struct in6_addr *saddr, |
50 | struct in6_addr *daddr) |
51 | { |
52 | struct dst_entry *ndst; |
53 | struct flowi6 fl6 = { { 0 } }; |
54 | |
55 | memset(&fl6, 0, sizeof(fl6)); |
56 | fl6.flowi6_oif = ndev->ifindex; |
57 | memcpy(&fl6.saddr, saddr, sizeof(*saddr)); |
58 | memcpy(&fl6.daddr, daddr, sizeof(*daddr)); |
59 | fl6.flowi6_proto = IPPROTO_UDP; |
60 | |
61 | ndst = ipv6_stub->ipv6_dst_lookup_flow(sock_net(sk: recv_sockets.sk6->sk), |
62 | recv_sockets.sk6->sk, &fl6, |
63 | NULL); |
64 | if (IS_ERR(ptr: ndst)) { |
65 | rxe_dbg_qp(qp, "no route to %pI6\n" , daddr); |
66 | return NULL; |
67 | } |
68 | |
69 | if (unlikely(ndst->error)) { |
70 | rxe_dbg_qp(qp, "no route to %pI6\n" , daddr); |
71 | goto put; |
72 | } |
73 | |
74 | return ndst; |
75 | put: |
76 | dst_release(dst: ndst); |
77 | return NULL; |
78 | } |
79 | |
80 | #else |
81 | |
82 | static struct dst_entry *rxe_find_route6(struct rxe_qp *qp, |
83 | struct net_device *ndev, |
84 | struct in6_addr *saddr, |
85 | struct in6_addr *daddr) |
86 | { |
87 | return NULL; |
88 | } |
89 | |
90 | #endif |
91 | |
92 | static struct dst_entry *rxe_find_route(struct net_device *ndev, |
93 | struct rxe_qp *qp, |
94 | struct rxe_av *av) |
95 | { |
96 | struct dst_entry *dst = NULL; |
97 | |
98 | if (qp_type(qp) == IB_QPT_RC) |
99 | dst = sk_dst_get(sk: qp->sk->sk); |
100 | |
101 | if (!dst || !dst_check(dst, cookie: qp->dst_cookie)) { |
102 | if (dst) |
103 | dst_release(dst); |
104 | |
105 | if (av->network_type == RXE_NETWORK_TYPE_IPV4) { |
106 | struct in_addr *saddr; |
107 | struct in_addr *daddr; |
108 | |
109 | saddr = &av->sgid_addr._sockaddr_in.sin_addr; |
110 | daddr = &av->dgid_addr._sockaddr_in.sin_addr; |
111 | dst = rxe_find_route4(qp, ndev, saddr, daddr); |
112 | } else if (av->network_type == RXE_NETWORK_TYPE_IPV6) { |
113 | struct in6_addr *saddr6; |
114 | struct in6_addr *daddr6; |
115 | |
116 | saddr6 = &av->sgid_addr._sockaddr_in6.sin6_addr; |
117 | daddr6 = &av->dgid_addr._sockaddr_in6.sin6_addr; |
118 | dst = rxe_find_route6(qp, ndev, saddr: saddr6, daddr: daddr6); |
119 | #if IS_ENABLED(CONFIG_IPV6) |
120 | if (dst) |
121 | qp->dst_cookie = |
122 | rt6_get_cookie(rt: (struct rt6_info *)dst); |
123 | #endif |
124 | } |
125 | |
126 | if (dst && (qp_type(qp) == IB_QPT_RC)) { |
127 | dst_hold(dst); |
128 | sk_dst_set(sk: qp->sk->sk, dst); |
129 | } |
130 | } |
131 | return dst; |
132 | } |
133 | |
134 | static int rxe_udp_encap_recv(struct sock *sk, struct sk_buff *skb) |
135 | { |
136 | struct udphdr *udph; |
137 | struct rxe_dev *rxe; |
138 | struct net_device *ndev = skb->dev; |
139 | struct rxe_pkt_info *pkt = SKB_TO_PKT(skb); |
140 | |
141 | /* takes a reference on rxe->ib_dev |
142 | * drop when skb is freed |
143 | */ |
144 | rxe = rxe_get_dev_from_net(ndev); |
145 | if (!rxe && is_vlan_dev(dev: ndev)) |
146 | rxe = rxe_get_dev_from_net(ndev: vlan_dev_real_dev(dev: ndev)); |
147 | if (!rxe) |
148 | goto drop; |
149 | |
150 | if (skb_linearize(skb)) { |
151 | ib_device_put(device: &rxe->ib_dev); |
152 | goto drop; |
153 | } |
154 | |
155 | udph = udp_hdr(skb); |
156 | pkt->rxe = rxe; |
157 | pkt->port_num = 1; |
158 | pkt->hdr = (u8 *)(udph + 1); |
159 | pkt->mask = RXE_GRH_MASK; |
160 | pkt->paylen = be16_to_cpu(udph->len) - sizeof(*udph); |
161 | |
162 | /* remove udp header */ |
163 | skb_pull(skb, len: sizeof(struct udphdr)); |
164 | |
165 | rxe_rcv(skb); |
166 | |
167 | return 0; |
168 | drop: |
169 | kfree_skb(skb); |
170 | |
171 | return 0; |
172 | } |
173 | |
174 | static struct socket *rxe_setup_udp_tunnel(struct net *net, __be16 port, |
175 | bool ipv6) |
176 | { |
177 | int err; |
178 | struct socket *sock; |
179 | struct udp_port_cfg udp_cfg = { }; |
180 | struct udp_tunnel_sock_cfg tnl_cfg = { }; |
181 | |
182 | if (ipv6) { |
183 | udp_cfg.family = AF_INET6; |
184 | udp_cfg.ipv6_v6only = 1; |
185 | } else { |
186 | udp_cfg.family = AF_INET; |
187 | } |
188 | |
189 | udp_cfg.local_udp_port = port; |
190 | |
191 | /* Create UDP socket */ |
192 | err = udp_sock_create(net, cfg: &udp_cfg, sockp: &sock); |
193 | if (err < 0) |
194 | return ERR_PTR(error: err); |
195 | |
196 | tnl_cfg.encap_type = 1; |
197 | tnl_cfg.encap_rcv = rxe_udp_encap_recv; |
198 | |
199 | /* Setup UDP tunnel */ |
200 | setup_udp_tunnel_sock(net, sock, sock_cfg: &tnl_cfg); |
201 | |
202 | return sock; |
203 | } |
204 | |
205 | static void rxe_release_udp_tunnel(struct socket *sk) |
206 | { |
207 | if (sk) |
208 | udp_tunnel_sock_release(sock: sk); |
209 | } |
210 | |
211 | static void prepare_udp_hdr(struct sk_buff *skb, __be16 src_port, |
212 | __be16 dst_port) |
213 | { |
214 | struct udphdr *udph; |
215 | |
216 | __skb_push(skb, len: sizeof(*udph)); |
217 | skb_reset_transport_header(skb); |
218 | udph = udp_hdr(skb); |
219 | |
220 | udph->dest = dst_port; |
221 | udph->source = src_port; |
222 | udph->len = htons(skb->len); |
223 | udph->check = 0; |
224 | } |
225 | |
226 | static void prepare_ipv4_hdr(struct dst_entry *dst, struct sk_buff *skb, |
227 | __be32 saddr, __be32 daddr, __u8 proto, |
228 | __u8 tos, __u8 ttl, __be16 df, bool xnet) |
229 | { |
230 | struct iphdr *iph; |
231 | |
232 | skb_scrub_packet(skb, xnet); |
233 | |
234 | skb_clear_hash(skb); |
235 | skb_dst_set(skb, dst: dst_clone(dst)); |
236 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); |
237 | |
238 | skb_push(skb, len: sizeof(struct iphdr)); |
239 | skb_reset_network_header(skb); |
240 | |
241 | iph = ip_hdr(skb); |
242 | |
243 | iph->version = IPVERSION; |
244 | iph->ihl = sizeof(struct iphdr) >> 2; |
245 | iph->tot_len = htons(skb->len); |
246 | iph->frag_off = df; |
247 | iph->protocol = proto; |
248 | iph->tos = tos; |
249 | iph->daddr = daddr; |
250 | iph->saddr = saddr; |
251 | iph->ttl = ttl; |
252 | __ip_select_ident(net: dev_net(dev: dst->dev), iph, |
253 | skb_shinfo(skb)->gso_segs ?: 1); |
254 | } |
255 | |
256 | static void prepare_ipv6_hdr(struct dst_entry *dst, struct sk_buff *skb, |
257 | struct in6_addr *saddr, struct in6_addr *daddr, |
258 | __u8 proto, __u8 prio, __u8 ttl) |
259 | { |
260 | struct ipv6hdr *ip6h; |
261 | |
262 | memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); |
263 | IPCB(skb)->flags &= ~(IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED |
264 | | IPSKB_REROUTED); |
265 | skb_dst_set(skb, dst: dst_clone(dst)); |
266 | |
267 | __skb_push(skb, len: sizeof(*ip6h)); |
268 | skb_reset_network_header(skb); |
269 | ip6h = ipv6_hdr(skb); |
270 | ip6_flow_hdr(hdr: ip6h, tclass: prio, htonl(0)); |
271 | ip6h->payload_len = htons(skb->len); |
272 | ip6h->nexthdr = proto; |
273 | ip6h->hop_limit = ttl; |
274 | ip6h->daddr = *daddr; |
275 | ip6h->saddr = *saddr; |
276 | ip6h->payload_len = htons(skb->len - sizeof(*ip6h)); |
277 | } |
278 | |
279 | static int prepare4(struct rxe_av *av, struct rxe_pkt_info *pkt, |
280 | struct sk_buff *skb) |
281 | { |
282 | struct rxe_qp *qp = pkt->qp; |
283 | struct dst_entry *dst; |
284 | bool xnet = false; |
285 | __be16 df = htons(IP_DF); |
286 | struct in_addr *saddr = &av->sgid_addr._sockaddr_in.sin_addr; |
287 | struct in_addr *daddr = &av->dgid_addr._sockaddr_in.sin_addr; |
288 | |
289 | dst = rxe_find_route(ndev: skb->dev, qp, av); |
290 | if (!dst) { |
291 | rxe_dbg_qp(qp, "Host not reachable\n" ); |
292 | return -EHOSTUNREACH; |
293 | } |
294 | |
295 | prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), |
296 | cpu_to_be16(ROCE_V2_UDP_DPORT)); |
297 | |
298 | prepare_ipv4_hdr(dst, skb, saddr: saddr->s_addr, daddr: daddr->s_addr, IPPROTO_UDP, |
299 | tos: av->grh.traffic_class, ttl: av->grh.hop_limit, df, xnet); |
300 | |
301 | dst_release(dst); |
302 | return 0; |
303 | } |
304 | |
305 | static int prepare6(struct rxe_av *av, struct rxe_pkt_info *pkt, |
306 | struct sk_buff *skb) |
307 | { |
308 | struct rxe_qp *qp = pkt->qp; |
309 | struct dst_entry *dst; |
310 | struct in6_addr *saddr = &av->sgid_addr._sockaddr_in6.sin6_addr; |
311 | struct in6_addr *daddr = &av->dgid_addr._sockaddr_in6.sin6_addr; |
312 | |
313 | dst = rxe_find_route(ndev: skb->dev, qp, av); |
314 | if (!dst) { |
315 | rxe_dbg_qp(qp, "Host not reachable\n" ); |
316 | return -EHOSTUNREACH; |
317 | } |
318 | |
319 | prepare_udp_hdr(skb, cpu_to_be16(qp->src_port), |
320 | cpu_to_be16(ROCE_V2_UDP_DPORT)); |
321 | |
322 | prepare_ipv6_hdr(dst, skb, saddr, daddr, IPPROTO_UDP, |
323 | prio: av->grh.traffic_class, |
324 | ttl: av->grh.hop_limit); |
325 | |
326 | dst_release(dst); |
327 | return 0; |
328 | } |
329 | |
330 | int rxe_prepare(struct rxe_av *av, struct rxe_pkt_info *pkt, |
331 | struct sk_buff *skb) |
332 | { |
333 | int err = 0; |
334 | |
335 | if (skb->protocol == htons(ETH_P_IP)) |
336 | err = prepare4(av, pkt, skb); |
337 | else if (skb->protocol == htons(ETH_P_IPV6)) |
338 | err = prepare6(av, pkt, skb); |
339 | |
340 | if (ether_addr_equal(addr1: skb->dev->dev_addr, addr2: av->dmac)) |
341 | pkt->mask |= RXE_LOOPBACK_MASK; |
342 | |
343 | return err; |
344 | } |
345 | |
346 | static void rxe_skb_tx_dtor(struct sk_buff *skb) |
347 | { |
348 | struct sock *sk = skb->sk; |
349 | struct rxe_qp *qp = sk->sk_user_data; |
350 | int skb_out = atomic_dec_return(v: &qp->skb_out); |
351 | |
352 | if (unlikely(qp->need_req_skb && |
353 | skb_out < RXE_INFLIGHT_SKBS_PER_QP_LOW)) |
354 | rxe_sched_task(task: &qp->req.task); |
355 | |
356 | rxe_put(qp); |
357 | } |
358 | |
359 | static int rxe_send(struct sk_buff *skb, struct rxe_pkt_info *pkt) |
360 | { |
361 | int err; |
362 | |
363 | skb->destructor = rxe_skb_tx_dtor; |
364 | skb->sk = pkt->qp->sk->sk; |
365 | |
366 | rxe_get(pkt->qp); |
367 | atomic_inc(v: &pkt->qp->skb_out); |
368 | |
369 | if (skb->protocol == htons(ETH_P_IP)) { |
370 | err = ip_local_out(net: dev_net(dev: skb_dst(skb)->dev), sk: skb->sk, skb); |
371 | } else if (skb->protocol == htons(ETH_P_IPV6)) { |
372 | err = ip6_local_out(net: dev_net(dev: skb_dst(skb)->dev), sk: skb->sk, skb); |
373 | } else { |
374 | rxe_dbg_qp(pkt->qp, "Unknown layer 3 protocol: %d\n" , |
375 | skb->protocol); |
376 | atomic_dec(v: &pkt->qp->skb_out); |
377 | rxe_put(pkt->qp); |
378 | kfree_skb(skb); |
379 | return -EINVAL; |
380 | } |
381 | |
382 | if (unlikely(net_xmit_eval(err))) { |
383 | rxe_dbg_qp(pkt->qp, "error sending packet: %d\n" , err); |
384 | return -EAGAIN; |
385 | } |
386 | |
387 | return 0; |
388 | } |
389 | |
390 | /* fix up a send packet to match the packets |
391 | * received from UDP before looping them back |
392 | */ |
393 | static int rxe_loopback(struct sk_buff *skb, struct rxe_pkt_info *pkt) |
394 | { |
395 | memcpy(SKB_TO_PKT(skb), pkt, sizeof(*pkt)); |
396 | |
397 | if (skb->protocol == htons(ETH_P_IP)) |
398 | skb_pull(skb, len: sizeof(struct iphdr)); |
399 | else |
400 | skb_pull(skb, len: sizeof(struct ipv6hdr)); |
401 | |
402 | if (WARN_ON(!ib_device_try_get(&pkt->rxe->ib_dev))) { |
403 | kfree_skb(skb); |
404 | return -EIO; |
405 | } |
406 | |
407 | /* remove udp header */ |
408 | skb_pull(skb, len: sizeof(struct udphdr)); |
409 | |
410 | rxe_rcv(skb); |
411 | |
412 | return 0; |
413 | } |
414 | |
415 | int rxe_xmit_packet(struct rxe_qp *qp, struct rxe_pkt_info *pkt, |
416 | struct sk_buff *skb) |
417 | { |
418 | int err; |
419 | int is_request = pkt->mask & RXE_REQ_MASK; |
420 | struct rxe_dev *rxe = to_rdev(dev: qp->ibqp.device); |
421 | unsigned long flags; |
422 | |
423 | spin_lock_irqsave(&qp->state_lock, flags); |
424 | if ((is_request && (qp_state(qp) < IB_QPS_RTS)) || |
425 | (!is_request && (qp_state(qp) < IB_QPS_RTR))) { |
426 | spin_unlock_irqrestore(lock: &qp->state_lock, flags); |
427 | rxe_dbg_qp(qp, "Packet dropped. QP is not in ready state\n" ); |
428 | goto drop; |
429 | } |
430 | spin_unlock_irqrestore(lock: &qp->state_lock, flags); |
431 | |
432 | rxe_icrc_generate(skb, pkt); |
433 | |
434 | if (pkt->mask & RXE_LOOPBACK_MASK) |
435 | err = rxe_loopback(skb, pkt); |
436 | else |
437 | err = rxe_send(skb, pkt); |
438 | if (err) { |
439 | rxe_counter_inc(rxe, index: RXE_CNT_SEND_ERR); |
440 | return err; |
441 | } |
442 | |
443 | if ((qp_type(qp) != IB_QPT_RC) && |
444 | (pkt->mask & RXE_END_MASK)) { |
445 | pkt->wqe->state = wqe_state_done; |
446 | rxe_sched_task(task: &qp->comp.task); |
447 | } |
448 | |
449 | rxe_counter_inc(rxe, index: RXE_CNT_SENT_PKTS); |
450 | goto done; |
451 | |
452 | drop: |
453 | kfree_skb(skb); |
454 | err = 0; |
455 | done: |
456 | return err; |
457 | } |
458 | |
459 | struct sk_buff *rxe_init_packet(struct rxe_dev *rxe, struct rxe_av *av, |
460 | int paylen, struct rxe_pkt_info *pkt) |
461 | { |
462 | unsigned int hdr_len; |
463 | struct sk_buff *skb = NULL; |
464 | struct net_device *ndev; |
465 | const struct ib_gid_attr *attr; |
466 | const int port_num = 1; |
467 | |
468 | attr = rdma_get_gid_attr(device: &rxe->ib_dev, port_num, index: av->grh.sgid_index); |
469 | if (IS_ERR(ptr: attr)) |
470 | return NULL; |
471 | |
472 | if (av->network_type == RXE_NETWORK_TYPE_IPV4) |
473 | hdr_len = ETH_HLEN + sizeof(struct udphdr) + |
474 | sizeof(struct iphdr); |
475 | else |
476 | hdr_len = ETH_HLEN + sizeof(struct udphdr) + |
477 | sizeof(struct ipv6hdr); |
478 | |
479 | rcu_read_lock(); |
480 | ndev = rdma_read_gid_attr_ndev_rcu(attr); |
481 | if (IS_ERR(ptr: ndev)) { |
482 | rcu_read_unlock(); |
483 | goto out; |
484 | } |
485 | skb = alloc_skb(size: paylen + hdr_len + LL_RESERVED_SPACE(ndev), |
486 | GFP_ATOMIC); |
487 | |
488 | if (unlikely(!skb)) { |
489 | rcu_read_unlock(); |
490 | goto out; |
491 | } |
492 | |
493 | skb_reserve(skb, len: hdr_len + LL_RESERVED_SPACE(ndev)); |
494 | |
495 | /* FIXME: hold reference to this netdev until life of this skb. */ |
496 | skb->dev = ndev; |
497 | rcu_read_unlock(); |
498 | |
499 | if (av->network_type == RXE_NETWORK_TYPE_IPV4) |
500 | skb->protocol = htons(ETH_P_IP); |
501 | else |
502 | skb->protocol = htons(ETH_P_IPV6); |
503 | |
504 | pkt->rxe = rxe; |
505 | pkt->port_num = port_num; |
506 | pkt->hdr = skb_put(skb, len: paylen); |
507 | pkt->mask |= RXE_GRH_MASK; |
508 | |
509 | out: |
510 | rdma_put_gid_attr(attr); |
511 | return skb; |
512 | } |
513 | |
514 | /* |
515 | * this is required by rxe_cfg to match rxe devices in |
516 | * /sys/class/infiniband up with their underlying ethernet devices |
517 | */ |
518 | const char *rxe_parent_name(struct rxe_dev *rxe, unsigned int port_num) |
519 | { |
520 | return rxe->ndev->name; |
521 | } |
522 | |
523 | int rxe_net_add(const char *ibdev_name, struct net_device *ndev) |
524 | { |
525 | int err; |
526 | struct rxe_dev *rxe = NULL; |
527 | |
528 | rxe = ib_alloc_device(rxe_dev, ib_dev); |
529 | if (!rxe) |
530 | return -ENOMEM; |
531 | |
532 | rxe->ndev = ndev; |
533 | |
534 | err = rxe_add(rxe, mtu: ndev->mtu, ibdev_name); |
535 | if (err) { |
536 | ib_dealloc_device(device: &rxe->ib_dev); |
537 | return err; |
538 | } |
539 | |
540 | return 0; |
541 | } |
542 | |
543 | static void rxe_port_event(struct rxe_dev *rxe, |
544 | enum ib_event_type event) |
545 | { |
546 | struct ib_event ev; |
547 | |
548 | ev.device = &rxe->ib_dev; |
549 | ev.element.port_num = 1; |
550 | ev.event = event; |
551 | |
552 | ib_dispatch_event(event: &ev); |
553 | } |
554 | |
555 | /* Caller must hold net_info_lock */ |
556 | void rxe_port_up(struct rxe_dev *rxe) |
557 | { |
558 | struct rxe_port *port; |
559 | |
560 | port = &rxe->port; |
561 | port->attr.state = IB_PORT_ACTIVE; |
562 | |
563 | rxe_port_event(rxe, event: IB_EVENT_PORT_ACTIVE); |
564 | dev_info(&rxe->ib_dev.dev, "set active\n" ); |
565 | } |
566 | |
567 | /* Caller must hold net_info_lock */ |
568 | void rxe_port_down(struct rxe_dev *rxe) |
569 | { |
570 | struct rxe_port *port; |
571 | |
572 | port = &rxe->port; |
573 | port->attr.state = IB_PORT_DOWN; |
574 | |
575 | rxe_port_event(rxe, event: IB_EVENT_PORT_ERR); |
576 | rxe_counter_inc(rxe, index: RXE_CNT_LINK_DOWNED); |
577 | dev_info(&rxe->ib_dev.dev, "set down\n" ); |
578 | } |
579 | |
580 | void rxe_set_port_state(struct rxe_dev *rxe) |
581 | { |
582 | if (netif_running(dev: rxe->ndev) && netif_carrier_ok(dev: rxe->ndev)) |
583 | rxe_port_up(rxe); |
584 | else |
585 | rxe_port_down(rxe); |
586 | } |
587 | |
588 | static int rxe_notify(struct notifier_block *not_blk, |
589 | unsigned long event, |
590 | void *arg) |
591 | { |
592 | struct net_device *ndev = netdev_notifier_info_to_dev(info: arg); |
593 | struct rxe_dev *rxe = rxe_get_dev_from_net(ndev); |
594 | |
595 | if (!rxe) |
596 | return NOTIFY_OK; |
597 | |
598 | switch (event) { |
599 | case NETDEV_UNREGISTER: |
600 | ib_unregister_device_queued(ib_dev: &rxe->ib_dev); |
601 | break; |
602 | case NETDEV_UP: |
603 | rxe_port_up(rxe); |
604 | break; |
605 | case NETDEV_DOWN: |
606 | rxe_port_down(rxe); |
607 | break; |
608 | case NETDEV_CHANGEMTU: |
609 | rxe_dbg_dev(rxe, "%s changed mtu to %d\n" , ndev->name, ndev->mtu); |
610 | rxe_set_mtu(rxe, dev_mtu: ndev->mtu); |
611 | break; |
612 | case NETDEV_CHANGE: |
613 | rxe_set_port_state(rxe); |
614 | break; |
615 | case NETDEV_REBOOT: |
616 | case NETDEV_GOING_DOWN: |
617 | case NETDEV_CHANGEADDR: |
618 | case NETDEV_CHANGENAME: |
619 | case NETDEV_FEAT_CHANGE: |
620 | default: |
621 | rxe_dbg_dev(rxe, "ignoring netdev event = %ld for %s\n" , |
622 | event, ndev->name); |
623 | break; |
624 | } |
625 | |
626 | ib_device_put(device: &rxe->ib_dev); |
627 | return NOTIFY_OK; |
628 | } |
629 | |
630 | static struct notifier_block rxe_net_notifier = { |
631 | .notifier_call = rxe_notify, |
632 | }; |
633 | |
634 | static int rxe_net_ipv4_init(void) |
635 | { |
636 | recv_sockets.sk4 = rxe_setup_udp_tunnel(net: &init_net, |
637 | htons(ROCE_V2_UDP_DPORT), ipv6: false); |
638 | if (IS_ERR(ptr: recv_sockets.sk4)) { |
639 | recv_sockets.sk4 = NULL; |
640 | pr_err("Failed to create IPv4 UDP tunnel\n" ); |
641 | return -1; |
642 | } |
643 | |
644 | return 0; |
645 | } |
646 | |
647 | static int rxe_net_ipv6_init(void) |
648 | { |
649 | #if IS_ENABLED(CONFIG_IPV6) |
650 | |
651 | recv_sockets.sk6 = rxe_setup_udp_tunnel(net: &init_net, |
652 | htons(ROCE_V2_UDP_DPORT), ipv6: true); |
653 | if (PTR_ERR(ptr: recv_sockets.sk6) == -EAFNOSUPPORT) { |
654 | recv_sockets.sk6 = NULL; |
655 | pr_warn("IPv6 is not supported, can not create a UDPv6 socket\n" ); |
656 | return 0; |
657 | } |
658 | |
659 | if (IS_ERR(ptr: recv_sockets.sk6)) { |
660 | recv_sockets.sk6 = NULL; |
661 | pr_err("Failed to create IPv6 UDP tunnel\n" ); |
662 | return -1; |
663 | } |
664 | #endif |
665 | return 0; |
666 | } |
667 | |
668 | void rxe_net_exit(void) |
669 | { |
670 | rxe_release_udp_tunnel(sk: recv_sockets.sk6); |
671 | rxe_release_udp_tunnel(sk: recv_sockets.sk4); |
672 | unregister_netdevice_notifier(nb: &rxe_net_notifier); |
673 | } |
674 | |
675 | int rxe_net_init(void) |
676 | { |
677 | int err; |
678 | |
679 | recv_sockets.sk6 = NULL; |
680 | |
681 | err = rxe_net_ipv4_init(); |
682 | if (err) |
683 | return err; |
684 | err = rxe_net_ipv6_init(); |
685 | if (err) |
686 | goto err_out; |
687 | err = register_netdevice_notifier(nb: &rxe_net_notifier); |
688 | if (err) { |
689 | pr_err("Failed to register netdev notifier\n" ); |
690 | goto err_out; |
691 | } |
692 | return 0; |
693 | err_out: |
694 | rxe_net_exit(); |
695 | return err; |
696 | } |
697 | |