From 82d673f8c9dd39cc78cb7567fe59ebda2b88bf2d Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Mon, 12 Sep 2016 10:14:50 +0200 Subject: Implement IPV6_TCLASS --- erts/emulator/drivers/common/inet_drv.c | 53 ++++++++++++++++++++++++++++++++ erts/preloaded/ebin/prim_inet.beam | Bin 76268 -> 76544 bytes erts/preloaded/src/prim_inet.erl | 15 ++++++++- lib/kernel/doc/src/inet.xml | 9 ++++++ lib/kernel/src/inet.erl | 10 +++--- lib/kernel/src/inet_int.hrl | 1 + lib/kernel/test/gen_tcp_api_SUITE.erl | 21 ++++++++++++- 7 files changed, 102 insertions(+), 7 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 254d3baeb1..14fb1fada6 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -777,6 +777,7 @@ static int is_nonzero(const char *s, size_t n) #define INET_LOPT_NETNS 38 /* Network namespace pathname */ #define INET_LOPT_TCP_SHOW_ECONNRESET 39 /* tell user about incoming RST */ #define INET_LOPT_LINE_DELIM 40 /* Line delimiting char */ +#define INET_OPT_TCLASS 41 /* IPv6 transport class */ /* SCTP options: a separate range, from 100: */ #define SCTP_OPT_RTOINFO 100 #define SCTP_OPT_ASSOCINFO 101 @@ -1330,6 +1331,7 @@ static ErlDrvTermData am_reuseaddr; static ErlDrvTermData am_dontroute; static ErlDrvTermData am_priority; static ErlDrvTermData am_tos; +static ErlDrvTermData am_tclass; static ErlDrvTermData am_ipv6_v6only; static ErlDrvTermData am_netns; #endif @@ -3720,6 +3722,7 @@ static void inet_init_sctp(void) { INIT_ATOM(dontroute); INIT_ATOM(priority); INIT_ATOM(tos); + INIT_ATOM(tclass); INIT_ATOM(ipv6_v6only); INIT_ATOM(netns); @@ -6228,6 +6231,17 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #else continue; #endif + case INET_OPT_TCLASS: +#if defined(IPV6_TCLASS) && defined(SOL_IPV6) + proto = SOL_IPV6; + type = IPV6_TCLASS; + propagate = 1; + DEBUGF(("inet_set_opts(%ld): s=%d, IPV6_TCLASS=%d\r\n", + (long)desc->port, desc->s, ival)); + break; +#else + continue; +#endif case TCP_OPT_NODELAY: proto = IPPROTO_TCP; @@ -6661,6 +6675,21 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) continue; /* Option not supported -- ignore it */ # endif + case INET_OPT_TCLASS: +# if defined(IPV6_TCLASS) && defined(SOL_IPV6) + { + arg.ival= get_int32 (curr); curr += 4; + proto = SOL_IPV6; + type = IPV6_TCLASS; + arg_ptr = (char*) (&arg.ival); + arg_sz = sizeof ( arg.ival); + break; + } +# else + continue; /* Option not supported -- ignore it */ +# endif + + case INET_OPT_IPV6_V6ONLY: # if HAVE_DECL_IPV6_V6ONLY { @@ -7161,6 +7190,16 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, *ptr++ = opt; put_int32(0, ptr); continue; +#endif + case INET_OPT_TCLASS: +#if defined(IPV6_TCLASS) && defined(SOL_IPV6) + proto = SOL_IPV6; + type = IPV6_TCLASS; + break; +#else + *ptr++ = opt; + put_int32(0, ptr); + continue; #endif case INET_OPT_REUSEADDR: type = SO_REUSEADDR; @@ -7556,6 +7595,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, case INET_OPT_DONTROUTE: case INET_OPT_PRIORITY : case INET_OPT_TOS : + case INET_OPT_TCLASS : case INET_OPT_IPV6_V6ONLY: case SCTP_OPT_AUTOCLOSE: case SCTP_OPT_MAXSEG : @@ -7627,6 +7667,19 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, # else /* Not supported -- ignore */ continue; +# endif + } + case INET_OPT_TCLASS: + { +# if defined(IPV6_TCLASS) && defined(SOL_IPV6) + proto = SOL_IPV6; + type = IPV6_TCLASS; + is_int = 1; + tag = am_tclass; + break; +# else + /* Not supported -- ignore */ + continue; # endif } case INET_OPT_IPV6_V6ONLY: diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam index ae4861c336..1a573ce297 100644 Binary files a/erts/preloaded/ebin/prim_inet.beam and b/erts/preloaded/ebin/prim_inet.beam differ diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index bcf16402b0..61f727e8a4 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -347,7 +347,17 @@ accept_opts(L, S) -> case getopts(L, [active, nodelay, keepalive, delay_send, priority, tos]) of {ok, Opts} -> case setopts(S, Opts) of - ok -> {ok, S}; + ok -> + case getopts(L, [tclass]) of + {ok, []} -> + {ok, S}; + {ok, TClassOpts} -> + case setopts(S, TClassOpts) of + ok -> + {ok, S}; + Error -> close(S), Error + end + end; Error -> close(S), Error end; Error -> @@ -1196,6 +1206,7 @@ enc_opt(sndbuf) -> ?INET_OPT_SNDBUF; enc_opt(recbuf) -> ?INET_OPT_RCVBUF; enc_opt(priority) -> ?INET_OPT_PRIORITY; enc_opt(tos) -> ?INET_OPT_TOS; +enc_opt(tclass) -> ?INET_OPT_TCLASS; enc_opt(nodelay) -> ?TCP_OPT_NODELAY; enc_opt(multicast_if) -> ?UDP_OPT_MULTICAST_IF; enc_opt(multicast_ttl) -> ?UDP_OPT_MULTICAST_TTL; @@ -1255,6 +1266,7 @@ dec_opt(?INET_OPT_SNDBUF) -> sndbuf; dec_opt(?INET_OPT_RCVBUF) -> recbuf; dec_opt(?INET_OPT_PRIORITY) -> priority; dec_opt(?INET_OPT_TOS) -> tos; +dec_opt(?INET_OPT_TCLASS) -> tclass; dec_opt(?TCP_OPT_NODELAY) -> nodelay; dec_opt(?UDP_OPT_MULTICAST_IF) -> multicast_if; dec_opt(?UDP_OPT_MULTICAST_TTL) -> multicast_ttl; @@ -1329,6 +1341,7 @@ type_opt_1(sndbuf) -> int; type_opt_1(recbuf) -> int; type_opt_1(priority) -> int; type_opt_1(tos) -> int; +type_opt_1(tclass) -> int; type_opt_1(nodelay) -> bool; type_opt_1(ipv6_v6only) -> bool; %% multicast diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 3f4e3684f4..d907cef7d3 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -1092,6 +1092,15 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp The option is ignored on platforms where it is not implemented. Use with caution.

