Skip to content

Commit 75b54cb

Browse files
committed
rxrpc: Add IPv6 support
Add IPv6 support to AF_RXRPC. With this, AF_RXRPC sockets can be created: service = socket(AF_RXRPC, SOCK_DGRAM, PF_INET6); instead of: service = socket(AF_RXRPC, SOCK_DGRAM, PF_INET); The AFS filesystem doesn't support IPv6 at the moment, though, since that requires upgrades to some of the RPC calls. Note that a good portion of this patch is replacing "%pI4:%u" in print statements with "%pISpc" which is able to handle both protocols and print the port. Signed-off-by: David Howells <[email protected]>
1 parent 1c2bc7b commit 75b54cb

File tree

7 files changed

+154
-83
lines changed

7 files changed

+154
-83
lines changed

net/rxrpc/af_rxrpc.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,19 +106,23 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx,
106106
case AF_INET:
107107
if (srx->transport_len < sizeof(struct sockaddr_in))
108108
return -EINVAL;
109-
_debug("INET: %x @ %pI4",
110-
ntohs(srx->transport.sin.sin_port),
111-
&srx->transport.sin.sin_addr);
112109
tail = offsetof(struct sockaddr_rxrpc, transport.sin.__pad);
113110
break;
114111

115112
case AF_INET6:
113+
if (srx->transport_len < sizeof(struct sockaddr_in6))
114+
return -EINVAL;
115+
tail = offsetof(struct sockaddr_rxrpc, transport) +
116+
sizeof(struct sockaddr_in6);
117+
break;
118+
116119
default:
117120
return -EAFNOSUPPORT;
118121
}
119122

120123
if (tail < len)
121124
memset((void *)srx + tail, 0, len - tail);
125+
_debug("INET: %pISp", &srx->transport);
122126
return 0;
123127
}
124128

@@ -409,6 +413,9 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
409413
case AF_INET:
410414
rx->srx.transport_len = sizeof(struct sockaddr_in);
411415
break;
416+
case AF_INET6:
417+
rx->srx.transport_len = sizeof(struct sockaddr_in6);
418+
break;
412419
default:
413420
ret = -EAFNOSUPPORT;
414421
goto error_unlock;
@@ -563,7 +570,7 @@ static int rxrpc_create(struct net *net, struct socket *sock, int protocol,
563570
return -EAFNOSUPPORT;
564571

565572
/* we support transport protocol UDP/UDP6 only */
566-
if (protocol != PF_INET)
573+
if (protocol != PF_INET && protocol != PF_INET6)
567574
return -EPROTONOSUPPORT;
568575

569576
if (sock->type != SOCK_DGRAM)

net/rxrpc/conn_object.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,14 @@ struct rxrpc_connection *rxrpc_find_connection_rcu(struct rxrpc_local *local,
134134
srx.transport.sin.sin_addr.s_addr)
135135
goto not_found;
136136
break;
137+
case AF_INET6:
138+
if (peer->srx.transport.sin6.sin6_port !=
139+
srx.transport.sin6.sin6_port ||
140+
memcmp(&peer->srx.transport.sin6.sin6_addr,
141+
&srx.transport.sin6.sin6_addr,
142+
sizeof(struct in6_addr)) != 0)
143+
goto not_found;
144+
break;
137145
default:
138146
BUG();
139147
}

net/rxrpc/local_object.c

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ static long rxrpc_local_cmp_key(const struct rxrpc_local *local,
5858
memcmp(&local->srx.transport.sin.sin_addr,
5959
&srx->transport.sin.sin_addr,
6060
sizeof(struct in_addr));
61+
case AF_INET6:
62+
/* If the choice of UDP6 port is left up to the transport, then
63+
* the endpoint record doesn't match.
64+
*/
65+
return ((u16 __force)local->srx.transport.sin6.sin6_port -
66+
(u16 __force)srx->transport.sin6.sin6_port) ?:
67+
memcmp(&local->srx.transport.sin6.sin6_addr,
68+
&srx->transport.sin6.sin6_addr,
69+
sizeof(struct in6_addr));
6170
default:
6271
BUG();
6372
}
@@ -100,7 +109,8 @@ static int rxrpc_open_socket(struct rxrpc_local *local)
100109
struct sock *sock;
101110
int ret, opt;
102111

