mirror of
https://github.com/openvswitch/ovs
synced 2025-08-22 01:51:26 +00:00
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>
This commit is contained in:
parent
fd245f1da9
commit
5d77b36b5c
2
NEWS
2
NEWS
@ -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
|
||||
---------------------
|
||||
|
@ -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>
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user