aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-18 12:05:00 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit1a3aca0a849af0bae994c9cf89de0dcfe7b310c2 (patch)
treeb8085134c12d89b06afd3a251005e074e186ca4c
parentebd626e7b4259bdfb4ddb34ce2d298d0feb0a1c8 (diff)
downloadotp-1a3aca0a849af0bae994c9cf89de0dcfe7b310c2.tar.gz
otp-1a3aca0a849af0bae994c9cf89de0dcfe7b310c2.tar.bz2
otp-1a3aca0a849af0bae994c9cf89de0dcfe7b310c2.zip
[socket-nif] Add support for socket (level ipv6) option mtu_discover
Added support for the VPv6 socket option MTU_DISCOVER. OTP-14831.
-rw-r--r--erts/doc/src/socket_usage.xml21
-rw-r--r--erts/emulator/nifs/common/socket_nif.c190
-rw-r--r--erts/preloaded/ebin/socket.beambin51480 -> 51660 bytes
-rw-r--r--erts/preloaded/src/socket.erl16
4 files changed, 217 insertions, 10 deletions
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index cdd98090e8..247cd0eccb 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -145,7 +145,7 @@
<cell>none</cell>
</row>
<row>
- <cell>peep_off</cell>
+ <cell>peek_off</cell>
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
@@ -255,7 +255,7 @@
</row>
<row>
<cell>mtu_discover</cell>
- <cell>ip_mtu_discover()</cell>
+ <cell>ip_pmtudisc()</cell>
<cell>yes</cell>
<cell>yes</cell>
<cell>none</cell>
@@ -377,6 +377,13 @@
<cell>Get: Only after the socket has been connected</cell>
</row>
<row>
+ <cell>mtu_discover</cell>
+ <cell>ipv6_pmtudisc()</cell>
+ <cell>yes</cell>
+ <cell>yes</cell>
+ <cell>none</cell>
+ </row>
+ <row>
<cell>v6only</cell>
<cell>boolean()</cell>
<cell>yes</cell>
@@ -406,14 +413,14 @@
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>type = stream, protocol = tcp</cell>
+ <cell>none</cell>
</row>
<row>
<cell>nodelay</cell>
<cell>boolean()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>type = stream, protocol = tcp</cell>
+ <cell>none</cell>
</row>
</table>
@@ -431,7 +438,7 @@
<cell>boolean()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>type = dgram, protocol = udp</cell>
+ <cell>none</cell>
</row>
</table>
@@ -449,14 +456,14 @@
<cell>integer()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>protocol = sctp</cell>
+ <cell>none</cell>
</row>
<row>
<cell>nodelay</cell>
<cell>boolean()</cell>
<cell>yes</cell>
<cell>yes</cell>
- <cell>protocol = sctp</cell>
+ <cell>none</cell>
</row>
</table>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 0222d58e6d..d2f7e21ad0 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -389,6 +389,7 @@ typedef union {
#define SOCKET_OPT_IPV6_DROP_MEMBERSHIP 6
#define SOCKET_OPT_IPV6_HOPLIMIT 12
#define SOCKET_OPT_IPV6_MTU 17
+#define SOCKET_OPT_IPV6_MTU_DISCOVER 18
#define SOCKET_OPT_IPV6_V6ONLY 33
#define SOCKET_OPT_TCP_CONGESTION 1
@@ -1014,6 +1015,11 @@ static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(IPV6_MTU_DISCOVER)
+static ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(IPV6_V6ONLY)
static ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1237,6 +1243,10 @@ static ERL_NIF_TERM ngetopt_lvl_ipv6_hoplimit(ErlNifEnv* env,
static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env,
SocketDescriptor* descP);
#endif
+#if defined(IPV6_MTU_DISCOVER)
+static ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ SocketDescriptor* descP);
+#endif
#if defined(IPV6_V6ONLY)
static ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
SocketDescriptor* descP);
@@ -1451,6 +1461,16 @@ static void encode_ip_pmtudisc(ErlNifEnv* env,
int val,
ERL_NIF_TERM* eVal);
#endif
+#if defined(IPV6_MTU_DISCOVER)
+static char* decode_ipv6_pmtudisc(ErlNifEnv* env,
+ ERL_NIF_TERM eVal,
+ int* val);
+#endif
+#if defined(IPV6_MTU_DISCOVER)
+static void encode_ipv6_pmtudisc(ErlNifEnv* env,
+ int val,
+ ERL_NIF_TERM* eVal);
+#endif
/*
static BOOLEAN_T decode_bool(ErlNifEnv* env,
@@ -4977,6 +4997,12 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_MTU_DISCOVER)
+ case SOCKET_OPT_IPV6_MTU_DISCOVER:
+ result = nsetopt_lvl_ipv6_mtu_discover(env, descP, eVal);
+ break;
+#endif
+
#if defined(IPV6_V6ONLY)
case SOCKET_OPT_IPV6_V6ONLY:
result = nsetopt_lvl_ipv6_v6only(env, descP, eVal);
@@ -5038,6 +5064,42 @@ ERL_NIF_TERM nsetopt_lvl_ipv6_mtu(ErlNifEnv* env,
#endif
+/* nsetopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
+ *
+ * The value is an atom of the type ipv6_pmtudisc().
+ */
+#if defined(IPV6_MTU_DISCOVER)
+static
+ERL_NIF_TERM nsetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ int val;
+ char* xres;
+ int res;
+
+ if ((xres = decode_ipv6_pmtudisc(env, eVal, &val)) != NULL) {
+
+ result = esock_make_error_str(env, xres);
+
+ } else {
+
+ res = socket_setopt(descP->sock, SOL_IPV6, IPV6_MTU_DISCOVER,
+ &val, sizeof(val));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ }
+
+ return result;
+}
+#endif
+
+
#if defined(IPV6_V6ONLY)
static
ERL_NIF_TERM nsetopt_lvl_ipv6_v6only(ErlNifEnv* env,
@@ -6731,6 +6793,12 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env,
break;
#endif
+#if defined(IPV6_MTU_DISCOVER)
+ case SOCKET_OPT_IPV6_MTU_DISCOVER:
+ result = ngetopt_lvl_ipv6_mtu_discover(env, descP);
+ break;
+#endif
+
#if defined(IPV6_V6ONLY)
case SOCKET_OPT_IPV6_V6ONLY:
result = ngetopt_lvl_ipv6_v6only(env, descP);
@@ -6771,6 +6839,35 @@ ERL_NIF_TERM ngetopt_lvl_ipv6_mtu(ErlNifEnv* env,
#endif
+/* ngetopt_lvl_ipv6_mtu_discover - Level IPv6 MTU_DISCOVER option
+ */
+#if defined(IPV6_MTU_DISCOVER)
+static
+ERL_NIF_TERM ngetopt_lvl_ipv6_mtu_discover(ErlNifEnv* env,
+ SocketDescriptor* descP)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eMtuDisc;
+ int mtuDisc;
+ SOCKOPTLEN_T mtuDiscSz = sizeof(mtuDisc);
+ int res;
+
+ res = sock_getopt(descP->sock, SOL_IPV6, IPV6_MTU_DISCOVER,
+ &mtuDisc, &mtuDiscSz);
+
+ if (res != 0) {
+ result = esock_make_error_errno(env, sock_errno());
+ } else {
+ encode_ipv6_pmtudisc(env, mtuDisc, &eMtuDisc);
+ result = esock_make_ok2(env, eMtuDisc);
+ }
+
+ return result;
+
+}
+#endif
+
+
#if defined(IPV6_V6ONLY)
static
ERL_NIF_TERM ngetopt_lvl_ipv6_v6only(ErlNifEnv* env,
@@ -7723,6 +7820,57 @@ char* decode_ip_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
+/* +++ decode the ipv6 socket option MTU_DISCOVER +++
+ * The (ip) option can be provide in two ways:
+ *
+ * atom() | integer()
+ *
+ * When its an atom it can have the values:
+ *
+ * want | dont | do | probe
+ *
+ */
+#if defined(IPV6_MTU_DISCOVER)
+static
+char* decode_ipv6_pmtudisc(ErlNifEnv* env, ERL_NIF_TERM eVal, int* val)
+{
+ char* res = NULL;
+
+ if (IS_ATOM(env, eVal)) {
+
+ if (COMPARE(eVal, atom_want) == 0) {
+ *val = IPV6_PMTUDISC_WANT;
+ } else if (COMPARE(eVal, atom_dont) == 0) {
+ *val = IPV6_PMTUDISC_DONT;
+ } else if (COMPARE(eVal, atom_do) == 0) {
+ *val = IPV6_PMTUDISC_DO;
+ } else if (COMPARE(eVal, atom_probe) == 0) {
+ *val = IPV6_PMTUDISC_PROBE;
+ } else {
+ *val = -1;
+ res = ESOCK_STR_EINVAL;
+ }
+
+ } else if (IS_NUM(env, eVal)) {
+
+ if (!GET_INT(env, eVal, val)) {
+ *val = -1;
+ res = ESOCK_STR_EINVAL;
+ }
+
+ } else {
+
+ *val = -1;
+ res = ESOCK_STR_EINVAL;
+
+ }
+
+ return res;
+}
+#endif
+
+
+
/* +++ encode the ip socket option MTU_DISCOVER +++
* The (ip) option can be provide in two ways:
*
@@ -7765,6 +7913,48 @@ void encode_ip_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal)
+/* +++ encode the ipv6 socket option MTU_DISCOVER +++
+ * The (ipv6) option can be provide in two ways:
+ *
+ * atom() | integer()
+ *
+ * If its one of the "known" values, it will be an atom:
+ *
+ * want | dont | do | probe
+ *
+ */
+#if defined(IPV6_MTU_DISCOVER)
+static
+void encode_ipv6_pmtudisc(ErlNifEnv* env, int val, ERL_NIF_TERM* eVal)
+{
+ switch (val) {
+ case IPV6_PMTUDISC_WANT:
+ *eVal = atom_want;
+ break;
+
+ case IPV6_PMTUDISC_DONT:
+ *eVal = atom_dont;
+ break;
+
+ case IPV6_PMTUDISC_DO:
+ *eVal = atom_do;
+ break;
+
+ case IPV6_PMTUDISC_PROBE:
+ *eVal = atom_probe;
+ break;
+
+ default:
+ *eVal = MKI(env, val);
+ break;
+ }
+
+ return;
+}
+#endif
+
+
+
/* +++ decocde the native getopt option +++
* The option is in this case provide in the form of a two tuple:
*
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 7ab8b0b3c4..cb1c5fc815 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 41df672ef5..ead058c607 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -93,6 +93,7 @@
ip_mreq_source/0,
ip_pmtudisc/0,
ipv6_mreq/0,
+ ipv6_pmtudisc/0,
msg_hdr/0
@@ -164,6 +165,8 @@
-type ipv6_mreq() :: #{multiaddr := ip6_address(),
interface := non_neg_integer()}.
+-type ipv6_pmtudisc() :: ip_pmtudisc().
+
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
@@ -587,7 +590,7 @@
%% -define(SOCKET_OPT_IPV6_JOIN_GROUP, 15).
%% -define(SOCKET_OPT_IPV6_LEAVE_GROUP, 16).
-define(SOCKET_OPT_IPV6_MTU, 17).
-%% -define(SOCKET_OPT_IPV6_MTU_DISCOVER, 18).
+-define(SOCKET_OPT_IPV6_MTU_DISCOVER, 18).
%% -define(SOCKET_OPT_IPV6_MULTICAST_HOPS, 19).
%% -define(SOCKET_OPT_IPV6_MULTICAST_IF, 20).
%% -define(SOCKET_OPT_IPV6_MULTICAST_LOOP, 21).
@@ -2107,6 +2110,13 @@ enc_setopt_value(ipv6, hoplimit, V, _D, T, _P)
V;
enc_setopt_value(ipv6, mtu, V, _D, _T, _P) when is_integer(V) ->
V;
+enc_setopt_value(ipv6, mtu_discover, V, _D, _T, _P)
+ when (V =:= want) orelse
+ (V =:= dont) orelse
+ (V =:= do) orelse
+ (V =:= probe) orelse
+ is_integer(V) ->
+ V;
enc_setopt_value(ipv6, v6only, V, _D, _T, _P) when is_boolean(V) ->
V;
enc_setopt_value(ipv6 = L, Opt, V, _D, _T, _P) ->
@@ -2462,8 +2472,8 @@ enc_sockopt_key(ipv6 = L, leave_group = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = _L, mtu = _Opt, _Dir, _D, _T, _P) ->
?SOCKET_OPT_IPV6_MTU;
-enc_sockopt_key(ipv6 = L, mtu_discover = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(ipv6 = _L, mtu_discover = _Opt, _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_IPV6_MTU_DISCOVER;
enc_sockopt_key(ipv6 = L, multicast_hops = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, multicast_if = Opt, _Dir, _D, T, _P)