Skip to content

Commit

Permalink
socket-util: Use correct address family in set_dscp(), instead of gue…
Browse files Browse the repository at this point in the history
…ssing.

The set_dscp() function, until now, tried to set the DSCP as IPv4 and as
IPv6. This worked OK on Linux, where an ENOPROTOOPT error made it really
clear which one was wrong, but FreeBSD uses EINVAL instead, which has
multiple meanings and which it therefore seems somewhat risky to ignore.
Instead, this commit just tries to set the correct address family's DSCP
option.

Tested by Alex Wang on FreeBSD 9.3.

Reported-by: Atanu Ghosh <[email protected]>
Signed-off-by: Ben Pfaff <[email protected]>
Co-authored-by: Alex Wang <[email protected]>
Signed-off-by: Alex Wang <[email protected]>
Tested-by: Alex Wang <[email protected]>
  • Loading branch information
blp and yew011 committed Feb 20, 2015
1 parent c2e3cba commit afc1d53
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 40 deletions.
44 changes: 20 additions & 24 deletions lib/socket-util.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -101,11 +101,14 @@ setsockopt_tcp_nodelay(int fd)
}
}

/* Sets the DSCP value of socket 'fd' to 'dscp', which must be 63 or less.
* 'family' must indicate the socket's address family (AF_INET or AF_INET6, to
* do anything useful). */
int
set_dscp(int fd, uint8_t dscp)
set_dscp(int fd, int family, uint8_t dscp)
{
int retval;
int val;
bool success;

#ifdef _WIN32
/* XXX: Consider using QoS2 APIs for Windows to set dscp. */
Expand All @@ -115,29 +118,22 @@ set_dscp(int fd, uint8_t dscp)
if (dscp > 63) {
return EINVAL;
}

/* Note: this function is used for both of IPv4 and IPv6 sockets */
success = false;
val = dscp << 2;
if (setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val)) {
if (sock_errno() != ENOPROTOOPT) {
return sock_errno();
}
} else {
success = true;
}
if (setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof val)) {
if (sock_errno() != ENOPROTOOPT) {
return sock_errno();
}
} else {
success = true;
}
if (!success) {

switch (family) {
case AF_INET:
retval = setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val);
break;

case AF_INET6:
retval = setsockopt(fd, IPPROTO_IPV6, IPV6_TCLASS, &val, sizeof val);
break;

default:
return ENOPROTOOPT;
}

return 0;
return retval ? sock_errno() : 0;
}

/* Translates 'host_name', which must be a string representation of an IP
Expand Down Expand Up @@ -470,7 +466,7 @@ inet_open_active(int style, const char *target, uint16_t default_port,
/* The dscp bits must be configured before connect() to ensure that the
* TOS field is set during the connection establishment. If set after
* connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp);
error = set_dscp(fd, ss.ss_family, dscp);
if (error) {
VLOG_ERR("%s: set_dscp: %s", target, sock_strerror(error));
goto exit;
Expand Down Expand Up @@ -611,7 +607,7 @@ inet_open_passive(int style, const char *target, int default_port,
/* The dscp bits must be configured before connect() to ensure that the TOS
* field is set during the connection establishment. If set after
* connect(), the handshake SYN frames will be sent with a TOS of 0. */
error = set_dscp(fd, dscp);
error = set_dscp(fd, ss.ss_family, dscp);
if (error) {
VLOG_ERR("%s: set_dscp: %s", target, sock_strerror(error));
goto error;
Expand Down
4 changes: 2 additions & 2 deletions lib/socket-util.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Nicira, Inc.
* Copyright (c) 2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,7 +30,7 @@
int set_nonblocking(int fd);
void xset_nonblocking(int fd);
void setsockopt_tcp_nodelay(int fd);
int set_dscp(int fd, uint8_t dscp);
int set_dscp(int fd, int family, uint8_t dscp);

int lookup_ip(const char *host_name, struct in_addr *address);
int lookup_ipv6(const char *host_name, struct in6_addr *address);
Expand Down
29 changes: 15 additions & 14 deletions python/ovs/socket_util.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2010, 2012, 2014 Nicira, Inc.
# Copyright (c) 2010, 2012, 2014, 2015 Nicira, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -213,14 +213,16 @@ def inet_open_active(style, target, default_port, dscp):
is_addr_inet = is_valid_ipv4_address(address[0])
if is_addr_inet:
sock = socket.socket(socket.AF_INET, style, 0)
family = socket.AF_INET
else:
sock = socket.socket(socket.AF_INET6, style, 0)
family = socket.AF_INET6
except socket.error, e:
return get_exception_errno(e), None

try:
set_nonblocking(sock)
set_dscp(sock, dscp)
set_dscp(sock, family, dscp)
try:
sock.connect(address)
except socket.error, e:
Expand Down Expand Up @@ -292,21 +294,20 @@ def set_nonblocking(sock):
% os.strerror(get_exception_errno(e)))


def set_dscp(sock, dscp):
def set_dscp(sock, family, dscp):
if dscp > 63:
raise ValueError("Invalid dscp %d" % dscp)

# Note: this function is used for both of IPv4 and IPv6 sockets
success = False
val = dscp << 2
try:
sock.setsockopt(socket.IPPROTO_IP, socket.IP_TOS, val)
except socket.error, e:
if get_exception_errno(e) != errno.ENOPROTOOPT:
if family == socket.AF_INET:
try:
sock.setsockopt(socket.IPPROTO_IP, socket.IP_TOS, val)
except socket.error, e:
raise
success = True
try:
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_TCLASS, val)
except socket.error, e:
if get_exception_errno(e) != errno.ENOPROTOOPT or not success:
elif family == socket.AF_INET6:
try:
sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_TCLASS, val)
except socket.error, e:
raise
else:
raise

0 comments on commit afc1d53

Please sign in to comment.