diff options
author | Ben Pfaff <blp@ovn.org> | 2017-07-14 14:33:46 -0700 |
---|---|---|
committer | Ben Pfaff <blp@ovn.org> | 2017-07-17 10:05:57 -0700 |
commit | 5d77b36b5ce5282bc39e52cb54f3cf37eee9334c (patch) | |
tree | 59dd3379c27b16a032ec6cbb37601f33e4a4051e | |
parent | fd245f1da9c4f87ebb737951a41429cdbe1d8cda (diff) | |
download | openvswitch-5d77b36b5ce5282bc39e52cb54f3cf37eee9334c.tar.gz |
Support IPv6 link-local address scopes on Linux.
I hadn't even heard of this feature before, but it seems to be at least
semi-standard to support Linux link-local address scopes via a % suffix,
e.g. fe80::1234%eth0 for a link-local address scoped to eth0. This commit
adds support.
I'd appreciate feedback from folks who understand this feature better than
me.
Reported-by: Ali Volkan Atli <Volkan.Atli@argela.com.tr>
Signed-off-by: Ben Pfaff <blp@ovn.org>
Acked-by: Darrell Ball <dlu998@gmail.com>
Tested-by: Numan Siddique <nusiddiq@redhat.com>
Acked-by: Numan Siddique <nusiddiq@redhat.com>
-rw-r--r-- | NEWS | 2 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | lib/socket-util.c | 65 | ||||
-rw-r--r-- | lib/vconn-active.man | 7 | ||||
-rw-r--r-- | lib/vconn-passive.man | 10 | ||||
-rw-r--r-- | ovsdb/remote-active.man | 20 | ||||
-rw-r--r-- | ovsdb/remote-passive.man | 29 |
7 files changed, 92 insertions, 44 deletions
@@ -69,6 +69,8 @@ Post-v2.7.0 - Add experimental support for hardware offloading * HW offloading is disabled by default. * HW offloading is done through the TC interface. + - IPv6 link local addresses are now supported on Linux. Use % to designate + the scope device. v2.7.0 - 21 Feb 2017 --------------------- diff --git a/configure.ac b/configure.ac index 23afe4c71..194c4b92e 100644 --- a/configure.ac +++ b/configure.ac @@ -107,6 +107,9 @@ AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec], [], [], [[#include <sys/stat.h>]]) AC_CHECK_MEMBERS([struct ifreq.ifr_flagshigh], [], [], [[#include <net/if.h>]]) AC_CHECK_MEMBERS([struct mmsghdr.msg_len], [], [], [[#include <sys/socket.h>]]) +AC_CHECK_MEMBERS([struct sockaddr_in6.sin6_scope_id], [], [], + [[#include <sys/socket.h> +#include <netinet/in.h>]]) AC_CHECK_FUNCS([mlockall strnlen getloadavg statvfs getmntent_r sendmmsg]) AC_CHECK_HEADERS([mntent.h sys/statvfs.h linux/types.h linux/if_ether.h stdatomic.h]) AC_CHECK_HEADERS([net/if_mib.h], [], [], [[#include <sys/types.h> diff --git a/lib/socket-util.c b/lib/socket-util.c index 82975aa62..85ed54c05 100644 --- a/lib/socket-util.c +++ b/lib/socket-util.c @@ -17,6 +17,7 @@ #include <config.h> #include "socket-util.h" #include <arpa/inet.h> +#include <ctype.h> #include <errno.h> #include <fcntl.h> #include <net/if.h> @@ -365,7 +366,7 @@ parse_bracketed_token(char **pp) static bool parse_sockaddr_components(struct sockaddr_storage *ss, - const char *host_s, + char *host_s, const char *port_s, uint16_t default_port, const char *s) { @@ -382,20 +383,38 @@ parse_sockaddr_components(struct sockaddr_storage *ss, } memset(ss, 0, sizeof *ss); - if (strchr(host_s, ':')) { + if (host_s && strchr(host_s, ':')) { struct sockaddr_in6 *sin6 = ALIGNED_CAST(struct sockaddr_in6 *, ss); + char *addr = strsep(&host_s, "%"); + sin6->sin6_family = AF_INET6; sin6->sin6_port = htons(port); - if (!ipv6_parse(host_s, &sin6->sin6_addr)) { - VLOG_ERR("%s: bad IPv6 address \"%s\"", s, host_s); + if (!addr || !*addr || !ipv6_parse(addr, &sin6->sin6_addr)) { + VLOG_ERR("%s: bad IPv6 address \"%s\"", s, addr ? addr : ""); goto exit; } + +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID + char *scope = strsep(&host_s, "%"); + if (scope && *scope) { + if (!scope[strspn(scope, "0123456789")]) { + sin6->sin6_scope_id = atoi(scope); + } else { + sin6->sin6_scope_id = if_nametoindex(scope); + if (!sin6->sin6_scope_id) { + VLOG_ERR("%s: bad IPv6 scope \"%s\" (%s)", + s, scope, ovs_strerror(errno)); + goto exit; + } + } + } +#endif } else { sin->sin_family = AF_INET; sin->sin_port = htons(port); - if (!ip_parse(host_s, &sin->sin_addr.s_addr)) { + if (host_s && !ip_parse(host_s, &sin->sin_addr.s_addr)) { VLOG_ERR("%s: bad IPv4 address \"%s\"", s, host_s); goto exit; } @@ -421,7 +440,7 @@ inet_parse_active(const char *target_, uint16_t default_port, { char *target = xstrdup(target_); const char *port; - const char *host; + char *host; char *p; bool ok; @@ -548,7 +567,7 @@ inet_parse_passive(const char *target_, int default_port, { char *target = xstrdup(target_); const char *port; - const char *host; + char *host; char *p; bool ok; @@ -559,8 +578,7 @@ inet_parse_passive(const char *target_, int default_port, VLOG_ERR("%s: port must be specified", target_); ok = false; } else { - ok = parse_sockaddr_components(ss, host ? host : "0.0.0.0", - port, default_port, target_); + ok = parse_sockaddr_components(ss, host, port, default_port, target_); } if (!ok) { memset(ss, 0, sizeof *ss); @@ -958,6 +976,21 @@ ss_get_port(const struct sockaddr_storage *ss) } } +/* Returns true if 'name' is safe to include inside a network address field. + * We want to avoid names that include confusing punctuation, etc. */ +static bool OVS_UNUSED +is_safe_name(const char *name) +{ + if (!name[0] || isdigit((unsigned char) name[0])) { + return false; + } + for (const char *p = name; *p; p++) { + if (!isalnum((unsigned char) *p) && *p != '-' && *p != '_') { + return false; + } + } + return true; +} /* Formats the IPv4 or IPv6 address in 'ss' into 's'. If 'ss' is an IPv6 * address, puts square brackets around the address. 'bufsize' should be at @@ -980,6 +1013,20 @@ ss_format_address(const struct sockaddr_storage *ss, struct ds *s) inet_ntop(AF_INET6, sin6->sin6_addr.s6_addr, tail, INET6_ADDRSTRLEN); s->length += strlen(tail); +#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID + uint32_t scope = sin6->sin6_scope_id; + if (scope) { + char namebuf[IF_NAMESIZE]; + char *name = if_indextoname(scope, namebuf); + ds_put_char(s, '%'); + if (name && is_safe_name(name)) { + ds_put_cstr(s, name); + } else { + ds_put_format(s, "%"PRIu32, scope); + } + } +#endif + ds_put_char(s, ']'); } else { OVS_NOT_REACHED(); diff --git a/lib/vconn-active.man b/lib/vconn-active.man index 3e789cc88..395879c8a 100644 --- a/lib/vconn-active.man +++ b/lib/vconn-active.man @@ -3,8 +3,11 @@ The specified \fIport\fR on the host at the given \fIip\fR, which must be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address format. Wrap IPv6 addresses in square brackets, -e.g. \fBtcp:[::1]:6653\fR. For \fBssl\fR, the \fB\-\-private\-key\fR, -\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory. +e.g. \fBtcp:[::1]:6653\fR. On Linux, use \fB%\fIdevice\fR to +designate a scope for IPv6 link-level addresses, +e.g. \fBtcp:[fe80::1234%eth0]:6653\fR. For \fBssl\fR, the +\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR +options are mandatory. .IP If \fIport\fR is not specified, it defaults to 6653. .TP diff --git a/lib/vconn-passive.man b/lib/vconn-passive.man index 9d9050b02..1ffa18397 100644 --- a/lib/vconn-passive.man +++ b/lib/vconn-passive.man @@ -1,10 +1,12 @@ .IP "\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]" .IQ "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]" Listens for OpenFlow connections on \fIport\fR. The default -\fIport\fR is 6653. By default, connections -are allowed from any IPv4 address. Specify \fIip\fR as an IPv4 -address or a bracketed IPv6 address (e.g. \fBptcp:6653:[::1]\fR). DNS -names may not be used. For \fBpssl\fR, the +\fIport\fR is 6653. By default, connections are allowed from any IPv4 +address. Specify \fIip\fR as an IPv4 address or a bracketed IPv6 +address (e.g. \fBptcp:6653:[::1]\fR). On Linux, use \fB%\fIdevice\fR +to designate a scope for IPv6 link-level addresses, +e.g. \fBptcp:6653:[fe80::1234%eth0]\fR. DNS names may +not be used. For \fBpssl\fR, the \fB\-\-private\-key\fR,\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory. .IP diff --git a/ovsdb/remote-active.man b/ovsdb/remote-active.man index 83d64652d..bf5b323dd 100644 --- a/ovsdb/remote-active.man +++ b/ovsdb/remote-active.man @@ -1,15 +1,13 @@ .IP "\fBssl:\fIip\fB:\fIport\fR" -The specified SSL \fIport\fR on the host at the given \fIip\fR, which -must be expressed as an IP address (not a DNS name) in IPv4 or IPv6 address -format. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with square -brackets, e.g.: \fBssl:[::1]:6640\fR. -The \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR -options are mandatory when this form is used. -. -.IP "\fBtcp:\fIip\fB:\fIport\fR" -Connect to the given TCP \fIport\fR on \fIip\fR, where \fIip\fR can be IPv4 -or IPv6 address. If \fIip\fR is an IPv6 address, then wrap \fIip\fR with -square brackets, e.g.: \fBtcp:[::1]:6640\fR. +.IQ "\fBtcp:\fIip\fB:\fIport\fR" +The given SSL or plain TCP \fIport\fR on the host at the given +\fIip\fR, which must be expressed as an IP address (not a DNS name) in +IPv4 or IPv6 address format. If \fIip\fR is an IPv6 address, then +wrap \fIip\fR with square brackets, e.g.: \fBssl:[::1]:6640\fR. On +Linux, use \fB%\fIdevice\fR to designate a scope for IPv6 link-level +addresses, e.g. \fBssl:[fe80::1234%eth0]:6653\fR. For \fBssl\fR, the +\fB\-\-private\-key\fR, \fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR +options are mandatory. . .IP "\fBunix:\fIfile\fR" On POSIX, connect to the Unix domain server socket named \fIfile\fR. diff --git a/ovsdb/remote-passive.man b/ovsdb/remote-passive.man index 5da2de87b..f2a186844 100644 --- a/ovsdb/remote-passive.man +++ b/ovsdb/remote-passive.man @@ -1,22 +1,15 @@ .IP "\fBpssl:\fIport\fR[\fB:\fIip\fR]" -Listen on the given SSL \fIport\fR for a connection. By default, -connections are not bound to a particular local IP address and -it listens only on IPv4 (but not IPv6) addresses, but -specifying \fIip\fR limits connections to those from the given -\fIip\fR, either IPv4 or IPv6 address. If \fIip\fR is -an IPv6 address, then wrap \fIip\fR with square brackets, e.g.: -\fBpssl:6640:[::1]\fR. The \fB\-\-private\-key\fR, -\fB\-\-certificate\fR, and \fB\-\-ca\-cert\fR options are mandatory -when this form is used. -. -.IP "\fBptcp:\fIport\fR[\fB:\fIip\fR]" -Listen on the given TCP \fIport\fR for a connection. By default, -connections are not bound to a particular local IP address and -it listens only on IPv4 (but not IPv6) addresses, but -\fIip\fR may be specified to listen only for connections to the given -\fIip\fR, either IPv4 or IPv6 address. If \fIip\fR is -an IPv6 address, then wrap \fIip\fR with square brackets, e.g.: -\fBptcp:6640:[::1]\fR. +.IQ "\fBptcp:\fIport\fR[\fB:\fIip\fR]" +Listen on the given SSL or TCP \fIport\fR for a connection. By +default, connections are not bound to a particular local IP address +and it listens only on IPv4 (but not IPv6) addresses, but specifying +\fIip\fR limits connections to those from the given \fIip\fR, either +IPv4 or IPv6 address. If \fIip\fR is an IPv6 address, then wrap +\fIip\fR with square brackets, e.g.: \fBpssl:6640:[::1]\fR. On Linux, +use \fB%\fIdevice\fR to designate a scope for IPv6 link-level +addresses, e.g. \fBpssl:6653:[fe80::1234%eth0]\fR. For \fBpssl\fR, +the \fB\-\-private\-key\fR, \fB\-\-certificate\fR, and +\fB\-\-ca\-cert\fR options are mandatory. . .IP "\fBpunix:\fIfile\fR" On POSIX, listen on the Unix domain server socket named \fIfile\fR for a |