+ {tclass, Integer} + +

+ Sets IPV6_TCLASS IP level options on platforms + where this is implemented. The behavior and allowed range + varies between different systems. + The option is ignored on platforms where it is not + implemented. Use with caution.

+

In addition to these options, raw option specifications can be used. The raw options are diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl index 75dd800c6b..f5c13ecdd7 100644 --- a/lib/kernel/src/inet.erl +++ b/lib/kernel/src/inet.erl @@ -677,7 +677,7 @@ parse_strict_address(Addr) -> %% Return a list of available options options() -> [ - tos, priority, reuseaddr, keepalive, dontroute, linger, + tos, tclass, priority, reuseaddr, keepalive, dontroute, linger, broadcast, sndbuf, recbuf, nodelay, ipv6_v6only, buffer, header, active, packet, deliver, mode, multicast_if, multicast_ttl, multicast_loop, @@ -698,7 +698,7 @@ stats() -> %% Available options for tcp:connect %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% connect_options() -> - [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, + [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, packet_size, buffer, mode, deliver, line_delimiter, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, raw, @@ -766,7 +766,7 @@ con_add(Name, Val, #connect_opts{} = R, Opts, AllOpts) -> %% Available options for tcp:listen %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% listen_options() -> - [tos, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, + [tos, tclass, priority, reuseaddr, keepalive, linger, sndbuf, recbuf, nodelay, header, active, packet, buffer, mode, deliver, backlog, ipv6_v6only, exit_on_close, high_watermark, low_watermark, high_msgq_watermark, low_msgq_watermark, send_timeout, send_timeout_close, delay_send, @@ -846,7 +846,7 @@ tcp_module_1(Opts, Address) -> %% Available options for udp:open %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% udp_options() -> - [tos, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, + [tos, tclass, priority, reuseaddr, sndbuf, recbuf, header, active, buffer, mode, deliver, ipv6_v6only, broadcast, dontroute, multicast_if, multicast_ttl, multicast_loop, add_membership, drop_membership, read_packets,raw, @@ -917,7 +917,7 @@ udp_module(Opts) -> % (*) passing of open FDs ("fdopen") is not supported. sctp_options() -> [ % The following are generic inet options supported for SCTP sockets: - mode, active, buffer, tos, priority, dontroute, reuseaddr, linger, sndbuf, + mode, active, buffer, tos, tclass, priority, dontroute, reuseaddr, linger, sndbuf, recbuf, ipv6_v6only, high_msgq_watermark, low_msgq_watermark, % Other options are SCTP-specific (though they may be similar to their diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl index c8a8962e78..4e8f59a3b9 100644 --- a/lib/kernel/src/inet_int.hrl +++ b/lib/kernel/src/inet_int.hrl @@ -153,6 +153,7 @@ -define(INET_LOPT_NETNS, 38). -define(INET_LOPT_TCP_SHOW_ECONNRESET, 39). -define(INET_LOPT_LINE_DELIM, 40). +-define(INET_OPT_TCLASS, 41). % Specific SCTP options: separate range: -define(SCTP_OPT_RTOINFO, 100). -define(SCTP_OPT_ASSOCINFO, 101). diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index 77ec89b4f4..d630032480 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -38,7 +38,7 @@ t_local_basic/1, t_local_unbound/1, t_local_fdopen/1, t_local_fdopen_listen/1, t_local_fdopen_listen_unbound/1, t_local_fdopen_connect/1, t_local_fdopen_connect_unbound/1, - t_local_abstract/1]). + t_local_abstract/1, t_accept_inet6_tclass/1]). -export([getsockfd/0,closesockfd/1]). @@ -50,6 +50,7 @@ all() -> [{group, t_accept}, {group, t_connect}, {group, t_recv}, t_shutdown_write, t_shutdown_both, t_shutdown_error, t_shutdown_async, t_fdopen, t_fdconnect, t_implicit_inet6, + t_accept_inet6_tclass, {group, t_local}]. groups() -> @@ -521,6 +522,24 @@ local_handshake(S, SAddr, C, CAddr) -> SData = ok(gen_tcp:recv(C, length(SData))), ok. +t_accept_inet6_tclass(Config) when is_list(Config) -> + TClassOpt = {tclass,8#56 bsl 2}, % Expedited forwarding + case gen_tcp:listen(0, [inet6,TClassOpt]) of + {ok,L} -> + LPort = ok(inet:port(L)), + Loopback = {0,0,0,0,0,0,0,1}, + Sa = ok(gen_tcp:connect(Loopback, LPort, [])), + Sb = ok(gen_tcp:accept(L)), + [TClassOpt] = ok(inet:getopts(Sb, [tclass])), + ok = gen_tcp:close(Sb), + ok = gen_tcp:close(Sa), + ok = gen_tcp:close(L), + ok; + {error,_} -> + {skip,"IPv6 not supported"} + end. + + %%% Utilities %% Calls M:F/length(A), which should return a timeout error, and complete -- cgit v1.2.3 From 8d5a41b9eeae54d1135c570878fecc2ad3ad1d8e Mon Sep 17 00:00:00 2001 From: Raimo Niskanen Date: Tue, 13 Sep 2016 09:40:01 +0200 Subject: Tune 'tclass' semantics --- erts/emulator/drivers/common/inet_drv.c | 11 +++-------- lib/kernel/test/gen_tcp_api_SUITE.erl | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 14fb1fada6..1885338ce5 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -6231,16 +6231,14 @@ static int inet_set_opts(inet_descriptor* desc, char* ptr, int len) #else continue; #endif - case INET_OPT_TCLASS: #if defined(IPV6_TCLASS) && defined(SOL_IPV6) + case INET_OPT_TCLASS: proto = SOL_IPV6; type = IPV6_TCLASS; propagate = 1; DEBUGF(("inet_set_opts(%ld): s=%d, IPV6_TCLASS=%d\r\n", (long)desc->port, desc->s, ival)); break; -#else - continue; #endif case TCP_OPT_NODELAY: @@ -6675,8 +6673,8 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) continue; /* Option not supported -- ignore it */ # endif - case INET_OPT_TCLASS: # if defined(IPV6_TCLASS) && defined(SOL_IPV6) + case INET_OPT_TCLASS: { arg.ival= get_int32 (curr); curr += 4; proto = SOL_IPV6; @@ -6685,8 +6683,6 @@ static int sctp_set_opts(inet_descriptor* desc, char* ptr, int len) arg_sz = sizeof ( arg.ival); break; } -# else - continue; /* Option not supported -- ignore it */ # endif @@ -7197,8 +7193,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, type = IPV6_TCLASS; break; #else - *ptr++ = opt; - put_int32(0, ptr); + TRUNCATE_TO(0,ptr); continue; #endif case INET_OPT_REUSEADDR: diff --git a/lib/kernel/test/gen_tcp_api_SUITE.erl b/lib/kernel/test/gen_tcp_api_SUITE.erl index d630032480..92a74465b7 100644 --- a/lib/kernel/test/gen_tcp_api_SUITE.erl +++ b/lib/kernel/test/gen_tcp_api_SUITE.erl @@ -536,7 +536,7 @@ t_accept_inet6_tclass(Config) when is_list(Config) -> ok = gen_tcp:close(L), ok; {error,_} -> - {skip,"IPv6 not supported"} + {skip,"IPv6 TCLASS not supported"} end. -- cgit v1.2.3