Skip to content

Commit

Permalink
afs: Allow IPv6 address specification of VL servers
Browse files Browse the repository at this point in the history
Allow VL server specifications to be given IPv6 addresses as well as IPv4
addresses, for example as:

	echo add foo.org 1111:2222:3333:0:4444:5555:6666:7777 >/proc/fs/afs/cells

Note that ':' is the expected separator for separating IPv4 addresses, but
if a ',' is detected or no '.' is detected in the string, the delimiter is
switched to ','.

This also works with DNS AFSDB or SRV record strings fetched by upcall from
userspace.

Signed-off-by: David Howells <dhowells@redhat.com>
  • Loading branch information
David Howells committed Nov 13, 2017
1 parent 4d9df98 commit 3838d3e
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 26 deletions.
31 changes: 21 additions & 10 deletions fs/afs/cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include <linux/ctype.h>
#include <linux/dns_resolver.h>
#include <linux/sched.h>
#include <linux/inet.h>
#include <keys/rxrpc-type.h>
#include "internal.h"

Expand Down Expand Up @@ -86,28 +87,38 @@ static struct afs_cell *afs_cell_alloc(struct afs_net *net,
delimiter = ',';

} else {
if (strchr(vllist, ',') || !strchr(vllist, '.'))
delimiter = ',';
_vllist = vllist;
}

/* fill in the VL server list from the rest of the string */
do {
struct sockaddr_rxrpc *srx = &cell->vl_addrs[cell->vl_naddrs];
unsigned a, b, c, d;
const char *end;

next = strchr(_vllist, delimiter);
if (next)
*next++ = 0;

if (sscanf(_vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
goto bad_address;

if (a > 255 || b > 255 || c > 255 || d > 255)
if (in4_pton(_vllist, -1, (u8 *)&srx->transport.sin6.sin6_addr.s6_addr32[3],
-1, &end)) {
srx->transport_len = sizeof(struct sockaddr_in6);
srx->transport.sin6.sin6_family = AF_INET6;
srx->transport.sin6.sin6_flowinfo = 0;
srx->transport.sin6.sin6_scope_id = 0;
srx->transport.sin6.sin6_addr.s6_addr32[0] = 0;
srx->transport.sin6.sin6_addr.s6_addr32[1] = 0;
srx->transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
} else if (in6_pton(_vllist, -1, srx->transport.sin6.sin6_addr.s6_addr,
-1, &end)) {
srx->transport_len = sizeof(struct sockaddr_in6);
srx->transport.sin6.sin6_family = AF_INET6;
srx->transport.sin6.sin6_flowinfo = 0;
srx->transport.sin6.sin6_scope_id = 0;
} else {
goto bad_address;

srx->transport_len = sizeof(struct sockaddr_in);
srx->transport.sin.sin_family = AF_INET;
srx->transport.sin.sin_addr.s_addr =
htonl((a << 24) | (b << 16) | (c << 8) | d);
}

} while (cell->vl_naddrs++,
cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (_vllist = next));
Expand Down
2 changes: 1 addition & 1 deletion fs/afs/proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -662,7 +662,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v)

/* display one cell per line on subsequent lines */
sprintf(ipaddr, "%pISp", &server->addr.transport);
seq_printf(m, "%3d %-15.15s %5d\n",
seq_printf(m, "%3d %-15s %5d\n",
atomic_read(&server->usage), ipaddr, server->fs_state);

return 0;
Expand Down
11 changes: 5 additions & 6 deletions fs/afs/rxrpc.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,21 +46,20 @@ int afs_open_socket(struct afs_net *net)

_enter("");

ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET, &socket);
ret = sock_create_kern(&init_net, AF_RXRPC, SOCK_DGRAM, PF_INET6, &socket);
if (ret < 0)
goto error_1;

socket->sk->sk_allocation = GFP_NOFS;

/* bind the callback manager's address to make this a server socket */
memset(&srx, 0, sizeof(srx));
srx.srx_family = AF_RXRPC;
srx.srx_service = CM_SERVICE;
srx.transport_type = SOCK_DGRAM;
srx.transport_len = sizeof(srx.transport.sin);
srx.transport.sin.sin_family = AF_INET;
srx.transport.sin.sin_port = htons(AFS_CM_PORT);
memset(&srx.transport.sin.sin_addr, 0,
sizeof(srx.transport.sin.sin_addr));
srx.transport_len = sizeof(srx.transport.sin6);
srx.transport.sin6.sin6_family = AF_INET6;
srx.transport.sin6.sin6_port = htons(AFS_CM_PORT);

ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx));
if (ret < 0)
Expand Down
5 changes: 0 additions & 5 deletions fs/afs/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,6 @@ struct afs_server *afs_find_server(struct afs_net *net,

_enter("{%d,%pIS}", srx->transport.family, &srx->transport);

if (srx->transport.family != AF_INET) {
WARN(true, "AFS does not yes support non-IPv4 addresses\n");
return NULL;
}

read_lock(&net->servers_lock);

p = net->servers.rb_node;
Expand Down
13 changes: 9 additions & 4 deletions fs/afs/vlclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,15 @@ static int afs_deliver_vl_get_entry_by_xxx(struct afs_call *call)
entry->servers[loop].srx_family = AF_RXRPC;
entry->servers[loop].srx_service = FS_SERVICE;
entry->servers[loop].transport_type = SOCK_DGRAM;
entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin);
entry->servers[loop].transport.sin.sin_family = AF_INET;
entry->servers[loop].transport.sin.sin_port = htons(AFS_FS_PORT);
entry->servers[loop].transport.sin.sin_addr.s_addr = *bp++;
entry->servers[loop].transport_len = sizeof(entry->servers[loop].transport.sin6);
entry->servers[loop].transport.sin6.sin6_family = AF_INET6;
entry->servers[loop].transport.sin6.sin6_port = htons(AFS_FS_PORT);
entry->servers[loop].transport.sin6.sin6_flowinfo = 0;
entry->servers[loop].transport.sin6.sin6_scope_id = 0;
entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[0] = 0;
entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[1] = 0;
entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
entry->servers[loop].transport.sin6.sin6_addr.s6_addr32[3] = *bp++;
}

bp += 8; /* partition IDs */
Expand Down

0 comments on commit 3838d3e

Please sign in to comment.