103-
_enter("%p{%d}", local, local->srx.transport_type);
112+
_enter("%p{%d,%d}",
113+
local, local->srx.transport_type, local->srx.transport.family);
104114

105115
/* create a socket to represent the local endpoint */
106116
ret = sock_create_kern(&init_net, local->srx.transport.family,
@@ -169,18 +179,8 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
169179
long diff;
170180
int ret;
171181

172-
if (srx->transport.family == AF_INET) {
173-
_enter("{%d,%u,%pI4+%hu}",
174-
srx->transport_type,
175-
srx->transport.family,
176-
&srx->transport.sin.sin_addr,
177-
ntohs(srx->transport.sin.sin_port));
178-
} else {
179-
_enter("{%d,%u}",
180-
srx->transport_type,
181-
srx->transport.family);
182-
return ERR_PTR(-EAFNOSUPPORT);
183-
}
182+
_enter("{%d,%d,%pISp}",
183+
srx->transport_type, srx->transport.family, &srx->transport);
184184

185185
mutex_lock(&rxrpc_local_mutex);
186186

@@ -233,13 +233,8 @@ struct rxrpc_local *rxrpc_lookup_local(const struct sockaddr_rxrpc *srx)
233233
found:
234234
mutex_unlock(&rxrpc_local_mutex);
235235

236-
_net("LOCAL %s %d {%d,%u,%pI4+%hu}",
237-
age,
238-
local->debug_id,
239-
local->srx.transport_type,
240-
local->srx.transport.family,
241-
&local->srx.transport.sin.sin_addr,
242-
ntohs(local->srx.transport.sin.sin_port));
236+
_net("LOCAL %s %d {%pISp}",
237+
age, local->debug_id, &local->srx.transport);
243238

244239
_leave(" = %p", local);
245240
return local;

net/rxrpc/output.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,22 @@ int rxrpc_send_data_packet(struct rxrpc_connection *conn, struct sk_buff *skb)
258258
(char *)&opt, sizeof(opt));
259259
}
260260
break;
261+
262+
case AF_INET6:
263+
opt = IPV6_PMTUDISC_DONT;
264+
ret = kernel_setsockopt(conn->params.local->socket,
265+
SOL_IPV6, IPV6_MTU_DISCOVER,
266+
(char *)&opt, sizeof(opt));
267+
if (ret == 0) {
268+
ret = kernel_sendmsg(conn->params.local->socket, &msg,
269+
iov, 1, iov[0].iov_len);
270+
271+
opt = IPV6_PMTUDISC_DO;
272+
kernel_setsockopt(conn->params.local->socket,
273+
SOL_IPV6, IPV6_MTU_DISCOVER,
274+
(char *)&opt, sizeof(opt));
275+
}
276+
break;
261277
}
262278

263279
up_write(&conn->params.local->defrag_sem);

net/rxrpc/peer_event.c

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ static struct rxrpc_peer *rxrpc_lookup_peer_icmp_rcu(struct rxrpc_local *local,
6666
}
6767
break;
6868

69+
case AF_INET6:
70+
srx.transport.sin6.sin6_port = serr->port;
71+
srx.transport_len = sizeof(struct sockaddr_in6);
72+
switch (serr->ee.ee_origin) {
73+
case SO_EE_ORIGIN_ICMP6:
74+
_net("Rx ICMP6");
75+
memcpy(&srx.transport.sin6.sin6_addr,
76+
skb_network_header(skb) + serr->addr_offset,
77+
sizeof(struct in6_addr));
78+
break;
79+
case SO_EE_ORIGIN_ICMP:
80+
_net("Rx ICMP on v6 sock");
81+
memcpy(&srx.transport.sin6.sin6_addr.s6_addr + 12,
82+
skb_network_header(skb) + serr->addr_offset,
83+
sizeof(struct in_addr));
84+
break;
85+
default:
86+
memcpy(&srx.transport.sin6.sin6_addr,
87+
&ipv6_hdr(skb)->saddr,
88+
sizeof(struct in6_addr));
89+
break;
90+
}
91+
break;
92+
6993
default:
7094
BUG();
7195
}

