Set DSCP values when sending IP packets in socket-default

This commit is contained in:
Martin Willi 2013-02-06 13:17:55 +01:00
parent 6e82269ee6
commit ea5917afd8

View file

@ -55,6 +55,9 @@
#ifndef SOL_IPV6
#define SOL_IPV6 IPPROTO_IPV6
#endif
#ifndef IPV6_TCLASS
#define IPV6_TCLASS 67
#endif
/* IPV6_RECVPKTINFO is defined in RFC 3542 which obsoletes RFC 2292 that
* previously defined IPV6_PKTINFO */
@ -112,6 +115,26 @@ struct private_socket_default_socket_t {
*/
int ipv6_natt;
/**
* DSCP value set on IPv4 socket
*/
u_int8_t dscp4;
/**
* DSCP value set on IPv4 socket for NAT-T (4500 or natt)
*/
u_int8_t dscp4_natt;
/**
* DSCP value set on IPv6 socket (500 or port)
*/
u_int8_t dscp6;
/**
* DSCP value set on IPv6 socket for NAT-T (4500 or natt)
*/
u_int8_t dscp6_natt;
/**
* Maximum packet size to receive
*/
@ -310,6 +333,7 @@ METHOD(socket_t, sender, status_t,
struct msghdr msg;
struct cmsghdr *cmsg;
struct iovec iov;
u_int8_t *dscp;
src = packet->get_source(packet);
dst = packet->get_destination(packet);
@ -326,9 +350,11 @@ METHOD(socket_t, sender, status_t,
{
case AF_INET:
skt = this->ipv4;
dscp = &this->dscp4;
break;
case AF_INET6:
skt = this->ipv6;
dscp = &this->dscp6;
break;
default:
return FAILED;
@ -340,9 +366,11 @@ METHOD(socket_t, sender, status_t,
{
case AF_INET:
skt = this->ipv4_natt;
dscp = &this->dscp4_natt;
break;
case AF_INET6:
skt = this->ipv6_natt;
dscp = &this->dscp6_natt;
break;
default:
return FAILED;
@ -354,6 +382,43 @@ METHOD(socket_t, sender, status_t,
return FAILED;
}
/* setting DSCP values per-packet in a cmsg seems not to be supported
* on Linux. We instead setsockopt() before sending it, this should be
* safe as only a single thread calls send(). */
if (*dscp != packet->get_dscp(packet))
{
if (family == AF_INET)
{
u_int8_t ds4;
ds4 = packet->get_dscp(packet) << 2;
if (setsockopt(skt, SOL_IP, IP_TOS, &ds4, sizeof(ds4)) == 0)
{
*dscp = packet->get_dscp(packet);
}
else
{
DBG1(DBG_NET, "unable to set IP_TOS on socket: %s",
strerror(errno));
}
}
else
{
u_int ds6;
ds6 = packet->get_dscp(packet) << 2;
if (setsockopt(skt, SOL_IPV6, IPV6_TCLASS, &ds6, sizeof(ds6)) == 0)
{
*dscp = packet->get_dscp(packet);
}
else
{
DBG1(DBG_NET, "unable to set IPV6_TCLASS on socket: %s",
strerror(errno));
}
}
}
memset(&msg, 0, sizeof(struct msghdr));
msg.msg_name = dst->get_sockaddr(dst);;
msg.msg_namelen = *dst->get_sockaddr_len(dst);
@ -640,4 +705,3 @@ socket_default_socket_t *socket_default_socket_create()
return &this->public;
}