Skip to content

Commit f5dd3d0

Browse files
David Herrmanndavem330
authored andcommitted
net: introduce SO_BINDTOIFINDEX sockopt
This introduces a new generic SOL_SOCKET-level socket option called SO_BINDTOIFINDEX. It behaves similar to SO_BINDTODEVICE, but takes a network interface index as argument, rather than the network interface name. User-space often refers to network-interfaces via their index, but has to temporarily resolve it to a name for a call into SO_BINDTODEVICE. This might pose problems when the network-device is renamed asynchronously by other parts of the system. When this happens, the SO_BINDTODEVICE might either fail, or worse, it might bind to the wrong device. In most cases user-space only ever operates on devices which they either manage themselves, or otherwise have a guarantee that the device name will not change (e.g., devices that are UP cannot be renamed). However, particularly in libraries this guarantee is non-obvious and it would be nice if that race-condition would simply not exist. It would make it easier for those libraries to operate even in situations where the device-name might change under the hood. A real use-case that we recently hit is trying to start the network stack early in the initrd but make it survive into the real system. Existing distributions rename network-interfaces during the transition from initrd into the real system. This, obviously, cannot affect devices that are up and running (unless you also consider moving them between network-namespaces). However, the network manager now has to make sure its management engine for dormant devices will not run in parallel to these renames. Particularly, when you offload operations like DHCP into separate processes, these might setup their sockets early, and thus have to resolve the device-name possibly running into this race-condition. By avoiding a call to resolve the device-name, we no longer depend on the name and can run network setup of dormant devices in parallel to the transition off the initrd. The SO_BINDTOIFINDEX ioctl plugs this race. Reviewed-by: Tom Gundersen <[email protected]> Signed-off-by: David Herrmann <[email protected]> Acked-by: Willem de Bruijn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 692d7b5 commit f5dd3d0

File tree

9 files changed

+52
-10
lines changed

9 files changed

+52
-10
lines changed

arch/alpha/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,4 +115,6 @@
115115
#define SO_TXTIME 61
116116
#define SCM_TXTIME SO_TXTIME
117117

118+
#define SO_BINDTOIFINDEX 62
119+
118120
#endif /* _UAPI_ASM_SOCKET_H */

arch/ia64/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,4 +117,6 @@
117117
#define SO_TXTIME 61
118118
#define SCM_TXTIME SO_TXTIME
119119

120+
#define SO_BINDTOIFINDEX 62
121+
120122
#endif /* _ASM_IA64_SOCKET_H */

arch/mips/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,4 +126,6 @@
126126
#define SO_TXTIME 61
127127
#define SCM_TXTIME SO_TXTIME
128128

129+
#define SO_BINDTOIFINDEX 62
130+
129131
#endif /* _UAPI_ASM_SOCKET_H */

arch/parisc/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,6 @@
107107
#define SO_TXTIME 0x4036
108108
#define SCM_TXTIME SO_TXTIME
109109

110+
#define SO_BINDTOIFINDEX 0x4037
111+
110112
#endif /* _UAPI_ASM_SOCKET_H */

arch/s390/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,6 @@
114114
#define SO_TXTIME 61
115115
#define SCM_TXTIME SO_TXTIME
116116

117+
#define SO_BINDTOIFINDEX 62
118+
117119
#endif /* _ASM_SOCKET_H */

arch/sparc/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@
104104
#define SO_TXTIME 0x003f
105105
#define SCM_TXTIME SO_TXTIME
106106

107+
#define SO_BINDTOIFINDEX 0x0041
108+
107109
/* Security levels - as per NRL IPv6 - don't actually do anything */
108110
#define SO_SECURITY_AUTHENTICATION 0x5001
109111
#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002

arch/xtensa/include/uapi/asm/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,6 @@
119119
#define SO_TXTIME 61
120120
#define SCM_TXTIME SO_TXTIME
121121

122+
#define SO_BINDTOIFINDEX 62
123+
122124
#endif /* _XTENSA_SOCKET_H */

include/uapi/asm-generic/socket.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,6 @@
110110
#define SO_TXTIME 61
111111
#define SCM_TXTIME SO_TXTIME
112112

113+
#define SO_BINDTOIFINDEX 62
114+
113115
#endif /* __ASM_GENERIC_SOCKET_H */

net/core/sock.c

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -520,20 +520,43 @@ struct dst_entry *sk_dst_check(struct sock *sk, u32 cookie)
520520
}
521521
EXPORT_SYMBOL(sk_dst_check);
522522

523-
static int sock_setbindtodevice(struct sock *sk, char __user *optval,
524-
int optlen)
523+
static int sock_setbindtodevice_locked(struct sock *sk, int ifindex)
525524
{
526525
int ret = -ENOPROTOOPT;
527526
#ifdef CONFIG_NETDEVICES
528527
struct net *net = sock_net(sk);
529-
char devname[IFNAMSIZ];
530-
int index;
531528

532529
/* Sorry... */
533530
ret = -EPERM;
534531
if (!ns_capable(net->user_ns, CAP_NET_RAW))
535532
goto out;
536533

534+
ret = -EINVAL;
535+
if (ifindex < 0)
536+
goto out;
537+
538+
sk->sk_bound_dev_if = ifindex;
539+
if (sk->sk_prot->rehash)
540+
sk->sk_prot->rehash(sk);
541+
sk_dst_reset(sk);
542+
543+
ret = 0;
544+
545+
out:
546+
#endif
547+
548+
return ret;
549+
}
550+
551+
static int sock_setbindtodevice(struct sock *sk, char __user *optval,
552+
int optlen)
553+
{
554+
int ret = -ENOPROTOOPT;
555+
#ifdef CONFIG_NETDEVICES
556+
struct net *net = sock_net(sk);
557+
char devname[IFNAMSIZ];
558+
int index;
559+
537560
ret = -EINVAL;
538561
if (optlen < 0)
539562
goto out;
@@ -566,14 +589,9 @@ static int sock_setbindtodevice(struct sock *sk, char __user *optval,
566589
}
567590

568591
lock_sock(sk);
569-
sk->sk_bound_dev_if = index;
570-
if (sk->sk_prot->rehash)
571-
sk->sk_prot->rehash(sk);
572-
sk_dst_reset(sk);
592+
ret = sock_setbindtodevice_locked(sk, index);
573593
release_sock(sk);
574594

575-
ret = 0;
576-
577595
out:
578596
#endif
579597

@@ -1055,6 +1073,10 @@ int sock_setsockopt(struct socket *sock, int level, int optname,
10551073
}
10561074
break;
10571075

1076+
case SO_BINDTOIFINDEX:
1077+
ret = sock_setbindtodevice_locked(sk, val);
1078+
break;
1079+
10581080
default:
10591081
ret = -ENOPROTOOPT;
10601082
break;
@@ -1399,6 +1421,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
13991421
SOF_TXTIME_REPORT_ERRORS : 0;
14001422
break;
14011423

1424+
case SO_BINDTOIFINDEX:
1425+
v.val = sk->sk_bound_dev_if;
1426+
break;
1427+
14021428
default:
14031429
/* We implement the SO_SNDLOWAT etc to not be settable
14041430
* (1003.1g 7).

0 commit comments

Comments
 (0)