net/rxrpc/peer_object.c

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@
1616
#include <linux/skbuff.h>
1717
#include <linux/udp.h>
1818
#include <linux/in.h>
19+
#include <linux/in6.h>
1920
#include <linux/slab.h>
2021
#include <linux/hashtable.h>
2122
#include <net/sock.h>
2223
#include <net/af_rxrpc.h>
2324
#include <net/ip.h>
2425
#include <net/route.h>
26+
#include <net/ip6_route.h>
2527
#include "ar-internal.h"
2628

2729
static DEFINE_HASHTABLE(rxrpc_peer_hash, 10);
@@ -50,6 +52,11 @@ static unsigned long rxrpc_peer_hash_key(struct rxrpc_local *local,
5052
size = sizeof(srx->transport.sin.sin_addr);
5153
p = (u16 *)&srx->transport.sin.sin_addr;
5254
break;
55+
case AF_INET6:
56+
hash_key += (u16 __force)srx->transport.sin.sin_port;
57+
size = sizeof(srx->transport.sin6.sin6_addr);
58+
p = (u16 *)&srx->transport.sin6.sin6_addr;
59+
break;
5360
default:
5461
WARN(1, "AF_RXRPC: Unsupported transport address family\n");
5562
return 0;
@@ -93,6 +100,12 @@ static long rxrpc_peer_cmp_key(const struct rxrpc_peer *peer,
93100
memcmp(&peer->srx.transport.sin.sin_addr,
94101
&srx->transport.sin.sin_addr,
95102
sizeof(struct in_addr));
103+
case AF_INET6:
104+
return ((u16 __force)peer->srx.transport.sin6.sin6_port -
105+
(u16 __force)srx->transport.sin6.sin6_port) ?:
106+
memcmp(&peer->srx.transport.sin6.sin6_addr,
107+
&srx->transport.sin6.sin6_addr,
108+
sizeof(struct in6_addr));
96109
default:
97110
BUG();
98111
}
@@ -130,17 +143,7 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
130143

131144
peer = __rxrpc_lookup_peer_rcu(local, srx, hash_key);
132145
if (peer) {
133-
switch (srx->transport.family) {
134-
case AF_INET:
135-
_net("PEER %d {%d,%u,%pI4+%hu}",
136-
peer->debug_id,
137-
peer->srx.transport_type,
138-
peer->srx.transport.family,
139-
&peer->srx.transport.sin.sin_addr,
140-
ntohs(peer->srx.transport.sin.sin_port));
141-
break;
142-
}
143-
146+
_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
144147
_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
145148
}
146149
return peer;
@@ -152,22 +155,49 @@ struct rxrpc_peer *rxrpc_lookup_peer_rcu(struct rxrpc_local *local,
152155
*/
153156
static void rxrpc_assess_MTU_size(struct rxrpc_peer *peer)
154157
{
158+
struct dst_entry *dst;
155159
struct rtable *rt;
156-
struct flowi4 fl4;
160+
struct flowi fl;
161+
struct flowi4 *fl4 = &fl.u.ip4;
162+
struct flowi6 *fl6 = &fl.u.ip6;
157163

158164
peer->if_mtu = 1500;
159165

160-
rt = ip_route_output_ports(&init_net, &fl4, NULL,
161-
peer->srx.transport.sin.sin_addr.s_addr, 0,
162-
htons(7000), htons(7001),
163-
IPPROTO_UDP, 0, 0);
164-
if (IS_ERR(rt)) {
165-
_leave(" [route err %ld]", PTR_ERR(rt));
166-
return;
166+
memset(&fl, 0, sizeof(fl));
167+
switch (peer->srx.transport.family) {
168+
case AF_INET:
169+
rt = ip_route_output_ports(
170+
&init_net, fl4, NULL,
171+
peer->srx.transport.sin.sin_addr.s_addr, 0,
172+
htons(7000), htons(7001), IPPROTO_UDP, 0, 0);
173+
if (IS_ERR(rt)) {
174+
_leave(" [route err %ld]", PTR_ERR(rt));
175+
return;
176+
}
177+
dst = &rt->dst;
178+
break;
179+
180+
case AF_INET6:
181+
fl6->flowi6_iif = LOOPBACK_IFINDEX;
182+
fl6->flowi6_scope = RT_SCOPE_UNIVERSE;
183+
fl6->flowi6_proto = IPPROTO_UDP;
184+
memcpy(&fl6->daddr, &peer->srx.transport.sin6.sin6_addr,
185+
sizeof(struct in6_addr));
186+
fl6->fl6_dport = htons(7001);
187+
fl6->fl6_sport = htons(7000);
188+
dst = ip6_route_output(&init_net, NULL, fl6);
189+
if (IS_ERR(dst)) {
190+
_leave(" [route err %ld]", PTR_ERR(dst));
191+
return;
192+
}
193+
break;
194+
195+
default:
196+
BUG();
167197
}
168198

169-
peer->if_mtu = dst_mtu(&rt->dst);
170-
dst_release(&rt->dst);
199+
peer->if_mtu = dst_mtu(dst);
200+
dst_release(dst);
171201

172202
_leave(" [if_mtu %u]", peer->if_mtu);
173203
}
@@ -207,17 +237,22 @@ static void rxrpc_init_peer(struct rxrpc_peer *peer, unsigned long hash_key)
207237
rxrpc_assess_MTU_size(peer);
208238
peer->mtu = peer->if_mtu;
209239

210-
if (peer->srx.transport.family == AF_INET) {
240+
switch (peer->srx.transport.family) {
241+
case AF_INET:
211242
peer->hdrsize = sizeof(struct iphdr);
212-
switch (peer->srx.transport_type) {
213-
case SOCK_DGRAM:
214-
peer->hdrsize += sizeof(struct udphdr);
215-
break;
216-
default:
217-
BUG();
218-
break;
219-
}
220-
} else {
243+
break;
244+
case AF_INET6:
245+
peer->hdrsize = sizeof(struct ipv6hdr);
246+
break;
247+
default:
248+
BUG();
249+
}
250+
251+
switch (peer->srx.transport_type) {
252+
case SOCK_DGRAM:
253+
peer->hdrsize += sizeof(struct udphdr);
254+
break;
255+
default:
221256
BUG();
222257
}
223258

@@ -285,11 +320,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
285320
struct rxrpc_peer *peer, *candidate;
286321
unsigned long hash_key = rxrpc_peer_hash_key(local, srx);
287322

288-
_enter("{%d,%d,%pI4+%hu}",
289-
srx->transport_type,
290-
srx->transport_len,
291-
&srx->transport.sin.sin_addr,
292-
ntohs(srx->transport.sin.sin_port));
323+
_enter("{%pISp}", &srx->transport);
293324

294325
/* search the peer list first */
295326
rcu_read_lock();
@@ -326,11 +357,7 @@ struct rxrpc_peer *rxrpc_lookup_peer(struct rxrpc_local *local,
326357
peer = candidate;
327358
}
328359

329-
_net("PEER %d {%d,%pI4+%hu}",
330-
peer->debug_id,
331-
peer->srx.transport_type,
332-
&peer->srx.transport.sin.sin_addr,
333-
ntohs(peer->srx.transport.sin.sin_port));
360+
_net("PEER %d {%pISp}", peer->debug_id, &peer->srx.transport);
334361

335362
_leave(" = %p {u=%d}", peer, atomic_read(&peer->usage));
336363
return peer;

0 commit comments

Comments
 (0)