summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlf Wiger <ulf@wiger.net>2016-03-23 10:01:28 +0100
committerUlf Wiger <ulf@wiger.net>2016-03-23 10:01:28 +0100
commit39fbfce033ef3984a481b88a6d46549c0c38f055 (patch)
tree13b94188dd71623e1697c5ef023b250b36ae7545
parent9a3db2baecdddbfba8e8bfeb71038e4de6a44225 (diff)
parentc69df631f683c99e8a322a8729bc67d94a355927 (diff)
downloadrvi_core-39fbfce033ef3984a481b88a6d46549c0c38f055.tar.gz
Merge pull request #97 from uwiger/uw-0_5_0-bugfix
Uw 0 5 0 bugfix
-rw-r--r--components/authorize/src/authorize_keys.erl189
-rw-r--r--components/authorize/src/authorize_rpc.erl193
-rw-r--r--components/dlink/src/dlink_data.erl2
-rw-r--r--components/dlink_bt/src/bt_connection_manager.erl55
-rw-r--r--components/dlink_bt/src/dlink_bt_rpc.erl13
-rw-r--r--components/dlink_sms/src/dlink_sms_rpc.erl10
-rw-r--r--components/dlink_sms/src/sms_connection_manager.erl53
-rw-r--r--components/dlink_tcp/src/connection_manager.erl46
-rw-r--r--components/dlink_tcp/src/dlink_tcp_rpc.erl14
-rw-r--r--components/dlink_tls/src/dlink_tls_connmgr.erl42
-rw-r--r--components/dlink_tls/src/dlink_tls_rpc.erl16
-rw-r--r--components/proto_bert/src/proto_bert_rpc.erl4
-rw-r--r--components/proto_json/src/proto_json_rpc.erl4
-rw-r--r--components/proto_msgpack/src/proto_msgpack_rpc.erl4
-rw-r--r--components/rvi_common/src/rvi_common.erl2
-rw-r--r--components/rvi_common/src/rvi_netlink.erl173
-rw-r--r--components/schedule/src/schedule_rpc.erl4
-rw-r--r--components/service_discovery/src/service_discovery_rpc.erl14
-rw-r--r--components/service_edge/src/service_edge_rpc.erl32
-rw-r--r--deps/netlink/LICENSE373
-rw-r--r--deps/netlink/README0
-rw-r--r--deps/netlink/c_src/.gitignore2
-rw-r--r--deps/netlink/c_src/Makefile13
-rw-r--r--deps/netlink/c_src/netlink_drv.c727
-rw-r--r--deps/netlink/include/log.hrl44
-rw-r--r--deps/netlink/include/netlink.hrl38
-rw-r--r--deps/netlink/priv/.gitignore1
-rw-r--r--deps/netlink/rebar.config12
-rw-r--r--deps/netlink/src/.gitignore1
-rw-r--r--deps/netlink/src/netl_codec.erl2376
-rw-r--r--deps/netlink/src/netl_codec.hrl200
-rw-r--r--deps/netlink/src/netlink.app.src12
-rw-r--r--deps/netlink/src/netlink.erl737
-rw-r--r--deps/netlink/src/netlink.hrl64
-rw-r--r--deps/netlink/src/netlink.inc981
-rw-r--r--deps/netlink/src/netlink_app.erl25
-rw-r--r--deps/netlink/src/netlink_codec.erl214
-rw-r--r--deps/netlink/src/netlink_drv.erl135
-rw-r--r--deps/netlink/src/netlink_gen.erl798
-rw-r--r--deps/netlink/src/netlink_stat.erl115
-rw-r--r--deps/netlink/src/netlink_sup.erl36
-rw-r--r--deps/netlink/tetrapak/build_drv.erl11
-rw-r--r--deps/netlink/tetrapak/config.ini8
-rw-r--r--deps/trace_runner/.gitignore10
-rw-r--r--deps/trace_runner/LICENSE373
-rw-r--r--deps/trace_runner/Makefile9
-rw-r--r--deps/trace_runner/README.md120
-rw-r--r--deps/trace_runner/doc/images/ttb-log-snap-1.pngbin0 -> 15391 bytes
-rw-r--r--deps/trace_runner/doc/images/ttb-log-snap-2.pngbin0 -> 98930 bytes
-rw-r--r--deps/trace_runner/doc/images/ttb-log-snap.pngbin0 -> 83352 bytes
-rw-r--r--deps/trace_runner/include/trace_runner.hrl29
-rw-r--r--deps/trace_runner/src/tr_ttb.erl213
-rw-r--r--deps/trace_runner/src/trace_runner.app.src22
-rw-r--r--rebar.config4
-rw-r--r--test/rvi_core_SUITE.erl57
55 files changed, 8277 insertions, 353 deletions
diff --git a/components/authorize/src/authorize_keys.erl b/components/authorize/src/authorize_keys.erl
index c2368d5..b5ffd72 100644
--- a/components/authorize/src/authorize_keys.erl
+++ b/components/authorize/src/authorize_keys.erl
@@ -7,7 +7,7 @@
get_pub_key/1,
provisioning_key/0,
signed_public_key/2,
- save_keys/2,
+ %% save_keys/2,
save_cred/5]).
-export([get_credentials/0,
get_credentials/1]).
@@ -18,6 +18,13 @@
-export([public_key_to_json/1,
json_to_public_key/1]).
+-export([cache_authorizations/1,
+ remove_cached_authorizations/1,
+ remove_cached_authorizations_for_conn/1,
+ update_authorization_cache/2]).
+
+-export([remove_connection/1]).
+
-export([self_signed_public_key/0]). % just temporary
-export([strip_nl/1]).
-export([pp_key/1,
@@ -41,13 +48,6 @@
dev_cert,
cred_dir}).
-%% -record(cert, {id,
-%% register = [],
-%% invoke = [],
-%% validity = [],
-%% jwt,
-%% cert}).
-
-record(cred, {id,
right_to_receive = [],
right_to_invoke = [],
@@ -56,11 +56,8 @@
jwt,
cred}).
--record(key, {id,
- key}).
-
-define(CREDS, authorize_creds).
--define(KEYS, authorize_keys).
+-define(CACHE, authorize_cache).
public_key_to_json(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
[
@@ -124,8 +121,16 @@ get_device_key() ->
validate_message(JWT, Conn) ->
gen_server:call(?MODULE, {validate_message, JWT, Conn}).
-validate_service_call(Service, Conn) ->
- gen_server:call(?MODULE, {validate_service_call, Service, Conn}).
+validate_service_call(Service, Conn0) ->
+ Conn = normalize_conn(Conn0),
+ case ets:lookup(?CACHE, {Service, Conn}) of
+ [{_, Res}] ->
+ ?debug("cached validation (~p): ~p", [{Service, Conn}, Res]),
+ Res;
+ [] ->
+ ?debug("no cached validation (~p)", [{Service, Conn}]),
+ gen_server:call(?MODULE, {validate_service_call, Service, Conn})
+ end.
get_credentials() ->
get_credentials(local).
@@ -142,12 +147,24 @@ find_cred_by_service(Service) ->
provisioning_key() ->
gen_server:call(?MODULE, provisioning_key).
-save_keys(Keys, Conn) ->
- gen_server:call(?MODULE, {save_keys, Keys, Conn}).
-
save_cred(Cred, JWT, Conn, PeerCert, LogId) ->
gen_server:call(?MODULE, {save_cred, Cred, JWT, Conn, PeerCert, LogId}).
+cache_authorizations(Svcs) ->
+ gen_server:cast(?MODULE, {cache_authorizations, Svcs}).
+
+remove_cached_authorizations(Svcs) ->
+ gen_server:cast(?MODULE, {remove_cached_authorizations, Svcs}).
+
+remove_cached_authorizations_for_conn(Conn) ->
+ remove_cached_authorizations_for_conn_(normalize_conn(Conn)).
+
+update_authorization_cache(Conn, CS) ->
+ gen_server:cast(?MODULE, {update_authorization_cache, Conn, CS}).
+
+remove_connection(Conn) ->
+ gen_server:cast(?MODULE, {remove_connection, Conn}).
+
%% Gen_server functions
start_link() ->
@@ -155,7 +172,7 @@ start_link() ->
case gen_server:start_link({local, ?MODULE}, ?MODULE, [], []) of
{ok, Pid} = Ok ->
ets:give_away(?CREDS, Pid, undefined),
- ets:give_away(?KEYS, Pid, undefined),
+ %% ets:give_away(?KEYS, Pid, undefined),
Ok;
Other ->
Other
@@ -191,16 +208,7 @@ handle_call_(provisioning_key, _, S) ->
handle_call_({get_credentials, Conn}, _, S) ->
Creds = creds_by_conn(normalize_conn(Conn)),
{reply, Creds, S};
-handle_call_({save_keys, Keys, Conn0}, _, S) ->
- Conn = normalize_conn(Conn0),
- ?debug("save_keys: Keys=~p, Conn=~p~n", [abbrev_k(Keys), Conn]),
- save_keys_(Keys, Conn),
- {reply, ok, S};
-handle_call_({validate_message, JWT, Conn0}, _, S) ->
- Conn = normalize_conn(Conn0),
- {reply, validate_message_(JWT, Conn), S};
-handle_call_({validate_service_call, Svc, Conn0}, _, S) ->
- Conn = normalize_conn(Conn0),
+handle_call_({validate_service_call, Svc, Conn}, _, S) ->
{reply, validate_service_call_(Svc, Conn), S};
handle_call_({save_cred, Cred, JWT, {IP, Port} = Conn0, PeerCert, LogId}, _, S) ->
Conn = normalize_conn(Conn0),
@@ -228,6 +236,21 @@ handle_call_({find_cred_by_service, Service} = R, _From, State) ->
handle_call_(_, _, S) ->
{reply, error, S}.
+handle_cast({cache_authorizations, Svcs}, S) ->
+ cache_authorizations_(Svcs),
+ {noreply, S};
+handle_cast({remove_cached_authorizations, Svcs}, S) ->
+ remove_cached_authorizations_(Svcs),
+ {noreply, S};
+handle_cast({update_authorization_cache, Conn0, CS}, S) ->
+ Conn = normalize_conn(Conn0),
+ update_authorization_cache_(Conn, CS),
+ {noreply, S};
+handle_cast({remove_connection, Conn0}, S) ->
+ Conn = normalize_conn(Conn0),
+ ets:select_delete(?CACHE, [{ {{'_', Conn}, '_'}, [], [true] }]),
+ ets:select_delete(?CREDS, [{ {{Conn, '_'}, '_'}, [], [true] }]),
+ {noreply, S};
handle_cast(_, S) ->
{noreply, S}.
@@ -449,7 +472,8 @@ get_pub_key_from_cert_rec(#'Certificate'{
create_ets() ->
create_ets(?CREDS, 1),
- create_ets(?KEYS, #key.id).
+ %% create_ets(?KEYS, #key.id),
+ create_ets(?CACHE, 1).
create_ets(Tab, KeyPos) ->
case ets:info(Tab, name) of
@@ -589,56 +613,73 @@ check_validity({Start, Stop}, UTC) ->
check_validity(Start, Stop, UTC) ->
(UTC > Start) andalso (UTC < Stop).
-save_keys_(Keys, Conn) ->
- lists:foreach(
- fun(K) ->
- save_key(K, Conn)
- end, Keys).
+validate_service_call_(Svc, Conn) ->
+ Res =
+ case lists:filter(fun(C) ->
+ can_invoke(Svc, C)
+ end, cred_recs_by_conn(Conn)) of
+ [] ->
+ invalid;
+ [#cred{id = ID}|_] ->
+ {ok, ID}
+ end,
+ ets:insert(?CACHE, {{Svc, Conn}, Res}),
+ Res.
-save_key(K, Conn) ->
- case json_to_public_key(K) of
- undefined ->
- ?warning("Unknown key type: ~p~n", [K]),
- skip;
- #'RSAPublicKey'{} = PubKey ->
- KeyID =
- case rvi_common:get_json_element(["kid"], K) of
- {ok, ID} -> {Conn, ID};
- _ -> {Conn, make_ref()}
- end,
- ?debug("Saving key ~p, PubKey = ~p~n", [KeyID, pp_key(PubKey)]),
- ets:insert(?KEYS, #key{id = KeyID, key = PubKey})
- end.
+cache_authorizations_(Svcs) ->
+ CacheEntries = ets:foldl(
+ fun(CEntry, Acc) ->
+ lists:foldr(
+ fun(Svc, Acc1) ->
+ cache_authorization_entry(
+ CEntry, Svc, Acc1)
+ end, Acc, Svcs)
+ end, [], ?CREDS),
+ ets:insert(?CACHE, CacheEntries),
+ ?debug("auth cache: ~p", [ets:tab2list(?CACHE)]),
+ ok.
-keys_by_conn(Conn) ->
- ?debug("keys_by_conn(~p); all keys: ~p",
- [Conn, ets:select(?KEYS, [{ #key{id = '$1', _='_'},
- [], ['$1'] }])]),
- ets:select(?KEYS, [{ #key{id = {Conn,'$1'},
- key = '$2', _='_'}, [], [{{'$1', '$2'}}] }]).
+cache_authorization_entry(Entry, Svc, Acc) ->
+ ?debug("cache_authorization_entry(~p, ~p)", [Entry, Svc]),
+ case {Entry, Acc} of
+ {{{Conn, _}, _C}, [{{Svc, Conn}, {ok,_}}|_]} ->
+ Acc;
+ {{{Conn, ID}, C}, Acc} ->
+ case can_invoke(Svc, C) of
+ true ->
+ case Acc of
+ [{{Svc, Conn}, invalid}|Rest] ->
+ [{{Svc, Conn}, {ok, ID}}|Rest];
+ _ ->
+ [{{Svc, Conn}, {ok, ID}}|Acc]
+ end;
+ false ->
+ case Acc of
+ [{{Svc, Conn}, invalid}|_] ->
+ Acc;
+ _ ->
+ [{{Svc, Conn}, invalid}|Acc]
+ end
+ end
+ end.
-validate_message_(JWT, Conn) ->
- ?debug("validate_message_(~p, ~p) -> ~p~n", [JWT, Conn, keys_by_conn(Conn)]),
- [_|_] = Keys = keys_by_conn(Conn),
- validate_message_1(Keys, JWT).
+remove_cached_authorizations_(Svc) ->
+ ets:select_delete(?CACHE, [{ {{Svc,'_'},'_'}, [], [true] }]),
+ ok.
-validate_message_1([{_,K}|T], JWT) ->
- case authorize_sig:decode_jwt(JWT, K) of
- invalid ->
- validate_message_1(T, JWT);
- {_, Msg} ->
- Msg
- end;
-validate_message_1([], _) ->
- error(invalid).
+update_authorization_cache_(Conn, CS) ->
+ remove_cached_authorizations_for_conn_(Conn),
+ [ok, Svcs] = service_discovery_rpc:get_all_services(CS),
+ ?debug("update authorization cache for ~p; Svs = ~p", [Conn, Svcs]),
+ lists:foreach(
+ fun(Svc) ->
+ validate_service_call_(Svc, Conn)
+ end, Svcs),
+ ?debug("auth cache: ~p", [ets:tab2list(?CACHE)]).
-validate_service_call_(Svc, Conn) ->
- case lists:filter(fun(C) -> can_invoke(Svc, C) end, cred_recs_by_conn(Conn)) of
- [] ->
- invalid;
- [#cred{id = ID}|_] ->
- {ok, ID}
- end.
+remove_cached_authorizations_for_conn_(Conn) ->
+ ets:select_delete(?CACHE, [{ {{'_', Conn}, '_'}, [], [true] }]),
+ ok.
can_invoke(Svc, #cred{right_to_invoke = In}) ->
lists:any(fun(I) -> match_svc(I, Svc) end, In).
diff --git a/components/authorize/src/authorize_rpc.erl b/components/authorize/src/authorize_rpc.erl
index ba54f3a..9fa052a 100644
--- a/components/authorize/src/authorize_rpc.erl
+++ b/components/authorize/src/authorize_rpc.erl
@@ -21,14 +21,17 @@
-export([get_credentials/1,
sign_message/2,
validate_message/3,
- validate_authorization/3,
- validate_authorization/4,
store_creds/3,
store_creds/4,
+ remove_connection/2,
authorize_local_message/3,
authorize_remote_message/3]).
-export([filter_by_service/3]).
+%% for service_discovery notifications
+-export([service_available/3,
+ service_unavailable/3]).
+
%% for testing & development
-export([public_key/0, public_key_json/0,
private_key/0]).
@@ -53,6 +56,8 @@ init([]) ->
{Priv, Pub} = authorize_keys:get_device_key(),
?debug("KeyPair = {~s, ~s}~n", [authorize_keys:pp_key(Priv),
authorize_keys:pp_key(Pub)]),
+ CS = rvi_common:get_component_specification(),
+ service_discovery_rpc:subscribe(CS, ?MODULE),
{ok, #st { cs = rvi_common:get_component_specification(),
private_key = Priv,
public_key = Pub} }.
@@ -78,22 +83,9 @@ get_credentials(CompSpec) ->
rvi_common:request(authorize, ?MODULE, get_credentials,
[], [status, creds], CompSpec).
-validate_authorization(CompSpec, JWT, Conn) ->
- ?debug("authorize_rpc:validate_authorization():"
- " Conn = ~p~n", [Conn]),
- rvi_common:request(authorize, ?MODULE, validate_authorization,
- [{jwt, JWT},
- {conn, Conn}],
- [status], CompSpec).
-
-validate_authorization(CompSpec, JWT, Creds, Conn) ->
- ?debug("authorize_rpc:validate_authorization():"
- " Conn = ~p~n", [Conn]),
- rvi_common:request(authorize, ?MODULE, validate_authorization,
- [{jwt, JWT},
- {creds, Creds},
- {conn, Conn}],
- [status], CompSpec).
+remove_connection(CompSpec, Conn) ->
+ rvi_common:notification(authorize, ?MODULE, remove_connection,
+ [{conn, Conn}], [status], CompSpec).
store_creds(CompSpec, Creds, Conn) ->
store_creds(CompSpec, Creds, Conn, undefined).
@@ -129,6 +121,14 @@ filter_by_service(CompSpec, Services, Conn) ->
{ conn, Conn }],
[status, services], CompSpec).
+service_available(CS, SvcName, _DLMod) ->
+ rvi_common:notification(authorize, ?MODULE, service_available,
+ [{service, SvcName}], CS).
+
+service_unavailable(CS, SvcName, _DLMod) ->
+ rvi_common:notification(authorize, ?MODULE, service_unavailable,
+ [{service, SvcName}], CS).
+
public_key() ->
gen_server:call(?SERVER, public_key).
@@ -140,7 +140,7 @@ private_key() ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_rpc("sign_message", Args) ->
+handle_rpc(<<"sign_message">>, Args) ->
{ok, Message} = rvi_common:get_json_element(["message"], Args),
LogId = rvi_common:get_json_log_id(Args),
[ Status, JWT ] =
@@ -148,7 +148,7 @@ handle_rpc("sign_message", Args) ->
?debug("Message signature = ~p~n", [JWT]),
{ok, [ {status, rvi_common:json_rpc_status(Status)},
{jwt, JWT} ]};
-handle_rpc("validate_message", Args) ->
+handle_rpc(<<"validate_message">>, Args) ->
?debug("validate_message; Args = ~p~n", [Args]),
{ok, JWT} = rvi_common:get_json_element(["jwt"], Args),
{ok, Conn} = rvi_common:get_json_element(["conn"], Args),
@@ -157,24 +157,12 @@ handle_rpc("validate_message", Args) ->
gen_server:call(?SERVER, { rvi, validate_message, [JWT, Conn, LogId] }),
{ok, [ {status, rvi_common:json_rpc_status(Status)},
{message, Msg} ]};
-handle_rpc("get_credentials", Args) ->
+handle_rpc(<<"get_credentials">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
[ Status | Rem ] =
gen_server:call(?SERVER, { rvi, get_credentials, [LogId] }),
{ok, [ rvi_common:json_rpc_status(Status) | Rem ] };
-handle_rpc("validate_authorization", Args) ->
- {ok, JWT} = rvi_common:get_json_element(["jwt"], Args),
- {ok, Conn} = rvi_common:get_json_element(["connection"], Args),
- LogId = rvi_common:get_json_log_id(Args),
- CmdArgs =
- case rvi_common:get_json_element(["creds"], Args) of
- {ok, Creds} -> [JWT, Creds, Conn, LogId];
- {error, _} -> [JWT, Conn, LogId]
- end,
- [ Status | Rem ] =
- gen_server:call(?SERVER, {rvi, validate_authorization, CmdArgs}),
- {ok, [ rvi_common:json_rpc_status(Status) | Rem] };
-handle_rpc("store_creds", Args) ->
+handle_rpc(<<"store_creds">>, Args) ->
{ok, Creds} = rvi_common:get_json_element(["creds"], Args),
{ok, Conn} = rvi_common:get_json_element(["conn"], Args),
{ok, PeerCert} = rvi_common:get_json_element(["peer_cert"], Args),
@@ -182,7 +170,7 @@ handle_rpc("store_creds", Args) ->
[ Status | Rem ] =
gen_server:call(?SERVER, {rvi, store_creds, [Creds, Conn, PeerCert, LogId]}),
{ok, [ rvi_common:json_rpc_status(Status) | Rem]};
-handle_rpc("authorize_local_message", Args) ->
+handle_rpc(<<"authorize_local_message">>, Args) ->
{ok, Service} = rvi_common:get_json_element(["service"], Args),
{ok, Params} = rvi_common:get_json_element(["parameters"], Args),
LogId = rvi_common:get_json_log_id(Args),
@@ -193,7 +181,7 @@ handle_rpc("authorize_local_message", Args) ->
{ ok, [ rvi_common:json_rpc_status(Status) | Rem] };
-handle_rpc("authorize_remote_message", Args) ->
+handle_rpc(<<"authorize_remote_message">>, Args) ->
{ok, Service} = rvi_common:get_json_element(["service"], Args),
{ok, Params} = rvi_common:get_json_element(["parameters"], Args),
LogId = rvi_common:get_json_log_id(Args),
@@ -201,7 +189,7 @@ handle_rpc("authorize_remote_message", Args) ->
[Service, Params, LogId]}),
{ ok, rvi_common:json_rpc_status(Status)};
-handle_rpc("filter_by_service", Args) ->
+handle_rpc(<<"filter_by_service">>, Args) ->
?debug("authorize_rpc:handle_rpc(\"filter_by_service\", ~p)~n", [Args]),
{ok, Services} = rvi_common:get_json_element(["services"], Args),
{ok, Conn} = rvi_common:get_json_element(["conn"], Args),
@@ -217,12 +205,24 @@ handle_rpc(Other, _Args) ->
{ ok, [ { status, rvi_common:json_rpc_status(invalid_command)} ] }.
+handle_notification(<<"service_available">>, Args) ->
+ {ok, SvcName} = rvi_common:get_json_element(["service"], Args),
+ gen_server:cast(?SERVER, {service_available, SvcName}),
+ ok;
+handle_notification(<<"service_unavailable">>, Args) ->
+ {ok, SvcName} = rvi_common:get_json_element(["service"], Args),
+ gen_server:cast(?SERVER, {service_unavailable, SvcName}),
+ ok;
+handle_notification(<<"remove_connection">>, Args) ->
+ {ok, Conn} = rvi_common:get_json_element(["conn"], Args),
+ gen_server:cast(?SERVER, {remove_connection, Conn}, Args),
+ ok;
handle_notification(Other, _Args) ->
?debug("authorize_rpc:handle_other(~p): unknown", [ Other ]),
ok.
%%
-%% Genserver implementation
+%% Gen_server implementation
%%
handle_call({rvi, sign_message, [Msg | LogId]}, _, #st{private_key = Key} = State) ->
Sign = authorize_sig:encode_jwt(Msg, Key),
@@ -241,62 +241,19 @@ handle_call({rvi, validate_message, [JWT, Conn | LogId]}, _, State) ->
handle_call({rvi, get_credentials, _Args}, _From, State) ->
{reply, [ ok, authorize_keys:get_credentials() ], State};
-handle_call({rvi, validate_authorization, [JWT, Conn | [_] = LogId]}, _From, State) ->
- %% The authorize JWT contains the public key used to sign the cred
- ?debug(
- "authorize_rpc:handle_call({rvi, validate_authorization, [_,_,_]})~n",
- []),
- try authorize_sig:decode_jwt(JWT, authorize_keys:provisioning_key()) of
- {_Header, Keys} ->
- log(LogId, result, "auth jwt validated", []),
- KeyStructs = get_json_element(["keys"], Keys, []),
- authorize_keys:save_keys(KeyStructs, Conn),
- {reply, [ok], State};
- invalid ->
- ?warning("Invalid auth JWT from ~p~n", [Conn]),
- log(LogId, error, "auth jwt INVALID", []),
- {reply, [not_found], State}
- catch
- error:_Err ->
- ?warning("Auth validation exception: ~p~n", [_Err]),
- {reply, [not_found], State}
- end;
-
-handle_call({rvi, validate_authorization, [JWT, Creds, Conn | [_] = LogId] }, _From, State) ->
- %% The authorize JWT contains the public key used to sign the cred
- ?debug(
- "authorize_rpc:handle_call({rvi, validate_authorization, [_,_,_]})~n",
- []),
- try authorize_sig:decode_jwt(JWT, authorize_keys:provisioning_key()) of
- {_Header, Keys} ->
- log(LogId, result, "auth jwt validated", []),
- KeyStructs = get_json_element(["keys"], Keys, []),
- ?debug("KeyStructs = ~p~n", [KeyStructs]),
- authorize_keys:save_keys(KeyStructs, Conn),
- do_store_creds(Creds, Conn, undefined, LogId),
- {reply, [ok], State};
- invalid ->
- ?warning("Invalid auth JWT from ~p~n", [Conn]),
- log(LogId, error, "auth jwt INVALID", []),
- {reply, [not_found], State}
- catch
- error:_Err ->
- ?warning("Auth validation exception: ~p~n", [_Err]),
- {reply, [not_found], State}
- end;
-
handle_call({rvi, store_creds, [Creds, Conn, PeerCert | LogId]}, _From, State) ->
- do_store_creds(Creds, Conn, PeerCert, LogId),
+ do_store_creds(Creds, Conn, PeerCert, LogId, State#st.cs),
{reply, [ok], State};
+
handle_call({rvi, authorize_local_message, [Service, _Params | LogId] } = R, _From, State) ->
?debug("authorize_rpc:handle_call(~p)~n", [R]),
- case authorize_keys:find_cred_by_service(Service) of
- {ok, {ID, _Cred}} ->
- log(LogId, result, "auth msg: Cred=~s", [authorize_keys:abbrev_bin(ID)]),
- {reply, [ok], State};
- _ ->
- log(LogId, error, "NO CREDS for ~s", [Service]),
- {reply, [ not_found ], State}
+ case authorize_keys:validate_service_call(Service, local) of
+ invalid ->
+ log(LogId, error, "local msg REJECTED", []),
+ {reply, [ not_found ], State};
+ {ok, Id} ->
+ log(LogId, result, "local msg allowed: Cred=~s", [Id]),
+ {reply, [ok], State}
end;
handle_call({rvi, authorize_remote_message, [_Service, Params | LogId]},
@@ -341,6 +298,15 @@ handle_call(Other, _From, State) ->
?warning("authorize_rpc:handle_call(~p): unknown", [ Other ]),
{ reply, unknown_command, State}.
+handle_cast({rvi, service_available, Svc}, State) ->
+ authorize_keys:cache_authorizations(Svc),
+ {noreply, State};
+handle_cast({rvi, service_unavailable, Svc}, State) ->
+ authorize_keys:remove_cached_authorizations(Svc),
+ {noreply, State};
+handle_cast({rvi, remove_connection, Conn}, State) ->
+ authorize_keys:remove_connection(Conn),
+ {noreply, State};
handle_cast(Other, State) ->
?warning("authorize_rpc:handle_cast(~p): unknown", [ Other ]),
{noreply, State}.
@@ -353,20 +319,14 @@ terminate(_Reason, _State) ->
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
-do_store_creds(Creds, Conn, PeerCert, LogId) ->
+do_store_creds(Creds, Conn, PeerCert, LogId, CS) ->
?debug("Storing ~p creds for conn ~p~nPeerCert = ~w",
[length(Creds), Conn, authorize_keys:abbrev(PeerCert)]),
+ authorize_keys:remove_cached_authorizations_for_conn(Conn),
lists:foreach(fun(Cred) ->
store_cred(Cred, Conn, PeerCert, LogId)
- end, Creds).
-
-get_json_element(Path, JSON, Default) ->
- case rvi_common:get_json_element(Path, JSON) of
- {ok, Value} ->
- Value;
- _ ->
- Default
- end.
+ end, Creds),
+ authorize_keys:update_authorization_cache(Conn, CS).
store_cred(CredJWT, Conn, PeerCert, LogId) ->
case authorize_sig:decode_jwt(authorize_keys:strip_nl(CredJWT), authorize_keys:provisioning_key()) of
@@ -389,36 +349,3 @@ log([ID], Lvl, Fmt, Args) ->
rvi_log:log(ID, Lvl, <<"authorize">>, rvi_log:format(Fmt, Args));
log(_, _, _, _) ->
ok.
-
-%% check_msg(Checks, Params) ->
-%% check_msg(Checks, Params, []).
-
- %% {ok, Timeout1} = rvi_common:get_json_element(["timeout"], Msg),
- %% {ok, SvcName1} = rvi_common:get_json_element(["service_name"], Msg),
- %% {ok, Params1} = rvi_common:get_json_element(["parameters"], Msg),
- %% ?debug("authorize_rpc:authorize_remote_message(): timeout1: ~p~n", [Timeout1]),
- %% ?debug("authorize_rpc:authorize_remote_message(): service_name1: ~p~n", [SvcName1]),
- %% ?debug("authorize_rpc:authorize_remote_message(): parameters1: ~p~n", [Params1]),
-
- %% if Timeout =:= Timeout1 * 1000,
- %% SvcName =:= SvcName1,
- %% Parameters =:= Params1 ->
- %% ?debug("Remote message authorized.~n", []),
- %% {reply, [ ok ], State};
- %% true ->
- %% ?debug("Remote message NOT authorized.~n", []),
- %% {reply, [ not_found ], State}
- %% end
- %% end;
-
-%% check_msg([], _, []) ->
-%% ok;
-%% check_msg([{Key, Expect}|T], Msg, Acc) ->
-%% case rvi_common:get_json_element([Key], Msg) of
-%% {ok, Expect} ->
-%% check_msg(T, Msg, Acc);
-%% _ ->
-%% check_msg(T, Msg, [Key|Acc])
-%% end;
-%% check_msg([], _, [_|_] = Acc) ->
-%% {error, {mismatch, lists:reverse(Acc)}}.
diff --git a/components/dlink/src/dlink_data.erl b/components/dlink/src/dlink_data.erl
index d16d923..4671b9a 100644
--- a/components/dlink/src/dlink_data.erl
+++ b/components/dlink/src/dlink_data.erl
@@ -47,7 +47,7 @@ do_decode(Data) ->
decoded(Decoded, Rest, F, Mod, FragOpts) ->
case rvi_frag:maybe_fragment(Decoded, Mod, FragOpts) of
true ->
- {ok, Rest};
+ decode(Rest, F, <<>>, Mod, FragOpts);
{true, Msg} ->
case do_decode(Msg) of
{ok, DecMsg, <<>>} ->
diff --git a/components/dlink_bt/src/bt_connection_manager.erl b/components/dlink_bt/src/bt_connection_manager.erl
index e86dda3..23a6609 100644
--- a/components/dlink_bt/src/bt_connection_manager.erl
+++ b/components/dlink_bt/src/bt_connection_manager.erl
@@ -35,6 +35,7 @@
-define(SERVER, ?MODULE).
-record(st, {
+ cs,
conn_by_pid = undefined,
conn_by_addr = undefined
}).
@@ -87,6 +88,7 @@ start_link() ->
%%--------------------------------------------------------------------
init([]) ->
{ok, #st{
+ cs = rvi_common:get_component_specification(),
conn_by_pid = dict:new(), %% All managed connection stored by pid
conn_by_addr = dict:new() %% All managed connection stored by address
}}.
@@ -114,36 +116,15 @@ handle_call({add_connection, BTAddr, Channel, Pid}, _From,
%% Store so that we can find connection both by pid and by address
NConPid = dict:store(Pid, { BTAddr, Channel }, ConPid),
NConBTAddr = dict:store({ BTAddr, Channel }, Pid, ConBTAddr),
-
+ erlang:monitor(process, Pid),
NSt = St#st { conn_by_pid = NConPid,
conn_by_addr = NConBTAddr },
{reply, ok, NSt};
%% Delete connection by pid
-handle_call({delete_connection_by_pid, Pid}, _From,
- #st { conn_by_pid = ConPid,
- conn_by_addr = ConBTAddr} = St) when is_pid(Pid)->
-
- %% Find address associated with Pid
- case dict:find(Pid, ConPid) of
- error ->
- ?debug("~p:handle_call(del_by_pid): not found: ~p",
- [ ?MODULE, Pid]),
- { reply, not_found, St};
-
- {ok, BTAddr } ->
- ?debug("~p:handle_call(del_by_pid): deleted Pid: ~p, BTAddress: ~p",
- [ ?MODULE, Pid, BTAddr]),
-
- NConPid = dict:erase(Pid, ConPid),
- NConBTAddr = dict:erase(BTAddr, ConBTAddr),
-
- NSt = St#st { conn_by_pid = NConPid,
- conn_by_addr = NConBTAddr },
-
- {reply, ok, NSt}
- end;
-
+handle_call({delete_connection_by_pid, Pid}, _From, St) when is_pid(Pid)->
+ {Res, NSt} = delete_connection_by_pid_(Pid, St),
+ {reply, Res, NSt};
%% Delete connection by address
handle_call({ delete_connection_by_address, BTAddr, Channel}, _From,
@@ -233,6 +214,9 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
+handle_info({'DOWN', _Ref, process, Pid, _}, St) ->
+ {_, NSt} = delete_connection_by_pid_(Pid, St),
+ {noreply, NSt};
handle_info(_Info, State) ->
?warning("~p:handle_cast(): Unknown info: ~p", [ ?MODULE, _Info]),
{noreply, State}.
@@ -265,3 +249,24 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
+
+delete_connection_by_pid_(Pid, #st{conn_by_pid = ConPid,
+ conn_by_addr = ConBTAddr,
+ cs = CS} = St) ->
+ %% Find address associated with Pid
+ case dict:find(Pid, ConPid) of
+ error ->
+ ?debug("del_by_pid: not found: ~p", [Pid]),
+ {not_found, St};
+
+ {ok, BTAddr } ->
+ ?debug("del_by_pid: deleted Pid: ~p, BTAddress: ~p", [Pid, BTAddr]),
+
+ NConPid = dict:erase(Pid, ConPid),
+ NConBTAddr = dict:erase(BTAddr, ConBTAddr),
+
+ NSt = St#st { conn_by_pid = NConPid,
+ conn_by_addr = NConBTAddr },
+ authorize_rpc:remove_connection(CS, BTAddr),
+ {ok, NSt}
+ end.
diff --git a/components/dlink_bt/src/dlink_bt_rpc.erl b/components/dlink_bt/src/dlink_bt_rpc.erl
index c4276bd..e0835f9 100644
--- a/components/dlink_bt/src/dlink_bt_rpc.erl
+++ b/components/dlink_bt/src/dlink_bt_rpc.erl
@@ -475,7 +475,7 @@ handle_socket(_FromPid, SetupBTAddr, SetupChannel, error, _ExtraArgs) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_notification("service_available", Args) ->
+handle_notification(<<"service_available">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -484,7 +484,7 @@ handle_notification("service_available", Args) ->
DataLinkModule ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -498,7 +498,7 @@ handle_notification(Other, _Args) ->
?info("dlink_bt:handle_notification(~p): unknown", [ Other ]),
ok.
-handle_rpc("setup_data_link", Args) ->
+handle_rpc(<<"setup_data_link">>, Args) ->
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Opts } = rvi_common:get_json_element(["opts"], Args),
@@ -508,12 +508,12 @@ handle_rpc("setup_data_link", Args) ->
{ok, [ {status, rvi_common:json_rpc_status(Res)} , { timeout, Timeout }]};
-handle_rpc("disconenct_data_link", Args) ->
+handle_rpc(<<"disconenct_data_link">>, Args) ->
{ ok, NetworkAddress} = rvi_common:get_json_element(["network_address"], Args),
[Res] = gen_server:call(?SERVER, { rvi, disconnect_data_link, [NetworkAddress]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("send_data", Args) ->
+handle_rpc(<<"send_data">>, Args) ->
{ ok, ProtoMod } = rvi_common:get_json_element(["proto_mod"], Args),
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Data } = rvi_common:get_json_element(["data"], Args),
@@ -602,7 +602,8 @@ handle_call({rvi, send_data, [ProtoMod, Service, Data, DataLinkOpts]}, _From, St
%% FIXME: What to do if we have multiple connections to the same service?
[ConnPid | _T] ->
- ?debug("dlink_bt:send(~p): ~s", [ProtoMod, Data]),
+ ?debug("dlink_bt:send(~p,Pid=~p[~p]): ~p",
+ [ProtoMod, ConnPid, catch is_process_alive(ConnPid), Data]),
Res = bt_connection:send(
ConnPid,
[ { ?DLINK_ARG_TRANSACTION_ID, 1 },
diff --git a/components/dlink_sms/src/dlink_sms_rpc.erl b/components/dlink_sms/src/dlink_sms_rpc.erl
index 2f20d2d..f57a88d 100644
--- a/components/dlink_sms/src/dlink_sms_rpc.erl
+++ b/components/dlink_sms/src/dlink_sms_rpc.erl
@@ -368,7 +368,7 @@ handle_sms(FromPid, Addr, data, Payload, [CompSpec]) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_notification("service_available", Args) ->
+handle_notification(<<"service_available">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -377,7 +377,7 @@ handle_notification("service_available", Args) ->
DataLinkModule ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -391,7 +391,7 @@ handle_notification(Other, _Args) ->
?info("dlink_sms:handle_notification(~p): unknown", [ Other ]),
ok.
-handle_rpc("setup_data_link", Args) ->
+handle_rpc(<<"setup_data_link">>, Args) ->
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Opts } = rvi_common:get_json_element(["opts"], Args),
@@ -401,12 +401,12 @@ handle_rpc("setup_data_link", Args) ->
{ok, [ {status, rvi_common:json_rpc_status(Res)} , { timeout, Timeout }]};
-handle_rpc("disconnect_data_link", Args) ->
+handle_rpc(<<"disconnect_data_link">>, Args) ->
{ ok, NetworkAddress} = rvi_common:get_json_element(["network_address"], Args),
[Res] = gen_server:call(?SERVER, { rvi, disconnect_data_link, [NetworkAddress]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("send_data", Args) ->
+handle_rpc(<<"send_data">>, Args) ->
{ ok, ProtoMod } = rvi_common:get_json_element(["proto_mod"], Args),
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Data } = rvi_common:get_json_element(["data"], Args),
diff --git a/components/dlink_sms/src/sms_connection_manager.erl b/components/dlink_sms/src/sms_connection_manager.erl
index 0e59b0b..df84989 100644
--- a/components/dlink_sms/src/sms_connection_manager.erl
+++ b/components/dlink_sms/src/sms_connection_manager.erl
@@ -37,6 +37,7 @@
-define(SERVER, ?MODULE).
-record(st, {
+ cs,
conn_by_pid = undefined,
conn_by_addr = undefined
}).
@@ -88,6 +89,7 @@ start_link() ->
%%--------------------------------------------------------------------
init([]) ->
{ok, #st{
+ cs = rvi_common:get_component_specification(),
conn_by_pid = dict:new(), %% All managed connection stored by pid
conn_by_addr = dict:new() %% All managed connection stored by address
}}.
@@ -116,34 +118,18 @@ handle_call({add_connection, Addr, Pid}, _From,
NConAddr = dict:store(Addr, Pid, ConAddr),
NSt = St#st {conn_by_pid = NConPid,
conn_by_addr = NConAddr},
+ erlang:monitor(process, Pid),
{reply, ok, NSt};
%% Delete connection by pid
-handle_call({delete_connection_by_pid, Pid}, _From,
- #st{conn_by_pid = ConPid,
- conn_by_addr = ConAddr} = St) when is_pid(Pid)->
- %% Find address associated with Pid
- case dict:find(Pid, ConPid) of
- error ->
- ?debug("~p:handle_call(del_by_pid): not found: ~p",
- [?MODULE, Pid]),
- {reply, not_found, St};
-
- {ok, Addr} ->
- ?debug("~p:handle_call(del_by_pid): deleted Pid: ~p, Address: ~p",
- [?MODULE, Pid, Addr]),
- NConPid = dict:erase(Pid, ConPid),
- NConAddr = dict:erase(Addr, ConAddr),
-
- NSt = St#st{conn_by_pid = NConPid,
- conn_by_addr = NConAddr},
- {reply, ok, NSt}
- end;
-
+handle_call({delete_connection_by_pid, Pid}, _From, St) when is_pid(Pid) ->
+ {Res, NSt} = delete_connection_by_pid_(Pid, St),
+ {reply, Res, NSt};
%% Delete connection by address
handle_call({delete_connection_by_address, Addr}, _From,
- #st{conn_by_pid = ConPid,
+ #st{cs = CS,
+ conn_by_pid = ConPid,
conn_by_addr = ConAddr} = St) ->
%% Find Pid associated with Address
@@ -158,6 +144,7 @@ handle_call({delete_connection_by_address, Addr}, _From,
[?MODULE, Pid, Addr]),
NConPid = dict:erase(Pid, ConPid),
NConAddr = dict:erase(Addr, ConAddr),
+ authorize_rpc:remove_connection(Addr, CS),
NSt = St#st {conn_by_pid = NConPid,
conn_by_addr = NConAddr},
{reply, ok, NSt}
@@ -225,6 +212,9 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
+handle_info({'DOWN', _Ref, process, Pid, _}, St) ->
+ {_, NSt} = delete_connection_by_pid_(Pid, St),
+ {noreply, NSt};
handle_info(_Info, State) ->
?warning("~p:handle_info(): Unknown info: ~p", [?MODULE, _Info]),
{noreply, State}.
@@ -257,3 +247,22 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
+
+delete_connection_by_pid_(Pid, #st{cs = CS,
+ conn_by_pid = ConPid,
+ conn_by_addr = ConAddr} = St) ->
+ %% Find address associated with Pid
+ case dict:find(Pid, ConPid) of
+ error ->
+ ?debug("del_by_pid: not found: ~p", [Pid]),
+ {not_found, St};
+
+ {ok, Addr} ->
+ ?debug("del_by_pid: deleted Pid: ~p, Address: ~p", [Pid, Addr]),
+ NConPid = dict:erase(Pid, ConPid),
+ NConAddr = dict:erase(Addr, ConAddr),
+ authorize_rpc:remove_connection(Addr, CS),
+ NSt = St#st{conn_by_pid = NConPid,
+ conn_by_addr = NConAddr},
+ {ok, NSt}
+ end.
diff --git a/components/dlink_tcp/src/connection_manager.erl b/components/dlink_tcp/src/connection_manager.erl
index e16f789..f279578 100644
--- a/components/dlink_tcp/src/connection_manager.erl
+++ b/components/dlink_tcp/src/connection_manager.erl
@@ -39,8 +39,7 @@
-define(ADDR_TAB, dlink_tcp_conn_by_addr).
-record(st, {
- conn_by_pid = undefined,
- conn_by_addr = undefined
+ cs
}).
%%%===================================================================
@@ -93,8 +92,7 @@ start_link() ->
%%--------------------------------------------------------------------
init([]) ->
{ok, #st{
- conn_by_pid = dict:new(), %% All managed connection stored by pid
- conn_by_addr = dict:new() %% All managed connection stored by address
+ cs = rvi_common:get_component_specification()
}}.
create_ets() ->
@@ -127,28 +125,16 @@ handle_call({add_connection, IP, Port, Pid}, _From, St) ->
?debug("~p:handle_call(add): Adding Pid: ~p, Address: ~p",
[ ?MODULE, Pid, { IP, Port }]),
%% Store so that we can find connection both by pid and by address
+ erlang:monitor(process, Pid),
ets_insert(?PID_TAB, {Pid, {IP, Port}}),
ets_insert(?ADDR_TAB, {{IP, Port}, Pid}),
{reply, ok, St};
%% Delete connection by pid
-handle_call({delete_connection_by_pid, Pid}, _From, St) when is_pid(Pid)->
- %% Find address associated with Pid
- case ets_lookup(?PID_TAB, Pid) of
- [] ->
- ?debug("~p:handle_call(del_by_pid): not found: ~p",
- [ ?MODULE, Pid]),
- { reply, not_found, St};
-
- [{_, Addr}] ->
- ?debug("~p:handle_call(del_by_pid): deleted Pid: ~p, Address: ~p",
- [ ?MODULE, Pid, Addr]),
-
- ets_delete(?PID_TAB, Pid),
- ets_delete(?ADDR_TAB, Addr),
- {reply, ok, St}
- end;
-
+handle_call({delete_connection_by_pid, Pid}, _From, #st{cs = CS} = St)
+ when is_pid(Pid)->
+ Res = delete_connection_by_pid_(Pid, CS),
+ {reply, Res, St};
%% Delete connection by address
handle_call({ delete_connection_by_address, IP, Port}, _From, St) ->
@@ -231,6 +217,9 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
+handle_info({'DOWN', _Ref, process, Pid, _}, #st{cs = CS} = St) ->
+ delete_connection_by_pid_(Pid, CS),
+ {noreply, St};
handle_info(_Info, State) ->
?warning("~p:handle_cast(): Unknown info: ~p", [ ?MODULE, _Info]),
{noreply, State}.
@@ -276,3 +265,18 @@ ets_delete(Tab, Key) ->
ets_select(Tab, Pattern) ->
ets:select(Tab, Pattern).
+
+delete_connection_by_pid_(Pid, CS) ->
+ case ets_lookup(?PID_TAB, Pid) of
+ [] ->
+ ?debug("del_by_pid: not found: ~p",
+ [ Pid]),
+ not_found;
+ [{_, Addr}] ->
+ ?debug("del_by_pid: deleted Pid: ~p, Address: ~p",
+ [ Pid, Addr]),
+ ets_delete(?PID_TAB, Pid),
+ ets_delete(?ADDR_TAB, Addr),
+ authorize_rpc:remove_connection(Pid, CS),
+ ok
+ end.
diff --git a/components/dlink_tcp/src/dlink_tcp_rpc.erl b/components/dlink_tcp/src/dlink_tcp_rpc.erl
index f094fff..9a8be64 100644
--- a/components/dlink_tcp/src/dlink_tcp_rpc.erl
+++ b/components/dlink_tcp/src/dlink_tcp_rpc.erl
@@ -385,7 +385,7 @@ handle_socket_(FromPid, PeerIP, PeerPort, data, Elems, CompSpec) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_notification("service_available", Args) ->
+handle_notification(<<"service_available">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element([<<"service">>], Args),
{ok, DataLinkModule} = rvi_common:get_json_element([<<"data_link_module">>], Args),
@@ -394,7 +394,7 @@ handle_notification("service_available", Args) ->
DataLinkModule ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element([<<"service">>], Args),
{ok, DataLinkModule} = rvi_common:get_json_element([<<"data_link_module">>], Args),
@@ -408,7 +408,7 @@ handle_notification(Other, _Args) ->
?info("dlink_tcp:handle_notification(~p): unknown", [ Other ]),
ok.
-handle_rpc("setup_data_link", Args) ->
+handle_rpc(<<"setup_data_link">>, Args) ->
{ ok, Service } = rvi_common:get_json_element([<<"service">>], Args),
{ ok, Opts } = rvi_common:get_json_element([<<"opts">>], Args),
@@ -418,12 +418,12 @@ handle_rpc("setup_data_link", Args) ->
{ok, [ {status, rvi_common:json_rpc_status(Res)} , { timeout, Timeout }]};
-handle_rpc("disconnect_data_link", Args) ->
+handle_rpc(<<"disconnect_data_link">>, Args) ->
{ ok, NetworkAddress} = rvi_common:get_json_element([<<"network_address">>], Args),
[Res] = gen_server:call(?SERVER, { rvi, disconnect_data_link, [NetworkAddress]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("send_data", Args) ->
+handle_rpc(<<"send_data">>, Args) ->
{ ok, ProtoMod } = rvi_common:get_json_element([<<"proto_mod">>], Args),
{ ok, Service } = rvi_common:get_json_element([<<"service">>], Args),
{ ok, Data } = rvi_common:get_json_element([<<"data">>], Args),
@@ -431,7 +431,7 @@ handle_rpc("send_data", Args) ->
[ Res ] = gen_server:call(?SERVER, { rvi, send_data, [ProtoMod, Service, Data, DataLinkOpts]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("connections", []) ->
+handle_rpc(<<"connections">>, []) ->
Res = gen_server:call(?SERVER, connections),
{ok, [ {status, ok} | {connections, Res} ]};
@@ -674,7 +674,7 @@ process_authorize(FromPid, PeerIP, PeerPort,
?debug("dlink_tcp:authorize(): Credentials: ~p", [ [authorize_keys:abbrev_bin(C) || C <- Credentials] ]),
F = fun() ->
- process_authorize_(FromPid, PeerIP, PeerPort,
+ process_authorize_(FromPid, PeerIP, PeerPort,
ProtoVersion, Credentials, CompSpec)
end,
case connection_manager:find_connection_by_address(PeerIP, PeerPort) of
diff --git a/components/dlink_tls/src/dlink_tls_connmgr.erl b/components/dlink_tls/src/dlink_tls_connmgr.erl
index 31e51bd..d27647d 100644
--- a/components/dlink_tls/src/dlink_tls_connmgr.erl
+++ b/components/dlink_tls/src/dlink_tls_connmgr.erl
@@ -38,7 +38,7 @@
-define(PID_TAB, dlink_tls_pid_tab).
-define(ADDR_TAB, dlink_tls_addr_tab).
--record(st, {}).
+-record(st, {cs}).
%%%===================================================================
%%% API
@@ -101,7 +101,7 @@ maybe_create(Tab) ->
%% @end
%%--------------------------------------------------------------------
init([]) ->
- {ok, #st{}}.
+ {ok, #st{cs = rvi_common:get_component_specification()}}.
%%--------------------------------------------------------------------
%% @private
@@ -122,28 +122,16 @@ handle_call({add_connection, IP, Port, Pid}, _From, St) ->
?debug("~p:handle_call(add): Adding Pid: ~p, Address: ~p",
[ ?MODULE, Pid, Addr]),
%% Store so that we can find connection both by pid and by address
+ erlang:monitor(process, Pid),
ets_insert(?PID_TAB, {Pid, Addr}),
ets_insert(?ADDR_TAB, {Addr, Pid}),
{reply, ok, St};
%% Delete connection by pid
-handle_call({delete_connection_by_pid, Pid}, _From, St) when is_pid(Pid) ->
- %% Find address associated with Pid
- case ets_lookup(?PID_TAB, Pid) of
- [] ->
- ?debug("~p:handle_call(del_by_pid): not found: ~p",
- [ ?MODULE, Pid]),
- { reply, not_found, St};
-
- [{_, Addr}] ->
- ?debug("~p:handle_call(del_by_pid): deleted Pid: ~p, Address: ~p",
- [ ?MODULE, Pid, Addr]),
-
- ets_delete(?PID_TAB, Pid),
- ets_delete(?ADDR_TAB, Addr),
- {reply, ok, St}
- end;
-
+handle_call({delete_connection_by_pid, Pid}, _From, #st{cs = CS} = St)
+ when is_pid(Pid) ->
+ Res = delete_connection_by_pid_(Pid, CS),
+ {reply, Res, St};
%% Delete connection by address
handle_call({ delete_connection_by_address, IP, Port}, _From, St) ->
@@ -224,6 +212,9 @@ handle_cast(_Msg, State) ->
%% {stop, Reason, State}
%% @end
%%--------------------------------------------------------------------
+handle_info({'DOWN', _Ref, process, Pid, _}, #st{cs = CS} = State) ->
+ delete_connection_by_pid_(Pid, CS),
+ {noreply, State};
handle_info(_Info, State) ->
?warning("~p:handle_cast(): Unknown info: ~p", [ ?MODULE, _Info]),
{noreply, State}.
@@ -268,3 +259,16 @@ ets_delete(Tab, Key) ->
ets_select(Tab, Pat) ->
ets:select(Tab, Pat).
+
+delete_connection_by_pid_(Pid, CS) ->
+ case ets_lookup(?PID_TAB, Pid) of
+ [] ->
+ ?debug("del_by_pid: not found: ~p", [ Pid]),
+ not_found;
+ [{_, Addr}] ->
+ ?debug("del_by_pid: deleted Pid: ~p, Address: ~p", [Pid, Addr]),
+ ets_delete(?PID_TAB, Pid),
+ ets_delete(?ADDR_TAB, Addr),
+ authorize_rpc:remove_connection(CS, Addr),
+ ok
+ end.
diff --git a/components/dlink_tls/src/dlink_tls_rpc.erl b/components/dlink_tls/src/dlink_tls_rpc.erl
index ad0d512..849271a 100644
--- a/components/dlink_tls/src/dlink_tls_rpc.erl
+++ b/components/dlink_tls/src/dlink_tls_rpc.erl
@@ -125,7 +125,7 @@ setup_initial_listeners([_|_] = TlsOpts, CompSpec) ->
{value, {_, Ports}, Rest} ->
setup_initial_listeners_(Rest, CompSpec),
[setup_initial_listeners_(
- [{port,P}|inherit_opts([ip], TlsOpts, POpts)], CompSpec)
+ [{port,P}|inherit_opts([ip, ifaddr], TlsOpts, POpts)], CompSpec)
|| {P, POpts} <- Ports];
false ->
setup_initial_listeners_(TlsOpts, CompSpec)
@@ -427,7 +427,7 @@ handle_socket(FromPid, PeerIP, PeerPort, data, Elems, CompSpec) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_notification("service_available", Args) ->
+handle_notification(<<"service_available">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -436,7 +436,7 @@ handle_notification("service_available", Args) ->
DataLinkModule ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -450,7 +450,7 @@ handle_notification(Other, _Args) ->
?info("dlink_tls:handle_notification(~p): unknown", [ Other ]),
ok.
-handle_rpc("setup_data_link", Args) ->
+handle_rpc(<<"setup_data_link">>, Args) ->
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Opts } = rvi_common:get_json_element(["opts"], Args),
@@ -460,12 +460,12 @@ handle_rpc("setup_data_link", Args) ->
{ok, [ {status, rvi_common:json_rpc_status(Res)} , { timeout, Timeout }]};
-handle_rpc("disconnect_data_link", Args) ->
+handle_rpc(<<"disconnect_data_link">>, Args) ->
{ ok, NetworkAddress} = rvi_common:get_json_element(["network_address"], Args),
[Res] = gen_server:call(?SERVER, { rvi, disconnect_data_link, [NetworkAddress]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("send_data", Args) ->
+handle_rpc(<<"send_data">>, Args) ->
{ ok, ProtoMod } = rvi_common:get_json_element(["proto_mod"], Args),
{ ok, Service } = rvi_common:get_json_element(["service"], Args),
{ ok, Data } = rvi_common:get_json_element(["data"], Args),
@@ -473,7 +473,7 @@ handle_rpc("send_data", Args) ->
[ Res ] = gen_server:call(?SERVER, { rvi, send_data, [ProtoMod, Service, Data, DataLinkOpts]}),
{ok, [ {status, rvi_common:json_rpc_status(Res)} ]};
-handle_rpc("connections", []) ->
+handle_rpc(<<"connections">>, []) ->
Res = gen_server:call(?SERVER, connections),
{ok, [ {status, ok} | {connections, {array, Res}} ]};
@@ -688,7 +688,7 @@ availability_msg(Availability, Services) ->
status_string(available ) -> ?DLINK_ARG_AVAILABLE;
status_string(unavailable) -> ?DLINK_ARG_UNAVAILABLE.
-process_authorize(FromPid, PeerIP, PeerPort,
+process_authorize(FromPid, PeerIP, PeerPort,
Credentials, ProtoVersion, CompSpec) ->
?info("dlink_tls:authorize(): Peer Address: ~s:~p", [PeerIP, PeerPort ]),
case ProtoVersion of
diff --git a/components/proto_bert/src/proto_bert_rpc.erl b/components/proto_bert/src/proto_bert_rpc.erl
index f1658a3..a3353c7 100644
--- a/components/proto_bert/src/proto_bert_rpc.erl
+++ b/components/proto_bert/src/proto_bert_rpc.erl
@@ -70,7 +70,7 @@ receive_message(CompSpec, {IP,Port}, Data) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_rpc("send_message", Args) ->
+handle_rpc(<<"send_message">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, TID} = rvi_common:get_json_element(["transaction_id"], Args),
{ok, ServiceName} = rvi_common:get_json_element(["service_name"], Args),
@@ -96,7 +96,7 @@ handle_rpc(Other, _Args) ->
?warning("proto_bert_rpc:handle_rpc(~p): Unknown~n", [ Other ]),
{ ok, [ { status, rvi_common:json_rpc_status(invalid_command)} ] }.
-handle_notification("receive_message", Args) ->
+handle_notification(<<"receive_message">>, Args) ->
{ok, Data} = rvi_common:get_json_element(["data"], Args),
{ok, RemoteIP} = rvi_common:get_json_element(["remote_ip"], Args),
{ok, RemotePort} = rvi_common:get_json_element(["remote_port"], Args),
diff --git a/components/proto_json/src/proto_json_rpc.erl b/components/proto_json/src/proto_json_rpc.erl
index 85f1aa6..e01a985 100644
--- a/components/proto_json/src/proto_json_rpc.erl
+++ b/components/proto_json/src/proto_json_rpc.erl
@@ -71,7 +71,7 @@ receive_message(CompSpec, {IP, Port}, Data) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_rpc("send_message", Args) ->
+handle_rpc(<<"send_message">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, TID} = rvi_common:get_json_element(["transaction_id"], Args),
{ok, ServiceName} = rvi_common:get_json_element(["service_name"], Args),
@@ -98,7 +98,7 @@ handle_rpc(Other, _Args) ->
{ ok, [ { status, rvi_common:json_rpc_status(invalid_command)} ] }.
-handle_notification("receive_message", Args) ->
+handle_notification(<<"receive_message">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Data} = rvi_common:get_json_element(["data"], Args),
{ok, RemoteIP} = rvi_common:get_json_element(["remote_ip"], Args),
diff --git a/components/proto_msgpack/src/proto_msgpack_rpc.erl b/components/proto_msgpack/src/proto_msgpack_rpc.erl
index 07352eb..7035353 100644
--- a/components/proto_msgpack/src/proto_msgpack_rpc.erl
+++ b/components/proto_msgpack/src/proto_msgpack_rpc.erl
@@ -74,7 +74,7 @@ receive_message(CompSpec, {IP, Port}, Data) ->
%% JSON-RPC entry point
%% CAlled by local exo http server
-handle_rpc("send_message", Args) ->
+handle_rpc(<<"send_message">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, TID} = rvi_common:get_json_element(["transaction_id"], Args),
{ok, ServiceName} = rvi_common:get_json_element(["service_name"], Args),
@@ -100,7 +100,7 @@ handle_rpc(Other, _Args) ->
{ ok, [ { status, rvi_common:json_rpc_status(invalid_command)} ] }.
-handle_notification("receive_message", Args) ->
+handle_notification(<<"receive_message">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Data} = rvi_common:get_json_element(["data"], Args),
{ok, RemoteIP} = rvi_common:get_json_element(["remote_ip"], Args),
diff --git a/components/rvi_common/src/rvi_common.erl b/components/rvi_common/src/rvi_common.erl
index 574aa51..ca75f7f 100644
--- a/components/rvi_common/src/rvi_common.erl
+++ b/components/rvi_common/src/rvi_common.erl
@@ -398,7 +398,7 @@ get_json_value(K, [{K1,V}|T], Def) ->
end;
get_json_value(K, [_|T], Def) ->
get_json_value(K, T, Def);
-get_json_value(_, [], Def) ->
+get_json_value(_, _, Def) ->
Def.
comp(A, A) -> true;
diff --git a/components/rvi_common/src/rvi_netlink.erl b/components/rvi_common/src/rvi_netlink.erl
new file mode 100644
index 0000000..82b3fbe
--- /dev/null
+++ b/components/rvi_common/src/rvi_netlink.erl
@@ -0,0 +1,173 @@
+%% -*- erlang-indent-level: 4; indent-tabs-mode: nil -*-
+%%
+%% Copyright (C) 2014, Jaguar Land Rover
+%%
+%% This program is licensed under the terms and conditions of the
+%% Mozilla Public License, version 2.0. The full text of the
+%% Mozilla Public License is at https://www.mozilla.org/MPL/2.0/
+%%
+-module(rvi_netlink).
+-behaviour(gen_server).
+
+-export([is_network_up/0,
+ subscribe/0, subscribe/1, subscribe/2]).
+
+-export([start_link/0]).
+
+%% Gen_server callbacks
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+-include_lib("lager/include/log.hrl").
+
+-record(iface, {name,
+ status = down,
+ opts = []}).
+
+-record(sub, {name, field, pid, ref}).
+
+-record(st, {connected = false,
+ ifs = [],
+ subscribers = [],
+ poll_ref}).
+
+-define(BADARG, {?MODULE, '__BADARG__'}).
+-define(POLL_INTERVAL, 3000). % we only poll if netlink_drv isn't present
+
+is_network_up() ->
+ call(is_network_up).
+
+subscribe() ->
+ subscribe(all, operstate).
+
+subscribe(Iface) ->
+ subscribe(Iface, operstate).
+
+subscribe(Iface, Field) ->
+ call({subscribe, Iface, Field}).
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+init(_) ->
+ Ref = case code:is_loaded(netlink_drv) of
+ false ->
+ %% Must fake event mechanism through polling
+ start_poll_timer();
+ {file, _} ->
+ netlink:subscribe("", [operstate], [flush]),
+ undefined
+ end,
+ Interfaces = get_interfaces(),
+ ?debug("get_interfaces() -> ~p", [Interfaces]),
+ {ok, #st{ifs = Interfaces,
+ poll_ref = Ref}}.
+
+handle_call(is_network_up, _From, #st{connected = Conn} = St) ->
+ {reply, Conn, St};
+handle_call({subscribe, Iface, Field}, {Pid, _},
+ #st{subscribers = Subs} = St) ->
+ Ref = erlang:monitor(process, Pid),
+ {reply, ok, St#st{subscribers = [#sub{name = Iface,
+ field = Field,
+ pid = Pid,
+ ref = Ref}|Subs]}};
+handle_call(_, _From, St) ->
+ {reply, ?BADARG, St}.
+
+handle_cast(_, St) ->
+ {noreply, St}.
+
+handle_info({timeout, _Ref, poll}, #st{ifs = Ifs} = S) ->
+ NewPollRef = start_poll_timer(),
+ NewIfs = get_interfaces(),
+ Diffs = lists:foldr(
+ fun(#iface{name = Name, status = St}, Acc) ->
+ case lists:keyfind(Name, #iface.name, Ifs) of
+ #iface{status = St0} when St0 =/= St ->
+ [{Name, operstate, St0, St}|Acc];
+ _ ->
+ Acc
+ end
+ end, [], NewIfs),
+ {noreply, tell_subscribers(Diffs, S#st{ifs = NewIfs,
+ poll_ref = NewPollRef})};
+handle_info({netlink, _NRef, Iface, Field, Prev, New}, St) ->
+ {Prev1, New1} = adjust_status(Iface, Field, Prev, New),
+ {noreply, tell_subscribers([{Iface, Field, Prev1, New1}], St)};
+handle_info(_, St) ->
+ {noreply, St}.
+
+terminate(_Reason, _St) ->
+ ok.
+
+code_change(_FromVsn, St, _Extra) ->
+ {ok, St}.
+
+call(Req) ->
+ case gen_server:call(?MODULE, Req) of
+ ?BADARG ->
+ error(badarg);
+ Reply ->
+ Reply
+ end.
+
+tell_subscribers(Evts, #st{subscribers = Subs} = St) ->
+ lists:foreach(
+ fun({Name, Field, Old, New}) ->
+ [Pid ! {rvi_netlink, Ref, Name, Field, Old, New}
+ || #sub{name = N, pid = Pid, ref = Ref} <- Subs,
+ match_name(N, Name)]
+ end, Evts),
+ St.
+
+get_interfaces() ->
+ case inet:getifaddrs() of
+ {ok, IFs} ->
+ [if_entry(I) || {_Name, _Flags} = I <- IFs];
+ Error ->
+ ?error("getifaddrs() -> ~p", [Error]),
+ []
+ end.
+
+if_entry({Name, Opts}) ->
+ #iface{name = Name,
+ status = if_status(Opts),
+ opts = Opts}.
+
+if_status(Opts) ->
+ case lists:member(up, opt(flags, Opts, [])) of
+ true -> up;
+ false -> down
+ end.
+
+adjust_status(IF, operstate, A, B) ->
+ {adjust_operstate(A, IF), adjust_operstate(B, IF)};
+adjust_status(_, _, A, B) ->
+ {A, B}.
+
+adjust_operstate(undefined, _) -> down;
+adjust_operstate(unknown, "lo") -> up;
+adjust_operstate(State, _) -> State.
+
+opt(Key, Opts, Default) ->
+ case lists:keyfind(Key, 1, Opts) of
+ {_, Val} ->
+ Val;
+ false ->
+ Default
+ end.
+
+match_name(_, all) -> true;
+match_name(N, N ) -> true;
+match_name(A, B) when is_binary(A), is_list(B) ->
+ binary_to_list(A) == B;
+match_name(_, _) ->
+ false.
+
+start_poll_timer() ->
+ erlang:start_timer(?POLL_INTERVAL, self(), poll).
diff --git a/components/schedule/src/schedule_rpc.erl b/components/schedule/src/schedule_rpc.erl
index 0faddba..7f5a0a9 100644
--- a/components/schedule/src/schedule_rpc.erl
+++ b/components/schedule/src/schedule_rpc.erl
@@ -178,7 +178,7 @@ handle_rpc(Other, _Args) ->
-handle_notification("service_available", Args) ->
+handle_notification(<<"service_available">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_mod"], Args),
LogId = rvi_common:get_json_log_id(Args),
@@ -189,7 +189,7 @@ handle_notification("service_available", Args) ->
LogId ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_mod"], Args),
LogId = rvi_common:get_json_log_id(Args),
diff --git a/components/service_discovery/src/service_discovery_rpc.erl b/components/service_discovery/src/service_discovery_rpc.erl
index 73673d7..a553e18 100644
--- a/components/service_discovery/src/service_discovery_rpc.erl
+++ b/components/service_discovery/src/service_discovery_rpc.erl
@@ -119,7 +119,7 @@ unsubscribe(CompSpec, SubscribingMod) ->
%% Called by local exo http server
%% Register remote services
-handle_notification("register_services", Args) ->
+handle_notification(<<"register_services">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Services} = rvi_common:get_json_element(["services"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
@@ -129,7 +129,7 @@ handle_notification("register_services", Args) ->
ok;
-handle_notification("unregister_services", Args) ->
+handle_notification(<<"unregister_services">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Services} = rvi_common:get_json_element(["services"], Args),
{ok, DataLinkModule } = rvi_common:get_json_element(["data_link_module"], Args),
@@ -138,7 +138,7 @@ handle_notification("unregister_services", Args) ->
ok;
-handle_notification("subscribe", Args) ->
+handle_notification(<<"subscribe">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Module } = rvi_common:get_json_element(["subscribing_module"], Args),
@@ -146,7 +146,7 @@ handle_notification("subscribe", Args) ->
gen_server:cast(?SERVER, { rvi, subscribe, [ list_to_atom(Module), LogId ]}),
ok;
-handle_notification("unsubscribe_from_service", Args) ->
+handle_notification(<<"unsubscribe_from_service">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Module } = rvi_common:get_json_element(["subscribing_module"], Args),
@@ -162,14 +162,14 @@ handle_notification( Other, _Args) ->
%%
%% Get all services
%%
-handle_rpc("get_all_services", Args) ->
+handle_rpc(<<"get_all_services">>, Args) ->
?debug("svc_disc:get_all_services(json-rpc)"),
LogId = rvi_common:get_json_log_id(Args),
[ok, Services ] = gen_server:call(?SERVER, { rvi, get_all_services, [LogId]}),
{ok, [ {status, rvi_common:json_rpc_status(ok)} , { services, Services }]};
-handle_rpc("get_services_by_module", Args) ->
+handle_rpc(<<"get_services_by_module">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, DataLinkMod } = rvi_common:get_json_element(["data_link_module"], Args),
?debug("svc_disc:get_services_by_module(json-rpc): ~p ", [DataLinkMod]),
@@ -180,7 +180,7 @@ handle_rpc("get_services_by_module", Args) ->
{ok, [ {status, rvi_common:json_rpc_status(ok)} , { services, { array, Services } }]};
-handle_rpc("get_modules_by_service", Args) ->
+handle_rpc(<<"get_modules_by_service">>, Args) ->
LogId = rvi_common:get_json_log_id(Args),
{ok, Service } = rvi_common:get_json_element(["service"], Args),
?debug("svc_disc:get_modules_by_service(json-rpc): ~p ", [Service]),
diff --git a/components/service_edge/src/service_edge_rpc.erl b/components/service_edge/src/service_edge_rpc.erl
index bee503e..4a61088 100644
--- a/components/service_edge/src/service_edge_rpc.erl
+++ b/components/service_edge/src/service_edge_rpc.erl
@@ -39,13 +39,15 @@
-export([service_available/3,
service_unavailable/3]).
-
+-export([record_fields/1]).
%%-include_lib("lhttpc/include/lhttpc.hrl").
-include_lib("lager/include/log.hrl").
-include_lib("rvi_common/include/rvi_common.hrl").
+-include_lib("trace_runner/include/trace_runner.hrl").
+
-define(SERVER, ?MODULE).
@@ -62,7 +64,10 @@
url = undefined %% URL where the service can be reached.
}).
-
+record_fields(service_entry) -> record_info(fields, service_entry);
+record_fields(st ) -> record_info(fields, st);
+record_fields(component_spec) -> record_info(fields, component_spec);
+record_fields(_) -> no.
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
@@ -180,6 +185,7 @@ start_websocket() ->
%% Invoked by service_discovery to announce service availability
%% Must be handled either as a JSON-RPC call or a gen_server call.
service_available(CompSpec, SvcName, DataLinkModule) ->
+ ?event({service_available, SvcName}),
rvi_common:notification(service_edge, ?MODULE,
service_available,
[{ service, SvcName },
@@ -187,12 +193,14 @@ service_available(CompSpec, SvcName, DataLinkModule) ->
service_unavailable(CompSpec, SvcName, DataLinkModule) ->
+ ?event({service_unavailable, SvcName}),
rvi_common:notification(service_edge, ?MODULE,
service_unavailable,
[{ service, SvcName },
{ data_link_module, DataLinkModule }], CompSpec).
handle_remote_message(CompSpec, Conn, SvcName, Timeout, Params) ->
+ ?event({handle_remote_message, [Conn, SvcName, Timeout, Params]}),
{IP, Port} = Conn,
rvi_common:notification(service_edge, ?MODULE,
handle_remote_message,
@@ -207,6 +215,7 @@ handle_remote_message(CompSpec, Conn, SvcName, Timeout, Params) ->
%% A message originated from a locally connected service
%% has timed out
handle_local_timeout(CompSpec, SvcName, TransID) ->
+ ?event({handle_local_timeout, [SvcName, TransID]}),
rvi_common:notification(service_edge, ?SERVER, handle_local_timeout,
[ { service, SvcName},
{ transaction_id, TransID} ],
@@ -220,6 +229,7 @@ handle_websocket(WSock, Mesg, Arg) ->
?debug("Failed decode of ~p: ~p", [Mesg, E0]),
Mesg
end,
+ ?event({handle_websocket, Decoded}),
?debug("Decoded Mesg = ~p", [Decoded]),
{ ok, Method } = rvi_common:get_json_element(["method"], Mesg),
{ ok, Params0 } = rvi_common:get_json_element(["params"], Mesg),
@@ -248,6 +258,7 @@ handle_ws_json_rpc(WSock, <<"message">>, Params, _Arg ) ->
{ ok, Timeout } = rvi_common:get_json_element(["timeout"], Params),
{ ok, Parameters } = rvi_common:get_json_element(["parameters"], Params),
SvcName = iolist_to_binary(SvcName0),
+ ?event({message, ws, [SvcName, Timeout, Parameters]}),
?debug("WS Parameters: ~p", [Parameters]),
%% Parameters = parse_ws_params(Parameters0),
LogId = log_id_json_tail(Params ++ Parameters),
@@ -270,6 +281,7 @@ handle_ws_json_rpc(WSock, <<"message">>, Params, _Arg ) ->
handle_ws_json_rpc(WSock, <<"register_service">>, Params,_Arg ) ->
{ ok, SvcName } = rvi_common:get_json_element(["service_name"], Params),
+ ?event({register_service, ws, SvcName}),
?debug("service_edge_rpc:websocket_register(~p) service: ~p", [ WSock, SvcName ]),
[ok, FullSvcName ] = gen_server:call(?SERVER,
{ rvi,
@@ -283,6 +295,7 @@ handle_ws_json_rpc(WSock, <<"register_service">>, Params,_Arg ) ->
handle_ws_json_rpc(WSock, <<"unregister_service">>, Params, _Arg ) ->
{ ok, SvcName } = rvi_common:get_json_element(["service_name"], Params),
+ ?event({unregister_service, ws, SvcName}),
?debug("service_edge_rpc:websocket_unregister(~p) service: ~p", [ WSock, SvcName ]),
gen_server:call(?SERVER, { rvi, unregister_local_service, [ SvcName ]}),
{ ok, [ { status, rvi_common:json_rpc_status(ok)} ]};
@@ -310,6 +323,7 @@ handle_ws_json_rpc(_Ws , <<"get_available_services">>, _Params, _Arg ) ->
%%
handle_rpc(<<"register_service">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element([<<"service">>], Args),
+ ?event({register_service, json_rpc, SvcName}),
{ok, URL} = rvi_common:get_json_element([<<"network_address">>], Args),
[ok, FullSvcName ] = gen_server:call(?SERVER,
{ rvi, register_local_service,
@@ -323,6 +337,7 @@ handle_rpc(<<"register_service">>, Args) ->
handle_rpc(<<"unregister_service">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
+ ?event({unregister_service, json_rpc, SvcName}),
gen_server:call(?SERVER, { rvi, unregister_local_service, [ SvcName]}),
{ok, [ { status, rvi_common:json_rpc_status(ok) },
{ method, <<"unregister_service">>}
@@ -341,6 +356,7 @@ handle_rpc(<<"message">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service_name"], Args),
{ok, Timeout} = rvi_common:get_json_element(["timeout"], Args),
{ok, Parameters} = rvi_common:get_json_element(["parameters"], Args),
+ ?event({message, json_rpc, [SvcName, Timeout, Parameters]}),
LogId = log_id_json_tail(Args ++ Parameters),
[ Res, TID ] = gen_server:call(?SERVER, { rvi, handle_local_message,
[ SvcName, Timeout, Parameters | LogId]}),
@@ -364,7 +380,7 @@ handle_notification(<<"service_available">>, Args) ->
[ SvcName, DataLinkModule ]}),
ok;
-handle_notification("service_unavailable", Args) ->
+handle_notification(<<"service_unavailable">>, Args) ->
{ok, SvcName} = rvi_common:get_json_element(["service"], Args),
{ok, DataLinkModule} = rvi_common:get_json_element(["data_link_module"], Args),
?debug("service_edge:service_unavailable(): service: ~p", [ SvcName]),
@@ -514,6 +530,7 @@ handle_cast({rvi, handle_remote_message,
Timeout,
Parameters
] }, #st{cs = CS} = St) ->
+ ?event({handle_remote_message, [IP, Port, SvcName, Timeout]}, St),
spawn(fun() ->
handle_remote_message_(
IP, Port, SvcName, Timeout, Parameters, CS)
@@ -629,9 +646,10 @@ do_handle_local_message_([SvcName, TimeoutArg, Parameters | _Tail], CS) ->
LookupRes = ets:lookup(?SERVICE_TABLE, SvcName),
?debug("Service LookupRes = ~p", [LookupRes]),
case LookupRes of
- [ #service_entry { url = URL } ] -> %% SvcName is local. Forward message
+ [ #service_entry { url = URL } = E ] -> %% SvcName is local. Forward message
?debug("service_edge_rpc:local_msg(): Service is local. Forwarding."),
log("dispatch to ~s", [URL], CS),
+ ?event({matching_service_entry, E}),
Res = forward_message_to_local_service(URL,
SvcName,
Parameters,
@@ -743,7 +761,8 @@ forward_message_to_local_service(URL,SvcName, Parameters, CompSpec) ->
SvcName, CompSpec)
catch
Tag:Err ->
- ?debug("Caught ~p:~p", [Tag,Err])
+ ?error("Caught ~p:~p~n~p",
+ [Tag,Err,erlang:get_stacktrace()])
end
end),
timer:sleep(500),
@@ -831,3 +850,6 @@ log_id_json_tail(Args) ->
{error, _} ->
[]
end.
+
+event(_, _, _) ->
+ ok.
diff --git a/deps/netlink/LICENSE b/deps/netlink/LICENSE
new file mode 100644
index 0000000..14e2f77
--- /dev/null
+++ b/deps/netlink/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/deps/netlink/README b/deps/netlink/README
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/deps/netlink/README
diff --git a/deps/netlink/c_src/.gitignore b/deps/netlink/c_src/.gitignore
new file mode 100644
index 0000000..d6ff91a
--- /dev/null
+++ b/deps/netlink/c_src/.gitignore
@@ -0,0 +1,2 @@
+*~
+*.o
diff --git a/deps/netlink/c_src/Makefile b/deps/netlink/c_src/Makefile
new file mode 100644
index 0000000..984e8dc
--- /dev/null
+++ b/deps/netlink/c_src/Makefile
@@ -0,0 +1,13 @@
+.PHONY: libnl
+
+PRIVDIR := ../priv
+
+all : $(PRIVDIR)/netlink_drv.so
+
+override CFLAGS += -fpic -shared
+
+$(PRIVDIR)/netlink_drv.so : netlink_drv.o
+ $(CC) -shared -fpic $(LDFLAGS) -o $@ $^
+
+clean:
+ $(RM) -f $(PRIVDIR)/netlink_drv.so netlink_drv.o
diff --git a/deps/netlink/c_src/netlink_drv.c b/deps/netlink/c_src/netlink_drv.c
new file mode 100644
index 0000000..15da7e5
--- /dev/null
+++ b/deps/netlink/c_src/netlink_drv.c
@@ -0,0 +1,727 @@
+/****** BEGIN COPYRIGHT *******************************************************
+ *
+ * Copyright (C) 2012 Feuerlabs, Inc. All rights reserved.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ ****** END COPYRIGHT ********************************************************/
+//
+// Netlink driver
+//
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "erl_driver.h"
+
+#define ATOM(NAME) am_ ## NAME
+#define INIT_ATOM(NAME) am_ ## NAME = driver_mk_atom(#NAME)
+
+// Hack to handle R15 driver used with pre R15 driver
+#if ERL_DRV_EXTENDED_MAJOR_VERSION == 1
+typedef int ErlDrvSizeT;
+typedef int ErlDrvSSizeT;
+#endif
+
+#if (ERL_DRV_EXTENDED_MAJOR_VERSION > 2) || ((ERL_DRV_EXTENDED_MAJOR_VERSION == 2) && (ERL_DRV_EXTENDED_MINOR_VERSION >= 1))
+#define SEND_TERM(ctx, to, message, len) erl_drv_send_term((ctx)->dport,(to),(message),(len))
+#else
+#define SEND_TERM(ctx, to, message, len) driver_send_term((ctx)->port,(to),(message),(len))
+#endif
+
+#ifndef SOL_NETLINK
+#define SOL_NETLINK 270
+#endif
+
+#define PORT_CONTROL_BINARY
+
+#define INT_EVENT(ptr) ((int)((long)(ptr)))
+
+typedef struct _nl_ctx_t {
+ ErlDrvPort port;
+ ErlDrvTermData dport;
+ ErlDrvTermData owner;
+ ErlDrvEvent fd; // netlink socket
+ int protocol; // netlink protocol
+ int active;
+ int is_selecting;
+ int is_sending;
+ void* nlbuf;
+ size_t nlbuf_len;
+} nl_ctx_t;
+
+#define CMD_ADD_MEMBERSHIP 1
+#define CMD_DROP_MEMBERSHIP 2
+#define CMD_ACTIVE 3
+#define CMD_DEBUG 4
+#define CMD_SET_RCVBUF 5
+#define CMD_SET_SNDBUF 6
+#define CMD_GET_RCVBUF 7
+#define CMD_GET_SNDBUF 8
+#define CMD_GET_SIZEOF 9
+
+
+#define CTL_OK 0
+#define CTL_INT 1
+#define CTL_PAIR 2
+#define CTL_BIN 3
+#define CTL_LIST 4
+#define CTL_ERR 255
+#define CTL_STRERR 254
+
+#define MIN_NL_BUFSIZE (32*1024)
+#define MAX_NL_BUFSIZE (512*1024)
+
+#define MAX_VSIZE 16
+
+ErlDrvTermData am_ok;
+ErlDrvTermData am_error;
+ErlDrvTermData am_undefined;
+ErlDrvTermData am_true;
+ErlDrvTermData am_false;
+ErlDrvTermData am_nl_data;
+
+#define push_atom(atm) do { \
+ message[i++] = ERL_DRV_ATOM; \
+ message[i++] = (atm); \
+ } while(0)
+
+#define push_port(prt) do { \
+ message[i++] = ERL_DRV_PORT; \
+ message[i++] = (prt); \
+ } while(0)
+
+#define push_pid(pid) do { \
+ message[i++] = ERL_DRV_PID; \
+ message[i++] = (pid); \
+ } while(0)
+
+#define push_bin(buf,len) do { \
+ message[i++] = ERL_DRV_BUF2BINARY; \
+ message[i++] = (ErlDrvTermData)(buf); \
+ message[i++] = (ErlDrvTermData)(len); \
+ } while(0)
+
+#define push_nil() do { \
+ message[i++] = ERL_DRV_NIL; \
+ } while(0)
+
+#define push_string(str) do { \
+ message[i++] = ERL_DRV_STRING; \
+ message[i++] = (ErlDrvTermData) (str); \
+ message[i++] = strlen(str); \
+ } while(0)
+
+#define push_int(val) do { \
+ message[i++] = ERL_DRV_INT; \
+ message[i++] = (val); \
+ } while(0)
+
+#define push_tuple(n) do { \
+ message[i++] = ERL_DRV_TUPLE; \
+ message[i++] = (n); \
+ } while(0)
+
+#define push_list(n) do { \
+ message[i++] = ERL_DRV_LIST; \
+ message[i++] = (n); \
+ } while(0)
+
+
+ErlDrvEntry nl_drv_entry;
+
+static inline uint32_t get_uint32(uint8_t* ptr)
+{
+ uint32_t value = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | (ptr[3]<<0);
+ return value;
+}
+
+static inline int32_t get_int32(uint8_t* ptr)
+{
+ uint32_t value = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | (ptr[3]<<0);
+ return (int32_t) value;
+}
+
+static inline uint16_t get_uint16(uint8_t* ptr)
+{
+ uint16_t value = (ptr[0]<<8) | (ptr[1]<<0);
+ return value;
+}
+
+static inline uint8_t get_uint8(uint8_t* ptr)
+{
+ return ptr[0];
+}
+
+static inline int8_t get_int8(uint8_t* ptr)
+{
+ return (int8_t) ptr[0];
+}
+
+static inline void put_uint16(uint8_t* ptr, uint16_t v)
+{
+ ptr[0] = v>>8;
+ ptr[1] = v;
+}
+
+static inline void put_uint32(uint8_t* ptr, uint32_t v)
+{
+ ptr[0] = v>>24;
+ ptr[1] = v>>16;
+ ptr[2] = v>>8;
+ ptr[3] = v;
+}
+
+static int nl_drv_init(void);
+static void nl_drv_finish(void);
+static void nl_drv_stop(ErlDrvData);
+static void nl_drv_output(ErlDrvData,char*,ErlDrvSizeT);
+#if 0
+static void nl_drv_outputv(ErlDrvData, ErlIOVec*);
+#endif
+static void nl_drv_ready_input(ErlDrvData, ErlDrvEvent);
+static void nl_drv_ready_output(ErlDrvData data, ErlDrvEvent event);
+static ErlDrvData nl_drv_start(ErlDrvPort, char* command);
+static ErlDrvSSizeT nl_drv_ctl(ErlDrvData,unsigned int,char*,ErlDrvSizeT,char**,ErlDrvSizeT);
+static void nl_drv_timeout(ErlDrvData);
+static void nl_drv_stop_select(ErlDrvEvent event, void* arg);
+
+#define DLOG_DEBUG 7
+#define DLOG_INFO 6
+#define DLOG_NOTICE 5
+#define DLOG_WARNING 4
+#define DLOG_ERROR 3
+#define DLOG_CRITICAL 2
+#define DLOG_ALERT 1
+#define DLOG_EMERGENCY 0
+#define DLOG_NONE -1
+
+#ifndef DLOG_DEFAULT
+#define DLOG_DEFAULT DLOG_NONE
+#endif
+
+#define DLOG(level,file,line,args...) do { \
+ if (((level) == DLOG_EMERGENCY) || \
+ ((debug_level >= 0) && ((level) <= debug_level))) { \
+ emit_log((level),(file),(line),args); \
+ } \
+ } while(0)
+
+#define DEBUGF(args...) DLOG(DLOG_DEBUG,__FILE__,__LINE__,args)
+#define INFOF(args...) DLOG(DLOG_INFO,__FILE__,__LINE__,args)
+#define NOTICEF(args...) DLOG(DLOG_NOTICE,__FILE__,__LINE__,args)
+#define WARNINGF(args...) DLOG(DLOG_WARNING,__FILE__,__LINE__,args)
+#define ERRORF(args...) DLOG(DLOG_ERROR,__FILE__,__LINE__,args)
+#define CRITICALF(args...) DLOG(DLOG_CRITICAL,__FILE__,__LINE__,args)
+#define ALERTF(args...) DLOG(DLOG_ALERT,__FILE__,__LINE__,args)
+#define EMERGENCYF(args...) DLOG(DLOG_EMERGENCY,__FILE__,__LINE__,args)
+
+static int debug_level = DLOG_DEFAULT;
+
+static void emit_log(int level, char* file, int line, ...)
+{
+ va_list ap;
+ char* fmt;
+
+ if ((level == DLOG_EMERGENCY) ||
+ ((debug_level >= 0) && (level <= debug_level))) {
+ int save_errno = errno;
+ va_start(ap, line);
+ fmt = va_arg(ap, char*);
+ fprintf(stderr, "%s:%d: ", file, line);
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\r\n");
+ va_end(ap);
+ errno = save_errno;
+ }
+}
+
+/* general control reply function */
+static ErlDrvSSizeT ctl_reply(int rep, void* buf, ErlDrvSizeT len,
+ char** rbuf, ErlDrvSizeT rsize)
+{
+ char* ptr;
+
+ if ((len+1) > rsize) {
+#ifdef PORT_CONTROL_BINARY
+ ErlDrvBinary* bin = driver_alloc_binary(len+1);
+ if (bin == NULL)
+ return -1;
+ ptr = bin->orig_bytes;
+ *rbuf = (char*) bin;
+#else
+ if ((ptr = driver_alloc(len+1)) == NULL)
+ return -1;
+ *rbuf = ptr;
+#endif
+ }
+ else
+ ptr = *rbuf;
+ *ptr++ = rep;
+ memcpy(ptr, buf, len);
+ return len+1;
+}
+
+static void* nl_realloc_buffer(nl_ctx_t* ctx, size_t len)
+{
+ if (ctx->nlbuf_len < len) {
+ ctx->nlbuf = driver_realloc(ctx->nlbuf, NLMSG_SPACE(len));
+ ctx->nlbuf_len = len;
+ }
+ return ctx->nlbuf;
+}
+
+static int nl_drv_init(void)
+{
+ INIT_ATOM(ok);
+ INIT_ATOM(error);
+ INIT_ATOM(undefined);
+ INIT_ATOM(true);
+ INIT_ATOM(false);
+ INIT_ATOM(nl_data);
+ return 0;
+}
+
+static void nl_drv_finish(void)
+{
+}
+
+static void nl_drv_stop(ErlDrvData d)
+{
+ nl_ctx_t* ctx = (nl_ctx_t*) d;
+
+ if (ctx) {
+ if (ctx->is_selecting)
+ driver_select(ctx->port, ctx->fd, ERL_DRV_READ, 0);
+ if (ctx->is_sending)
+ driver_select(ctx->port, ctx->fd, ERL_DRV_WRITE, 0);
+ driver_select(ctx->port, ctx->fd, ERL_DRV_USE, 0);
+ driver_free(ctx);
+ }
+}
+
+static void nl_drv_output(ErlDrvData d, char* buf,ErlDrvSizeT len)
+{
+ nl_ctx_t* ctx = (nl_ctx_t*) d;
+ int n;
+ struct nlmsghdr* nlh = (struct nlmsghdr*) buf;
+
+ if (!NLMSG_OK(nlh, len)) {
+ DEBUGF("netlink_drv: data not OK");
+ }
+ else {
+ DEBUGF("netlink_drv: output len=%d, type=%d, seq=%d, pid=%d",
+ nlh->nlmsg_len, nlh->nlmsg_type, nlh->nlmsg_seq, nlh->nlmsg_pid);
+ if ((n = driver_sizeq(ctx->port)) > 0) {
+ driver_enq(ctx->port, buf, len);
+ DEBUGF("netlink_drv_output: put on queue pending=%d", n+len);
+ }
+ else { // try send directly
+ struct sockaddr_nl dest_addr;
+ struct iovec iov;
+ struct msghdr msg;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&dest_addr, 0, sizeof(dest_addr));
+
+ dest_addr.nl_family = AF_NETLINK;
+ dest_addr.nl_pid = 0; // to kernel
+ dest_addr.nl_groups = 0; // unicast
+
+ iov.iov_base = (void*) buf;
+ iov.iov_len = len;
+
+ msg.msg_name = (void*) &dest_addr;
+ msg.msg_namelen = sizeof(dest_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ n = sendmsg(INT_EVENT(ctx->fd), &msg, 0);
+ if (n < 0) {
+ ERRORF("write error=%s", strerror(errno));
+ if ((errno == EAGAIN) || (errno = ENOBUFS)) {
+ DEBUGF("netlink_drv: put on queue", n);
+ driver_enq(ctx->port, buf, len);
+ driver_select(ctx->port, ctx->fd, ERL_DRV_WRITE, 1);
+ ctx->is_sending = 1;
+ }
+ }
+ }
+ }
+}
+
+
+// netlink socket triggered process data
+static void nl_drv_ready_input(ErlDrvData d, ErlDrvEvent event)
+{
+ nl_ctx_t* ctx = (nl_ctx_t*) d;
+ struct sockaddr_nl src_addr;
+ struct iovec iov;
+ struct msghdr msg;
+ struct nlmsghdr* nlh;
+ int n;
+ int part = 0;
+ int recv_count = 10;
+
+ DEBUGF("nl_drv_ready_input");
+
+again:
+ if (!--recv_count)
+ return;
+ memset(&iov, 0, sizeof(iov));
+ memset(&msg, 0, sizeof(msg));
+ memset(&src_addr, 0, sizeof(src_addr));
+
+ nlh = nl_realloc_buffer(ctx, MIN_NL_BUFSIZE);
+
+ iov.iov_base = (void*) nlh;
+ iov.iov_len = ctx->nlbuf_len;
+ msg.msg_name = (void*) &src_addr;
+ msg.msg_namelen = sizeof(src_addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ if ((n = recvmsg(INT_EVENT(ctx->fd), &msg, 0)) < 0) {
+ if (errno == EAGAIN)
+ return;
+ // send error to erlang ?
+ WARNINGF("nl_drv_read_input: read error=%s", strerror(errno));
+ }
+ else if (n == 0) {
+ WARNINGF("nl_drv_read_input: read eof?");
+ }
+ else {
+ ErlDrvTermData message[16];
+
+ while(NLMSG_OK(nlh, n)) {
+ int i = 0;
+ // {nl_data, <port>, <data>}
+ push_atom(ATOM(nl_data));
+ push_port(ctx->dport);
+ push_bin((char*)nlh, nlh->nlmsg_len);
+ push_tuple(3);
+ DEBUGF("nl_drv_read_input: part = %d", part);
+ part++;
+ if (ctx->active) {
+ SEND_TERM(ctx, ctx->owner, message, i);
+ if (ctx->active > 0) {
+ ctx->active--;
+ if (ctx->active == 0) {
+ ctx->is_selecting = 0;
+ driver_select(ctx->port, ctx->fd, ERL_DRV_READ, 0);
+ }
+ }
+ }
+ nlh = NLMSG_NEXT(nlh, n);
+ }
+ goto again;
+ }
+}
+
+static void nl_drv_ready_output(ErlDrvData d, ErlDrvEvent event)
+{
+ nl_ctx_t* ctx = (nl_ctx_t*) d;
+ struct sockaddr_nl dest_addr;
+ int vsize;
+ SysIOVec* iovp;
+ struct msghdr msg;
+ int n;
+
+ DEBUGF("nl_drv_ready_output called");
+
+ if (ctx->fd != event) {
+ DEBUGF("nl_drv_ready_output bad event");
+ return;
+ }
+
+ if ((iovp = driver_peekq(ctx->port, &vsize)) == NULL) {
+ driver_select(ctx->port, ctx->fd, ERL_DRV_WRITE, 0);
+ ctx->is_sending = 0;
+ return;
+ }
+ vsize = vsize > MAX_VSIZE ? MAX_VSIZE : vsize;
+
+ memset(&msg, 0, sizeof(msg));
+ memset(&dest_addr, 0, sizeof(dest_addr));
+
+ dest_addr.nl_family = AF_NETLINK;
+ dest_addr.nl_pid = 0; // to kernel
+ dest_addr.nl_groups = 0; // unicast
+
+ msg.msg_name = (void*) &dest_addr;
+ msg.msg_namelen = sizeof(dest_addr);
+ msg.msg_iov = (struct iovec*) iovp;
+ msg.msg_iovlen = vsize;
+
+ DEBUGF("nl_drv_ready_output: try send vsize=%d", vsize);
+ n = sendmsg(INT_EVENT(ctx->fd), &msg, 0);
+ if (n < 0) {
+ if ((errno == EAGAIN) || (errno == ENOBUFS))
+ return;
+ ERRORF("write error=%s", strerror(errno));
+ return;
+ }
+ DEBUGF("nl_drv_ready_output: sent %d bytes", n);
+ if (driver_deq(ctx->port, n) == 0) {
+ driver_select(ctx->port, ctx->fd, ERL_DRV_WRITE, 0);
+ ctx->is_sending = 0;
+ }
+}
+
+static ErlDrvSSizeT nl_drv_ctl(ErlDrvData d,unsigned int cmd,char* buf0,
+ ErlDrvSizeT len,char** rbuf,ErlDrvSizeT rsize)
+{
+ uint8_t* buf = (uint8_t*) buf0;
+ nl_ctx_t* ctx = (nl_ctx_t*) d;
+
+ DEBUGF("nl_drv_ctl cmd=%d", cmd);
+
+ switch(cmd) {
+ case CMD_ADD_MEMBERSHIP: {
+ int opt;
+ if (len != 4)
+ goto badarg;
+ opt = get_int32(buf);
+ if (setsockopt(INT_EVENT(ctx->fd), SOL_NETLINK,
+ NETLINK_ADD_MEMBERSHIP,
+ (void*) &opt, sizeof(opt)) < 0)
+ goto error;
+ goto ok;
+ }
+ case CMD_DROP_MEMBERSHIP: {
+ int opt;
+ if (len != 4)
+ goto badarg;
+ opt = get_int32(buf);
+
+ if (setsockopt(INT_EVENT(ctx->fd), SOL_NETLINK,
+ NETLINK_DROP_MEMBERSHIP,
+ (void*) &opt, sizeof(opt)) < 0)
+ goto error;
+ goto ok;
+ }
+
+ case CMD_SET_RCVBUF: {
+ int opt;
+ if (len != 4)
+ goto badarg;
+ opt = get_int32(buf);
+ if (setsockopt(INT_EVENT(ctx->fd), SOL_SOCKET,
+ SO_RCVBUF,
+ (void*) &opt, sizeof(opt)) < 0)
+ goto error;
+ if (opt > 0) {
+ // make sure i/o buffer match
+ nl_realloc_buffer(ctx, (size_t)opt);
+ }
+ goto ok;
+ }
+
+ case CMD_SET_SNDBUF: {
+ int opt;
+ if (len != 4)
+ goto badarg;
+ opt = get_int32(buf);
+ if (setsockopt(INT_EVENT(ctx->fd), SOL_SOCKET,
+ SO_SNDBUF,
+ (void*) &opt, sizeof(opt)) < 0)
+ goto error;
+ if (opt > 0) {
+ // make sure i/o buffer match
+ nl_realloc_buffer(ctx, (size_t)opt);
+ }
+ goto ok;
+ }
+
+ case CMD_GET_RCVBUF: {
+ int opt;
+ socklen_t optlen;
+ if (len != 0)
+ goto badarg;
+ optlen = sizeof(opt);
+ opt = get_int32(buf);
+ if (getsockopt(INT_EVENT(ctx->fd), SOL_SOCKET,
+ SO_RCVBUF,
+ (void*) &opt, &optlen) < 0)
+ goto error;
+ return ctl_reply(CTL_INT, &opt, sizeof(opt), rbuf, rsize);
+ }
+
+ case CMD_GET_SNDBUF: {
+ int opt;
+ socklen_t optlen;
+ if (len != 0)
+ goto badarg;
+ optlen = sizeof(opt);
+ opt = get_int32(buf);
+ if (getsockopt(INT_EVENT(ctx->fd), SOL_SOCKET,
+ SO_SNDBUF,
+ (void*) &opt, &optlen) < 0)
+ goto error;
+ return ctl_reply(CTL_INT, &opt, sizeof(opt), rbuf, rsize);
+ }
+
+ case CMD_GET_SIZEOF: {
+ uint8_t sizes[6];
+
+ sizes[0] = (uint8_t) sizeof(char);
+ sizes[1] = (uint8_t) sizeof(short);
+ sizes[2] = (uint8_t) sizeof(int);
+ sizes[3] = (uint8_t) sizeof(long);
+ sizes[4] = (uint8_t) sizeof(long long);
+ sizes[5] = (uint8_t) sizeof(void*);
+ return ctl_reply(CTL_LIST, sizes, 6, rbuf, rsize);
+ }
+
+ case CMD_ACTIVE: {
+ int active;
+
+ if (len != 4)
+ goto badarg;
+ active = get_int32(buf);
+ if (active) {
+ if (!ctx->is_selecting)
+ driver_select(ctx->port, ctx->fd, ERL_DRV_READ, 1);
+ ctx->is_selecting = 1;
+ ctx->active = active;
+ }
+ else {
+ if (ctx->is_selecting)
+ driver_select(ctx->port, ctx->fd, ERL_DRV_READ, 0);
+ ctx->is_selecting = 0;
+ ctx->active = 0;
+ }
+ goto ok;
+ break;
+ }
+ case CMD_DEBUG: {
+ if (len != 4)
+ goto badarg;
+ debug_level = get_int32(buf);
+ goto ok;
+ }
+
+ default:
+ return -1;
+ }
+
+ok:
+ return ctl_reply(CTL_OK, NULL, 0, rbuf, rsize);
+badarg:
+ errno = EINVAL;
+error: {
+ char* err_str = erl_errno_id(errno);
+ return ctl_reply(CTL_ERR, err_str, strlen(err_str), rbuf, rsize);
+}
+}
+
+
+static void nl_drv_timeout(ErlDrvData d)
+{
+ (void) d;
+ fprintf(stderr, "nl_drv_timeout called!!!\r\n");
+}
+
+static void nl_drv_stop_select(ErlDrvEvent event, void* arg)
+{
+ (void) arg;
+ DEBUGF("eth_drv: stop_select event=%d", INT_EVENT(event));
+ close(INT_EVENT(event));
+}
+
+
+static ErlDrvData nl_drv_start(ErlDrvPort port, char* command)
+{
+ (void) command;
+ nl_ctx_t* ctx;
+ int flags;
+ int fd;
+ int protocol;
+ char* ptr;
+ char* arg;
+ struct sockaddr_nl addr;
+
+ ptr = command;
+ while(*ptr && (*ptr != ' ')) ptr++; // skip command
+ while(*ptr && (*ptr == ' ')) ptr++; // and blanks
+ arg = ptr;
+ while(*ptr && (*ptr >= '0') && (*ptr <= '9')) ptr++;
+ if ((arg == ptr) || (*ptr != '\0')) {
+ errno = EINVAL;
+ return ERL_DRV_ERROR_ERRNO;
+ }
+ protocol = atoi(arg);
+
+ if ((fd = socket(PF_NETLINK, SOCK_RAW, protocol)) < 0)
+ return ERL_DRV_ERROR_ERRNO;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.nl_family = AF_NETLINK;
+ addr.nl_groups = 0; // start with no groups
+ addr.nl_pid = getpid(); // bind using this pid?
+
+ if (bind(fd, (struct sockaddr* ) &addr, sizeof(addr)) < 0)
+ return ERL_DRV_ERROR_ERRNO;
+
+ flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ if (!(ctx = driver_alloc(sizeof(nl_ctx_t))))
+ return ERL_DRV_ERROR_ERRNO;
+ memset(ctx, 0, sizeof(nl_ctx_t));
+ ctx->port = port;
+ ctx->dport = driver_mk_port(port);
+ ctx->owner = driver_caller(port);
+ ctx->protocol = protocol;
+ ctx->fd = (ErlDrvEvent)((long)fd);
+
+ nl_realloc_buffer(ctx, MIN_NL_BUFSIZE); // create i/o buffer
+
+#ifdef PORT_CONTROL_BINARY
+ set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
+#endif
+
+ return (ErlDrvData) ctx;
+}
+
+DRIVER_INIT(nl_drv)
+{
+ ErlDrvEntry* ptr = &nl_drv_entry;
+
+ ptr->driver_name = "netlink_drv";
+ ptr->init = nl_drv_init;
+ ptr->start = nl_drv_start;
+ ptr->stop = nl_drv_stop;
+ ptr->output = nl_drv_output;
+ ptr->ready_input = nl_drv_ready_input;
+ ptr->ready_output = nl_drv_ready_output;
+ ptr->finish = nl_drv_finish;
+ ptr->control = nl_drv_ctl;
+ ptr->timeout = nl_drv_timeout;
+#if 0
+ ptr->outputv = nl_drv_outputv;
+#endif
+ ptr->ready_async = 0;
+ ptr->flush = 0;
+ ptr->call = 0;
+ ptr->event = 0;
+ ptr->extended_marker = ERL_DRV_EXTENDED_MARKER;
+ ptr->major_version = ERL_DRV_EXTENDED_MAJOR_VERSION;
+ ptr->minor_version = ERL_DRV_EXTENDED_MINOR_VERSION;
+ ptr->driver_flags = ERL_DRV_FLAG_USE_PORT_LOCKING;
+ ptr->process_exit = 0;
+ ptr->stop_select = nl_drv_stop_select;
+
+ return (ErlDrvEntry*) ptr;
+}
diff --git a/deps/netlink/include/log.hrl b/deps/netlink/include/log.hrl
new file mode 100644
index 0000000..270f06c
--- /dev/null
+++ b/deps/netlink/include/log.hrl
@@ -0,0 +1,44 @@
+%%
+%% Log macros
+%%
+-ifndef(__LOG_HRL__).
+-define(__LOG_HRL__, true).
+
+-compile({parse_transform, lager_transform}).
+
+%% Lager logging levels
+%% debug, info, notice, warning, error, critical, alert, emergency, none.
+
+-define(debug(Fmt), lager:debug(Fmt)).
+-define(debug(Fmt, Args), lager:debug(Fmt, Args)).
+-define(debug(Attrs, Fmt, Args), lager:debug(Attrs, Fmt, Args)).
+
+-define(info(Fmt), lager:info(Fmt)).
+-define(info(Fmt, Args), lager:info(Fmt, Args)).
+-define(info(Attrs, Fmt, Args), lager:info(Attrs, Fmt, Args)).
+
+-define(notice(Fmt), lager:notice(Fmt)).
+-define(notice(Fmt, Args), lager:notice(Fmt, Args)).
+-define(notice(Attrs, Fmt, Args), lager:notice(Attrs, Fmt, Args)).
+
+-define(warning(Fmt), lager:warning(Fmt)).
+-define(warning(Fmt, Args), lager:warning(Fmt, Args)).
+-define(warning(Attrs, Fmt, Args), lager:warning(Attrs, Fmt, Args)).
+
+-define(error(Fmt), lager:error(Fmt)).
+-define(error(Fmt, Args), lager:error(Fmt, Args)).
+-define(error(Attrs, Fmt, Args), lager:error(Attrs, Fmt, Args)).
+
+-define(critical(Fmt), lager:critical(Fmt)).
+-define(critical(Fmt, Args), lager:critical(Fmt, Args)).
+-define(critical(Attrs, Fmt, Args), lager:critical(Attrs, Fmt, Args)).
+
+-define(alert(Fmt), lager:alert(Fmt)).
+-define(alert(Fmt, Args), lager:alert(Fmt, Args)).
+-define(alert(Attrs, Fmt, Args), lager:alert(Attrs, Fmt, Args)).
+
+-define(emergency(Fmt), lager:emergency(Fmt)).
+-define(emergency(Fmt, Args), lager:emergency(Fmt, Args)).
+-define(emergency(Attrs, Fmt, Args), lager:emergency(Attrs, Fmt, Args)).
+
+-endif.
diff --git a/deps/netlink/include/netlink.hrl b/deps/netlink/include/netlink.hrl
new file mode 100644
index 0000000..8575420
--- /dev/null
+++ b/deps/netlink/include/netlink.hrl
@@ -0,0 +1,38 @@
+
+-ifndef(__NETLINK_HRL__).
+-define(__NETLINK_HRL__, true).
+
+
+-record(rtnl_link_stats, {
+ rx_packets, %% total packets received
+ tx_packets, %% total packets transmitted
+ rx_bytes, %% total bytes received
+ tx_bytes, %% total bytes transmitted
+ rx_errors, %% bad packets received
+ tx_errors, %% packet transmit problems
+ rx_dropped, %% no space in linux buffers
+ tx_dropped, %% no space available in linux
+ multicast, %% multicast packets received
+ collisions,
+
+ %% detailed rx_errors:
+ rx_length_errors,
+ rx_over_errors, %% receiver ring buff overflow
+ rx_crc_errors, %% recved pkt with crc error
+ rx_frame_errors, %% recv'd frame alignment error
+ rx_fifo_errors, %% recv'r fifo overrun
+ rx_missed_errors, %% receiver missed packet
+
+ %% detailed tx_errors
+ tx_aborted_errors,
+ tx_carrier_errors,
+ tx_fifo_errors,
+ tx_heartbeat_errors,
+ tx_window_errors,
+
+ %% for cslip etc
+ rx_compressed,
+ tx_compressed
+}).
+
+-endif.
diff --git a/deps/netlink/priv/.gitignore b/deps/netlink/priv/.gitignore
new file mode 100644
index 0000000..140f8cf
--- /dev/null
+++ b/deps/netlink/priv/.gitignore
@@ -0,0 +1 @@
+*.so
diff --git a/deps/netlink/rebar.config b/deps/netlink/rebar.config
new file mode 100644
index 0000000..64350f3
--- /dev/null
+++ b/deps/netlink/rebar.config
@@ -0,0 +1,12 @@
+%% -*- erlang -*-
+%% Config file for netlink-application
+{deps, [{lager, ".*", {git, "git://github.com/basho/lager.git", {tag,"3.0.2"}}}]}.
+{erl_opts, [debug_info, fail_on_warning]}.
+
+{port_env, [
+ {"CFLAGS", "$CFLAGS -DDLOG_DEFAULT=DLOG_INFO"}
+ ]}.
+
+{port_specs, [
+ {"(linux)","priv/netlink_drv.so",["c_src/*.c"]}
+ ]}.
diff --git a/deps/netlink/src/.gitignore b/deps/netlink/src/.gitignore
new file mode 100644
index 0000000..b25c15b
--- /dev/null
+++ b/deps/netlink/src/.gitignore
@@ -0,0 +1 @@
+*~
diff --git a/deps/netlink/src/netl_codec.erl b/deps/netlink/src/netl_codec.erl
new file mode 100644
index 0000000..25e4c89
--- /dev/null
+++ b/deps/netlink/src/netl_codec.erl
@@ -0,0 +1,2376 @@
+-module(netl_codec).
+-include("netl_codec.hrl").
+-export([dec_protocol/1, enc_protocol/1]).
+-export([dec_rtnetlink_rtm_protocol/1, enc_rtnetlink_rtm_protocol/1]).
+-export([dec_ctm_msgtype_netlink/1, enc_ctm_msgtype_netlink/1]).
+-export([dec_ctm_msgtype_ctnetlink/1, enc_ctm_msgtype_ctnetlink/1]).
+-export([dec_family/1, enc_family/1]).
+-export([dec_nlmsg_type/1, enc_nlmsg_type/1]).
+-export([dec_ctnetlink_protoinfo_tcp_state/1, enc_ctnetlink_protoinfo_tcp_state/1]).
+-export([dec_rtnetlink_rtm_type/1, enc_rtnetlink_rtm_type/1]).
+-export([dec_rtnetlink_rtm_scope/1, enc_rtnetlink_rtm_scope/1]).
+-export([dec_rtnetlink_rtm_table/1, enc_rtnetlink_rtm_table/1]).
+-export([dec_rtnetlink_link_operstate/1, enc_rtnetlink_link_operstate/1]).
+-export([dec_rtnetlink_link_linkmode/1, enc_rtnetlink_link_linkmode/1]).
+-export([dec_arphrd/1, enc_arphrd/1]).
+-export([dec_iff_flags/1, enc_iff_flags/1]).
+-export([dec_nlm_flags/1, enc_nlm_flags/1]).
+-export([dec_nlm_get_flags/1, enc_nlm_get_flags/1]).
+-export([dec_nlm_new_flags/1, enc_nlm_new_flags/1]).
+-export([dec_ctnetlink_status/1, enc_ctnetlink_status/1]).
+-export([dec_ctnetlink_exp_flags/1, enc_ctnetlink_exp_flags/1]).
+-export([dec_rtnetlink_rtm_flags/1, enc_rtnetlink_rtm_flags/1]).
+-export([dec_rtnetlink_link_protinfo_flags/1, enc_rtnetlink_link_protinfo_flags/1]).
+-export([dec_ifa_flags/1, enc_ifa_flags/1]).
+-export([dec_ctm_msgtype_ctnetlink_exp/1, enc_ctm_msgtype_ctnetlink_exp/1]).
+-export([dec_ctnetlink_tuple_proto/1, enc_ctnetlink_tuple_proto/1]).
+-export([dec_ctnetlink_protoinfo/1, enc_ctnetlink_protoinfo/1]).
+-export([dec_ctnetlink_exp_tuple_proto/1, enc_ctnetlink_exp_tuple_proto/1]).
+-export([dec_rtnetlink_link_linkinfo/1, enc_rtnetlink_link_linkinfo/1]).
+-export([dec_rtnetlink_link_protinfo/1, enc_rtnetlink_link_protinfo/1]).
+-export([dec_ctnetlink/1, enc_ctnetlink/1]).
+-export([dec_rtnetlink_link/1, enc_rtnetlink_link/1]).
+-export([dec_ctnetlink_nat_seq_adj/1, enc_ctnetlink_nat_seq_adj/1]).
+-export([dec_rtnetlink_neigh/1, enc_rtnetlink_neigh/1]).
+-export([dec_rtnetlink_prefix/1, enc_rtnetlink_prefix/1]).
+-export([dec_ctnetlink_tuple/1, enc_ctnetlink_tuple/1]).
+-export([dec_ctnetlink_exp_tuple/1, enc_ctnetlink_exp_tuple/1]).
+-export([dec_rtnetlink_route/1, enc_rtnetlink_route/1]).
+-export([dec_ctnetlink_counters/1, enc_ctnetlink_counters/1]).
+-export([dec_rtnetlink_route_metrics/1, enc_rtnetlink_route_metrics/1]).
+-export([dec_rtnetlink_addr/1, enc_rtnetlink_addr/1]).
+-export([dec_ctnetlink_tuple_ip/1, enc_ctnetlink_tuple_ip/1]).
+-export([dec_ctnetlink_protoinfo_tcp/1, enc_ctnetlink_protoinfo_tcp/1]).
+-export([dec_ctnetlink_help/1, enc_ctnetlink_help/1]).
+-export([dec_ctnetlink_timestamp/1, enc_ctnetlink_timestamp/1]).
+-export([dec_ctnetlink_exp_tuple_ip/1, enc_ctnetlink_exp_tuple_ip/1]).
+-export([dec_ctnetlink_exp/1, enc_ctnetlink_exp/1]).
+-export([dec_overrun/1, enc_overrun/1]).
+-export([dec_newlink/1, enc_newlink/1]).
+-export([dec_dellink/1, enc_dellink/1]).
+-export([dec_getlink/1, enc_getlink/1]).
+-export([dec_newneigh/1, enc_newneigh/1]).
+-export([dec_delneigh/1, enc_delneigh/1]).
+-export([dec_getneigh/1, enc_getneigh/1]).
+-export([dec_ifaddrmsg/1, enc_ifaddrmsg/1]).
+-export([dec_ifinfomsg/1, enc_ifinfomsg/1]).
+-export([dec_rtmsg/1, enc_rtmsg/1]).
+-export([dec_ndmsg/1, enc_ndmsg/1]).
+-export([dec_newroute/1, enc_newroute/1]).
+-export([dec_delroute/1, enc_delroute/1]).
+-export([dec_getroute/1, enc_getroute/1]).
+-export([dec_done/1, enc_done/1]).
+-export([dec_nlmsghdr/1, enc_nlmsghdr/1]).
+-export([dec_newaddr/1, enc_newaddr/1]).
+-export([dec_deladdr/1, enc_deladdr/1]).
+-export([dec_getaddr/1, enc_getaddr/1]).
+-export([dec_error/1, enc_error/1]).
+-export([dec_if_map/1, enc_if_map/1]).
+-export([dec_noop/1, enc_noop/1]).
+dec_protocol(0) -> ip;
+dec_protocol(1) -> icmp;
+dec_protocol(2) -> igmp;
+dec_protocol(4) -> ipip;
+dec_protocol(6) -> tcp;
+dec_protocol(8) -> egp;
+dec_protocol(12) -> pup;
+dec_protocol(17) -> udp;
+dec_protocol(22) -> idp;
+dec_protocol(29) -> tp;
+dec_protocol(33) -> dccp;
+dec_protocol(41) -> ipv6;
+dec_protocol(43) -> routing;
+dec_protocol(44) -> fragment;
+dec_protocol(46) -> rsvp;
+dec_protocol(47) -> gre;
+dec_protocol(50) -> esp;
+dec_protocol(51) -> ah;
+dec_protocol(58) -> icmpv6;
+dec_protocol(59) -> none;
+dec_protocol(60) -> dstopts;
+dec_protocol(92) -> mtp;
+dec_protocol(98) -> encap;
+dec_protocol(103) -> pim;
+dec_protocol(108) -> comp;
+dec_protocol(132) -> sctp;
+dec_protocol(136) -> udplite;
+dec_protocol(255) -> raw;
+dec_protocol(V) -> V.
+enc_protocol(ip) -> 0;
+enc_protocol(icmp) -> 1;
+enc_protocol(igmp) -> 2;
+enc_protocol(ipip) -> 4;
+enc_protocol(tcp) -> 6;
+enc_protocol(egp) -> 8;
+enc_protocol(pup) -> 12;
+enc_protocol(udp) -> 17;
+enc_protocol(idp) -> 22;
+enc_protocol(tp) -> 29;
+enc_protocol(dccp) -> 33;
+enc_protocol(ipv6) -> 41;
+enc_protocol(routing) -> 43;
+enc_protocol(fragment) -> 44;
+enc_protocol(rsvp) -> 46;
+enc_protocol(gre) -> 47;
+enc_protocol(esp) -> 50;
+enc_protocol(ah) -> 51;
+enc_protocol(icmpv6) -> 58;
+enc_protocol(none) -> 59;
+enc_protocol(dstopts) -> 60;
+enc_protocol(mtp) -> 92;
+enc_protocol(encap) -> 98;
+enc_protocol(pim) -> 103;
+enc_protocol(comp) -> 108;
+enc_protocol(sctp) -> 132;
+enc_protocol(udplite) -> 136;
+enc_protocol(raw) -> 255;
+enc_protocol(V) when is_integer(V) -> V;
+enc_protocol(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_rtm_protocol(0) -> unspec;
+dec_rtnetlink_rtm_protocol(1) -> redirect;
+dec_rtnetlink_rtm_protocol(2) -> kernel;
+dec_rtnetlink_rtm_protocol(3) -> boot;
+dec_rtnetlink_rtm_protocol(4) -> static;
+dec_rtnetlink_rtm_protocol(8) -> gated;
+dec_rtnetlink_rtm_protocol(9) -> ra;
+dec_rtnetlink_rtm_protocol(10) -> mrt;
+dec_rtnetlink_rtm_protocol(11) -> zebra;
+dec_rtnetlink_rtm_protocol(12) -> bird;
+dec_rtnetlink_rtm_protocol(13) -> dnrouted;
+dec_rtnetlink_rtm_protocol(14) -> xorp;
+dec_rtnetlink_rtm_protocol(15) -> ntk;
+dec_rtnetlink_rtm_protocol(16) -> dhcp;
+dec_rtnetlink_rtm_protocol(V) -> V.
+enc_rtnetlink_rtm_protocol(unspec) -> 0;
+enc_rtnetlink_rtm_protocol(redirect) -> 1;
+enc_rtnetlink_rtm_protocol(kernel) -> 2;
+enc_rtnetlink_rtm_protocol(boot) -> 3;
+enc_rtnetlink_rtm_protocol(static) -> 4;
+enc_rtnetlink_rtm_protocol(gated) -> 8;
+enc_rtnetlink_rtm_protocol(ra) -> 9;
+enc_rtnetlink_rtm_protocol(mrt) -> 10;
+enc_rtnetlink_rtm_protocol(zebra) -> 11;
+enc_rtnetlink_rtm_protocol(bird) -> 12;
+enc_rtnetlink_rtm_protocol(dnrouted) -> 13;
+enc_rtnetlink_rtm_protocol(xorp) -> 14;
+enc_rtnetlink_rtm_protocol(ntk) -> 15;
+enc_rtnetlink_rtm_protocol(dhcp) -> 16;
+enc_rtnetlink_rtm_protocol(V) when is_integer(V) -> V;
+enc_rtnetlink_rtm_protocol(E) -> erlang:error({undefined,E}).
+dec_ctm_msgtype_netlink(1) -> noop;
+dec_ctm_msgtype_netlink(2) -> error;
+dec_ctm_msgtype_netlink(3) -> done;
+dec_ctm_msgtype_netlink(4) -> overrun;
+dec_ctm_msgtype_netlink(V) -> V.
+enc_ctm_msgtype_netlink(noop) -> 1;
+enc_ctm_msgtype_netlink(error) -> 2;
+enc_ctm_msgtype_netlink(done) -> 3;
+enc_ctm_msgtype_netlink(overrun) -> 4;
+enc_ctm_msgtype_netlink(V) when is_integer(V) -> V;
+enc_ctm_msgtype_netlink(E) -> erlang:error({undefined,E}).
+dec_ctm_msgtype_ctnetlink(0) -> new;
+dec_ctm_msgtype_ctnetlink(1) -> get;
+dec_ctm_msgtype_ctnetlink(2) -> delete;
+dec_ctm_msgtype_ctnetlink(3) -> get_ctrzero;
+dec_ctm_msgtype_ctnetlink(V) -> V.
+enc_ctm_msgtype_ctnetlink(new) -> 0;
+enc_ctm_msgtype_ctnetlink(get) -> 1;
+enc_ctm_msgtype_ctnetlink(delete) -> 2;
+enc_ctm_msgtype_ctnetlink(get_ctrzero) -> 3;
+enc_ctm_msgtype_ctnetlink(V) when is_integer(V) -> V;
+enc_ctm_msgtype_ctnetlink(E) -> erlang:error({undefined,E}).
+dec_family(0) -> unspec;
+dec_family(1) -> local;
+dec_family(2) -> inet;
+dec_family(3) -> ax25;
+dec_family(4) -> ipx;
+dec_family(5) -> appletalk;
+dec_family(6) -> netrom;
+dec_family(7) -> bridge;
+dec_family(8) -> atmpvc;
+dec_family(9) -> x25;
+dec_family(10) -> inet6;
+dec_family(11) -> rose;
+dec_family(12) -> decnet;
+dec_family(13) -> netbeui;
+dec_family(14) -> security;
+dec_family(15) -> key;
+dec_family(16) -> netlink;
+dec_family(17) -> packet;
+dec_family(18) -> ash;
+dec_family(19) -> econet;
+dec_family(20) -> atmsvc;
+dec_family(21) -> rds;
+dec_family(22) -> sna;
+dec_family(23) -> irda;
+dec_family(24) -> pppox;
+dec_family(25) -> wanpipe;
+dec_family(26) -> llc;
+dec_family(29) -> can;
+dec_family(30) -> tipc;
+dec_family(31) -> bluetooth;
+dec_family(32) -> iucv;
+dec_family(33) -> rxrpc;
+dec_family(34) -> isdn;
+dec_family(35) -> phonet;
+dec_family(36) -> ieee802154;
+dec_family(V) -> V.
+enc_family(unspec) -> 0;
+enc_family(local) -> 1;
+enc_family(inet) -> 2;
+enc_family(ax25) -> 3;
+enc_family(ipx) -> 4;
+enc_family(appletalk) -> 5;
+enc_family(netrom) -> 6;
+enc_family(bridge) -> 7;
+enc_family(atmpvc) -> 8;
+enc_family(x25) -> 9;
+enc_family(inet6) -> 10;
+enc_family(rose) -> 11;
+enc_family(decnet) -> 12;
+enc_family(netbeui) -> 13;
+enc_family(security) -> 14;
+enc_family(key) -> 15;
+enc_family(netlink) -> 16;
+enc_family(packet) -> 17;
+enc_family(ash) -> 18;
+enc_family(econet) -> 19;
+enc_family(atmsvc) -> 20;
+enc_family(rds) -> 21;
+enc_family(sna) -> 22;
+enc_family(irda) -> 23;
+enc_family(pppox) -> 24;
+enc_family(wanpipe) -> 25;
+enc_family(llc) -> 26;
+enc_family(can) -> 29;
+enc_family(tipc) -> 30;
+enc_family(bluetooth) -> 31;
+enc_family(iucv) -> 32;
+enc_family(rxrpc) -> 33;
+enc_family(isdn) -> 34;
+enc_family(phonet) -> 35;
+enc_family(ieee802154) -> 36;
+enc_family(V) when is_integer(V) -> V;
+enc_family(E) -> erlang:error({undefined,E}).
+dec_nlmsg_type(1) -> noop;
+dec_nlmsg_type(2) -> error;
+dec_nlmsg_type(3) -> done;
+dec_nlmsg_type(4) -> overrun;
+dec_nlmsg_type(16) -> newlink;
+dec_nlmsg_type(17) -> dellink;
+dec_nlmsg_type(18) -> getlink;
+dec_nlmsg_type(19) -> setlink;
+dec_nlmsg_type(20) -> newaddr;
+dec_nlmsg_type(21) -> deladdr;
+dec_nlmsg_type(22) -> getaddr;
+dec_nlmsg_type(24) -> newroute;
+dec_nlmsg_type(25) -> delroute;
+dec_nlmsg_type(26) -> getroute;
+dec_nlmsg_type(28) -> newneigh;
+dec_nlmsg_type(29) -> delneigh;
+dec_nlmsg_type(30) -> getneigh;
+dec_nlmsg_type(32) -> newrule;
+dec_nlmsg_type(33) -> delrule;
+dec_nlmsg_type(34) -> getrule;
+dec_nlmsg_type(36) -> newqdisc;
+dec_nlmsg_type(37) -> delqdisc;
+dec_nlmsg_type(38) -> getqdisc;
+dec_nlmsg_type(40) -> newtclass;
+dec_nlmsg_type(41) -> deltclass;
+dec_nlmsg_type(42) -> gettclass;
+dec_nlmsg_type(44) -> newtfilter;
+dec_nlmsg_type(45) -> deltfilter;
+dec_nlmsg_type(46) -> gettfilter;
+dec_nlmsg_type(48) -> newaction;
+dec_nlmsg_type(49) -> delaction;
+dec_nlmsg_type(50) -> getaction;
+dec_nlmsg_type(52) -> newprefix;
+dec_nlmsg_type(58) -> getmulticast;
+dec_nlmsg_type(62) -> getanycast;
+dec_nlmsg_type(64) -> newneightbl;
+dec_nlmsg_type(66) -> getneightbl;
+dec_nlmsg_type(67) -> setneightbl;
+dec_nlmsg_type(68) -> newnduseropt;
+dec_nlmsg_type(72) -> newaddrlabel;
+dec_nlmsg_type(73) -> deladdrlabel;
+dec_nlmsg_type(74) -> getaddrlabel;
+dec_nlmsg_type(78) -> getdcb;
+dec_nlmsg_type(79) -> setdcb;
+dec_nlmsg_type(V) -> V.
+enc_nlmsg_type(noop) -> 1;
+enc_nlmsg_type(error) -> 2;
+enc_nlmsg_type(done) -> 3;
+enc_nlmsg_type(overrun) -> 4;
+enc_nlmsg_type(newlink) -> 16;
+enc_nlmsg_type(dellink) -> 17;
+enc_nlmsg_type(getlink) -> 18;
+enc_nlmsg_type(setlink) -> 19;
+enc_nlmsg_type(newaddr) -> 20;
+enc_nlmsg_type(deladdr) -> 21;
+enc_nlmsg_type(getaddr) -> 22;
+enc_nlmsg_type(newroute) -> 24;
+enc_nlmsg_type(delroute) -> 25;
+enc_nlmsg_type(getroute) -> 26;
+enc_nlmsg_type(newneigh) -> 28;
+enc_nlmsg_type(delneigh) -> 29;
+enc_nlmsg_type(getneigh) -> 30;
+enc_nlmsg_type(newrule) -> 32;
+enc_nlmsg_type(delrule) -> 33;
+enc_nlmsg_type(getrule) -> 34;
+enc_nlmsg_type(newqdisc) -> 36;
+enc_nlmsg_type(delqdisc) -> 37;
+enc_nlmsg_type(getqdisc) -> 38;
+enc_nlmsg_type(newtclass) -> 40;
+enc_nlmsg_type(deltclass) -> 41;
+enc_nlmsg_type(gettclass) -> 42;
+enc_nlmsg_type(newtfilter) -> 44;
+enc_nlmsg_type(deltfilter) -> 45;
+enc_nlmsg_type(gettfilter) -> 46;
+enc_nlmsg_type(newaction) -> 48;
+enc_nlmsg_type(delaction) -> 49;
+enc_nlmsg_type(getaction) -> 50;
+enc_nlmsg_type(newprefix) -> 52;
+enc_nlmsg_type(getmulticast) -> 58;
+enc_nlmsg_type(getanycast) -> 62;
+enc_nlmsg_type(newneightbl) -> 64;
+enc_nlmsg_type(getneightbl) -> 66;
+enc_nlmsg_type(setneightbl) -> 67;
+enc_nlmsg_type(newnduseropt) -> 68;
+enc_nlmsg_type(newaddrlabel) -> 72;
+enc_nlmsg_type(deladdrlabel) -> 73;
+enc_nlmsg_type(getaddrlabel) -> 74;
+enc_nlmsg_type(getdcb) -> 78;
+enc_nlmsg_type(setdcb) -> 79;
+enc_nlmsg_type(V) when is_integer(V) -> V;
+enc_nlmsg_type(E) -> erlang:error({undefined,E}).
+dec_ctnetlink_protoinfo_tcp_state(0) -> none;
+dec_ctnetlink_protoinfo_tcp_state(1) -> syn_sent;
+dec_ctnetlink_protoinfo_tcp_state(2) -> syn_recv;
+dec_ctnetlink_protoinfo_tcp_state(3) -> established;
+dec_ctnetlink_protoinfo_tcp_state(4) -> fin_wait;
+dec_ctnetlink_protoinfo_tcp_state(5) -> close_wait;
+dec_ctnetlink_protoinfo_tcp_state(6) -> last_ack;
+dec_ctnetlink_protoinfo_tcp_state(7) -> time_wait;
+dec_ctnetlink_protoinfo_tcp_state(8) -> close;
+dec_ctnetlink_protoinfo_tcp_state(9) -> listen;
+dec_ctnetlink_protoinfo_tcp_state(10) -> max;
+dec_ctnetlink_protoinfo_tcp_state(11) -> ignore;
+dec_ctnetlink_protoinfo_tcp_state(V) -> V.
+enc_ctnetlink_protoinfo_tcp_state(none) -> 0;
+enc_ctnetlink_protoinfo_tcp_state(syn_sent) -> 1;
+enc_ctnetlink_protoinfo_tcp_state(syn_recv) -> 2;
+enc_ctnetlink_protoinfo_tcp_state(established) -> 3;
+enc_ctnetlink_protoinfo_tcp_state(fin_wait) -> 4;
+enc_ctnetlink_protoinfo_tcp_state(close_wait) -> 5;
+enc_ctnetlink_protoinfo_tcp_state(last_ack) -> 6;
+enc_ctnetlink_protoinfo_tcp_state(time_wait) -> 7;
+enc_ctnetlink_protoinfo_tcp_state(close) -> 8;
+enc_ctnetlink_protoinfo_tcp_state(listen) -> 9;
+enc_ctnetlink_protoinfo_tcp_state(max) -> 10;
+enc_ctnetlink_protoinfo_tcp_state(ignore) -> 11;
+enc_ctnetlink_protoinfo_tcp_state(V) when is_integer(V) -> V;
+enc_ctnetlink_protoinfo_tcp_state(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_rtm_type(0) -> unspec;
+dec_rtnetlink_rtm_type(1) -> unicast;
+dec_rtnetlink_rtm_type(2) -> local;
+dec_rtnetlink_rtm_type(3) -> broadcast;
+dec_rtnetlink_rtm_type(4) -> anycast;
+dec_rtnetlink_rtm_type(5) -> multicast;
+dec_rtnetlink_rtm_type(6) -> blackhole;
+dec_rtnetlink_rtm_type(7) -> unreachable;
+dec_rtnetlink_rtm_type(8) -> prohibit;
+dec_rtnetlink_rtm_type(9) -> throw;
+dec_rtnetlink_rtm_type(10) -> nat;
+dec_rtnetlink_rtm_type(11) -> xresolve;
+dec_rtnetlink_rtm_type(V) -> V.
+enc_rtnetlink_rtm_type(unspec) -> 0;
+enc_rtnetlink_rtm_type(unicast) -> 1;
+enc_rtnetlink_rtm_type(local) -> 2;
+enc_rtnetlink_rtm_type(broadcast) -> 3;
+enc_rtnetlink_rtm_type(anycast) -> 4;
+enc_rtnetlink_rtm_type(multicast) -> 5;
+enc_rtnetlink_rtm_type(blackhole) -> 6;
+enc_rtnetlink_rtm_type(unreachable) -> 7;
+enc_rtnetlink_rtm_type(prohibit) -> 8;
+enc_rtnetlink_rtm_type(throw) -> 9;
+enc_rtnetlink_rtm_type(nat) -> 10;
+enc_rtnetlink_rtm_type(xresolve) -> 11;
+enc_rtnetlink_rtm_type(V) when is_integer(V) -> V;
+enc_rtnetlink_rtm_type(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_rtm_scope(0) -> universe;
+dec_rtnetlink_rtm_scope(200) -> site;
+dec_rtnetlink_rtm_scope(253) -> link;
+dec_rtnetlink_rtm_scope(254) -> host;
+dec_rtnetlink_rtm_scope(255) -> nowhere;
+dec_rtnetlink_rtm_scope(V) -> V.
+enc_rtnetlink_rtm_scope(universe) -> 0;
+enc_rtnetlink_rtm_scope(site) -> 200;
+enc_rtnetlink_rtm_scope(link) -> 253;
+enc_rtnetlink_rtm_scope(host) -> 254;
+enc_rtnetlink_rtm_scope(nowhere) -> 255;
+enc_rtnetlink_rtm_scope(V) when is_integer(V) -> V;
+enc_rtnetlink_rtm_scope(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_rtm_table(0) -> unspec;
+dec_rtnetlink_rtm_table(252) -> compat;
+dec_rtnetlink_rtm_table(253) -> default;
+dec_rtnetlink_rtm_table(254) -> main;
+dec_rtnetlink_rtm_table(255) -> local;
+dec_rtnetlink_rtm_table(V) -> V.
+enc_rtnetlink_rtm_table(unspec) -> 0;
+enc_rtnetlink_rtm_table(compat) -> 252;
+enc_rtnetlink_rtm_table(default) -> 253;
+enc_rtnetlink_rtm_table(main) -> 254;
+enc_rtnetlink_rtm_table(local) -> 255;
+enc_rtnetlink_rtm_table(V) when is_integer(V) -> V;
+enc_rtnetlink_rtm_table(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_link_operstate(0) -> unknown;
+dec_rtnetlink_link_operstate(1) -> notpresent;
+dec_rtnetlink_link_operstate(2) -> down;
+dec_rtnetlink_link_operstate(3) -> lowerlayerdown;
+dec_rtnetlink_link_operstate(4) -> testing;
+dec_rtnetlink_link_operstate(5) -> dormant;
+dec_rtnetlink_link_operstate(6) -> up;
+dec_rtnetlink_link_operstate(V) -> V.
+enc_rtnetlink_link_operstate(unknown) -> 0;
+enc_rtnetlink_link_operstate(notpresent) -> 1;
+enc_rtnetlink_link_operstate(down) -> 2;
+enc_rtnetlink_link_operstate(lowerlayerdown) -> 3;
+enc_rtnetlink_link_operstate(testing) -> 4;
+enc_rtnetlink_link_operstate(dormant) -> 5;
+enc_rtnetlink_link_operstate(up) -> 6;
+enc_rtnetlink_link_operstate(V) when is_integer(V) -> V;
+enc_rtnetlink_link_operstate(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_link_linkmode(0) -> default;
+dec_rtnetlink_link_linkmode(1) -> dormant;
+dec_rtnetlink_link_linkmode(V) -> V.
+enc_rtnetlink_link_linkmode(default) -> 0;
+enc_rtnetlink_link_linkmode(dormant) -> 1;
+enc_rtnetlink_link_linkmode(V) when is_integer(V) -> V;
+enc_rtnetlink_link_linkmode(E) -> erlang:error({undefined,E}).
+dec_arphrd(0) -> netrom;
+dec_arphrd(1) -> ether;
+dec_arphrd(2) -> eether;
+dec_arphrd(3) -> ax25;
+dec_arphrd(4) -> pronet;
+dec_arphrd(5) -> chaos;
+dec_arphrd(6) -> ieee802;
+dec_arphrd(7) -> arcnet;
+dec_arphrd(8) -> appletlk;
+dec_arphrd(15) -> dlci;
+dec_arphrd(19) -> atm;
+dec_arphrd(23) -> metricom;
+dec_arphrd(24) -> ieee1394;
+dec_arphrd(27) -> eui64;
+dec_arphrd(32) -> infiniband;
+dec_arphrd(256) -> slip;
+dec_arphrd(257) -> cslip;
+dec_arphrd(258) -> slip6;
+dec_arphrd(259) -> cslip6;
+dec_arphrd(260) -> rsrvd;
+dec_arphrd(264) -> adapt;
+dec_arphrd(270) -> rose;
+dec_arphrd(271) -> x25;
+dec_arphrd(272) -> hwx25;
+dec_arphrd(280) -> can;
+dec_arphrd(512) -> ppp;
+dec_arphrd(513) -> hdlc;
+dec_arphrd(516) -> lapb;
+dec_arphrd(517) -> ddcmp;
+dec_arphrd(518) -> rawhdlc;
+dec_arphrd(768) -> tunnel;
+dec_arphrd(769) -> tunnel6;
+dec_arphrd(770) -> frad;
+dec_arphrd(771) -> skip;
+dec_arphrd(772) -> loopback;
+dec_arphrd(773) -> localtlk;
+dec_arphrd(774) -> fddi;
+dec_arphrd(775) -> bif;
+dec_arphrd(776) -> sit;
+dec_arphrd(777) -> ipddp;
+dec_arphrd(778) -> ipgre;
+dec_arphrd(779) -> pimreg;
+dec_arphrd(780) -> hippi;
+dec_arphrd(781) -> ash;
+dec_arphrd(782) -> econet;
+dec_arphrd(783) -> irda;
+dec_arphrd(784) -> fcpp;
+dec_arphrd(785) -> fcal;
+dec_arphrd(786) -> fcpl;
+dec_arphrd(787) -> fcfabric;
+dec_arphrd(800) -> ieee802_tr;
+dec_arphrd(801) -> ieee80211;
+dec_arphrd(802) -> ieee80211_prism;
+dec_arphrd(803) -> ieee80211_radiotap;
+dec_arphrd(804) -> ieee802154;
+dec_arphrd(820) -> phonet;
+dec_arphrd(821) -> phonet_pipe;
+dec_arphrd(822) -> caif;
+dec_arphrd(65535) -> void;
+dec_arphrd(65534) -> none;
+dec_arphrd(V) -> V.
+enc_arphrd(netrom) -> 0;
+enc_arphrd(ether) -> 1;
+enc_arphrd(eether) -> 2;
+enc_arphrd(ax25) -> 3;
+enc_arphrd(pronet) -> 4;
+enc_arphrd(chaos) -> 5;
+enc_arphrd(ieee802) -> 6;
+enc_arphrd(arcnet) -> 7;
+enc_arphrd(appletlk) -> 8;
+enc_arphrd(dlci) -> 15;
+enc_arphrd(atm) -> 19;
+enc_arphrd(metricom) -> 23;
+enc_arphrd(ieee1394) -> 24;
+enc_arphrd(eui64) -> 27;
+enc_arphrd(infiniband) -> 32;
+enc_arphrd(slip) -> 256;
+enc_arphrd(cslip) -> 257;
+enc_arphrd(slip6) -> 258;
+enc_arphrd(cslip6) -> 259;
+enc_arphrd(rsrvd) -> 260;
+enc_arphrd(adapt) -> 264;
+enc_arphrd(rose) -> 270;
+enc_arphrd(x25) -> 271;
+enc_arphrd(hwx25) -> 272;
+enc_arphrd(can) -> 280;
+enc_arphrd(ppp) -> 512;
+enc_arphrd(hdlc) -> 513;
+enc_arphrd(lapb) -> 516;
+enc_arphrd(ddcmp) -> 517;
+enc_arphrd(rawhdlc) -> 518;
+enc_arphrd(tunnel) -> 768;
+enc_arphrd(tunnel6) -> 769;
+enc_arphrd(frad) -> 770;
+enc_arphrd(skip) -> 771;
+enc_arphrd(loopback) -> 772;
+enc_arphrd(localtlk) -> 773;
+enc_arphrd(fddi) -> 774;
+enc_arphrd(bif) -> 775;
+enc_arphrd(sit) -> 776;
+enc_arphrd(ipddp) -> 777;
+enc_arphrd(ipgre) -> 778;
+enc_arphrd(pimreg) -> 779;
+enc_arphrd(hippi) -> 780;
+enc_arphrd(ash) -> 781;
+enc_arphrd(econet) -> 782;
+enc_arphrd(irda) -> 783;
+enc_arphrd(fcpp) -> 784;
+enc_arphrd(fcal) -> 785;
+enc_arphrd(fcpl) -> 786;
+enc_arphrd(fcfabric) -> 787;
+enc_arphrd(ieee802_tr) -> 800;
+enc_arphrd(ieee80211) -> 801;
+enc_arphrd(ieee80211_prism) -> 802;
+enc_arphrd(ieee80211_radiotap) -> 803;
+enc_arphrd(ieee802154) -> 804;
+enc_arphrd(phonet) -> 820;
+enc_arphrd(phonet_pipe) -> 821;
+enc_arphrd(caif) -> 822;
+enc_arphrd(void) -> 65535;
+enc_arphrd(none) -> 65534;
+enc_arphrd(V) when is_integer(V) -> V;
+enc_arphrd(E) -> erlang:error({undefined,E}).
+dec_iff_flags(0) -> up;
+dec_iff_flags(1) -> broadcast;
+dec_iff_flags(2) -> debug;
+dec_iff_flags(3) -> loopback;
+dec_iff_flags(4) -> pointopoint;
+dec_iff_flags(5) -> notrailers;
+dec_iff_flags(6) -> running;
+dec_iff_flags(7) -> noarp;
+dec_iff_flags(8) -> promisc;
+dec_iff_flags(9) -> allmulti;
+dec_iff_flags(10) -> master;
+dec_iff_flags(11) -> slave;
+dec_iff_flags(12) -> multicast;
+dec_iff_flags(13) -> portsel;
+dec_iff_flags(14) -> automedia;
+dec_iff_flags(15) -> ynamic;
+dec_iff_flags(16) -> lower_up;
+dec_iff_flags(17) -> dormant;
+dec_iff_flags(18) -> echo;
+dec_iff_flags(V) -> V.
+enc_iff_flags(up) -> 0;
+enc_iff_flags(broadcast) -> 1;
+enc_iff_flags(debug) -> 2;
+enc_iff_flags(loopback) -> 3;
+enc_iff_flags(pointopoint) -> 4;
+enc_iff_flags(notrailers) -> 5;
+enc_iff_flags(running) -> 6;
+enc_iff_flags(noarp) -> 7;
+enc_iff_flags(promisc) -> 8;
+enc_iff_flags(allmulti) -> 9;
+enc_iff_flags(master) -> 10;
+enc_iff_flags(slave) -> 11;
+enc_iff_flags(multicast) -> 12;
+enc_iff_flags(portsel) -> 13;
+enc_iff_flags(automedia) -> 14;
+enc_iff_flags(ynamic) -> 15;
+enc_iff_flags(lower_up) -> 16;
+enc_iff_flags(dormant) -> 17;
+enc_iff_flags(echo) -> 18;
+enc_iff_flags(V) when is_integer(V) -> V;
+enc_iff_flags(E) -> erlang:error({undefined,E}).
+dec_nlm_flags(0) -> request;
+dec_nlm_flags(1) -> multi;
+dec_nlm_flags(2) -> ack;
+dec_nlm_flags(3) -> echo;
+dec_nlm_flags(V) -> V.
+enc_nlm_flags(request) -> 0;
+enc_nlm_flags(multi) -> 1;
+enc_nlm_flags(ack) -> 2;
+enc_nlm_flags(echo) -> 3;
+enc_nlm_flags(V) when is_integer(V) -> V;
+enc_nlm_flags(E) -> erlang:error({undefined,E}).
+dec_nlm_get_flags(0) -> request;
+dec_nlm_get_flags(1) -> multi;
+dec_nlm_get_flags(2) -> ack;
+dec_nlm_get_flags(3) -> echo;
+dec_nlm_get_flags(8) -> root;
+dec_nlm_get_flags(9) -> match;
+dec_nlm_get_flags(10) -> atomic;
+dec_nlm_get_flags(V) -> V.
+enc_nlm_get_flags(request) -> 0;
+enc_nlm_get_flags(multi) -> 1;
+enc_nlm_get_flags(ack) -> 2;
+enc_nlm_get_flags(echo) -> 3;
+enc_nlm_get_flags(root) -> 8;
+enc_nlm_get_flags(match) -> 9;
+enc_nlm_get_flags(atomic) -> 10;
+enc_nlm_get_flags(V) when is_integer(V) -> V;
+enc_nlm_get_flags(E) -> erlang:error({undefined,E}).
+dec_nlm_new_flags(0) -> request;
+dec_nlm_new_flags(1) -> multi;
+dec_nlm_new_flags(2) -> ack;
+dec_nlm_new_flags(3) -> echo;
+dec_nlm_new_flags(8) -> replace;
+dec_nlm_new_flags(9) -> excl;
+dec_nlm_new_flags(10) -> create;
+dec_nlm_new_flags(11) -> append;
+dec_nlm_new_flags(V) -> V.
+enc_nlm_new_flags(request) -> 0;
+enc_nlm_new_flags(multi) -> 1;
+enc_nlm_new_flags(ack) -> 2;
+enc_nlm_new_flags(echo) -> 3;
+enc_nlm_new_flags(replace) -> 8;
+enc_nlm_new_flags(excl) -> 9;
+enc_nlm_new_flags(create) -> 10;
+enc_nlm_new_flags(append) -> 11;
+enc_nlm_new_flags(V) when is_integer(V) -> V;
+enc_nlm_new_flags(E) -> erlang:error({undefined,E}).
+dec_ctnetlink_status(0) -> expected;
+dec_ctnetlink_status(1) -> seen_reply;
+dec_ctnetlink_status(2) -> assured;
+dec_ctnetlink_status(3) -> confirmed;
+dec_ctnetlink_status(4) -> src_nat;
+dec_ctnetlink_status(5) -> dst_nat;
+dec_ctnetlink_status(6) -> seq_adjust;
+dec_ctnetlink_status(7) -> src_nat_done;
+dec_ctnetlink_status(8) -> dst_nat_done;
+dec_ctnetlink_status(9) -> dying;
+dec_ctnetlink_status(10) -> fixed_timeout;
+dec_ctnetlink_status(V) -> V.
+enc_ctnetlink_status(expected) -> 0;
+enc_ctnetlink_status(seen_reply) -> 1;
+enc_ctnetlink_status(assured) -> 2;
+enc_ctnetlink_status(confirmed) -> 3;
+enc_ctnetlink_status(src_nat) -> 4;
+enc_ctnetlink_status(dst_nat) -> 5;
+enc_ctnetlink_status(seq_adjust) -> 6;
+enc_ctnetlink_status(src_nat_done) -> 7;
+enc_ctnetlink_status(dst_nat_done) -> 8;
+enc_ctnetlink_status(dying) -> 9;
+enc_ctnetlink_status(fixed_timeout) -> 10;
+enc_ctnetlink_status(V) when is_integer(V) -> V;
+enc_ctnetlink_status(E) -> erlang:error({undefined,E}).
+dec_ctnetlink_exp_flags(0) -> permanent;
+dec_ctnetlink_exp_flags(1) -> inactive;
+dec_ctnetlink_exp_flags(2) -> userspace;
+dec_ctnetlink_exp_flags(V) -> V.
+enc_ctnetlink_exp_flags(permanent) -> 0;
+enc_ctnetlink_exp_flags(inactive) -> 1;
+enc_ctnetlink_exp_flags(userspace) -> 2;
+enc_ctnetlink_exp_flags(V) when is_integer(V) -> V;
+enc_ctnetlink_exp_flags(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_rtm_flags(256) -> notify;
+dec_rtnetlink_rtm_flags(512) -> cloned;
+dec_rtnetlink_rtm_flags(1024) -> equalize;
+dec_rtnetlink_rtm_flags(2048) -> prefix;
+dec_rtnetlink_rtm_flags(V) -> V.
+enc_rtnetlink_rtm_flags(notify) -> 256;
+enc_rtnetlink_rtm_flags(cloned) -> 512;
+enc_rtnetlink_rtm_flags(equalize) -> 1024;
+enc_rtnetlink_rtm_flags(prefix) -> 2048;
+enc_rtnetlink_rtm_flags(V) when is_integer(V) -> V;
+enc_rtnetlink_rtm_flags(E) -> erlang:error({undefined,E}).
+dec_rtnetlink_link_protinfo_flags(4) -> rs_sent;
+dec_rtnetlink_link_protinfo_flags(5) -> ra_rcvd;
+dec_rtnetlink_link_protinfo_flags(6) -> ra_managed;
+dec_rtnetlink_link_protinfo_flags(7) -> ra_othercon;
+dec_rtnetlink_link_protinfo_flags(31) -> ready;
+dec_rtnetlink_link_protinfo_flags(V) -> V.
+enc_rtnetlink_link_protinfo_flags(rs_sent) -> 4;
+enc_rtnetlink_link_protinfo_flags(ra_rcvd) -> 5;
+enc_rtnetlink_link_protinfo_flags(ra_managed) -> 6;
+enc_rtnetlink_link_protinfo_flags(ra_othercon) -> 7;
+enc_rtnetlink_link_protinfo_flags(ready) -> 31;
+enc_rtnetlink_link_protinfo_flags(V) when is_integer(V) -> V;
+enc_rtnetlink_link_protinfo_flags(E) -> erlang:error({undefined,E}).
+dec_ifa_flags(0) -> secondary;
+dec_ifa_flags(1) -> nodad;
+dec_ifa_flags(2) -> optimistic;
+dec_ifa_flags(3) -> dadfailed;
+dec_ifa_flags(4) -> homeaddress;
+dec_ifa_flags(5) -> deprecated;
+dec_ifa_flags(6) -> tentative;
+dec_ifa_flags(7) -> permanent;
+dec_ifa_flags(V) -> V.
+enc_ifa_flags(secondary) -> 0;
+enc_ifa_flags(nodad) -> 1;
+enc_ifa_flags(optimistic) -> 2;
+enc_ifa_flags(dadfailed) -> 3;
+enc_ifa_flags(homeaddress) -> 4;
+enc_ifa_flags(deprecated) -> 5;
+enc_ifa_flags(tentative) -> 6;
+enc_ifa_flags(permanent) -> 7;
+enc_ifa_flags(V) when is_integer(V) -> V;
+enc_ifa_flags(E) -> erlang:error({undefined,E}).
+dec_ctm_msgtype_ctnetlink_exp(0) -> new;
+dec_ctm_msgtype_ctnetlink_exp(1) -> get;
+dec_ctm_msgtype_ctnetlink_exp(2) -> delete;
+dec_ctm_msgtype_ctnetlink_exp(V) -> V.
+enc_ctm_msgtype_ctnetlink_exp(new) -> 0;
+enc_ctm_msgtype_ctnetlink_exp(get) -> 1;
+enc_ctm_msgtype_ctnetlink_exp(delete) -> 2;
+enc_ctm_msgtype_ctnetlink_exp(V) when is_integer(V) -> V;
+enc_ctm_msgtype_ctnetlink_exp(E) -> erlang:error({undefined,E}).
+dec_ctnetlink_tuple_proto({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple_proto({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple_proto({1,native,<<Xe:8/unsigned-native>>}) ->
+ {num,dec_protocol(Xe)};
+dec_ctnetlink_tuple_proto({1,big,<<Xe:8/unsigned-big>>}) ->
+ {num,dec_protocol(Xe)};
+dec_ctnetlink_tuple_proto({2,native,<<X:16/unsigned-native>>}) ->
+ {src_port,X};
+dec_ctnetlink_tuple_proto({2,big,<<X:16/unsigned-big>>}) ->
+ {src_port,X};
+dec_ctnetlink_tuple_proto({3,native,<<X:16/unsigned-native>>}) ->
+ {dst_port,X};
+dec_ctnetlink_tuple_proto({3,big,<<X:16/unsigned-big>>}) ->
+ {dst_port,X};
+dec_ctnetlink_tuple_proto({4,native,<<X:16/unsigned-native>>}) ->
+ {icmp_id,X};
+dec_ctnetlink_tuple_proto({4,big,<<X:16/unsigned-big>>}) ->
+ {icmp_id,X};
+dec_ctnetlink_tuple_proto({5,native,<<X:8/unsigned-native>>}) ->
+ {icmp_type,X};
+dec_ctnetlink_tuple_proto({5,big,<<X:8/unsigned-big>>}) ->
+ {icmp_type,X};
+dec_ctnetlink_tuple_proto({6,native,<<X:8/unsigned-native>>}) ->
+ {icmp_code,X};
+dec_ctnetlink_tuple_proto({6,big,<<X:8/unsigned-big>>}) ->
+ {icmp_code,X};
+dec_ctnetlink_tuple_proto({7,native,<<X/binary>>}) ->
+ {icmpv6_id,X};
+dec_ctnetlink_tuple_proto({7,big,<<X/binary>>}) ->
+ {icmpv6_id,X};
+dec_ctnetlink_tuple_proto({8,native,<<X/binary>>}) ->
+ {icmpv6_type,X};
+dec_ctnetlink_tuple_proto({8,big,<<X/binary>>}) ->
+ {icmpv6_type,X};
+dec_ctnetlink_tuple_proto({9,native,<<X/binary>>}) ->
+ {icmpv6_code,X};
+dec_ctnetlink_tuple_proto({9,big,<<X/binary>>}) ->
+ {icmpv6_code,X};
+dec_ctnetlink_tuple_proto({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_tuple_proto({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_tuple_proto({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_tuple_proto({num,native,X}) ->
+ {1,native,<<(enc_protocol(X)):8/unsigned-native>>};
+enc_ctnetlink_tuple_proto({num,big,X}) ->
+ {1,big,<<(enc_protocol(X)):8/unsigned-big>>};
+enc_ctnetlink_tuple_proto({src_port,native,X}) ->
+ {2,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_tuple_proto({src_port,big,X}) ->
+ {2,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_tuple_proto({dst_port,native,X}) ->
+ {3,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_tuple_proto({dst_port,big,X}) ->
+ {3,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_tuple_proto({icmp_id,native,X}) ->
+ {4,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_tuple_proto({icmp_id,big,X}) ->
+ {4,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_tuple_proto({icmp_type,native,X}) ->
+ {5,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_tuple_proto({icmp_type,big,X}) ->
+ {5,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_tuple_proto({icmp_code,native,X}) ->
+ {6,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_tuple_proto({icmp_code,big,X}) ->
+ {6,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_tuple_proto({icmpv6_id,native,X}) ->
+ {7,native,<<X>>};
+enc_ctnetlink_tuple_proto({icmpv6_id,big,X}) ->
+ {7,big,<<X>>};
+enc_ctnetlink_tuple_proto({icmpv6_type,native,X}) ->
+ {8,native,<<X>>};
+enc_ctnetlink_tuple_proto({icmpv6_type,big,X}) ->
+ {8,big,<<X>>};
+enc_ctnetlink_tuple_proto({icmpv6_code,native,X}) ->
+ {9,native,<<X>>};
+enc_ctnetlink_tuple_proto({icmpv6_code,big,X}) ->
+ {9,big,<<X>>};
+enc_ctnetlink_tuple_proto({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_protoinfo({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_protoinfo({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_protoinfo({1,native,<<X/binary>>}) ->
+ {tcp,dec_ctnetlink_protoinfo_tcp(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_protoinfo({1,big,<<X/binary>>}) ->
+ {tcp,dec_ctnetlink_protoinfo_tcp(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_protoinfo({2,native,<<X/binary>>}) ->
+ {dccp,X};
+dec_ctnetlink_protoinfo({2,big,<<X/binary>>}) ->
+ {dccp,X};
+dec_ctnetlink_protoinfo({3,native,<<X/binary>>}) ->
+ {sctp,X};
+dec_ctnetlink_protoinfo({3,big,<<X/binary>>}) ->
+ {sctp,X};
+dec_ctnetlink_protoinfo({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_protoinfo({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_protoinfo({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_protoinfo({tcp,native,X}) ->
+ {1,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_protoinfo_tcp(X)))>>};
+enc_ctnetlink_protoinfo({tcp,big,X}) ->
+ {1,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_protoinfo_tcp(X)))>>};
+enc_ctnetlink_protoinfo({dccp,native,X}) ->
+ {2,native,<<X>>};
+enc_ctnetlink_protoinfo({dccp,big,X}) ->
+ {2,big,<<X>>};
+enc_ctnetlink_protoinfo({sctp,native,X}) ->
+ {3,native,<<X>>};
+enc_ctnetlink_protoinfo({sctp,big,X}) ->
+ {3,big,<<X>>};
+enc_ctnetlink_protoinfo({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_exp_tuple_proto({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple_proto({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple_proto({1,native,<<Xe:8/unsigned-native>>}) ->
+ {num,dec_protocol(Xe)};
+dec_ctnetlink_exp_tuple_proto({1,big,<<Xe:8/unsigned-big>>}) ->
+ {num,dec_protocol(Xe)};
+dec_ctnetlink_exp_tuple_proto({2,native,<<X:16/unsigned-native>>}) ->
+ {src_port,X};
+dec_ctnetlink_exp_tuple_proto({2,big,<<X:16/unsigned-big>>}) ->
+ {src_port,X};
+dec_ctnetlink_exp_tuple_proto({3,native,<<X:16/unsigned-native>>}) ->
+ {dst_port,X};
+dec_ctnetlink_exp_tuple_proto({3,big,<<X:16/unsigned-big>>}) ->
+ {dst_port,X};
+dec_ctnetlink_exp_tuple_proto({4,native,<<X:16/unsigned-native>>}) ->
+ {icmp_id,X};
+dec_ctnetlink_exp_tuple_proto({4,big,<<X:16/unsigned-big>>}) ->
+ {icmp_id,X};
+dec_ctnetlink_exp_tuple_proto({5,native,<<X:8/unsigned-native>>}) ->
+ {icmp_type,X};
+dec_ctnetlink_exp_tuple_proto({5,big,<<X:8/unsigned-big>>}) ->
+ {icmp_type,X};
+dec_ctnetlink_exp_tuple_proto({6,native,<<X:8/unsigned-native>>}) ->
+ {icmp_code,X};
+dec_ctnetlink_exp_tuple_proto({6,big,<<X:8/unsigned-big>>}) ->
+ {icmp_code,X};
+dec_ctnetlink_exp_tuple_proto({7,native,<<X/binary>>}) ->
+ {icmpv6_id,X};
+dec_ctnetlink_exp_tuple_proto({7,big,<<X/binary>>}) ->
+ {icmpv6_id,X};
+dec_ctnetlink_exp_tuple_proto({8,native,<<X/binary>>}) ->
+ {icmpv6_type,X};
+dec_ctnetlink_exp_tuple_proto({8,big,<<X/binary>>}) ->
+ {icmpv6_type,X};
+dec_ctnetlink_exp_tuple_proto({9,native,<<X/binary>>}) ->
+ {icmpv6_code,X};
+dec_ctnetlink_exp_tuple_proto({9,big,<<X/binary>>}) ->
+ {icmpv6_code,X};
+dec_ctnetlink_exp_tuple_proto({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_exp_tuple_proto({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_exp_tuple_proto({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_exp_tuple_proto({num,native,X}) ->
+ {1,native,<<(enc_protocol(X)):8/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({num,big,X}) ->
+ {1,big,<<(enc_protocol(X)):8/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({src_port,native,X}) ->
+ {2,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({src_port,big,X}) ->
+ {2,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({dst_port,native,X}) ->
+ {3,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({dst_port,big,X}) ->
+ {3,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({icmp_id,native,X}) ->
+ {4,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({icmp_id,big,X}) ->
+ {4,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({icmp_type,native,X}) ->
+ {5,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({icmp_type,big,X}) ->
+ {5,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({icmp_code,native,X}) ->
+ {6,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_exp_tuple_proto({icmp_code,big,X}) ->
+ {6,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_id,native,X}) ->
+ {7,native,<<X>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_id,big,X}) ->
+ {7,big,<<X>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_type,native,X}) ->
+ {8,native,<<X>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_type,big,X}) ->
+ {8,big,<<X>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_code,native,X}) ->
+ {9,native,<<X>>};
+enc_ctnetlink_exp_tuple_proto({icmpv6_code,big,X}) ->
+ {9,big,<<X>>};
+enc_ctnetlink_exp_tuple_proto({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_link_linkinfo({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link_linkinfo({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link_linkinfo({1,native,<<X/binary>>}) ->
+ {kind,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link_linkinfo({1,big,<<X/binary>>}) ->
+ {kind,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link_linkinfo({2,native,<<X/binary>>}) ->
+ {data,X};
+dec_rtnetlink_link_linkinfo({2,big,<<X/binary>>}) ->
+ {data,X};
+dec_rtnetlink_link_linkinfo({3,native,<<X/binary>>}) ->
+ {xstats,X};
+dec_rtnetlink_link_linkinfo({3,big,<<X/binary>>}) ->
+ {xstats,X};
+dec_rtnetlink_link_linkinfo({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_link_linkinfo({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_link_linkinfo({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_link_linkinfo({kind,native,X}) ->
+ {1,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link_linkinfo({kind,big,X}) ->
+ {1,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link_linkinfo({data,native,X}) ->
+ {2,native,<<X>>};
+enc_rtnetlink_link_linkinfo({data,big,X}) ->
+ {2,big,<<X>>};
+enc_rtnetlink_link_linkinfo({xstats,native,X}) ->
+ {3,native,<<X>>};
+enc_rtnetlink_link_linkinfo({xstats,big,X}) ->
+ {3,big,<<X>>};
+enc_rtnetlink_link_linkinfo({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_link_protinfo({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link_protinfo({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link_protinfo({1,native,<<Xf:32/unsigned-native>>}) ->
+ {flags,netlink_codec:decode_flags(Xf,fun dec_rtnetlink_link_protinfo_flags/1)};
+dec_rtnetlink_link_protinfo({1,big,<<Xf:32/unsigned-big>>}) ->
+ {flags,netlink_codec:decode_flags(Xf,fun dec_rtnetlink_link_protinfo_flags/1)};
+dec_rtnetlink_link_protinfo({2,native,<<X/binary>>}) ->
+ {conf,[Xi || <<Xi:32/signed-native>> <= X]};
+dec_rtnetlink_link_protinfo({2,big,<<X/binary>>}) ->
+ {conf,[Xi || <<Xi:32/signed-big>> <= X]};
+dec_rtnetlink_link_protinfo({3,native,<<X/binary>>}) ->
+ {stats,[Xi || <<Xi:64/unsigned-native>> <= X]};
+dec_rtnetlink_link_protinfo({3,big,<<X/binary>>}) ->
+ {stats,[Xi || <<Xi:64/unsigned-big>> <= X]};
+dec_rtnetlink_link_protinfo({4,native,<<X/binary>>}) ->
+ {mcast,X};
+dec_rtnetlink_link_protinfo({4,big,<<X/binary>>}) ->
+ {mcast,X};
+dec_rtnetlink_link_protinfo({5,native,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_link_protinfo({5,big,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_link_protinfo({6,native,<<X/binary>>}) ->
+ {icmp6stats,[Xi || <<Xi:64/unsigned-native>> <= X]};
+dec_rtnetlink_link_protinfo({6,big,<<X/binary>>}) ->
+ {icmp6stats,[Xi || <<Xi:64/unsigned-big>> <= X]};
+dec_rtnetlink_link_protinfo({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_link_protinfo({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_link_protinfo({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_link_protinfo({flags,native,X}) ->
+ {1,native,<<(netlink_codec:encode_flags(X,fun enc_rtnetlink_link_protinfo_flags/1)):32/unsigned-native>>};
+enc_rtnetlink_link_protinfo({flags,big,X}) ->
+ {1,big,<<(netlink_codec:encode_flags(X,fun enc_rtnetlink_link_protinfo_flags/1)):32/unsigned-big>>};
+enc_rtnetlink_link_protinfo({conf,native,X}) ->
+ {2,native,<<(<< <<Xi:32/signed-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({conf,big,X}) ->
+ {2,big,<<(<< <<Xi:32/signed-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({stats,native,X}) ->
+ {3,native,<<(<< <<Xi:64/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({stats,big,X}) ->
+ {3,big,<<(<< <<Xi:64/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({mcast,native,X}) ->
+ {4,native,<<X>>};
+enc_rtnetlink_link_protinfo({mcast,big,X}) ->
+ {4,big,<<X>>};
+enc_rtnetlink_link_protinfo({cacheinfo,native,X}) ->
+ {5,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({cacheinfo,big,X}) ->
+ {5,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({icmp6stats,native,X}) ->
+ {6,native,<<(<< <<Xi:64/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({icmp6stats,big,X}) ->
+ {6,big,<<(<< <<Xi:64/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link_protinfo({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink({1,native,<<X/binary>>}) ->
+ {tuple_orig,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({1,big,<<X/binary>>}) ->
+ {tuple_orig,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({2,native,<<X/binary>>}) ->
+ {tuple_reply,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({2,big,<<X/binary>>}) ->
+ {tuple_reply,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({3,native,<<Xf:32/unsigned-native>>}) ->
+ {status,netlink_codec:decode_flags(Xf,fun dec_ctnetlink_status/1)};
+dec_ctnetlink({3,big,<<Xf:32/unsigned-big>>}) ->
+ {status,netlink_codec:decode_flags(Xf,fun dec_ctnetlink_status/1)};
+dec_ctnetlink({4,native,<<X/binary>>}) ->
+ {protoinfo,dec_ctnetlink_protoinfo(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({4,big,<<X/binary>>}) ->
+ {protoinfo,dec_ctnetlink_protoinfo(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({5,native,<<X/binary>>}) ->
+ {help,dec_ctnetlink_help(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({5,big,<<X/binary>>}) ->
+ {help,dec_ctnetlink_help(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({6,native,<<X/binary>>}) ->
+ {nat_src,X};
+dec_ctnetlink({6,big,<<X/binary>>}) ->
+ {nat_src,X};
+dec_ctnetlink({7,native,<<X:32/unsigned-native>>}) ->
+ {timeout,X};
+dec_ctnetlink({7,big,<<X:32/unsigned-big>>}) ->
+ {timeout,X};
+dec_ctnetlink({8,native,<<X:32/unsigned-native>>}) ->
+ {mark,X};
+dec_ctnetlink({8,big,<<X:32/unsigned-big>>}) ->
+ {mark,X};
+dec_ctnetlink({9,native,<<X/binary>>}) ->
+ {counters_orig,dec_ctnetlink_counters(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({9,big,<<X/binary>>}) ->
+ {counters_orig,dec_ctnetlink_counters(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({10,native,<<X/binary>>}) ->
+ {counters_reply,dec_ctnetlink_counters(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({10,big,<<X/binary>>}) ->
+ {counters_reply,dec_ctnetlink_counters(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({11,native,<<X:32/unsigned-native>>}) ->
+ {use,X};
+dec_ctnetlink({11,big,<<X:32/unsigned-big>>}) ->
+ {use,X};
+dec_ctnetlink({12,native,<<X:32/unsigned-native>>}) ->
+ {id,X};
+dec_ctnetlink({12,big,<<X:32/unsigned-big>>}) ->
+ {id,X};
+dec_ctnetlink({13,native,<<X/binary>>}) ->
+ {nat_dst,X};
+dec_ctnetlink({13,big,<<X/binary>>}) ->
+ {nat_dst,X};
+dec_ctnetlink({14,native,<<X/binary>>}) ->
+ {tuple_master,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({14,big,<<X/binary>>}) ->
+ {tuple_master,dec_ctnetlink_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({15,native,<<X/binary>>}) ->
+ {nat_seq_adj_orig,dec_ctnetlink_nat_seq_adj(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({15,big,<<X/binary>>}) ->
+ {nat_seq_adj_orig,dec_ctnetlink_nat_seq_adj(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({16,native,<<X/binary>>}) ->
+ {nat_seq_adj_reply,dec_ctnetlink_nat_seq_adj(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({16,big,<<X/binary>>}) ->
+ {nat_seq_adj_reply,dec_ctnetlink_nat_seq_adj(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({17,native,<<X:32/unsigned-native>>}) ->
+ {secmark,X};
+dec_ctnetlink({17,big,<<X:32/unsigned-big>>}) ->
+ {secmark,X};
+dec_ctnetlink({18,native,<<X:16/unsigned-native>>}) ->
+ {zone,X};
+dec_ctnetlink({18,big,<<X:16/unsigned-big>>}) ->
+ {zone,X};
+dec_ctnetlink({19,native,<<X/binary>>}) ->
+ {secctx,X};
+dec_ctnetlink({19,big,<<X/binary>>}) ->
+ {secctx,X};
+dec_ctnetlink({20,native,<<X/binary>>}) ->
+ {timestamp,dec_ctnetlink_timestamp(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({20,big,<<X/binary>>}) ->
+ {timestamp,dec_ctnetlink_timestamp(netlink_codec:decode_tlv(X))};
+dec_ctnetlink({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink({tuple_orig,native,X}) ->
+ {1,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({tuple_orig,big,X}) ->
+ {1,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({tuple_reply,native,X}) ->
+ {2,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({tuple_reply,big,X}) ->
+ {2,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({status,native,X}) ->
+ {3,native,<<(netlink_codec:encode_flags(X,fun enc_ctnetlink_status/1)):32/unsigned-native>>};
+enc_ctnetlink({status,big,X}) ->
+ {3,big,<<(netlink_codec:encode_flags(X,fun enc_ctnetlink_status/1)):32/unsigned-big>>};
+enc_ctnetlink({protoinfo,native,X}) ->
+ {4,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_protoinfo(X)))>>};
+enc_ctnetlink({protoinfo,big,X}) ->
+ {4,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_protoinfo(X)))>>};
+enc_ctnetlink({help,native,X}) ->
+ {5,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_help(X)))>>};
+enc_ctnetlink({help,big,X}) ->
+ {5,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_help(X)))>>};
+enc_ctnetlink({nat_src,native,X}) ->
+ {6,native,<<X>>};
+enc_ctnetlink({nat_src,big,X}) ->
+ {6,big,<<X>>};
+enc_ctnetlink({timeout,native,X}) ->
+ {7,native,<<X:32/unsigned-native>>};
+enc_ctnetlink({timeout,big,X}) ->
+ {7,big,<<X:32/unsigned-big>>};
+enc_ctnetlink({mark,native,X}) ->
+ {8,native,<<X:32/unsigned-native>>};
+enc_ctnetlink({mark,big,X}) ->
+ {8,big,<<X:32/unsigned-big>>};
+enc_ctnetlink({counters_orig,native,X}) ->
+ {9,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_counters(X)))>>};
+enc_ctnetlink({counters_orig,big,X}) ->
+ {9,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_counters(X)))>>};
+enc_ctnetlink({counters_reply,native,X}) ->
+ {10,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_counters(X)))>>};
+enc_ctnetlink({counters_reply,big,X}) ->
+ {10,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_counters(X)))>>};
+enc_ctnetlink({use,native,X}) ->
+ {11,native,<<X:32/unsigned-native>>};
+enc_ctnetlink({use,big,X}) ->
+ {11,big,<<X:32/unsigned-big>>};
+enc_ctnetlink({id,native,X}) ->
+ {12,native,<<X:32/unsigned-native>>};
+enc_ctnetlink({id,big,X}) ->
+ {12,big,<<X:32/unsigned-big>>};
+enc_ctnetlink({nat_dst,native,X}) ->
+ {13,native,<<X>>};
+enc_ctnetlink({nat_dst,big,X}) ->
+ {13,big,<<X>>};
+enc_ctnetlink({tuple_master,native,X}) ->
+ {14,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({tuple_master,big,X}) ->
+ {14,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple(X)))>>};
+enc_ctnetlink({nat_seq_adj_orig,native,X}) ->
+ {15,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_nat_seq_adj(X)))>>};
+enc_ctnetlink({nat_seq_adj_orig,big,X}) ->
+ {15,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_nat_seq_adj(X)))>>};
+enc_ctnetlink({nat_seq_adj_reply,native,X}) ->
+ {16,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_nat_seq_adj(X)))>>};
+enc_ctnetlink({nat_seq_adj_reply,big,X}) ->
+ {16,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_nat_seq_adj(X)))>>};
+enc_ctnetlink({secmark,native,X}) ->
+ {17,native,<<X:32/unsigned-native>>};
+enc_ctnetlink({secmark,big,X}) ->
+ {17,big,<<X:32/unsigned-big>>};
+enc_ctnetlink({zone,native,X}) ->
+ {18,native,<<X:16/unsigned-native>>};
+enc_ctnetlink({zone,big,X}) ->
+ {18,big,<<X:16/unsigned-big>>};
+enc_ctnetlink({secctx,native,X}) ->
+ {19,native,<<X>>};
+enc_ctnetlink({secctx,big,X}) ->
+ {19,big,<<X>>};
+enc_ctnetlink({timestamp,native,X}) ->
+ {20,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_timestamp(X)))>>};
+enc_ctnetlink({timestamp,big,X}) ->
+ {20,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_timestamp(X)))>>};
+enc_ctnetlink({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_link({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_link({1,native,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_link({1,big,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_link({2,native,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {broadcast,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_link({2,big,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {broadcast,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_link({3,native,<<X/binary>>}) ->
+ {ifname,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({3,big,<<X/binary>>}) ->
+ {ifname,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({4,native,<<X:32/unsigned-native>>}) ->
+ {mtu,X};
+dec_rtnetlink_link({4,big,<<X:32/unsigned-big>>}) ->
+ {mtu,X};
+dec_rtnetlink_link({5,native,<<X:32/unsigned-native>>}) ->
+ {link,X};
+dec_rtnetlink_link({5,big,<<X:32/unsigned-big>>}) ->
+ {link,X};
+dec_rtnetlink_link({6,native,<<X/binary>>}) ->
+ {qdisc,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({6,big,<<X/binary>>}) ->
+ {qdisc,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({7,native,<<X/binary>>}) ->
+ {stats,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_link({7,big,<<X/binary>>}) ->
+ {stats,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_link({8,native,<<X/binary>>}) ->
+ {cost,X};
+dec_rtnetlink_link({8,big,<<X/binary>>}) ->
+ {cost,X};
+dec_rtnetlink_link({9,native,<<X/binary>>}) ->
+ {priority,X};
+dec_rtnetlink_link({9,big,<<X/binary>>}) ->
+ {priority,X};
+dec_rtnetlink_link({10,native,<<X/binary>>}) ->
+ {master,X};
+dec_rtnetlink_link({10,big,<<X/binary>>}) ->
+ {master,X};
+dec_rtnetlink_link({11,native,<<X/binary>>}) ->
+ {wireless,X};
+dec_rtnetlink_link({11,big,<<X/binary>>}) ->
+ {wireless,X};
+dec_rtnetlink_link({12,native,<<X/binary>>}) ->
+ {protinfo,[dec_rtnetlink_link_protinfo(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_link({12,big,<<X/binary>>}) ->
+ {protinfo,[dec_rtnetlink_link_protinfo(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_link({13,native,<<X:32/unsigned-native>>}) ->
+ {txqlen,X};
+dec_rtnetlink_link({13,big,<<X:32/unsigned-big>>}) ->
+ {txqlen,X};
+dec_rtnetlink_link({14,native,<<X1:64/unsigned-native,X2:64/unsigned-native,X3:64/unsigned-native,X4:16/unsigned-native,X5:8/unsigned-native,X6:8/unsigned-native>>}) ->
+ {map,#if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}};
+dec_rtnetlink_link({14,big,<<X1:64/unsigned-big,X2:64/unsigned-big,X3:64/unsigned-big,X4:16/unsigned-big,X5:8/unsigned-big,X6:8/unsigned-big>>}) ->
+ {map,#if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}};
+dec_rtnetlink_link({15,native,<<X/binary>>}) ->
+ {weight,X};
+dec_rtnetlink_link({15,big,<<X/binary>>}) ->
+ {weight,X};
+dec_rtnetlink_link({16,native,<<Xe:8/unsigned-native>>}) ->
+ {operstate,dec_rtnetlink_link_operstate(Xe)};
+dec_rtnetlink_link({16,big,<<Xe:8/unsigned-big>>}) ->
+ {operstate,dec_rtnetlink_link_operstate(Xe)};
+dec_rtnetlink_link({17,native,<<Xe:8/unsigned-native>>}) ->
+ {linkmode,dec_rtnetlink_link_linkmode(Xe)};
+dec_rtnetlink_link({17,big,<<Xe:8/unsigned-big>>}) ->
+ {linkmode,dec_rtnetlink_link_linkmode(Xe)};
+dec_rtnetlink_link({18,native,<<X/binary>>}) ->
+ {linkinfo,[dec_rtnetlink_link_linkinfo(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_link({18,big,<<X/binary>>}) ->
+ {linkinfo,[dec_rtnetlink_link_linkinfo(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_link({19,native,<<X/binary>>}) ->
+ {net_ns_pid,X};
+dec_rtnetlink_link({19,big,<<X/binary>>}) ->
+ {net_ns_pid,X};
+dec_rtnetlink_link({20,native,<<X/binary>>}) ->
+ {ifalias,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({20,big,<<X/binary>>}) ->
+ {ifalias,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_link({21,native,<<X:32/unsigned-native>>}) ->
+ {num_vf,X};
+dec_rtnetlink_link({21,big,<<X:32/unsigned-big>>}) ->
+ {num_vf,X};
+dec_rtnetlink_link({22,native,<<X/binary>>}) ->
+ {vfinfo_list,X};
+dec_rtnetlink_link({22,big,<<X/binary>>}) ->
+ {vfinfo_list,X};
+dec_rtnetlink_link({23,native,<<X/binary>>}) ->
+ {stats64,[Xi || <<Xi:64/unsigned-native>> <= X]};
+dec_rtnetlink_link({23,big,<<X/binary>>}) ->
+ {stats64,[Xi || <<Xi:64/unsigned-big>> <= X]};
+dec_rtnetlink_link({24,native,<<X/binary>>}) ->
+ {vf_ports,X};
+dec_rtnetlink_link({24,big,<<X/binary>>}) ->
+ {vf_ports,X};
+dec_rtnetlink_link({25,native,<<X/binary>>}) ->
+ {port_self,X};
+dec_rtnetlink_link({25,big,<<X/binary>>}) ->
+ {port_self,X};
+dec_rtnetlink_link({26,native,<<X/binary>>}) ->
+ {af_spec,X};
+dec_rtnetlink_link({26,big,<<X/binary>>}) ->
+ {af_spec,X};
+dec_rtnetlink_link({27,native,<<X:32/unsigned-native>>}) ->
+ {group,X};
+dec_rtnetlink_link({27,big,<<X:32/unsigned-big>>}) ->
+ {group,X};
+dec_rtnetlink_link({28,native,<<X/binary>>}) ->
+ {net_ns_fd,X};
+dec_rtnetlink_link({28,big,<<X/binary>>}) ->
+ {net_ns_fd,X};
+dec_rtnetlink_link({29,native,<<X/binary>>}) ->
+ {ext_mask,X};
+dec_rtnetlink_link({29,big,<<X/binary>>}) ->
+ {ext_mask,X};
+dec_rtnetlink_link({30,native,<<X:32/unsigned-native>>}) ->
+ {promiscuity,X};
+dec_rtnetlink_link({30,big,<<X:32/unsigned-big>>}) ->
+ {promiscuity,X};
+dec_rtnetlink_link({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_link({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_link({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_link({address,native,{X1,X2,X3,X4,X5,X6}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_link({address,big,{X1,X2,X3,X4,X5,X6}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_link({broadcast,native,{X1,X2,X3,X4,X5,X6}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_link({broadcast,big,{X1,X2,X3,X4,X5,X6}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_link({ifname,native,X}) ->
+ {3,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({ifname,big,X}) ->
+ {3,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({mtu,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({mtu,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({link,native,X}) ->
+ {5,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({link,big,X}) ->
+ {5,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({qdisc,native,X}) ->
+ {6,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({qdisc,big,X}) ->
+ {6,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({stats,native,X}) ->
+ {7,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link({stats,big,X}) ->
+ {7,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link({cost,native,X}) ->
+ {8,native,<<X>>};
+enc_rtnetlink_link({cost,big,X}) ->
+ {8,big,<<X>>};
+enc_rtnetlink_link({priority,native,X}) ->
+ {9,native,<<X>>};
+enc_rtnetlink_link({priority,big,X}) ->
+ {9,big,<<X>>};
+enc_rtnetlink_link({master,native,X}) ->
+ {10,native,<<X>>};
+enc_rtnetlink_link({master,big,X}) ->
+ {10,big,<<X>>};
+enc_rtnetlink_link({wireless,native,X}) ->
+ {11,native,<<X>>};
+enc_rtnetlink_link({wireless,big,X}) ->
+ {11,big,<<X>>};
+enc_rtnetlink_link({protinfo,native,X}) ->
+ {12,native,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_link_protinfo(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_link({protinfo,big,X}) ->
+ {12,big,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_link_protinfo(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_link({txqlen,native,X}) ->
+ {13,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({txqlen,big,X}) ->
+ {13,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({map,native,#if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}}) ->
+ {14,native,<<X1:64/unsigned-native,X2:64/unsigned-native,X3:64/unsigned-native,X4:16/unsigned-native,X5:8/unsigned-native,X6:8/unsigned-native>>};
+enc_rtnetlink_link({map,big,#if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}}) ->
+ {14,big,<<X1:64/unsigned-big,X2:64/unsigned-big,X3:64/unsigned-big,X4:16/unsigned-big,X5:8/unsigned-big,X6:8/unsigned-big>>};
+enc_rtnetlink_link({weight,native,X}) ->
+ {15,native,<<X>>};
+enc_rtnetlink_link({weight,big,X}) ->
+ {15,big,<<X>>};
+enc_rtnetlink_link({operstate,native,X}) ->
+ {16,native,<<(enc_rtnetlink_link_operstate(X)):8/unsigned-native>>};
+enc_rtnetlink_link({operstate,big,X}) ->
+ {16,big,<<(enc_rtnetlink_link_operstate(X)):8/unsigned-big>>};
+enc_rtnetlink_link({linkmode,native,X}) ->
+ {17,native,<<(enc_rtnetlink_link_linkmode(X)):8/unsigned-native>>};
+enc_rtnetlink_link({linkmode,big,X}) ->
+ {17,big,<<(enc_rtnetlink_link_linkmode(X)):8/unsigned-big>>};
+enc_rtnetlink_link({linkinfo,native,X}) ->
+ {18,native,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_link_linkinfo(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_link({linkinfo,big,X}) ->
+ {18,big,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_link_linkinfo(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_link({net_ns_pid,native,X}) ->
+ {19,native,<<X>>};
+enc_rtnetlink_link({net_ns_pid,big,X}) ->
+ {19,big,<<X>>};
+enc_rtnetlink_link({ifalias,native,X}) ->
+ {20,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({ifalias,big,X}) ->
+ {20,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_link({num_vf,native,X}) ->
+ {21,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({num_vf,big,X}) ->
+ {21,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({vfinfo_list,native,X}) ->
+ {22,native,<<X>>};
+enc_rtnetlink_link({vfinfo_list,big,X}) ->
+ {22,big,<<X>>};
+enc_rtnetlink_link({stats64,native,X}) ->
+ {23,native,<<(<< <<Xi:64/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link({stats64,big,X}) ->
+ {23,big,<<(<< <<Xi:64/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_link({vf_ports,native,X}) ->
+ {24,native,<<X>>};
+enc_rtnetlink_link({vf_ports,big,X}) ->
+ {24,big,<<X>>};
+enc_rtnetlink_link({port_self,native,X}) ->
+ {25,native,<<X>>};
+enc_rtnetlink_link({port_self,big,X}) ->
+ {25,big,<<X>>};
+enc_rtnetlink_link({af_spec,native,X}) ->
+ {26,native,<<X>>};
+enc_rtnetlink_link({af_spec,big,X}) ->
+ {26,big,<<X>>};
+enc_rtnetlink_link({group,native,X}) ->
+ {27,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({group,big,X}) ->
+ {27,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({net_ns_fd,native,X}) ->
+ {28,native,<<X>>};
+enc_rtnetlink_link({net_ns_fd,big,X}) ->
+ {28,big,<<X>>};
+enc_rtnetlink_link({ext_mask,native,X}) ->
+ {29,native,<<X>>};
+enc_rtnetlink_link({ext_mask,big,X}) ->
+ {29,big,<<X>>};
+enc_rtnetlink_link({promiscuity,native,X}) ->
+ {30,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_link({promiscuity,big,X}) ->
+ {30,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_link({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_nat_seq_adj({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_nat_seq_adj({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_nat_seq_adj({1,native,<<X:32/unsigned-native>>}) ->
+ {correction_pos,X};
+dec_ctnetlink_nat_seq_adj({1,big,<<X:32/unsigned-big>>}) ->
+ {correction_pos,X};
+dec_ctnetlink_nat_seq_adj({2,native,<<X:32/unsigned-native>>}) ->
+ {offset_before,X};
+dec_ctnetlink_nat_seq_adj({2,big,<<X:32/unsigned-big>>}) ->
+ {offset_before,X};
+dec_ctnetlink_nat_seq_adj({3,native,<<X:32/unsigned-native>>}) ->
+ {offset_after,X};
+dec_ctnetlink_nat_seq_adj({3,big,<<X:32/unsigned-big>>}) ->
+ {offset_after,X};
+dec_ctnetlink_nat_seq_adj({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_nat_seq_adj({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_nat_seq_adj({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_nat_seq_adj({correction_pos,native,X}) ->
+ {1,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_nat_seq_adj({correction_pos,big,X}) ->
+ {1,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_nat_seq_adj({offset_before,native,X}) ->
+ {2,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_nat_seq_adj({offset_before,big,X}) ->
+ {2,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_nat_seq_adj({offset_after,native,X}) ->
+ {3,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_nat_seq_adj({offset_after,big,X}) ->
+ {3,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_nat_seq_adj({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_neigh({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_neigh({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_neigh({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {dst,{X1,X2,X3,X4}};
+dec_rtnetlink_neigh({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {dst,{X1,X2,X3,X4}};
+dec_rtnetlink_neigh({1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_neigh({1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_neigh({2,native,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {lladdr,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_neigh({2,big,<<X1,X2,X3,X4,X5,X6>>}) ->
+ {lladdr,{X1,X2,X3,X4,X5,X6}};
+dec_rtnetlink_neigh({3,native,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_neigh({3,big,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_neigh({4,native,<<X:32/unsigned-native>>}) ->
+ {probes,X};
+dec_rtnetlink_neigh({4,big,<<X:32/unsigned-big>>}) ->
+ {probes,X};
+dec_rtnetlink_neigh({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_neigh({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_neigh({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_neigh({dst,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_neigh({dst,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_neigh({dst,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_neigh({dst,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_neigh({lladdr,native,{X1,X2,X3,X4,X5,X6}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_neigh({lladdr,big,{X1,X2,X3,X4,X5,X6}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8,X5:8,X6:8>>};
+enc_rtnetlink_neigh({cacheinfo,native,X}) ->
+ {3,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_neigh({cacheinfo,big,X}) ->
+ {3,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_neigh({probes,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_neigh({probes,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_neigh({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_prefix({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_prefix({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_prefix({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {address,{X1,X2,X3,X4}};
+dec_rtnetlink_prefix({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {address,{X1,X2,X3,X4}};
+dec_rtnetlink_prefix({1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_prefix({1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_prefix({2,native,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_prefix({2,big,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_prefix({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_prefix({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_prefix({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_prefix({address,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_prefix({address,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_prefix({address,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_prefix({address,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_prefix({cacheinfo,native,X}) ->
+ {2,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_prefix({cacheinfo,big,X}) ->
+ {2,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_prefix({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_tuple({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple({1,native,<<X/binary>>}) ->
+ {ip,dec_ctnetlink_tuple_ip(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_tuple({1,big,<<X/binary>>}) ->
+ {ip,dec_ctnetlink_tuple_ip(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_tuple({2,native,<<X/binary>>}) ->
+ {proto,dec_ctnetlink_tuple_proto(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_tuple({2,big,<<X/binary>>}) ->
+ {proto,dec_ctnetlink_tuple_proto(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_tuple({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_tuple({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_tuple({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_tuple({ip,native,X}) ->
+ {1,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple_ip(X)))>>};
+enc_ctnetlink_tuple({ip,big,X}) ->
+ {1,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple_ip(X)))>>};
+enc_ctnetlink_tuple({proto,native,X}) ->
+ {2,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple_proto(X)))>>};
+enc_ctnetlink_tuple({proto,big,X}) ->
+ {2,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_tuple_proto(X)))>>};
+enc_ctnetlink_tuple({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_exp_tuple({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple({1,native,<<X/binary>>}) ->
+ {ip,dec_ctnetlink_exp_tuple_ip(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp_tuple({1,big,<<X/binary>>}) ->
+ {ip,dec_ctnetlink_exp_tuple_ip(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp_tuple({2,native,<<X/binary>>}) ->
+ {proto,dec_ctnetlink_exp_tuple_proto(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp_tuple({2,big,<<X/binary>>}) ->
+ {proto,dec_ctnetlink_exp_tuple_proto(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp_tuple({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_exp_tuple({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_exp_tuple({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_exp_tuple({ip,native,X}) ->
+ {1,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple_ip(X)))>>};
+enc_ctnetlink_exp_tuple({ip,big,X}) ->
+ {1,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple_ip(X)))>>};
+enc_ctnetlink_exp_tuple({proto,native,X}) ->
+ {2,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple_proto(X)))>>};
+enc_ctnetlink_exp_tuple({proto,big,X}) ->
+ {2,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple_proto(X)))>>};
+enc_ctnetlink_exp_tuple({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_route({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_route({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_route({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {dst,{X1,X2,X3,X4}};
+dec_rtnetlink_route({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {dst,{X1,X2,X3,X4}};
+dec_rtnetlink_route({1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({2,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {src,{X1,X2,X3,X4}};
+dec_rtnetlink_route({2,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {src,{X1,X2,X3,X4}};
+dec_rtnetlink_route({2,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({2,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({3,native,<<X:32/unsigned-native>>}) ->
+ {iif,X};
+dec_rtnetlink_route({3,big,<<X:32/unsigned-big>>}) ->
+ {iif,X};
+dec_rtnetlink_route({4,native,<<X:32/unsigned-native>>}) ->
+ {oif,X};
+dec_rtnetlink_route({4,big,<<X:32/unsigned-big>>}) ->
+ {oif,X};
+dec_rtnetlink_route({5,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {gateway,{X1,X2,X3,X4}};
+dec_rtnetlink_route({5,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {gateway,{X1,X2,X3,X4}};
+dec_rtnetlink_route({5,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {gateway,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({5,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {gateway,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({6,native,<<X:32/unsigned-native>>}) ->
+ {priority,X};
+dec_rtnetlink_route({6,big,<<X:32/unsigned-big>>}) ->
+ {priority,X};
+dec_rtnetlink_route({7,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {prefsrc,{X1,X2,X3,X4}};
+dec_rtnetlink_route({7,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {prefsrc,{X1,X2,X3,X4}};
+dec_rtnetlink_route({7,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {prefsrc,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({7,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {prefsrc,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_route({8,native,<<X/binary>>}) ->
+ {metrics,[dec_rtnetlink_route_metrics(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_route({8,big,<<X/binary>>}) ->
+ {metrics,[dec_rtnetlink_route_metrics(Xi) || Xi <- netlink_codec:decode_tlv_list(X)]};
+dec_rtnetlink_route({9,native,<<X/binary>>}) ->
+ {multipath,X};
+dec_rtnetlink_route({9,big,<<X/binary>>}) ->
+ {multipath,X};
+dec_rtnetlink_route({10,native,<<X/binary>>}) ->
+ {protoinfo,X};
+dec_rtnetlink_route({10,big,<<X/binary>>}) ->
+ {protoinfo,X};
+dec_rtnetlink_route({11,native,<<X:32/unsigned-native>>}) ->
+ {flow,X};
+dec_rtnetlink_route({11,big,<<X:32/unsigned-big>>}) ->
+ {flow,X};
+dec_rtnetlink_route({12,native,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_route({12,big,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_route({13,native,<<X/binary>>}) ->
+ {session,X};
+dec_rtnetlink_route({13,big,<<X/binary>>}) ->
+ {session,X};
+dec_rtnetlink_route({14,native,<<X/binary>>}) ->
+ {mp_algo,X};
+dec_rtnetlink_route({14,big,<<X/binary>>}) ->
+ {mp_algo,X};
+dec_rtnetlink_route({15,native,<<X:32/unsigned-native>>}) ->
+ {table,X};
+dec_rtnetlink_route({15,big,<<X:32/unsigned-big>>}) ->
+ {table,X};
+dec_rtnetlink_route({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_route({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_route({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_route({dst,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({dst,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({dst,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({dst,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({src,native,{X1,X2,X3,X4}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({src,big,{X1,X2,X3,X4}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({src,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {2,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({src,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {2,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({iif,native,X}) ->
+ {3,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route({iif,big,X}) ->
+ {3,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route({oif,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route({oif,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route({gateway,native,{X1,X2,X3,X4}}) ->
+ {5,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({gateway,big,{X1,X2,X3,X4}}) ->
+ {5,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({gateway,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {5,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({gateway,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {5,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({priority,native,X}) ->
+ {6,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route({priority,big,X}) ->
+ {6,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route({prefsrc,native,{X1,X2,X3,X4}}) ->
+ {7,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({prefsrc,big,{X1,X2,X3,X4}}) ->
+ {7,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_route({prefsrc,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {7,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({prefsrc,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {7,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_route({metrics,native,X}) ->
+ {8,native,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_route_metrics(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_route({metrics,big,X}) ->
+ {8,big,<<(netlink_codec:encode_tlv_list([enc_rtnetlink_route_metrics(Xi) || Xi <- X]))/binary>>};
+enc_rtnetlink_route({multipath,native,X}) ->
+ {9,native,<<X>>};
+enc_rtnetlink_route({multipath,big,X}) ->
+ {9,big,<<X>>};
+enc_rtnetlink_route({protoinfo,native,X}) ->
+ {10,native,<<X>>};
+enc_rtnetlink_route({protoinfo,big,X}) ->
+ {10,big,<<X>>};
+enc_rtnetlink_route({flow,native,X}) ->
+ {11,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route({flow,big,X}) ->
+ {11,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route({cacheinfo,native,X}) ->
+ {12,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_route({cacheinfo,big,X}) ->
+ {12,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_route({session,native,X}) ->
+ {13,native,<<X>>};
+enc_rtnetlink_route({session,big,X}) ->
+ {13,big,<<X>>};
+enc_rtnetlink_route({mp_algo,native,X}) ->
+ {14,native,<<X>>};
+enc_rtnetlink_route({mp_algo,big,X}) ->
+ {14,big,<<X>>};
+enc_rtnetlink_route({table,native,X}) ->
+ {15,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route({table,big,X}) ->
+ {15,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_counters({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_counters({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_counters({1,native,<<X:64/unsigned-native>>}) ->
+ {packets,X};
+dec_ctnetlink_counters({1,big,<<X:64/unsigned-big>>}) ->
+ {packets,X};
+dec_ctnetlink_counters({2,native,<<X:64/unsigned-native>>}) ->
+ {bytes,X};
+dec_ctnetlink_counters({2,big,<<X:64/unsigned-big>>}) ->
+ {bytes,X};
+dec_ctnetlink_counters({3,native,<<X:32/unsigned-native>>}) ->
+ {packets32,X};
+dec_ctnetlink_counters({3,big,<<X:32/unsigned-big>>}) ->
+ {packets32,X};
+dec_ctnetlink_counters({4,native,<<X:32/unsigned-native>>}) ->
+ {bytes32,X};
+dec_ctnetlink_counters({4,big,<<X:32/unsigned-big>>}) ->
+ {bytes32,X};
+dec_ctnetlink_counters({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_counters({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_counters({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_counters({packets,native,X}) ->
+ {1,native,<<X:64/unsigned-native>>};
+enc_ctnetlink_counters({packets,big,X}) ->
+ {1,big,<<X:64/unsigned-big>>};
+enc_ctnetlink_counters({bytes,native,X}) ->
+ {2,native,<<X:64/unsigned-native>>};
+enc_ctnetlink_counters({bytes,big,X}) ->
+ {2,big,<<X:64/unsigned-big>>};
+enc_ctnetlink_counters({packets32,native,X}) ->
+ {3,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_counters({packets32,big,X}) ->
+ {3,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_counters({bytes32,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_counters({bytes32,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_counters({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_route_metrics({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_route_metrics({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_route_metrics({1,native,<<X:32/unsigned-native>>}) ->
+ {lock,X};
+dec_rtnetlink_route_metrics({1,big,<<X:32/unsigned-big>>}) ->
+ {lock,X};
+dec_rtnetlink_route_metrics({2,native,<<X:32/unsigned-native>>}) ->
+ {mtu,X};
+dec_rtnetlink_route_metrics({2,big,<<X:32/unsigned-big>>}) ->
+ {mtu,X};
+dec_rtnetlink_route_metrics({3,native,<<X:32/unsigned-native>>}) ->
+ {window,X};
+dec_rtnetlink_route_metrics({3,big,<<X:32/unsigned-big>>}) ->
+ {window,X};
+dec_rtnetlink_route_metrics({4,native,<<X:32/unsigned-native>>}) ->
+ {rtt,X};
+dec_rtnetlink_route_metrics({4,big,<<X:32/unsigned-big>>}) ->
+ {rtt,X};
+dec_rtnetlink_route_metrics({5,native,<<X:32/unsigned-native>>}) ->
+ {rttvar,X};
+dec_rtnetlink_route_metrics({5,big,<<X:32/unsigned-big>>}) ->
+ {rttvar,X};
+dec_rtnetlink_route_metrics({6,native,<<X:32/unsigned-native>>}) ->
+ {ssthresh,X};
+dec_rtnetlink_route_metrics({6,big,<<X:32/unsigned-big>>}) ->
+ {ssthresh,X};
+dec_rtnetlink_route_metrics({7,native,<<X:32/unsigned-native>>}) ->
+ {cwnd,X};
+dec_rtnetlink_route_metrics({7,big,<<X:32/unsigned-big>>}) ->
+ {cwnd,X};
+dec_rtnetlink_route_metrics({8,native,<<X:32/unsigned-native>>}) ->
+ {advmss,X};
+dec_rtnetlink_route_metrics({8,big,<<X:32/unsigned-big>>}) ->
+ {advmss,X};
+dec_rtnetlink_route_metrics({9,native,<<X:32/unsigned-native>>}) ->
+ {reordering,X};
+dec_rtnetlink_route_metrics({9,big,<<X:32/unsigned-big>>}) ->
+ {reordering,X};
+dec_rtnetlink_route_metrics({10,native,<<X:32/unsigned-native>>}) ->
+ {hoplimit,X};
+dec_rtnetlink_route_metrics({10,big,<<X:32/unsigned-big>>}) ->
+ {hoplimit,X};
+dec_rtnetlink_route_metrics({11,native,<<X:32/unsigned-native>>}) ->
+ {initcwnd,X};
+dec_rtnetlink_route_metrics({11,big,<<X:32/unsigned-big>>}) ->
+ {initcwnd,X};
+dec_rtnetlink_route_metrics({12,native,<<X:32/unsigned-native>>}) ->
+ {features,X};
+dec_rtnetlink_route_metrics({12,big,<<X:32/unsigned-big>>}) ->
+ {features,X};
+dec_rtnetlink_route_metrics({13,native,<<X:32/unsigned-native>>}) ->
+ {rto_min,X};
+dec_rtnetlink_route_metrics({13,big,<<X:32/unsigned-big>>}) ->
+ {rto_min,X};
+dec_rtnetlink_route_metrics({14,native,<<X:32/unsigned-native>>}) ->
+ {initrwnd,X};
+dec_rtnetlink_route_metrics({14,big,<<X:32/unsigned-big>>}) ->
+ {initrwnd,X};
+dec_rtnetlink_route_metrics({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_route_metrics({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_route_metrics({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_route_metrics({lock,native,X}) ->
+ {1,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({lock,big,X}) ->
+ {1,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({mtu,native,X}) ->
+ {2,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({mtu,big,X}) ->
+ {2,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({window,native,X}) ->
+ {3,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({window,big,X}) ->
+ {3,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({rtt,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({rtt,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({rttvar,native,X}) ->
+ {5,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({rttvar,big,X}) ->
+ {5,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({ssthresh,native,X}) ->
+ {6,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({ssthresh,big,X}) ->
+ {6,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({cwnd,native,X}) ->
+ {7,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({cwnd,big,X}) ->
+ {7,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({advmss,native,X}) ->
+ {8,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({advmss,big,X}) ->
+ {8,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({reordering,native,X}) ->
+ {9,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({reordering,big,X}) ->
+ {9,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({hoplimit,native,X}) ->
+ {10,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({hoplimit,big,X}) ->
+ {10,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({initcwnd,native,X}) ->
+ {11,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({initcwnd,big,X}) ->
+ {11,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({features,native,X}) ->
+ {12,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({features,big,X}) ->
+ {12,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({rto_min,native,X}) ->
+ {13,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({rto_min,big,X}) ->
+ {13,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({initrwnd,native,X}) ->
+ {14,native,<<X:32/unsigned-native>>};
+enc_rtnetlink_route_metrics({initrwnd,big,X}) ->
+ {14,big,<<X:32/unsigned-big>>};
+enc_rtnetlink_route_metrics({I,Endian,X}) -> {I,Endian,X}.
+dec_rtnetlink_addr({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_addr({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_rtnetlink_addr({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {address,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {address,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {address,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({2,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {local,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({2,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {local,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({2,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {local,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({2,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {local,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({3,native,<<X/binary>>}) ->
+ {label,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_addr({3,big,<<X/binary>>}) ->
+ {label,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_rtnetlink_addr({4,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {broadcast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({4,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {broadcast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {broadcast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {broadcast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({5,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {anycast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({5,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {anycast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({5,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {anycast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({5,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {anycast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({6,native,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-native>> <= X]};
+dec_rtnetlink_addr({6,big,<<X/binary>>}) ->
+ {cacheinfo,[Xi || <<Xi:32/unsigned-big>> <= X]};
+dec_rtnetlink_addr({7,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {multicast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({7,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {multicast,{X1,X2,X3,X4}};
+dec_rtnetlink_addr({7,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {multicast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({7,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {multicast,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_rtnetlink_addr({I,_Endian,Bin}) -> {I,Bin}.
+enc_rtnetlink_addr({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_rtnetlink_addr({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_rtnetlink_addr({address,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({address,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({address,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({address,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {1,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({local,native,{X1,X2,X3,X4}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({local,big,{X1,X2,X3,X4}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({local,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {2,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({local,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {2,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({label,native,X}) ->
+ {3,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_addr({label,big,X}) ->
+ {3,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_rtnetlink_addr({broadcast,native,{X1,X2,X3,X4}}) ->
+ {4,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({broadcast,big,{X1,X2,X3,X4}}) ->
+ {4,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({broadcast,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({broadcast,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({anycast,native,{X1,X2,X3,X4}}) ->
+ {5,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({anycast,big,{X1,X2,X3,X4}}) ->
+ {5,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({anycast,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {5,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({anycast,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {5,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({cacheinfo,native,X}) ->
+ {6,native,<<(<< <<Xi:32/unsigned-native>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_addr({cacheinfo,big,X}) ->
+ {6,big,<<(<< <<Xi:32/unsigned-big>> || Xi <- X>>)/binary>>};
+enc_rtnetlink_addr({multicast,native,{X1,X2,X3,X4}}) ->
+ {7,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({multicast,big,{X1,X2,X3,X4}}) ->
+ {7,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_rtnetlink_addr({multicast,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {7,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({multicast,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {7,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_rtnetlink_addr({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_tuple_ip({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple_ip({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_tuple_ip({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_src,{X1,X2,X3,X4}};
+dec_ctnetlink_tuple_ip({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_src,{X1,X2,X3,X4}};
+dec_ctnetlink_tuple_ip({2,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_dst,{X1,X2,X3,X4}};
+dec_ctnetlink_tuple_ip({2,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_dst,{X1,X2,X3,X4}};
+dec_ctnetlink_tuple_ip({3,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_tuple_ip({3,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_tuple_ip({4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_tuple_ip({4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_tuple_ip({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_tuple_ip({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_tuple_ip({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_tuple_ip({v4_src,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_tuple_ip({v4_src,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_tuple_ip({v4_dst,native,{X1,X2,X3,X4}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_tuple_ip({v4_dst,big,{X1,X2,X3,X4}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_tuple_ip({v6_src,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {3,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_tuple_ip({v6_src,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {3,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_tuple_ip({v6_dst,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_tuple_ip({v6_dst,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_tuple_ip({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_protoinfo_tcp({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_protoinfo_tcp({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_protoinfo_tcp({1,native,<<Xe:8/unsigned-native>>}) ->
+ {state,dec_ctnetlink_protoinfo_tcp_state(Xe)};
+dec_ctnetlink_protoinfo_tcp({1,big,<<Xe:8/unsigned-big>>}) ->
+ {state,dec_ctnetlink_protoinfo_tcp_state(Xe)};
+dec_ctnetlink_protoinfo_tcp({2,native,<<X:8/unsigned-native>>}) ->
+ {wscale_original,X};
+dec_ctnetlink_protoinfo_tcp({2,big,<<X:8/unsigned-big>>}) ->
+ {wscale_original,X};
+dec_ctnetlink_protoinfo_tcp({3,native,<<X:8/unsigned-native>>}) ->
+ {wscale_reply,X};
+dec_ctnetlink_protoinfo_tcp({3,big,<<X:8/unsigned-big>>}) ->
+ {wscale_reply,X};
+dec_ctnetlink_protoinfo_tcp({4,native,<<X:16/unsigned-native>>}) ->
+ {flags_original,X};
+dec_ctnetlink_protoinfo_tcp({4,big,<<X:16/unsigned-big>>}) ->
+ {flags_original,X};
+dec_ctnetlink_protoinfo_tcp({5,native,<<X:16/unsigned-native>>}) ->
+ {flags_reply,X};
+dec_ctnetlink_protoinfo_tcp({5,big,<<X:16/unsigned-big>>}) ->
+ {flags_reply,X};
+dec_ctnetlink_protoinfo_tcp({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_protoinfo_tcp({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_protoinfo_tcp({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_protoinfo_tcp({state,native,X}) ->
+ {1,native,<<(enc_ctnetlink_protoinfo_tcp_state(X)):8/unsigned-native>>};
+enc_ctnetlink_protoinfo_tcp({state,big,X}) ->
+ {1,big,<<(enc_ctnetlink_protoinfo_tcp_state(X)):8/unsigned-big>>};
+enc_ctnetlink_protoinfo_tcp({wscale_original,native,X}) ->
+ {2,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_protoinfo_tcp({wscale_original,big,X}) ->
+ {2,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_protoinfo_tcp({wscale_reply,native,X}) ->
+ {3,native,<<X:8/unsigned-native>>};
+enc_ctnetlink_protoinfo_tcp({wscale_reply,big,X}) ->
+ {3,big,<<X:8/unsigned-big>>};
+enc_ctnetlink_protoinfo_tcp({flags_original,native,X}) ->
+ {4,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_protoinfo_tcp({flags_original,big,X}) ->
+ {4,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_protoinfo_tcp({flags_reply,native,X}) ->
+ {5,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_protoinfo_tcp({flags_reply,big,X}) ->
+ {5,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_protoinfo_tcp({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_help({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_help({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_help({1,native,<<X/binary>>}) ->
+ {name,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_ctnetlink_help({1,big,<<X/binary>>}) ->
+ {name,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_ctnetlink_help({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_help({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_help({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_help({name,native,X}) ->
+ {1,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_ctnetlink_help({name,big,X}) ->
+ {1,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_ctnetlink_help({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_timestamp({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_timestamp({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_timestamp({1,native,<<X:64/unsigned-native>>}) ->
+ {start,X};
+dec_ctnetlink_timestamp({1,big,<<X:64/unsigned-big>>}) ->
+ {start,X};
+dec_ctnetlink_timestamp({2,native,<<X:64/unsigned-native>>}) ->
+ {stop,X};
+dec_ctnetlink_timestamp({2,big,<<X:64/unsigned-big>>}) ->
+ {stop,X};
+dec_ctnetlink_timestamp({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_timestamp({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_timestamp({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_timestamp({start,native,X}) ->
+ {1,native,<<X:64/unsigned-native>>};
+enc_ctnetlink_timestamp({start,big,X}) ->
+ {1,big,<<X:64/unsigned-big>>};
+enc_ctnetlink_timestamp({stop,native,X}) ->
+ {2,native,<<X:64/unsigned-native>>};
+enc_ctnetlink_timestamp({stop,big,X}) ->
+ {2,big,<<X:64/unsigned-big>>};
+enc_ctnetlink_timestamp({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_exp_tuple_ip({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple_ip({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp_tuple_ip({1,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_src,{X1,X2,X3,X4}};
+dec_ctnetlink_exp_tuple_ip({1,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_src,{X1,X2,X3,X4}};
+dec_ctnetlink_exp_tuple_ip({2,native,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_dst,{X1,X2,X3,X4}};
+dec_ctnetlink_exp_tuple_ip({2,big,<<X1:8,X2:8,X3:8,X4:8>>}) ->
+ {v4_dst,{X1,X2,X3,X4}};
+dec_ctnetlink_exp_tuple_ip({3,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_exp_tuple_ip({3,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_src,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_exp_tuple_ip({4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_exp_tuple_ip({4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>}) ->
+ {v6_dst,{X1,X2,X3,X4,X5,X6,X7,X8}};
+dec_ctnetlink_exp_tuple_ip({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_exp_tuple_ip({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_exp_tuple_ip({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_exp_tuple_ip({v4_src,native,{X1,X2,X3,X4}}) ->
+ {1,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_exp_tuple_ip({v4_src,big,{X1,X2,X3,X4}}) ->
+ {1,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_exp_tuple_ip({v4_dst,native,{X1,X2,X3,X4}}) ->
+ {2,native,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_exp_tuple_ip({v4_dst,big,{X1,X2,X3,X4}}) ->
+ {2,big,<<X1:8,X2:8,X3:8,X4:8>>};
+enc_ctnetlink_exp_tuple_ip({v6_src,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {3,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_exp_tuple_ip({v6_src,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {3,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_exp_tuple_ip({v6_dst,native,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,native,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_exp_tuple_ip({v6_dst,big,{X1,X2,X3,X4,X5,X6,X7,X8}}) ->
+ {4,big,<<X1:16,X2:16,X3:16,X4:16,X5:16,X6:16,X7:16,X8:16>>};
+enc_ctnetlink_exp_tuple_ip({I,Endian,X}) -> {I,Endian,X}.
+dec_ctnetlink_exp({0,native,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp({0,big,<<X/binary>>}) ->
+ {unspec,X};
+dec_ctnetlink_exp({1,native,<<X/binary>>}) ->
+ {master,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({1,big,<<X/binary>>}) ->
+ {master,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({2,native,<<X/binary>>}) ->
+ {tuple,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({2,big,<<X/binary>>}) ->
+ {tuple,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({3,native,<<X/binary>>}) ->
+ {mask,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({3,big,<<X/binary>>}) ->
+ {mask,dec_ctnetlink_exp_tuple(netlink_codec:decode_tlv(X))};
+dec_ctnetlink_exp({4,native,<<X:32/unsigned-native>>}) ->
+ {timeout,X};
+dec_ctnetlink_exp({4,big,<<X:32/unsigned-big>>}) ->
+ {timeout,X};
+dec_ctnetlink_exp({5,native,<<X:32/unsigned-native>>}) ->
+ {id,X};
+dec_ctnetlink_exp({5,big,<<X:32/unsigned-big>>}) ->
+ {id,X};
+dec_ctnetlink_exp({6,native,<<X/binary>>}) ->
+ {help_name,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_ctnetlink_exp({6,big,<<X/binary>>}) ->
+ {help_name,binary_to_list(hd(binary:split(X,<<0>>)))};
+dec_ctnetlink_exp({7,native,<<X:16/unsigned-native>>}) ->
+ {zone,X};
+dec_ctnetlink_exp({7,big,<<X:16/unsigned-big>>}) ->
+ {zone,X};
+dec_ctnetlink_exp({8,native,<<Xf:32/unsigned-native>>}) ->
+ {flags,netlink_codec:decode_flags(Xf,fun dec_ctnetlink_exp_flags/1)};
+dec_ctnetlink_exp({8,big,<<Xf:32/unsigned-big>>}) ->
+ {flags,netlink_codec:decode_flags(Xf,fun dec_ctnetlink_exp_flags/1)};
+dec_ctnetlink_exp({I,_Endian,Bin}) -> {I,Bin}.
+enc_ctnetlink_exp({unspec,native,X}) ->
+ {0,native,<<X>>};
+enc_ctnetlink_exp({unspec,big,X}) ->
+ {0,big,<<X>>};
+enc_ctnetlink_exp({master,native,X}) ->
+ {1,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({master,big,X}) ->
+ {1,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({tuple,native,X}) ->
+ {2,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({tuple,big,X}) ->
+ {2,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({mask,native,X}) ->
+ {3,native,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({mask,big,X}) ->
+ {3,big,<<(netlink_codec:encode_tlv(enc_ctnetlink_exp_tuple(X)))>>};
+enc_ctnetlink_exp({timeout,native,X}) ->
+ {4,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_exp({timeout,big,X}) ->
+ {4,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_exp({id,native,X}) ->
+ {5,native,<<X:32/unsigned-native>>};
+enc_ctnetlink_exp({id,big,X}) ->
+ {5,big,<<X:32/unsigned-big>>};
+enc_ctnetlink_exp({help_name,native,X}) ->
+ {6,native,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_ctnetlink_exp({help_name,big,X}) ->
+ {6,big,<<(erlang:iolist_to_binary([X,0]))/binary>>};
+enc_ctnetlink_exp({zone,native,X}) ->
+ {7,native,<<X:16/unsigned-native>>};
+enc_ctnetlink_exp({zone,big,X}) ->
+ {7,big,<<X:16/unsigned-big>>};
+enc_ctnetlink_exp({flags,native,X}) ->
+ {8,native,<<(netlink_codec:encode_flags(X,fun enc_ctnetlink_exp_flags/1)):32/unsigned-native>>};
+enc_ctnetlink_exp({flags,big,X}) ->
+ {8,big,<<(netlink_codec:encode_flags(X,fun enc_ctnetlink_exp_flags/1)):32/unsigned-big>>};
+enc_ctnetlink_exp({I,Endian,X}) -> {I,Endian,X}.
+dec_overrun({native,<<X1:32/unsigned-native>>}) ->
+ #overrun{status=X1}.
+enc_overrun({_Endian,#overrun{status=X1}}) -> <<X1:32/unsigned-native>>.
+dec_newlink({native,<<X1e:8/unsigned-native,_:8/unsigned-native,X3e:16/unsigned-native,X4:32/signed-native,X5f:32/unsigned-native,X6f:32/unsigned-native,X7/binary>>}) ->
+ #newlink{family=dec_family(X1e),arphrd=dec_arphrd(X3e),index=X4,flags=netlink_codec:decode_flags(X5f,fun dec_iff_flags/1),change=netlink_codec:decode_flags(X6f,fun dec_iff_flags/1),attributes=[dec_rtnetlink_link(X7i) || X7i <- netlink_codec:decode_tlv_list(X7)]}.
+enc_newlink({_Endian,#newlink{family=X1,arphrd=X3,index=X4,flags=X5,change=X6,attributes=X7}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,(enc_arphrd(X3)):16/unsigned-native,X4:32/signed-native,(netlink_codec:encode_flags(X5,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_flags(X6,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_link(X7i) || X7i <- X7]))/binary>>.
+dec_dellink({native,<<X1e:8/unsigned-native,_:8/unsigned-native,X3e:16/unsigned-native,X4:32/signed-native,X5f:32/unsigned-native,X6f:32/unsigned-native,X7/binary>>}) ->
+ #dellink{family=dec_family(X1e),arphrd=dec_arphrd(X3e),index=X4,flags=netlink_codec:decode_flags(X5f,fun dec_iff_flags/1),change=netlink_codec:decode_flags(X6f,fun dec_iff_flags/1),attributes=[dec_rtnetlink_link(X7i) || X7i <- netlink_codec:decode_tlv_list(X7)]}.
+enc_dellink({_Endian,#dellink{family=X1,arphrd=X3,index=X4,flags=X5,change=X6,attributes=X7}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,(enc_arphrd(X3)):16/unsigned-native,X4:32/signed-native,(netlink_codec:encode_flags(X5,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_flags(X6,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_link(X7i) || X7i <- X7]))/binary>>.
+dec_getlink({native,<<X1e:8/unsigned-native,_:8/unsigned-native,X3e:16/unsigned-native,X4:32/signed-native,X5f:32/unsigned-native,X6f:32/unsigned-native,X7/binary>>}) ->
+ #getlink{family=dec_family(X1e),arphrd=dec_arphrd(X3e),index=X4,flags=netlink_codec:decode_flags(X5f,fun dec_iff_flags/1),change=netlink_codec:decode_flags(X6f,fun dec_iff_flags/1),attributes=[dec_rtnetlink_link(X7i) || X7i <- netlink_codec:decode_tlv_list(X7)]}.
+enc_getlink({_Endian,#getlink{family=X1,arphrd=X3,index=X4,flags=X5,change=X6,attributes=X7}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,(enc_arphrd(X3)):16/unsigned-native,X4:32/signed-native,(netlink_codec:encode_flags(X5,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_flags(X6,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_link(X7i) || X7i <- X7]))/binary>>.
+dec_newneigh({native,<<X1e:8/unsigned-native,_:8/unsigned-native,_:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,X8/binary>>}) ->
+ #newneigh{family=dec_family(X1e),index=X4,state=X5,flags=X6,nmd_type=X7,attributes=[dec_rtnetlink_neigh(X8i) || X8i <- netlink_codec:decode_tlv_list(X8)]}.
+enc_newneigh({_Endian,#newneigh{family=X1,index=X4,state=X5,flags=X6,nmd_type=X7,attributes=X8}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,0:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_neigh(X8i) || X8i <- X8]))/binary>>.
+dec_delneigh({native,<<X1e:8/unsigned-native,_:8/unsigned-native,_:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,X8/binary>>}) ->
+ #delneigh{family=dec_family(X1e),index=X4,state=X5,flags=X6,nmd_type=X7,attributes=[dec_rtnetlink_neigh(X8i) || X8i <- netlink_codec:decode_tlv_list(X8)]}.
+enc_delneigh({_Endian,#delneigh{family=X1,index=X4,state=X5,flags=X6,nmd_type=X7,attributes=X8}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,0:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_neigh(X8i) || X8i <- X8]))/binary>>.
+dec_getneigh({native,<<X1e:8/unsigned-native,_:8/unsigned-native,_:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,X8/binary>>}) ->
+ #getneigh{family=dec_family(X1e),index=X4,state=X5,flags=X6,nmd_type=X7,attributes=[dec_rtnetlink_neigh(X8i) || X8i <- netlink_codec:decode_tlv_list(X8)]}.
+enc_getneigh({_Endian,#getneigh{family=X1,index=X4,state=X5,flags=X6,nmd_type=X7,attributes=X8}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,0:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_neigh(X8i) || X8i <- X8]))/binary>>.
+dec_ifaddrmsg({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3f:8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,X6/binary>>}) ->
+ #ifaddrmsg{family=dec_family(X1e),prefixlen=X2,flags=netlink_codec:decode_flags(X3f,fun dec_ifa_flags/1),scope=X4,index=X5,attributes=[dec_rtnetlink_addr(X6i) || X6i <- netlink_codec:decode_tlv_list(X6)]}.
+enc_ifaddrmsg({_Endian,#ifaddrmsg{family=X1,prefixlen=X2,flags=X3,scope=X4,index=X5,attributes=X6}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,(netlink_codec:encode_flags(X3,fun enc_ifa_flags/1)):8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_addr(X6i) || X6i <- X6]))/binary>>.
+dec_ifinfomsg({native,<<X1e:8/unsigned-native,_:8/unsigned-native,X3e:16/unsigned-native,X4:32/signed-native,X5f:32/unsigned-native,X6f:32/unsigned-native,X7/binary>>}) ->
+ #ifinfomsg{family=dec_family(X1e),arphrd=dec_arphrd(X3e),index=X4,flags=netlink_codec:decode_flags(X5f,fun dec_iff_flags/1),change=netlink_codec:decode_flags(X6f,fun dec_iff_flags/1),attributes=[dec_rtnetlink_link(X7i) || X7i <- netlink_codec:decode_tlv_list(X7)]}.
+enc_ifinfomsg({_Endian,#ifinfomsg{family=X1,arphrd=X3,index=X4,flags=X5,change=X6,attributes=X7}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,(enc_arphrd(X3)):16/unsigned-native,X4:32/signed-native,(netlink_codec:encode_flags(X5,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_flags(X6,fun enc_iff_flags/1)):32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_link(X7i) || X7i <- X7]))/binary>>.
+dec_rtmsg({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,X6e:8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,X10/binary>>}) ->
+ #rtmsg{family=dec_family(X1e),dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=dec_protocol(X6e),scope=X7,rtm_type=X8,flags=X9,attributes=[dec_rtnetlink_route(X10i) || X10i <- netlink_codec:decode_tlv_list(X10)]}.
+enc_rtmsg({_Endian,#rtmsg{family=X1,dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=X6,scope=X7,rtm_type=X8,flags=X9,attributes=X10}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,(enc_protocol(X6)):8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_route(X10i) || X10i <- X10]))/binary>>.
+dec_ndmsg({native,<<X1e:8/unsigned-native,_:8/unsigned-native,_:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,X8/binary>>}) ->
+ #ndmsg{family=dec_family(X1e),index=X4,state=X5,flags=X6,nmd_type=X7,attributes=[dec_rtnetlink_neigh(X8i) || X8i <- netlink_codec:decode_tlv_list(X8)]}.
+enc_ndmsg({_Endian,#ndmsg{family=X1,index=X4,state=X5,flags=X6,nmd_type=X7,attributes=X8}}) -> <<(enc_family(X1)):8/unsigned-native,0:8/unsigned-native,0:16/unsigned-native,X4:32/unsigned-native,X5:16/unsigned-native,X6:8/unsigned-native,X7:8/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_neigh(X8i) || X8i <- X8]))/binary>>.
+dec_newroute({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,X6e:8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,X10/binary>>}) ->
+ #newroute{family=dec_family(X1e),dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=dec_protocol(X6e),scope=X7,rtm_type=X8,flags=X9,attributes=[dec_rtnetlink_route(X10i) || X10i <- netlink_codec:decode_tlv_list(X10)]}.
+enc_newroute({_Endian,#newroute{family=X1,dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=X6,scope=X7,rtm_type=X8,flags=X9,attributes=X10}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,(enc_protocol(X6)):8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_route(X10i) || X10i <- X10]))/binary>>.
+dec_delroute({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,X6e:8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,X10/binary>>}) ->
+ #delroute{family=dec_family(X1e),dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=dec_protocol(X6e),scope=X7,rtm_type=X8,flags=X9,attributes=[dec_rtnetlink_route(X10i) || X10i <- netlink_codec:decode_tlv_list(X10)]}.
+enc_delroute({_Endian,#delroute{family=X1,dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=X6,scope=X7,rtm_type=X8,flags=X9,attributes=X10}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,(enc_protocol(X6)):8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_route(X10i) || X10i <- X10]))/binary>>.
+dec_getroute({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,X6e:8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,X10/binary>>}) ->
+ #getroute{family=dec_family(X1e),dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=dec_protocol(X6e),scope=X7,rtm_type=X8,flags=X9,attributes=[dec_rtnetlink_route(X10i) || X10i <- netlink_codec:decode_tlv_list(X10)]}.
+enc_getroute({_Endian,#getroute{family=X1,dstlen=X2,srclen=X3,tos=X4,table=X5,protocol=X6,scope=X7,rtm_type=X8,flags=X9,attributes=X10}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,X3:8/unsigned-native,X4:8/unsigned-native,X5:8/unsigned-native,(enc_protocol(X6)):8/unsigned-native,X7:8/unsigned-native,X8:8/unsigned-native,X9:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_route(X10i) || X10i <- X10]))/binary>>.
+dec_done({native,<<X1:32/unsigned-native>>}) ->
+ #done{status=X1}.
+enc_done({_Endian,#done{status=X1}}) -> <<X1:32/unsigned-native>>.
+dec_nlmsghdr({native,<<X1:32/unsigned-native,X2:16/unsigned-native,X3:16/unsigned-native,X4:32/unsigned-native,X5:32/unsigned-native>>}) ->
+ #nlmsghdr{len=X1,type=X2,flags=X3,seq=X4,pid=X5}.
+enc_nlmsghdr({_Endian,#nlmsghdr{len=X1,type=X2,flags=X3,seq=X4,pid=X5}}) -> <<X1:32/unsigned-native,X2:16/unsigned-native,X3:16/unsigned-native,X4:32/unsigned-native,X5:32/unsigned-native>>.
+dec_newaddr({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3f:8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,X6/binary>>}) ->
+ #newaddr{family=dec_family(X1e),prefixlen=X2,flags=netlink_codec:decode_flags(X3f,fun dec_ifa_flags/1),scope=X4,index=X5,attributes=[dec_rtnetlink_addr(X6i) || X6i <- netlink_codec:decode_tlv_list(X6)]}.
+enc_newaddr({_Endian,#newaddr{family=X1,prefixlen=X2,flags=X3,scope=X4,index=X5,attributes=X6}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,(netlink_codec:encode_flags(X3,fun enc_ifa_flags/1)):8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_addr(X6i) || X6i <- X6]))/binary>>.
+dec_deladdr({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3f:8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,X6/binary>>}) ->
+ #deladdr{family=dec_family(X1e),prefixlen=X2,flags=netlink_codec:decode_flags(X3f,fun dec_ifa_flags/1),scope=X4,index=X5,attributes=[dec_rtnetlink_addr(X6i) || X6i <- netlink_codec:decode_tlv_list(X6)]}.
+enc_deladdr({_Endian,#deladdr{family=X1,prefixlen=X2,flags=X3,scope=X4,index=X5,attributes=X6}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,(netlink_codec:encode_flags(X3,fun enc_ifa_flags/1)):8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_addr(X6i) || X6i <- X6]))/binary>>.
+dec_getaddr({native,<<X1e:8/unsigned-native,X2:8/unsigned-native,X3f:8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,X6/binary>>}) ->
+ #getaddr{family=dec_family(X1e),prefixlen=X2,flags=netlink_codec:decode_flags(X3f,fun dec_ifa_flags/1),scope=X4,index=X5,attributes=[dec_rtnetlink_addr(X6i) || X6i <- netlink_codec:decode_tlv_list(X6)]}.
+enc_getaddr({_Endian,#getaddr{family=X1,prefixlen=X2,flags=X3,scope=X4,index=X5,attributes=X6}}) -> <<(enc_family(X1)):8/unsigned-native,X2:8/unsigned-native,(netlink_codec:encode_flags(X3,fun enc_ifa_flags/1)):8/unsigned-native,X4:8/unsigned-native,X5:32/unsigned-native,(netlink_codec:encode_tlv_list([enc_rtnetlink_addr(X6i) || X6i <- X6]))/binary>>.
+dec_error({native,<<X1:32/signed-native,X21:32/unsigned-native,X22:16/unsigned-native,X23:16/unsigned-native,X24:32/unsigned-native,X25:32/unsigned-native,X3/binary>>}) ->
+ #error{errno=X1,msg=#nlmsghdr{len=X21,type=X22,flags=X23,seq=X24,pid=X25},data=X3}.
+enc_error({_Endian,#error{errno=X1,msg=#nlmsghdr{len=X21,type=X22,flags=X23,seq=X24,pid=X25},data=X3}}) -> <<X1:32/signed-native,X21:32/unsigned-native,X22:16/unsigned-native,X23:16/unsigned-native,X24:32/unsigned-native,X25:32/unsigned-native,X3>>.
+dec_if_map({native,<<X1:64/unsigned-native,X2:64/unsigned-native,X3:64/unsigned-native,X4:16/unsigned-native,X5:8/unsigned-native,X6:8/unsigned-native>>}) ->
+ #if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}.
+enc_if_map({_Endian,#if_map{memstart=X1,memend=X2,baseaddr=X3,irq=X4,dma=X5,port=X6}}) -> <<X1:64/unsigned-native,X2:64/unsigned-native,X3:64/unsigned-native,X4:16/unsigned-native,X5:8/unsigned-native,X6:8/unsigned-native>>.
+dec_noop({native,<<>>}) ->
+ #noop{}.
+enc_noop({_Endian,#noop{}}) -> <<>>.
diff --git a/deps/netlink/src/netl_codec.hrl b/deps/netlink/src/netl_codec.hrl
new file mode 100644
index 0000000..a5bcf47
--- /dev/null
+++ b/deps/netlink/src/netl_codec.hrl
@@ -0,0 +1,200 @@
+-define(AF_ATMPVC, 8).
+-define(AF_ATMSVC, 20).
+-define(ARPHRD_CHAOS, 5).
+-define(ARPHRD_RAWHDLC, 518).
+-define(RTM_DELADDR, 21).
+-define(RTM_GETADDR, 22).
+-define(ARPHRD_IEEE802, 6).
+-define(AF_SNA, 22).
+-define(NLMSG_NOOP, 1).
+-define(PROTO_ICMP, 1).
+-define(PROTO_IGMP, 2).
+-define(PROTO_IPIP, 4).
+-define(PROTO_UDP, 17).
+-define(PROTO_IDP, 22).
+-define(PROTO_MTP, 92).
+-define(PROTO_COMP, 108).
+-define(ARPHRD_ETHER , 1).
+-define(ARPHRD_CISCO, 513).
+-define(IPCTNL_MSG_CT_GET_CTRZERO, 3).
+-define(AF_CAN, 29).
+-define(ARPHRD_CAN, 280).
+-define(AF_NETROM, 6).
+-define(ARPHRD_NETROM, 0).
+-define(ARPHRD_METRICOM, 23).
+-define(RTM_NEWNEIGHTBL, 64).
+-define(RTM_GETNEIGHTBL, 66).
+-define(RTM_SETNEIGHTBL, 67).
+-define(ARPHRD_TUNNEL, 768).
+-define(ARPHRD_FCPL, 786).
+-define(RTM_DELLINK, 17).
+-define(RTM_GETLINK, 18).
+-define(AF_APPLETALK, 5).
+-define(ARPHRD_APPLETLK, 8).
+-define(ARPHRD_LOOPBACK, 772).
+-define(AF_NETBEUI, 13).
+-define(ARPHRD_FDDI, 774).
+-define(RTM_NEWNEIGH, 28).
+-define(RTM_DELNEIGH, 29).
+-define(RTM_GETNEIGH, 30).
+-define(RTM_NEWPREFIX, 52).
+-define(AF_IPX, 4).
+-define(AF_ASH, 18).
+-define(AF_PPPOX, 24).
+-define(AF_BLUETOOTH, 31).
+-define(ARPHRD_ASH, 781).
+-define(PROTO_ROUTING, 43).
+-define(PROTO_RAW, 255).
+-define(ARPHRD_PIMREG, 779).
+-define(PROTO_IPV6, 41).
+-define(ARPHRD_SLIP6, 258).
+-define(ARPHRD_CSLIP6, 259).
+-define(ARPHRD_TUNNEL6, 769).
+-define(ARPHRD_BIF, 775).
+-define(RTM_GETROUTE, 26).
+-define(RTM_DELRULE, 33).
+-define(RTM_GETRULE, 34).
+-define(AF_AX25, 3).
+-define(AF_BRIDGE, 7).
+-define(AF_X25, 9).
+-define(AF_ROSE, 11).
+-define(AF_ROUTE, 16).
+-define(PROTO_GRE, 47).
+-define(PROTO_UDPLITE, 136).
+-define(ARPHRD_X25, 271).
+-define(ARPHRD_HWX25, 272).
+-define(ARPHRD_NONE, 65534).
+-define(RTM_GETMULTICAST, 58).
+-define(RTM_GETANYCAST, 62).
+-define(RTM_NEWNDUSEROPT, 68).
+-define(AF_IEEE802154, 36).
+-define(PROTO_FRAGMENT, 44).
+-define(ARPHRD_EUI64, 27).
+-define(ARPHRD_INFINIBAND, 32).
+-define(ARPHRD_ADAPT, 264).
+-define(RTM_NEWQDISC, 36).
+-define(RTM_DELQDISC, 37).
+-define(RTM_NEWTCLASS, 40).
+-define(RTM_DELTCLASS, 41).
+-define(RTM_GETTCLASS, 42).
+-define(AF_UNSPEC, 0).
+-define(AF_RDS, 21).
+-define(AF_RXRPC, 33).
+-define(PROTO_DSTOPTS, 60).
+-define(ARPHRD_HDLC, 513).
+-define(NLMSG_ERROR, 2).
+-define(RTM_NEWADDR, 20).
+-define(RTM_NEWTFILTER, 44).
+-define(ARPHRD_LAPB, 516).
+-define(ARPHRD_IEEE802_TR, 800).
+-define(ARPHRD_IRDA, 783).
+-define(ARPHRD_IEEE80211, 801).
+-define(PROTO_IP, 0).
+-define(PROTO_TCP, 6).
+-define(PROTO_EGP, 8).
+-define(PROTO_PUP, 12).
+-define(PROTO_RSVP, 46).
+-define(PROTO_ESP, 50).
+-define(PROTO_ENCAP, 98).
+-define(PROTO_SCTP, 132).
+-define(ARPHRD_SLIP, 256).
+-define(ARPHRD_PPP, 512).
+-define(ARPHRD_SKIP, 771).
+-define(ARPHRD_IPDDP, 777).
+-define(ARPHRD_IEEE80211_RADIOTAP, 803).
+-define(NLMSG_OVERRUN, 4).
+-define(RTM_NEWACTION, 48).
+-define(RTM_DELACTION, 49).
+-define(RTM_GETACTION, 50).
+-define(AF_ISDN, 34).
+-define(PROTO_PIM, 103).
+-define(ARPHRD_ATM, 19).
+-define(ARPHRD_IEEE80211_PRISM, 802).
+-define(RTM_NEWADDRLABEL, 72).
+-define(RTM_DELADDRLABEL, 73).
+-define(RTM_GETADDRLABEL, 74).
+-define(AF_LOCAL, 1).
+-define(ARPHRD_FCAL, 785).
+-define(RTM_NEWLINK, 16).
+-define(RTM_SETLINK, 19).
+-define(AF_NETLINK, 16).
+-define(ARPHRD_LOCALTLK, 773).
+-define(AF_SECURITY, 14).
+-define(AF_KEY, 15).
+-define(ARPHRD_DLCI, 15).
+-define(ARPHRD_HIPPI, 780).
+-define(AF_UNIX, 1).
+-define(PROTO_AH, 51).
+-define(IPCTNL_MSG_CT_NEW, 0).
+-define(IPCTNL_MSG_EXP_NEW, 0).
+-define(AF_INET6, 10).
+-define(AF_IUCV, 32).
+-define(PROTO_ICMPV6, 58).
+-define(ARPHRD_CAIF, 822).
+-define(NLMSG_DONE, 3).
+-define(RTM_NEWROUTE, 24).
+-define(RTM_DELROUTE, 25).
+-define(RTM_NEWRULE, 32).
+-define(AF_FILE, 1).
+-define(AF_WANPIPE, 25).
+-define(PROTO_NONE, 59).
+-define(ARPHRD_AX25, 3).
+-define(ARPHRD_ROSE, 270).
+-define(ARPHRD_IPGRE, 778).
+-define(ARPHRD_PHONET_PIPE, 821).
+-define(IPCTNL_MSG_CT_DELETE, 2).
+-define(IPCTNL_MSG_EXP_DELETE, 2).
+-define(AF_INET, 2).
+-define(AF_DECNET, 12).
+-define(AF_PACKET, 17).
+-define(AF_ECONET, 19).
+-define(AF_PHONET, 35).
+-define(ARPHRD_PRONET, 4).
+-define(ARPHRD_ARCNET, 7).
+-define(ARPHRD_IEEE1394, 24).
+-define(ARPHRD_RSRVD, 260).
+-define(ARPHRD_FRAD, 770).
+-define(ARPHRD_SIT, 776).
+-define(ARPHRD_ECONET, 782).
+-define(ARPHRD_IEEE802154, 804).
+-define(ARPHRD_PHONET, 820).
+-define(ARPHRD_VOID, 65535).
+-define(IPCTNL_MSG_CT_GET, 1).
+-define(IPCTNL_MSG_EXP_GET, 1).
+-define(RTM_GETQDISC, 38).
+-define(AF_LLC, 26).
+-define(AF_TIPC, 30).
+-define(ARPHRD_FCFABRIC, 787).
+-define(RTM_DELTFILTER, 45).
+-define(RTM_GETTFILTER, 46).
+-define(RTM_GETDCB, 78).
+-define(RTM_SETDCB, 79).
+-define(ARPHRD_EETHER, 2).
+-define(AF_IRDA, 23).
+-define(PROTO_TP, 29).
+-define(PROTO_DCCP, 33).
+-define(ARPHRD_CSLIP, 257).
+-define(ARPHRD_DDCMP, 517).
+-define(ARPHRD_FCPP, 784).
+-record(overrun, {status}).
+-record(newlink, {family,arphrd,index,flags,change,attributes}).
+-record(dellink, {family,arphrd,index,flags,change,attributes}).
+-record(getlink, {family,arphrd,index,flags,change,attributes}).
+-record(newneigh, {family,index,state,flags,nmd_type,attributes}).
+-record(delneigh, {family,index,state,flags,nmd_type,attributes}).
+-record(getneigh, {family,index,state,flags,nmd_type,attributes}).
+-record(ifaddrmsg, {family,prefixlen,flags,scope,index,attributes}).
+-record(ifinfomsg, {family,arphrd,index,flags,change,attributes}).
+-record(rtmsg, {family,dstlen,srclen,tos,table,protocol,scope,rtm_type,flags,attributes}).
+-record(ndmsg, {family,index,state,flags,nmd_type,attributes}).
+-record(newroute, {family,dstlen,srclen,tos,table,protocol,scope,rtm_type,flags,attributes}).
+-record(delroute, {family,dstlen,srclen,tos,table,protocol,scope,rtm_type,flags,attributes}).
+-record(getroute, {family,dstlen,srclen,tos,table,protocol,scope,rtm_type,flags,attributes}).
+-record(done, {status}).
+-record(nlmsghdr, {len,type,flags,seq,pid}).
+-record(newaddr, {family,prefixlen,flags,scope,index,attributes}).
+-record(deladdr, {family,prefixlen,flags,scope,index,attributes}).
+-record(getaddr, {family,prefixlen,flags,scope,index,attributes}).
+-record(error, {errno,msg,data}).
+-record(if_map, {memstart,memend,baseaddr,irq,dma,port}).
+-record(noop, {}).
diff --git a/deps/netlink/src/netlink.app.src b/deps/netlink/src/netlink.app.src
new file mode 100644
index 0000000..1025181
--- /dev/null
+++ b/deps/netlink/src/netlink.app.src
@@ -0,0 +1,12 @@
+{application, netlink,
+ [
+ {description, ""},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib
+ ]},
+ {mod, { netlink_app, []}},
+ {env, []}
+ ]}.
diff --git a/deps/netlink/src/netlink.erl b/deps/netlink/src/netlink.erl
new file mode 100644
index 0000000..bd08477
--- /dev/null
+++ b/deps/netlink/src/netlink.erl
@@ -0,0 +1,737 @@
+%%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%%
+%%% Copyright (C) 2012 Feuerlabs, Inc. All rights reserved.
+%%%
+%%% This Source Code Form is subject to the terms of the Mozilla Public
+%%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%%
+%%%---- END COPYRIGHT ---------------------------------------------------------
+%%%-------------------------------------------------------------------
+%%% @author Tony Rogvall <tony@rogvall.se>
+%%% @doc
+%%% Netlink state monitor
+%%% @end
+%%% Created : 11 Jun 2012 by Tony Rogvall <tony@rogvall.se>
+%%%-------------------------------------------------------------------
+-module(netlink).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0, start_link/1]).
+-export([start/0, stop/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+-export([i/0, list/1]).
+-export([subscribe/1, subscribe/2, subscribe/3]).
+-export([unsubscribe/1]).
+-export([invalidate/2]).
+-export([get_root/2, get_match/3, get/4]).
+
+-include("log.hrl").
+-include("netlink.hrl").
+-include("netl_codec.hrl").
+
+-define(SERVER, ?MODULE).
+
+-type if_addr_field() :: address | local | broadcast | anycast | multicast.
+
+-type if_link_field() :: name | index | mtu | txqlen | flags |
+ operstate | qdisc | address | broadcast.
+
+-type uint8_t() :: 0..16#ff.
+-type uint16_t() :: 0..16#ffff.
+
+-type ipv4_addr() :: {uint8_t(),uint8_t(),uint8_t(),uint8_t()}.
+-type ipv6_addr() :: {uint16_t(),uint16_t(),uint16_t(),uint16_t(),
+ uint16_t(),uint16_t(),uint16_t(),uint16_t()}.
+
+-type if_addr() :: ipv4_addr() | ipv6_addr().
+
+-type if_field() :: if_link_field() | if_addr_field() |
+ {link,if_link_field()} | {addr,if_addr_field()}.
+
+-type if_name() :: string().
+
+
+-record(link,
+ {
+ name :: if_name(), %% interface name
+ index :: non_neg_integer(), %% interface index
+ attr :: term() %% attributes {atom(),term}
+ }).
+
+-record(addr,
+ {
+ addr :: if_addr(), %% the address
+ name :: if_name(), %% interface label
+ index :: non_neg_integer(), %% interface index
+ attr :: term() %% attributes
+ }).
+
+-record(subscription,
+ {
+ pid :: pid(), %% subscriber
+ mon :: reference(), %% monitor
+ name :: string(), %% name
+ fields=all :: all | addr | link | [if_field()]
+ }).
+
+-define(MIN_RCVBUF, (128*1024)).
+-define(MIN_SNDBUF, (32*1024)).
+
+-define(REQUEST_TMO, 2000).
+
+-record(request,
+ {
+ tmr, %% timer reference
+ call, %% call request
+ from, %% caller
+ reply=ok, %% reply to send when done
+ seq=0 %% sequence to expect in reply
+ }).
+
+-record(state,
+ {
+ port,
+ link_list = [] :: [#link {}],
+ addr_list = [] :: [#addr {}],
+ sub_list = [] :: [#subscription {}],
+ request :: undefined | #request{},
+ request_queue = [] :: [#request{}],
+ o_seq = 0,
+ i_seq = 0,
+ ospid
+ }).
+
+%%%===================================================================
+%%% API
+%%%===================================================================
+
+start() ->
+ application:start(netlink).
+
+i() ->
+ gen_server:call(?SERVER, {list,[]}).
+
+stop() ->
+ gen_server:call(?SERVER, stop).
+
+list(Match) ->
+ gen_server:call(?SERVER, {list,Match}).
+
+%% @doc
+%% Subscribe to interface changes, notifications will be
+%% sent in {netlink,reference(),if_name(),if_field(),OldValue,NewValue}
+%% @end
+
+-spec subscribe(Name::string()) ->
+ {ok,reference()}.
+
+subscribe(Name) ->
+ subscribe(Name,all,[]).
+
+-spec subscribe(Name::string(),Fields::all|[if_field()]) ->
+ {ok,reference()}.
+
+subscribe(Name,Fields) ->
+ subscribe(Name,Fields, []).
+
+-spec subscribe(Name::string(),Fields::all|[if_field()],Otions::[atom()]) ->
+ {ok,reference()}.
+subscribe(Name,Fields,Options) ->
+ gen_server:call(?SERVER, {subscribe, self(),Name,Options,Fields}).
+
+unsubscribe(Ref) ->
+ gen_server:call(?SERVER, {unsubscribe,Ref}).
+
+%% clear all attributes for interface Name
+invalidate(Name,Fields) ->
+ gen_server:call(?SERVER, {invalidate,Name,Fields}).
+
+get_root(What,Fam) ->
+ get(What,Fam,[root,match,request],[]).
+
+get_match(What,Fam,GetAttrs) ->
+ get(What,Fam,[match,request],GetAttrs).
+
+get(What,Fam,GetFlags,GetAttrs) ->
+ gen_server:call(?SERVER, {get,What,Fam,GetFlags,GetAttrs}).
+
+%%--------------------------------------------------------------------
+%% @doc
+%% Starts the server
+%%
+%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @end
+%%--------------------------------------------------------------------
+start_link() ->
+ start_link([]).
+start_link(Opts) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], []).
+
+%%%===================================================================
+%%% gen_server callbacks
+%%%===================================================================
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Initializes the server
+%%
+%% @spec init(Args) -> {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%% @end
+%%--------------------------------------------------------------------
+init([Opts]) ->
+ OsPid = list_to_integer(os:getpid()),
+ I_Seq = O_Seq = 1234, %% element(2,now()),
+ State = #state{ ospid = OsPid,
+ o_seq = O_Seq,
+ i_seq = I_Seq },
+
+ case os:type() of
+ {unix, linux} ->
+ init_drv(Opts, State);
+ _ ->
+ {ok, State}
+ end.
+
+init_drv(Opts, State) ->
+ Port = netlink_drv:open(?NETLINK_ROUTE),
+
+ netlink_drv:debug(Port, proplists:get_value(debug,Opts,none)),
+
+ {ok,Rcvbuf} = update_rcvbuf(Port, ?MIN_RCVBUF),
+ {ok,Sndbuf} = update_sndbuf(Port, ?MIN_SNDBUF),
+
+ ?info("Rcvbuf: ~w, Sndbuf: ~w", [Rcvbuf, Sndbuf]),
+
+ {ok,Sizes} = netlink_drv:get_sizeof(Port),
+ ?info("Sizes: ~w", [Sizes]),
+
+ ok = netlink_drv:add_membership(Port, ?RTNLGRP_LINK),
+ ok = netlink_drv:add_membership(Port, ?RTNLGRP_IPV4_IFADDR),
+ ok = netlink_drv:add_membership(Port, ?RTNLGRP_IPV6_IFADDR),
+
+ netlink_drv:activate(Port),
+ %% init sequence to fill the cache
+ T0 = erlang:start_timer(200, self(), request_timeout),
+ R0 = #request { tmr = T0,
+ call = noop,
+ from = {self(),make_ref()}
+ },
+ R1 = #request { tmr = {relative, ?REQUEST_TMO},
+ call = {get,link,unspec,
+ [root,match,request],
+ []},
+ from = {self(),make_ref()}
+ },
+ R2 = #request { tmr = {relative, 1000},
+ call = noop,
+ from = {self(),make_ref()}
+ },
+ R3 = #request { tmr = {relative,?REQUEST_TMO},
+ call = {get,addr,unspec,
+ [root,match,request],
+ []},
+ from = {self(),make_ref()}
+ },
+ {ok, State#state{ port=Port,
+ request = R0,
+ request_queue = [R1,R2,R3]
+ }}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling call messages
+%%
+%% @spec handle_call(Request, From, State) ->
+%% {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_call({list,Match}, _From, State) ->
+ lists:foreach(
+ fun(L) ->
+ %% select addresses that belong to link L
+ Ys = [Y || Y <- State#state.addr_list,
+ Y#addr.index =:= L#link.index],
+ FYs = [format_addr(Y) || Y <- Ys ],
+ case match(L#link.attr,dict:new(),Match) of
+ true ->
+ io:format("link {~s~s}\n",
+ [FYs,format_link(L)]);
+ false ->
+ ok
+ end
+ end, State#state.link_list),
+ {reply, ok, State};
+handle_call({subscribe, Pid, Name, Options, Fs}, _From, State) ->
+ Mon = erlang:monitor(process, Pid),
+ S = #subscription { pid=Pid, mon=Mon, name=Name, fields=Fs },
+ SList = [S | State#state.sub_list],
+ case proplists:get_bool(flush, Options) of
+ false ->
+ {reply, {ok,Mon}, State#state { sub_list = SList }};
+ true ->
+ lists:foreach(
+ fun(L) ->
+ As = dict:to_list(L#link.attr),
+ update_attrs(L#link.name, link, As, dict:new(), [S])
+ end, State#state.link_list),
+ lists:foreach(
+ fun(Y) ->
+ As = dict:to_list(Y#addr.attr),
+ update_attrs(Y#addr.name, addr, As, dict:new(), [S])
+ end, State#state.addr_list),
+ {reply, {ok,Mon}, State#state { sub_list = SList }}
+ end;
+handle_call({unsubscribe,Ref}, _From, State) ->
+ case lists:keytake(Ref, #subscription.mon, State#state.sub_list) of
+ false ->
+ {reply,ok,State};
+ {value,_S,SubList} ->
+ erlang:demonitor(Ref),
+ {reply,ok,State#state { sub_list=SubList }}
+ end;
+handle_call({invalidate,Name,Fields},_From,State) ->
+ case lists:keytake(Name, #link.name, State#state.link_list) of
+ false -> {reply, {error,enoent}, State};
+ {value,L,Ls} ->
+ Attr = lists:foldl(
+ fun(F,D) when is_atom(F) ->
+ dict:erase(F, D)
+ end, L#link.attr, Fields),
+ L1 = L#link { attr = Attr },
+ {reply, ok, State#state { link_list = [L1|Ls] } }
+ end;
+
+handle_call(Req={get,_What,_Fam,_Flags,_Attrs}, From, State) ->
+ ?debug("handle_call: GET: ~p", [Req]),
+ State1 = enq_request(Req, From, State),
+ State2 = dispatch_command(State1),
+ {noreply, State2};
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling cast messages
+%%
+%% @spec handle_cast(Msg, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Handling all non call/cast messages
+%%
+%% @spec handle_info(Info, State) -> {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State}
+%% @end
+%%--------------------------------------------------------------------
+
+handle_info(_Info={nl_data,Port,Data},State) when Port =:= State#state.port ->
+ try netlink_codec:decode(Data,[]) of
+ MsgList ->
+ %% FIXME: the messages should be delivered one by one from
+ %% the driver so the decoding could simplified.
+ State1 =
+ lists:foldl(
+ fun(Msg,StateI) ->
+ ?debug("handle_info: msg=~p", [Msg]),
+ _Hdr = Msg#nlmsg.hdr,
+ MsgData = Msg#nlmsg.data,
+ handle_nlmsg(MsgData, StateI)
+ end, State, MsgList),
+ {noreply, State1}
+ catch
+ error:_ ->
+ ?error("netlink: handle_info: Crash: ~p",
+ [erlang:get_stacktrace()]),
+ {noreply, State}
+ end;
+
+handle_info({'DOWN',Ref,process,Pid,Reason}, State) ->
+ case lists:keytake(Ref, #subscription.mon, State#state.sub_list) of
+ false ->
+ {noreply,State};
+ {value,_S,SubList} ->
+ ?debug("subscription from pid ~p deleted reason=~p",
+ [Pid, Reason]),
+ {noreply,State#state { sub_list=SubList }}
+ end;
+handle_info({timeout,Tmr,request_timeout}, State) ->
+ R = State#state.request,
+ if R#request.tmr =:= Tmr ->
+ ?debug("Timeout: ref current", []),
+ gen_server:reply(R#request.from, {error,timeout}),
+ State1 = State#state { request = undefined },
+ {noreply, dispatch_command(State1)};
+ true ->
+ case lists:keytake(Tmr, #request.tmr, State#state.request_queue) of
+ false ->
+ ?debug("Timeout: ref not found", []),
+ {noreply, State};
+ {value,#request { from = From},Q} ->
+ ?debug("Timeout: ref in queue", []),
+ gen_server:reply(From, {error,timeout}),
+ State1 = State#state { request_queue = Q },
+ {noreply,dispatch_command(State1)}
+ end
+ end;
+handle_info({Tag, Reply}, State) when is_reference(Tag) ->
+ ?debug("INFO: SELF Reply=~p", [Reply]),
+ {noreply, State};
+handle_info(_Info, State) ->
+ ?debug("INFO: ~p", [_Info]),
+ {noreply, State}.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% This function is called by a gen_server when it is about to
+%% terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_server terminates
+%% with Reason. The return value is ignored.
+%%
+%% @spec terminate(Reason, State) -> void()
+%% @end
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% @private
+%% @doc
+%% Convert process state when code is changed
+%%
+%% @spec code_change(OldVsn, State, Extra) -> {ok, NewState}
+%% @end
+%%--------------------------------------------------------------------
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+%%%===================================================================
+%%% Internal functions
+%%%===================================================================
+
+enq_request(Call, From, State) ->
+ Tmr = erlang:start_timer(?REQUEST_TMO, self(), request_timeout),
+ R = #request { tmr = Tmr,
+ call = Call,
+ from = From
+ },
+ Q = State#state.request_queue ++ [R],
+ State#state { request_queue = Q }.
+
+dispatch_command(State) when State#state.request =:= undefined ->
+ case State#state.request_queue of
+ [R=#request { call = {get,What,Fam,Flags,Attrs} } | Q ] ->
+ R1 = update_timer(R),
+ State1 = State#state { request_queue = Q, request = R1 },
+ ?debug("dispatch_command: ~p", [R1]),
+ get_command(What,Fam,Flags,Attrs,State1);
+ [R=#request { call = noop } | Q ] ->
+ R1 = update_timer(R),
+ State1 = State#state { request_queue = Q, request = R1 },
+ ?debug("dispatch_command: ~p", [R1]),
+ State1; %% let it timeout
+ [] ->
+ State
+ end;
+dispatch_command(State) ->
+ State.
+
+update_timer(R = #request { tmr = {relative,Tmo} })
+ when is_integer(Tmo), Tmo >= 0 ->
+ Tmr = erlang:start_timer(Tmo, self(), request_timeout),
+ R#request { tmr = Tmr };
+update_timer(R = #request { tmr = Tmr }) when is_reference(Tmr) ->
+ R.
+
+update_sndbuf(Port, Min) ->
+ case netlink_drv:get_sndbuf(Port) of
+ {ok,Size} when Size >= Min ->
+ {ok,Size};
+ {ok,_Size} ->
+ netlink_drv:set_sndbuf(Port, Min),
+ netlink_drv:get_sndbuf(Port);
+ Err -> Err
+ end.
+
+
+update_rcvbuf(Port, Min) ->
+ case netlink_drv:get_rcvbuf(Port) of
+ {ok,Size} when Size >= Min ->
+ {ok,Size};
+ {ok,_Size} ->
+ netlink_drv:set_rcvbuf(Port, Min),
+ netlink_drv:get_rcvbuf(Port);
+ Err -> Err
+ end.
+
+get_command(link,Fam,Flags,Attrs,State) ->
+ Seq = State#state.o_seq,
+ Get = #getlink{family=Fam,arphrd=ether,index=0,
+ flags=[], change=[], attributes=Attrs},
+ Hdr = #nlmsghdr { type = getlink,
+ flags = Flags,
+ seq = Seq,
+ pid = State#state.ospid },
+ Request = netlink_codec:encode(Hdr,Get),
+ netlink_drv:send(State#state.port, Request),
+ State#state { o_seq = (Seq+1) band 16#ffffffff };
+get_command(addr,Fam,Flags,Attrs,State) ->
+ Seq = State#state.o_seq,
+ Get = #getaddr{family=Fam,prefixlen=0,flags=[],scope=0,
+ index=0,attributes=Attrs},
+ Hdr = #nlmsghdr { type=getaddr,
+ flags=Flags,
+ seq=Seq,
+ pid=State#state.ospid },
+ Request = netlink_codec:encode(Hdr,Get),
+ netlink_drv:send(State#state.port, Request),
+ State#state { o_seq = (Seq+1) band 16#ffffffff}.
+
+handle_nlmsg(RTM=#newlink{family=_Fam,index=Index,flags=Fs,change=Cs,
+ attributes=As}, State) ->
+ ?debug("RTM = ~p", [RTM]),
+ Name = proplists:get_value(ifname, As, ""),
+ As1 = [{index,Index},{flags,Fs},{change,Cs}|As],
+ case lists:keytake(Index, #link.index, State#state.link_list) of
+ false ->
+ Attr = update_attrs(Name, link, As1, dict:new(), State#state.sub_list),
+ L = #link { index = Index, name = Name, attr = Attr },
+ Ls = [L|State#state.link_list],
+ State#state { link_list = Ls };
+ {value,L,Ls} ->
+ Attr = update_attrs(Name, link, As1, L#link.attr, State#state.sub_list),
+ L1 = L#link { name = Name, attr = Attr },
+ State#state { link_list = [L1|Ls] }
+ end;
+handle_nlmsg(RTM=#dellink{family=_Fam,index=Index,flags=_Fs,change=_Cs,
+ attributes=As}, State) ->
+ ?debug("RTM = ~p\n", [RTM]),
+ Name = proplists:get_value(ifname, As, ""),
+ %% does this delete the link?
+ case lists:keytake(Index, #link.index, State#state.link_list) of
+ false ->
+ ?warning("Warning link index=~w not found", [Index]),
+ State;
+ {value,L,Ls} ->
+ As1 = dict:to_list(L#link.attr),
+ update_attrs(Name, link, As1, undefined, State#state.sub_list),
+ State#state { link_list = Ls }
+ end;
+handle_nlmsg(RTM=#newaddr { family=Fam, prefixlen=Prefixlen,
+ flags=Flags, scope=Scope,
+ index=Index, attributes=As },
+ State) ->
+ ?debug("RTM = ~p", [RTM]),
+ Addr = proplists:get_value(address, As, {}),
+ Name = proplists:get_value(label, As, ""),
+ As1 = [{family,Fam},{prefixlen,Prefixlen},{flags,Flags},
+ {scope,Scope},{index,Index} | As],
+ case lists:keymember(Index, #link.index, State#state.link_list) of
+ false ->
+ ?warning("link index ~p does not exist", [Index]);
+ true ->
+ ok
+ end,
+ case lists:keytake(Addr, #addr.addr, State#state.addr_list) of
+ false ->
+ Attrs = update_attrs(Name,addr,As1,dict:new(),State#state.sub_list),
+ Y = #addr { addr=Addr, name = Name, index=Index, attr=Attrs },
+ Ys = [Y|State#state.addr_list],
+ State#state { addr_list = Ys };
+ {value,Y,Ys} ->
+ Attr = update_attrs(Name,addr,As1,Y#addr.attr,State#state.sub_list),
+ Y1 = Y#addr { index=Index, name=Name, attr = Attr },
+ State#state { addr_list = [Y1|Ys] }
+ end;
+
+handle_nlmsg(RTM=#deladdr { family=_Fam, index=_Index, attributes=As },
+ State) ->
+ ?debug("RTM = ~p", [RTM]),
+ Addr = proplists:get_value(address, As, {}),
+ Name = proplists:get_value(label, As, ""),
+ case lists:keytake(Addr, #addr.addr, State#state.addr_list) of
+ false ->
+ ?warning("Warning addr=~s not found", [Addr]),
+ State;
+ {value,Y,Ys} ->
+ As1 = dict:to_list(Y#addr.attr),
+ update_attrs(Name, addr, As1, undefined, State#state.sub_list),
+ State#state { addr_list = Ys }
+ end;
+handle_nlmsg(#done { }, State) ->
+ case State#state.request of
+ undefined ->
+ dispatch_command(State);
+ #request { tmr = Tmr, from = From, reply = Reply } ->
+ ?debug("handle_nlmsg: DONE: ~p",
+ [State#state.request]),
+ erlang:cancel_timer(Tmr),
+ gen_server:reply(From, Reply),
+ State1 = State#state { request = undefined },
+ dispatch_command(State1)
+ end;
+handle_nlmsg(Err=#error { errno=Err }, State) ->
+ ?debug("handle_nlmsg: ERROR: ~p", [State#state.request]),
+ case State#state.request of
+ undefined ->
+ dispatch_command(State);
+ #request { tmr = Tmr, from = From } ->
+ ?debug("handle_nlmsg: DONE: ~p",
+ [State#state.request]),
+ erlang:cancel_timer(Tmr),
+ %% fixme: convert errno to posix error (netlink.inc?)
+ gen_server:reply(From, {error,Err}),
+ State1 = State#state { request = undefined },
+ dispatch_command(State1)
+ end;
+
+handle_nlmsg(RTM, State) ->
+ ?debug("netlink: handle_nlmsg, ignore ~p", [RTM]),
+ State.
+
+%% update attributes form interface "Name"
+%% From to To Type is either link | addr
+update_attrs(Name,Type,As,undefined,Subs) ->
+ lists:foreach(
+ fun({K,Vold}) ->
+ send_event(Name,Type,K,Vold,undefined,Subs)
+ end, As),
+ undefined;
+update_attrs(Name,Type,As,To,Subs) ->
+ lists:foldl(
+ fun({K,Vnew},D) ->
+ case dict:find(K,D) of
+ error ->
+ send_event(Name,Type,K,undefined,Vnew,Subs),
+ dict:store(K,Vnew,D);
+ {ok,Vnew} -> D; %% already exist
+ {ok,Vold} ->
+ send_event(Name,Type,K,Vold,Vnew,Subs),
+ dict:store(K,Vnew,D)
+ end
+ end, To, As).
+
+
+send_event(Name,Type,Field,Old,New,[S|SList]) when
+ S#subscription.name =:= Name; S#subscription.name =:= "" ->
+ case S#subscription.fields =:= all orelse
+ S#subscription.fields =:= Type orelse
+ lists:member(Field,S#subscription.fields) orelse
+ lists:member({Type,Field},S#subscription.fields) of
+ true ->
+ S#subscription.pid ! {netlink,S#subscription.mon,
+ Name,Field,Old,New},
+ send_event(Name,Type,Field,Old,New,SList);
+ false ->
+ send_event(Name,Type,Field,Old,New,SList)
+ end;
+send_event(Name,Type,Field,Old,New,[_|SList]) ->
+ send_event(Name,Type,Field,Old,New,SList);
+send_event(_Name,_Type,_Field,_Old,_New,[]) ->
+ ok.
+
+
+match(Y,L,[{Field,Value}|Match]) when is_atom(Field) ->
+ case find2(Field,Y,L) of
+ {ok,Value} -> match(Y, L, Match);
+ _ -> false
+ end;
+match(Y,L,[{Op,Field,Value}|Match]) when is_atom(Op),is_atom(Field) ->
+ case find2(Y,L,Field) of
+ {ok,FValue} ->
+ case compare(Op,FValue,Value) of
+ true -> match(Y,L,Match);
+ false -> false
+ end;
+ error ->
+ false
+ end;
+match(_Y, _L, []) ->
+ true.
+
+find2(Key,D1,D2) ->
+ case dict:find(Key,D1) of
+ error ->
+ dict:find(Key,D2);
+ Res -> Res
+ end.
+
+
+format_link(L) ->
+ dict:fold(
+ fun(af_spec,_V,A) -> A;
+ (map,_V,A) -> A;
+ (stats,_V,A) -> A;
+ (stats64,_V,A) -> A;
+ (change,_V,A) -> A;
+ (K,V,A) ->
+ [["\n ",name_to_list(K), " ",value_to_list(K,V),";"]|A]
+ end, [], L#link.attr).
+
+format_addr(Y) ->
+ ["\n", " addr {",
+ dict:fold(
+ fun(cacheinfo,_V,A) -> A;
+ (K,V,A) ->
+ [[" ",name_to_list(K), " ",value_to_list(K,V),";"]|A]
+ end, [], Y#addr.attr), "}"].
+
+name_to_list(K) when is_atom(K) ->
+ atom_to_list(K);
+name_to_list(K) when is_integer(K) ->
+ integer_to_list(K).
+
+
+value_to_list(local,V) -> format_a(V);
+value_to_list(address,V) -> format_a(V);
+value_to_list(broadcast,V) -> format_a(V);
+value_to_list(multicast,V) -> format_a(V);
+value_to_list(anycast,V) -> format_a(V);
+value_to_list(_, V) -> io_lib:format("~p", [V]).
+
+format_a(undefined) -> "";
+format_a(A) when is_tuple(A), tuple_size(A) =:= 6 ->
+ io_lib:format("~2.16.0b:~2.16.0b:~2.16.0b:~2.16.0b:~2.16.0b:~2.16.0b",
+ tuple_to_list(A));
+format_a(A) when is_tuple(A), tuple_size(A) =:= 4 ->
+ inet_parse:ntoa(A);
+format_a(A) when is_tuple(A), tuple_size(A) =:= 8 ->
+ inet_parse:ntoa(A).
+
+compare('==',A,B) -> A == B;
+compare('=:=',A,B) -> A =:= B;
+compare('<' ,A,B) -> A < B;
+compare('=<' ,A,B) -> A =< B;
+compare('>' ,A,B) -> A > B;
+compare('>=' ,A,B) -> A >= B;
+compare('/=' ,A,B) -> A /= B;
+compare('=/=' ,A,B) -> A =/= B;
+compare(_,_,_) -> false.
diff --git a/deps/netlink/src/netlink.hrl b/deps/netlink/src/netlink.hrl
new file mode 100644
index 0000000..e03da66
--- /dev/null
+++ b/deps/netlink/src/netlink.hrl
@@ -0,0 +1,64 @@
+
+%% netlink protocols
+-define(NETLINK_ROUTE, 0). %% Routing/device hook
+-define(NETLINK_UNUSED, 1). %% Unused number
+-define(NETLINK_USERSOCK, 2). %% Reserved for user mode socket protocols
+-define(NETLINK_FIREWALL, 3). %% Unused number, formerly ip_queue
+-define(NETLINK_SOCK_DIAG, 4). %% socket monitoring
+-define(NETLINK_NFLOG, 5). %% netfilter/iptables ULOG */
+-define(NETLINK_XFRM, 6). %% ipsec */
+-define(NETLINK_SELINUX, 7). %% SELinux event notifications */
+-define(NETLINK_ISCSI, 8). %% Open-iSCSI */
+-define(NETLINK_AUDIT, 9). %% auditing */
+-define(NETLINK_FIB_LOOKUP, 10).
+-define(NETLINK_CONNECTOR, 11).
+-define(NETLINK_NETFILTER, 12). %% netfilter subsystem
+-define(NETLINK_IP6_FW, 13).
+-define(NETLINK_DNRTMSG, 14). %% DECnet routing messages
+-define(NETLINK_KOBJECT_UEVENT, 15). %% Kernel messages to userspace
+-define(NETLINK_GENERIC, 16).
+%% leave room for NETLINK_DM (DM Events)
+-define(NETLINK_SCSITRANSPORT, 18). %% SCSI Transports
+-define(NETLINK_ECRYPTFS, 19).
+-define(NETLINK_RDMA, 20).
+-define(NETLINK_CRYPTO, 21). %% Crypto layer */
+-define(NETLINK_INET_DIAG, ?NETLINK_SOCK_DIAG).
+
+-define(NFNLGRP_NONE, 0).
+-define(NFNLGRP_CONNTRACK_NEW, 1).
+-define(NFNLGRP_CONNTRACK_UPDATE, 2).
+-define(NFNLGRP_CONNTRACK_DESTROY, 3).
+-define(NFNLGRP_CONNTRACK_EXP_NEW, 4).
+-define(NFNLGRP_CONNTRACK_EXP_UPDATE, 5).
+-define(NFNLGRP_CONNTRACK_EXP_DESTROY, 6).
+
+-define(RTNLGRP_NONE, 0).
+-define(RTNLGRP_LINK, 1).
+-define(RTNLGRP_NOTIFY, 2).
+-define(RTNLGRP_NEIGH, 3).
+-define(RTNLGRP_TC, 4).
+-define(RTNLGRP_IPV4_IFADDR, 5).
+-define(RTNLGRP_IPV4_MROUTE, 6).
+-define(RTNLGRP_IPV4_ROUTE, 7).
+-define(RTNLGRP_IPV4_RULE, 8).
+-define(RTNLGRP_IPV6_IFADDR, 9).
+-define(RTNLGRP_IPV6_MROUTE, 10).
+-define(RTNLGRP_IPV6_ROUTE, 11).
+-define(RTNLGRP_IPV6_IFINFO, 12).
+-define(RTNLGRP_DECnet_IFADDR, 13).
+-define(RTNLGRP_NOP2, 14).
+-define(RTNLGRP_DECnet_ROUTE, 15).
+-define(RTNLGRP_DECnet_RULE, 16).
+-define(RTNLGRP_NOP4, 17).
+-define(RTNLGRP_IPV6_PREFIX, 18).
+-define(RTNLGRP_IPV6_RULE, 19).
+-define(RTNLGRP_ND_USEROPT, 20).
+-define(RTNLGRP_PHONET_IFADDR, 21).
+-define(RTNLGRP_PHONET_ROUTE, 22).
+-define(RTNLGRL_DCB, 23).
+
+-record(nlmsg,
+ {
+ hdr,
+ data
+ }).
diff --git a/deps/netlink/src/netlink.inc b/deps/netlink/src/netlink.inc
new file mode 100644
index 0000000..3d76d8d
--- /dev/null
+++ b/deps/netlink/src/netlink.inc
@@ -0,0 +1,981 @@
+%% -*- erlang -*-
+%%
+%% nlink data definitions
+%%
+{define, 'NLMSG_NOOP', 1}.
+{define, 'NLMSG_ERROR', 2}.
+{define, 'NLMSG_DONE', 3}.
+{define, 'NLMSG_OVERRUN', 4}.
+
+{define, 'RTM_NEWLINK', 16}.
+{define, 'RTM_DELLINK', 17}.
+{define, 'RTM_GETLINK', 18}.
+{define, 'RTM_SETLINK', 19}.
+{define, 'RTM_NEWADDR', 20}.
+{define, 'RTM_DELADDR', 21}.
+{define, 'RTM_GETADDR', 22}.
+{define, 'RTM_NEWROUTE', 24}.
+{define, 'RTM_DELROUTE', 25}.
+{define, 'RTM_GETROUTE', 26}.
+{define, 'RTM_NEWNEIGH', 28}.
+{define, 'RTM_DELNEIGH', 29}.
+{define, 'RTM_GETNEIGH', 30}.
+{define, 'RTM_NEWRULE', 32}.
+{define, 'RTM_DELRULE', 33}.
+{define, 'RTM_GETRULE', 34}.
+{define, 'RTM_NEWQDISC', 36}.
+{define, 'RTM_DELQDISC', 37}.
+{define, 'RTM_GETQDISC', 38}.
+{define, 'RTM_NEWTCLASS', 40}.
+{define, 'RTM_DELTCLASS', 41}.
+{define, 'RTM_GETTCLASS', 42}.
+{define, 'RTM_NEWTFILTER', 44}.
+{define, 'RTM_DELTFILTER', 45}.
+{define, 'RTM_GETTFILTER', 46}.
+{define, 'RTM_NEWACTION', 48}.
+{define, 'RTM_DELACTION', 49}.
+{define, 'RTM_GETACTION', 50}.
+{define, 'RTM_NEWPREFIX', 52}.
+{define, 'RTM_GETMULTICAST', 58}.
+{define, 'RTM_GETANYCAST', 62}.
+{define, 'RTM_NEWNEIGHTBL', 64}.
+{define, 'RTM_GETNEIGHTBL', 66}.
+{define, 'RTM_SETNEIGHTBL', 67}.
+{define, 'RTM_NEWNDUSEROPT', 68}.
+{define, 'RTM_NEWADDRLABEL', 72}.
+{define, 'RTM_DELADDRLABEL', 73}.
+{define, 'RTM_GETADDRLABEL', 74}.
+{define, 'RTM_GETDCB', 78}.
+{define, 'RTM_SETDCB', 79}.
+
+{define, 'AF_UNSPEC', 0}.
+{define, 'AF_LOCAL', 1}.
+{define, 'AF_UNIX', 1}.
+{define, 'AF_FILE', 1}.
+{define, 'AF_INET', 2}.
+{define, 'AF_AX25', 3}.
+{define, 'AF_IPX', 4}.
+{define, 'AF_APPLETALK', 5}.
+{define, 'AF_NETROM', 6}.
+{define, 'AF_BRIDGE', 7}.
+{define, 'AF_ATMPVC', 8}.
+{define, 'AF_X25', 9}.
+{define, 'AF_INET6', 10}.
+{define, 'AF_ROSE', 11}.
+{define, 'AF_DECNET', 12}.
+{define, 'AF_NETBEUI', 13}.
+{define, 'AF_SECURITY', 14}.
+{define, 'AF_KEY', 15}.
+{define, 'AF_NETLINK', 16}.
+{define, 'AF_ROUTE', 16}.
+{define, 'AF_PACKET', 17}.
+{define, 'AF_ASH', 18}.
+{define, 'AF_ECONET', 19}.
+{define, 'AF_ATMSVC', 20}.
+{define, 'AF_RDS', 21}.
+{define, 'AF_SNA', 22}.
+{define, 'AF_IRDA', 23}.
+{define, 'AF_PPPOX', 24}.
+{define, 'AF_WANPIPE', 25}.
+{define, 'AF_LLC', 26}.
+{define, 'AF_CAN', 29}.
+{define, 'AF_TIPC', 30}.
+{define, 'AF_BLUETOOTH', 31}.
+{define, 'AF_IUCV', 32}.
+{define, 'AF_RXRPC', 33}.
+{define, 'AF_ISDN', 34}.
+{define, 'AF_PHONET', 35}.
+{define, 'AF_IEEE802154', 36}.
+
+{define, 'PROTO_IP', 0}.
+{define, 'PROTO_ICMP', 1}.
+{define, 'PROTO_IGMP', 2}.
+{define, 'PROTO_IPIP', 4}.
+{define, 'PROTO_TCP', 6}.
+{define, 'PROTO_EGP', 8}.
+{define, 'PROTO_PUP', 12}.
+{define, 'PROTO_UDP', 17}.
+{define, 'PROTO_IDP', 22}.
+{define, 'PROTO_TP', 29}.
+{define, 'PROTO_DCCP', 33}.
+{define, 'PROTO_IPV6', 41}.
+{define, 'PROTO_ROUTING', 43}.
+{define, 'PROTO_FRAGMENT', 44}.
+{define, 'PROTO_RSVP', 46}.
+{define, 'PROTO_GRE', 47}.
+{define, 'PROTO_ESP', 50}.
+{define, 'PROTO_AH', 51}.
+{define, 'PROTO_ICMPV6', 58}.
+{define, 'PROTO_NONE', 59}.
+{define, 'PROTO_DSTOPTS', 60}.
+{define, 'PROTO_MTP', 92}.
+{define, 'PROTO_ENCAP', 98}.
+{define, 'PROTO_PIM', 103}.
+{define, 'PROTO_COMP', 108}.
+{define, 'PROTO_SCTP', 132}.
+{define, 'PROTO_UDPLITE', 136}.
+{define, 'PROTO_RAW', 255}.
+
+{define, 'ARPHRD_NETROM', 0}. %% from KA9Q: NET/ROM pseudo
+{define, 'ARPHRD_ETHER ', 1}. %% Ethernet 10Mbps
+{define, 'ARPHRD_EETHER', 2}. %% Experimental Ethernet
+{define, 'ARPHRD_AX25', 3}. %% AX.25 Level 2
+{define, 'ARPHRD_PRONET', 4}. %% PROnet token ring
+{define, 'ARPHRD_CHAOS', 5}. %% Chaosnet
+{define, 'ARPHRD_IEEE802',6}. %% IEEE 802.2 Ethernet/TR/TB
+{define, 'ARPHRD_ARCNET', 7}. %% ARCnet
+{define, 'ARPHRD_APPLETLK', 8}. %% APPLEtalk
+{define, 'ARPHRD_DLCI', 15}. %% Frame Relay DLCI
+{define, 'ARPHRD_ATM', 19}. %% ATM
+{define, 'ARPHRD_METRICOM', 23}. %% Metricom STRIP (new IANA id)
+{define, 'ARPHRD_IEEE1394', 24}. %% IEEE 1394 IPv4 - RFC 2734
+{define, 'ARPHRD_EUI64', 27}. %% EUI-64
+{define, 'ARPHRD_INFINIBAND', 32}. %% InfiniBand
+%% Dummy types for non ARP hardware
+{define, 'ARPHRD_SLIP', 256}.
+{define, 'ARPHRD_CSLIP', 257}.
+{define, 'ARPHRD_SLIP6', 258}.
+{define, 'ARPHRD_CSLIP6', 259}.
+{define, 'ARPHRD_RSRVD', 260}. %% Notional KISS type
+{define, 'ARPHRD_ADAPT', 264}.
+{define, 'ARPHRD_ROSE', 270}.
+{define, 'ARPHRD_X25', 271}. %% CCITT X.25
+{define, 'ARPHRD_HWX25', 272}. %% Boards with X.25 in firmware
+{define, 'ARPHRD_CAN', 280}. %% Controller Area Network
+{define, 'ARPHRD_PPP', 512}.
+{define, 'ARPHRD_CISCO', 513}. %% Cisco HDLC
+{define, 'ARPHRD_HDLC', 513}.
+{define, 'ARPHRD_LAPB', 516}. %% LAPB
+{define, 'ARPHRD_DDCMP', 517}. %% Digitals DDCMP protocol
+{define, 'ARPHRD_RAWHDLC', 518}. %% Raw HDLC
+{define, 'ARPHRD_TUNNEL', 768}. %% IPIP tunnel
+{define, 'ARPHRD_TUNNEL6', 769}. %% IP6IP6 tunnel
+{define, 'ARPHRD_FRAD', 770}. %% Frame Relay Access Device
+{define, 'ARPHRD_SKIP', 771}. %% SKIP vif
+{define, 'ARPHRD_LOOPBACK', 772}. %% Loopback device
+{define, 'ARPHRD_LOCALTLK', 773}. %% Localtalk device
+{define, 'ARPHRD_FDDI', 774}. %% Fiber Distributed Data Interface
+{define, 'ARPHRD_BIF', 775}. %% AP1000 BIF
+{define, 'ARPHRD_SIT', 776}. %% sit0 device - IPv6-in-IPv4
+{define, 'ARPHRD_IPDDP', 777}. %% IP over DDP tunneller
+{define, 'ARPHRD_IPGRE', 778}. %% GRE over IP
+{define, 'ARPHRD_PIMREG', 779}. %% PIMSM register interface
+{define, 'ARPHRD_HIPPI', 780}. %% High Performance Parallel Interface
+{define, 'ARPHRD_ASH', 781}. %% Nexus 64Mbps Ash
+{define, 'ARPHRD_ECONET', 782}. %% Acorn Econet
+{define, 'ARPHRD_IRDA', 783}. %% Linux-IrDA
+%% ARP works differently on different FC media .. so
+{define, 'ARPHRD_FCPP', 784}. %% Point to point fibrechannel
+{define, 'ARPHRD_FCAL', 785}. %% Fibrechannel arbitrated loop
+{define, 'ARPHRD_FCPL', 786}. %% Fibrechannel public loop
+{define, 'ARPHRD_FCFABRIC', 787}. %% Fibrechannel fabric
+ %% 787->799 reserved for fibrechannel media types
+{define, 'ARPHRD_IEEE802_TR', 800}. %% Magic type ident for TR
+{define, 'ARPHRD_IEEE80211', 801}. %% IEEE 802.11
+{define, 'ARPHRD_IEEE80211_PRISM', 802}. %% IEEE 802.11 + Prism2 header
+{define, 'ARPHRD_IEEE80211_RADIOTAP', 803}. %% IEEE 802.11 + radiotap header
+{define, 'ARPHRD_IEEE802154', 804}.
+{define, 'ARPHRD_PHONET', 820}. %% PhoNet media type
+{define, 'ARPHRD_PHONET_PIPE', 821}. %% PhoNet pipe header
+{define, 'ARPHRD_CAIF', 822}. %% CAIF media type
+{define, 'ARPHRD_VOID', 65535}. %% Void type, nothing is known
+{define, 'ARPHRD_NONE', 65534}. %% zero header length
+
+{enum, family,
+ [
+ {unspec, 'AF_UNSPEC'},
+ {local, 'AF_LOCAL'},
+ {inet, 'AF_INET'},
+ {ax25, 'AF_AX25'},
+ {ipx, 'AF_IPX'},
+ {appletalk, 'AF_APPLETALK'},
+ {netrom, 'AF_NETROM'},
+ {bridge, 'AF_BRIDGE'},
+ {atmpvc, 'AF_ATMPVC'},
+ {x25, 'AF_X25'},
+ {inet6, 'AF_INET6'},
+ {rose, 'AF_ROSE'},
+ {decnet, 'AF_DECNET'},
+ {netbeui, 'AF_NETBEUI'},
+ {security, 'AF_SECURITY'},
+ {key, 'AF_KEY'},
+ {netlink, 'AF_NETLINK'},
+ {packet, 'AF_PACKET'},
+ {ash, 'AF_ASH'},
+ {econet, 'AF_ECONET'},
+ {atmsvc, 'AF_ATMSVC'},
+ {rds, 'AF_RDS'},
+ {sna, 'AF_SNA'},
+ {irda, 'AF_IRDA'},
+ {pppox, 'AF_PPPOX'},
+ {wanpipe, 'AF_WANPIPE'},
+ {llc, 'AF_LLC'},
+ {can, 'AF_CAN'},
+ {tipc, 'AF_TIPC'},
+ {bluetooth, 'AF_BLUETOOTH'},
+ {iucv, 'AF_IUCV'},
+ {rxrpc, 'AF_RXRPC'},
+ {isdn, 'AF_ISDN'},
+ {phonet, 'AF_PHONET'},
+ {ieee802154, 'AF_IEEE802154'}
+]}.
+
+{enum, protocol,
+ [
+ {ip, 'PROTO_IP'},
+ {icmp, 'PROTO_ICMP'},
+ {igmp, 'PROTO_IGMP'},
+ {ipip, 'PROTO_IPIP'},
+ {tcp, 'PROTO_TCP'},
+ {egp, 'PROTO_EGP'},
+ {pup, 'PROTO_PUP'},
+ {udp, 'PROTO_UDP'},
+ {idp, 'PROTO_IDP'},
+ {tp, 'PROTO_TP'},
+ {dccp, 'PROTO_DCCP'},
+ {ipv6, 'PROTO_IPV6'},
+ {routing, 'PROTO_ROUTING'},
+ {fragment, 'PROTO_FRAGMENT'},
+ {rsvp, 'PROTO_RSVP'},
+ {gre, 'PROTO_GRE'},
+ {esp, 'PROTO_ESP'},
+ {ah, 'PROTO_AH'},
+ {icmpv6, 'PROTO_ICMPV6'},
+ {none, 'PROTO_NONE'},
+ {dstopts, 'PROTO_DSTOPTS'},
+ {mtp, 'PROTO_MTP'},
+ {encap, 'PROTO_ENCAP'},
+ {pim, 'PROTO_PIM'},
+ {comp, 'PROTO_COMP'},
+ {sctp, 'PROTO_SCTP'},
+ {udplite, 'PROTO_UDPLITE'},
+ {raw, 'PROTO_RAW'}
+]}.
+
+{enum, arphrd,
+ [
+ {netrom, 'ARPHRD_NETROM'},
+ {ether , 'ARPHRD_ETHER '},
+ {eether, 'ARPHRD_EETHER'},
+ {ax25, 'ARPHRD_AX25'},
+ {pronet, 'ARPHRD_PRONET'},
+ {chaos, 'ARPHRD_CHAOS'},
+ {ieee802, 'ARPHRD_IEEE802'},
+ {arcnet, 'ARPHRD_ARCNET'},
+ {appletlk, 'ARPHRD_APPLETLK'},
+ {dlci, 'ARPHRD_DLCI'},
+ {atm, 'ARPHRD_ATM'},
+ {metricom, 'ARPHRD_METRICOM'},
+ {ieee1394, 'ARPHRD_IEEE1394'},
+ {eui64, 'ARPHRD_EUI64'},
+ {infiniband, 'ARPHRD_INFINIBAND'},
+ {slip, 'ARPHRD_SLIP'},
+ {cslip, 'ARPHRD_CSLIP'},
+ {slip6, 'ARPHRD_SLIP6'},
+ {cslip6, 'ARPHRD_CSLIP6'},
+ {rsrvd, 'ARPHRD_RSRVD'},
+ {adapt, 'ARPHRD_ADAPT'},
+ {rose, 'ARPHRD_ROSE'},
+ {x25, 'ARPHRD_X25'},
+ {hwx25, 'ARPHRD_HWX25'},
+ {can, 'ARPHRD_CAN'},
+ {ppp, 'ARPHRD_PPP'},
+ {hdlc, 'ARPHRD_HDLC'},
+ {lapb, 'ARPHRD_LAPB'},
+ {ddcmp, 'ARPHRD_DDCMP'},
+ {rawhdlc, 'ARPHRD_RAWHDLC'},
+ {tunnel, 'ARPHRD_TUNNEL'},
+ {tunnel6, 'ARPHRD_TUNNEL6'},
+ {frad, 'ARPHRD_FRAD'},
+ {skip, 'ARPHRD_SKIP'},
+ {loopback, 'ARPHRD_LOOPBACK'},
+ {localtlk, 'ARPHRD_LOCALTLK'},
+ {fddi, 'ARPHRD_FDDI'},
+ {bif, 'ARPHRD_BIF'},
+ {sit, 'ARPHRD_SIT'},
+ {ipddp, 'ARPHRD_IPDDP'},
+ {ipgre, 'ARPHRD_IPGRE'},
+ {pimreg, 'ARPHRD_PIMREG'},
+ {hippi, 'ARPHRD_HIPPI'},
+ {ash, 'ARPHRD_ASH'},
+ {econet, 'ARPHRD_ECONET'},
+ {irda, 'ARPHRD_IRDA'},
+ {fcpp, 'ARPHRD_FCPP'},
+ {fcal, 'ARPHRD_FCAL'},
+ {fcpl, 'ARPHRD_FCPL'},
+ {fcfabric, 'ARPHRD_FCFABRIC'},
+ {ieee802_tr, 'ARPHRD_IEEE802_TR'},
+ {ieee80211, 'ARPHRD_IEEE80211'},
+ {ieee80211_prism, 'ARPHRD_IEEE80211_PRISM'},
+ {ieee80211_radiotap, 'ARPHRD_IEEE80211_RADIOTAP'},
+ {ieee802154, 'ARPHRD_IEEE802154'},
+ {phonet, 'ARPHRD_PHONET'},
+ {phonet_pipe, 'ARPHRD_PHONET_PIPE'},
+ {caif, 'ARPHRD_CAIF'},
+ {void, 'ARPHRD_VOID'},
+ {none, 'ARPHRD_NONE'}
+]}.
+
+
+{enum, nlmsg_type,
+ [
+ {noop, 'NLMSG_NOOP'},
+ {error, 'NLMSG_ERROR'},
+ {done, 'NLMSG_DONE'},
+ {overrun, 'NLMSG_OVERRUN'},
+ {newlink, 'RTM_NEWLINK'},
+ {dellink, 'RTM_DELLINK'},
+ {getlink, 'RTM_GETLINK'},
+ {setlink, 'RTM_SETLINK'},
+ {newaddr, 'RTM_NEWADDR'},
+ {deladdr, 'RTM_DELADDR'},
+ {getaddr, 'RTM_GETADDR'},
+ {newroute, 'RTM_NEWROUTE'},
+ {delroute, 'RTM_DELROUTE'},
+ {getroute, 'RTM_GETROUTE'},
+ {newneigh, 'RTM_NEWNEIGH'},
+ {delneigh, 'RTM_DELNEIGH'},
+ {getneigh, 'RTM_GETNEIGH'},
+ {newrule, 'RTM_NEWRULE'},
+ {delrule, 'RTM_DELRULE'},
+ {getrule, 'RTM_GETRULE'},
+ {newqdisc, 'RTM_NEWQDISC'},
+ {delqdisc, 'RTM_DELQDISC'},
+ {getqdisc, 'RTM_GETQDISC'},
+ {newtclass, 'RTM_NEWTCLASS'},
+ {deltclass, 'RTM_DELTCLASS'},
+ {gettclass, 'RTM_GETTCLASS'},
+ {newtfilter, 'RTM_NEWTFILTER'},
+ {deltfilter, 'RTM_DELTFILTER'},
+ {gettfilter, 'RTM_GETTFILTER'},
+ {newaction, 'RTM_NEWACTION'},
+ {delaction, 'RTM_DELACTION'},
+ {getaction, 'RTM_GETACTION'},
+ {newprefix, 'RTM_NEWPREFIX'},
+ {getmulticast, 'RTM_GETMULTICAST'},
+ {getanycast, 'RTM_GETANYCAST'},
+ {newneightbl, 'RTM_NEWNEIGHTBL'},
+ {getneightbl, 'RTM_GETNEIGHTBL'},
+ {setneightbl, 'RTM_SETNEIGHTBL'},
+ {newnduseropt, 'RTM_NEWNDUSEROPT'},
+ {newaddrlabel, 'RTM_NEWADDRLABEL'},
+ {deladdrlabel, 'RTM_DELADDRLABEL'},
+ {getaddrlabel, 'RTM_GETADDRLABEL'},
+ {getdcb, 'RTM_GETDCB'},
+ {setdcb, 'RTM_SETDCB'}
+ ]}.
+
+%% enumeration of flag numbers (up=0, broadcast=1 ...)
+%% used as flag then up = (1 << 0) broadcast = (1 << 1)
+{enum, iff_flags,
+ [
+ up,
+ broadcast,
+ debug,
+ loopback,
+ pointopoint,
+ notrailers,
+ running,
+ noarp,
+ promisc,
+ allmulti,
+ master,
+ slave,
+ multicast,
+ portsel,
+ automedia,
+ ynamic,
+ lower_up,
+ dormant,
+ echo
+ ]}.
+
+{enum, nlm_flags,
+ [
+ {request, 0},
+ {multi, 1},
+ {ack, 2},
+ {echo, 3}
+ ]}.
+
+{enum, nlm_get_flags,
+ [
+ {request, 0},
+ {multi, 1},
+ {ack, 2},
+ {echo, 3},
+ {root, 8},
+ {match, 9},
+ {atomic, 10}
+ ]}.
+
+{enum, nlm_new_flags,
+ [
+ {request, 0},
+ {multi, 1},
+ {ack, 2},
+ {echo, 3},
+ {replace, 8},
+ {excl, 9},
+ {create, 10},
+ {append, 11}
+ ]}.
+
+{define, 'IPCTNL_MSG_CT_NEW', 0}.
+{define, 'IPCTNL_MSG_CT_GET', 1}.
+{define, 'IPCTNL_MSG_CT_DELETE', 2}.
+{define, 'IPCTNL_MSG_CT_GET_CTRZERO', 3}.
+
+{enum, ctm_msgtype_netlink,
+ [
+ {noop, 'NLMSG_NOOP'},
+ {error, 'NLMSG_ERROR'},
+ {done, 'NLMSG_DONE'},
+ {overrun, 'NLMSG_OVERRUN'}
+ ]}.
+
+{define, 'IPCTNL_MSG_EXP_NEW', 0}.
+{define, 'IPCTNL_MSG_EXP_GET', 1}.
+{define, 'IPCTNL_MSG_EXP_DELETE', 2}.
+
+{enum, ctm_msgtype_ctnetlink,
+ [
+ {new, 'IPCTNL_MSG_CT_NEW'},
+ {get, 'IPCTNL_MSG_CT_GET'},
+ {delete, 'IPCTNL_MSG_CT_DELETE'},
+ {get_ctrzero, 'IPCTNL_MSG_CT_GET_CTRZERO'}
+ ]}.
+
+{enum, ctm_msgtype_ctnetlink_exp,
+ [
+ {new, 'IPCTNL_MSG_EXP_NEW'},
+ {get, 'IPCTNL_MSG_EXP_GET'},
+ {delete, 'IPCTNL_MSG_EXP_DELETE'}
+ ]}.
+
+{attribute, ctnetlink_tuple_ip,
+ [
+ {unspec, binary_t},
+ {v4_src, ipv4_addr_t},
+ {v4_dst, ipv4_addr_t},
+ {v6_src, ipv6_addr_t},
+ {v6_dst, ipv6_addr_t}
+ ]}.
+
+{attribute, ctnetlink_tuple_proto,
+ [
+ {unspec, binary_t},
+ {num, {enum,uint8_t,protocol}},
+ {src_port, uint16_t},
+ {dst_port, uint16_t},
+ {icmp_id, uint16_t},
+ {icmp_type, uint8_t},
+ {icmp_code, uint8_t},
+ {icmpv6_id, binary_t},
+ {icmpv6_type, binary_t},
+ {icmpv6_code, binary_t}
+ ]}.
+
+{attribute, ctnetlink_tuple,
+ [
+ {unspec, binary_t},
+ {ip, ctnetlink_tuple_ip},
+ {proto, ctnetlink_tuple_proto}
+ ]}.
+
+{attribute, ctnetlink_nat_seq_adj,
+ [
+ {unspec, binary_t},
+ {correction_pos, uint32_t},
+ {offset_before, uint32_t},
+ {offset_after, uint32_t}
+ ]}.
+
+{enum, ctnetlink_protoinfo_tcp_state,
+ [
+ none,
+ syn_sent,
+ syn_recv,
+ established,
+ fin_wait,
+ close_wait,
+ last_ack,
+ time_wait,
+ close,
+ listen,
+ max,
+ ignore
+ ]}.
+
+{attribute, ctnetlink_protoinfo_tcp,
+ [
+ {unspec, binary_t},
+ {state, {enum,uint8_t,ctnetlink_protoinfo_tcp_state}},
+ {wscale_original, uint8_t},
+ {wscale_reply, uint8_t},
+ {flags_original, uint16_t},
+ {flags_reply, uint16_t}
+ ]}.
+
+
+{attribute, ctnetlink_protoinfo,
+ [
+ {unspec, binary_t},
+ {tcp, ctnetlink_protoinfo_tcp},
+ {dccp, binary_t}, %% ctnetlink_protoinfo_dccp},
+ {sctp, binary_t} %% ctnetlink_protoinfo_sctp}
+ ]}.
+
+{enum, ctnetlink_status,
+ [
+ expected,
+ seen_reply,
+ assured,
+ confirmed,
+ src_nat,
+ dst_nat,
+ seq_adjust,
+ src_nat_done,
+ dst_nat_done,
+ dying,
+ fixed_timeout
+ ]}.
+
+{attribute, ctnetlink_help,
+ [
+ {unspec, binary_t},
+ {name, string_t}
+ ]}.
+
+{attribute, ctnetlink_counters,
+ [
+ {unspec, binary_t},
+ {packets, uint64_t},
+ {bytes, uint64_t},
+ {packets32, uint32_t},
+ {bytes32, uint32_t}
+ ]}.
+
+{attribute, ctnetlink_timestamp,
+ [
+ {unspec, binary_t},
+ {start, uint64_t},
+ {stop, uint64_t}
+ ]}.
+
+{attribute, ctnetlink_exp_tuple_ip,
+ [
+ {unspec, binary_t},
+ {v4_src, ipv4_addr_t},
+ {v4_dst, ipv4_addr_t},
+ {v6_src, ipv6_addr_t},
+ {v6_dst, ipv6_addr_t}
+ ]}.
+
+{attribute, ctnetlink_exp_tuple_proto,
+ [
+ {unspec, binary_t},
+ {num, {enum,uint8_t,protocol}},
+ {src_port, uint16_t},
+ {dst_port, uint16_t},
+ {icmp_id, uint16_t},
+ {icmp_type, uint8_t},
+ {icmp_code, uint8_t},
+ {icmpv6_id, binary_t},
+ {icmpv6_type, binary_t},
+ {icmpv6_code, binary_t}
+ ]}.
+
+{attribute, ctnetlink_exp_tuple,
+ [
+ {unspec, binary_t},
+ {ip, ctnetlink_exp_tuple_ip},
+ {proto, ctnetlink_exp_tuple_proto}
+ ]}.
+
+{enum, ctnetlink_exp_flags,
+ [
+ permanent,
+ inactive,
+ userspace
+ ]}.
+
+
+{attribute, ctnetlink_exp,
+ [
+ {unspec, binary_t},
+ {master, ctnetlink_exp_tuple},
+ {tuple, ctnetlink_exp_tuple},
+ {mask, ctnetlink_exp_tuple},
+ {timeout, uint32_t},
+ {id, uint32_t},
+ {help_name, string_t},
+ {zone, uint16_t},
+ {flags, {flags,uint32_t,ctnetlink_exp_flags}}
+ ]}.
+
+
+{attribute, ctnetlink,
+ [
+ {unspec, binary_t},
+ {tuple_orig, ctnetlink_tuple},
+ {tuple_reply, ctnetlink_tuple},
+ {status, {flags,uint32_t,ctnetlink_status}},
+ {protoinfo, ctnetlink_protoinfo},
+ {help, ctnetlink_help},
+ {nat_src, binary_t},
+ {timeout, uint32_t},
+ {mark, uint32_t},
+ {counters_orig, ctnetlink_counters},
+ {counters_reply, ctnetlink_counters},
+ {use, uint32_t},
+ {id, uint32_t},
+ {nat_dst, binary_t},
+ {tuple_master, ctnetlink_tuple},
+ {nat_seq_adj_orig, ctnetlink_nat_seq_adj},
+ {nat_seq_adj_reply, ctnetlink_nat_seq_adj},
+ {secmark, uint32_t},
+ {zone, uint16_t},
+ {secctx, binary_t},
+ {timestamp, ctnetlink_timestamp}
+ ]}.
+
+
+{attribute, rtnetlink_neigh,
+ [
+ {unspec, binary_t},
+ {dst, addr_t},
+ {lladdr, ether_addr_t},
+ {cacheinfo, {array,uint32_t}},
+ {probes, uint32_t}
+ ]}.
+
+{enum, rtnetlink_rtm_type,
+ [
+ unspec,
+ unicast,
+ local,
+ broadcast,
+ anycast,
+ multicast,
+ blackhole,
+ unreachable,
+ prohibit,
+ throw,
+ nat,
+ xresolve
+ ]}.
+
+{enum, rtnetlink_rtm_protocol,
+ [
+ {unspec, 0},
+ {redirect, 1},
+ {kernel, 2},
+ {boot, 3},
+ {static, 4},
+ {gated, 8},
+ {ra, 9},
+ {mrt, 10},
+ {zebra, 11},
+ {bird, 12},
+ {dnrouted, 13},
+ {xorp, 14},
+ {ntk, 15},
+ {dhcp, 16}
+ ]}.
+
+{enum, rtnetlink_rtm_scope,
+ [
+ {universe, 0},
+ {site, 200},
+ {link, 253},
+ {host, 254},
+ {nowhere, 255}
+ ]}.
+
+%% FIXME: should be bit number?
+{enum, rtnetlink_rtm_flags,
+ [
+ {notify, 16#100},
+ {cloned, 16#200},
+ {equalize, 16#400},
+ {prefix, 16#800}
+ ]}.
+
+{enum, rtnetlink_rtm_table,
+ [
+ {unspec, 0},
+ {compat, 252},
+ {default, 253},
+ {main, 254},
+ {local, 255}
+ ]}.
+
+{attribute, rtnetlink_route_metrics,
+ [
+ {unspec, binary_t},
+ {lock, uint32_t},
+ {mtu, uint32_t},
+ {window, uint32_t},
+ {rtt, uint32_t},
+ {rttvar, uint32_t},
+ {ssthresh, uint32_t},
+ {cwnd, uint32_t},
+ {advmss, uint32_t},
+ {reordering, uint32_t},
+ {hoplimit, uint32_t},
+ {initcwnd, uint32_t},
+ {features, uint32_t},
+ {rto_min, uint32_t},
+ {initrwnd, uint32_t}
+ ]}.
+
+{attribute, rtnetlink_addr,
+ [
+ {unspec, binary_t},
+ {address, addr_t},
+ {local, addr_t},
+ {label, string_t},
+ {broadcast, addr_t},
+ {anycast, addr_t},
+ {cacheinfo, {array,uint32_t}},
+ {multicast, addr_t}
+ ]}.
+
+{enum, rtnetlink_link_operstate,
+ [
+ unknown,
+ notpresent,
+ down,
+ lowerlayerdown,
+ testing,
+ dormant,
+ up
+ ]}.
+
+{enum, rtnetlink_link_linkmode,
+ [
+ default,
+ dormant
+ ]}.
+
+{record, if_map,
+ [
+ {memstart, uint64_t},
+ {memend, uint64_t},
+ {baseaddr, uint64_t},
+ {irq, uint16_t},
+ {dma, uint8_t},
+ {port, uint8_t}
+ %% fixme: 64 padding? on 64 bit machine?
+ ]}.
+
+{attribute, rtnetlink_route,
+ [
+ {unspec, binary_t},
+ {dst, addr_t},
+ {src, addr_t},
+ {iif, uint32_t},
+ {oif, uint32_t},
+ {gateway, addr_t},
+ {priority, uint32_t},
+ {prefsrc, addr_t},
+ {metrics, {tlvs,rtnetlink_route_metrics}},
+ {multipath, binary_t},
+ {protoinfo, binary_t},
+ {flow, uint32_t},
+ {cacheinfo, {array,uint32_t}},
+ {session, binary_t},
+ {mp_algo, binary_t},
+ {table, uint32_t}
+ ]}.
+
+{attribute, rtnetlink_link_linkinfo,
+ [
+ {unspec, binary_t},
+ {kind, string_t},
+ {data, binary_t},
+ {xstats, binary_t}
+ ]}.
+
+%% inet6?
+{enum, rtnetlink_link_protinfo_flags,
+ [
+ {rs_sent, 4},
+ {ra_rcvd, 5},
+ {ra_managed, 6},
+ {ra_othercon, 7},
+ {ready, 31}
+ ]}.
+
+%% inet6?
+{attribute, rtnetlink_link_protinfo,
+ [
+ {unspec, binary_t},
+ {flags, {flags,uint32_t,rtnetlink_link_protinfo_flags}},
+ {conf, {array,int32_t}},
+ {stats, {array,uint64_t}},
+ {mcast, binary_t},
+ {cacheinfo, {array,uint32_t}},
+ {icmp6stats, {array,uint64_t}}
+ ]}.
+
+
+{attribute, rtnetlink_link,
+ [
+ {unspec, binary_t},
+ {address, ether_addr_t},
+ {broadcast, ether_addr_t},
+ {ifname, string_t},
+ {mtu, uint32_t},
+ {link, uint32_t},
+ {qdisc, string_t},
+ {stats, {array,uint32_t}},
+ {cost, binary_t},
+ {priority, binary_t},
+ {master, binary_t},
+ {wireless, binary_t},
+ {protinfo, {tlvs,rtnetlink_link_protinfo}},
+ {txqlen, uint32_t},
+ {map, if_map},
+ {weight, binary_t},
+ {operstate, {enum,uint8_t,rtnetlink_link_operstate}},
+ {linkmode, {enum,uint8_t,rtnetlink_link_linkmode}},
+ {linkinfo, {tlvs,rtnetlink_link_linkinfo}},
+ {net_ns_pid, binary_t},
+ {ifalias, string_t},
+ {num_vf, uint32_t},
+ {vfinfo_list, binary_t},
+ {stats64, {array,uint64_t}},
+ {vf_ports, binary_t},
+ {port_self, binary_t},
+ {af_spec, binary_t},
+ {group, uint32_t}, %% Group the device belongs to
+ {net_ns_fd, binary_t},
+ {ext_mask, binary_t}, %% Extended info mask, VFs, etc
+ {promiscuity, uint32_t} %% Promiscuity count: > 0 means acts PROMISC
+
+ ] }.
+
+{attribute, rtnetlink_prefix,
+ [
+ {unspec, binary_t},
+ {address, addr_t},
+ {cacheinfo, {array,uint32_t}} %% fixme: add struct rta_cacheinfo
+ ]}.
+
+{enum, ifa_flags,
+ [
+ secondary,
+ nodad,
+ optimistic,
+ dadfailed,
+ homeaddress,
+ deprecated,
+ tentative,
+ permanent
+ ]}.
+
+{record, nlmsghdr,
+ [
+ {len, uint32_t},
+ {type, uint16_t},
+ {flags, uint16_t},
+ {seq, uint32_t},
+ {pid, uint32_t}
+ ]}.
+
+{record, ifaddrmsg,
+ [
+ {family, {enum,uint8_t,family}},
+ {prefixlen, uint8_t},
+ {flags, {flags,uint8_t,ifa_flags}},
+ {scope, uint8_t},
+ {index, uint32_t},
+ {attributes, {tlvs,rtnetlink_addr}}
+ ]}.
+
+{record, newaddr, ifaddrmsg}.
+{record, deladdr, ifaddrmsg}.
+{record, getaddr, ifaddrmsg}.
+
+{record, ifinfomsg,
+ [
+ {family, {enum,uchar_t,family}},
+ {'_', uchar_t},
+ {arphrd, {enum,ushort_t,arphrd}},
+ {index, int_t},
+ {flags, {flags,uint_t,iff_flags}},
+ {change, {flags,uint_t,iff_flags}},
+ {attributes, {tlvs,rtnetlink_link}}
+ ]}.
+
+{record, newlink, ifinfomsg}.
+{record, dellink, ifinfomsg}.
+{record, getlink, ifinfomsg}.
+
+{record, rtmsg,
+ [
+ {family, {enum,uchar_t,family}},
+ {dstlen, uchar_t},
+ {srclen, uchar_t},
+ {tos, uchar_t},
+ {table, uchar_t}, %% routing table id
+ {protocol, {enum,uchar_t,protocol}},
+ {scope, uchar_t},
+ {rtm_type, uchar_t},
+ {flags, uint_t},
+ {attributes, {tlvs, rtnetlink_route}}
+ ]}.
+
+{record, newroute, rtmsg}.
+{record, delroute, rtmsg}.
+{record, getroute, rtmsg}.
+
+{record, ndmsg,
+ [
+ {family, {enum,uint8_t,family}},
+ {'_', uint8_t},
+ {'_', uint16_t},
+ {index, uint32_t},
+ {state, uint16_t},
+ {flags, uint8_t},
+ {nmd_type, uint8_t},
+ {attributes, {tlvs, rtnetlink_neigh}}
+ ]}.
+
+{record, newneigh, ndmsg}.
+{record, delneigh, ndmsg}.
+{record, getneigh, ndmsg}.
+
+%% newrule, delrule, getrule
+%% newdisc, deldisc, getdisc
+%% newtclass, deltclass, gettclass
+%% newtfilter, deltfilter, gettfilter
+%% newaction, delaction, getaction
+%% newprefix, delprefix
+%% newneightbl, getneightbl, setneightbl
+%% newnduseropt
+%% newaddrlabel
+%% getdcb, setdcb
+
+{record, noop,
+ [
+ ]}.
+
+{record, error,
+ [
+ {errno, int_t},
+ {msg, nlmsghdr}, %% the original header
+ {data, binary_t} %% truncated data?
+ ]}.
+
+{record, done,
+ [
+ {status, uint32_t} %% ? int_t?
+ ]}.
+
+{record, overrun,
+ [
+ {status, uint32_t} %% ? int_t?
+ ]}.
diff --git a/deps/netlink/src/netlink_app.erl b/deps/netlink/src/netlink_app.erl
new file mode 100644
index 0000000..6bb292b
--- /dev/null
+++ b/deps/netlink/src/netlink_app.erl
@@ -0,0 +1,25 @@
+%%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%%
+%%% Copyright (C) 2012 Feuerlabs, Inc. All rights reserved.
+%%%
+%%% This Source Code Form is subject to the terms of the Mozilla Public
+%%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%%
+%%%---- END COPYRIGHT ---------------------------------------------------------
+-module(netlink_app).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+
+%% ===================================================================
+%% Application callbacks
+%% ===================================================================
+
+start(_StartType, _StartArgs) ->
+ netlink_sup:start_link().
+
+stop(_State) ->
+ ok.
diff --git a/deps/netlink/src/netlink_codec.erl b/deps/netlink/src/netlink_codec.erl
new file mode 100644
index 0000000..b611232
--- /dev/null
+++ b/deps/netlink/src/netlink_codec.erl
@@ -0,0 +1,214 @@
+%%% @author tony <tony@rogvall.se>
+%%% @copyright (C) 2013, tony
+%%% @doc
+%%% Encode / Decode of netlink messages
+%%% @end
+%%% Created : 21 May 2013 by tony <tony@rogvall.se>
+
+-module(netlink_codec).
+
+-export([encode_flags/2]).
+-export([decode_flags/2]).
+-export([encode_tlv/1, encode_tlv_list/1]).
+-export([decode_tlv/1, decode_tlv_list/1]).
+
+-export([decode/2]).
+-export([encode/2]).
+
+-compile(export_all).
+
+-include("netlink.hrl").
+-include("netl_codec.hrl").
+
+-define(ALIGNTO, 4).
+-define(ALIGNMASK, (?ALIGNTO-1)).
+-define(NLA_ALIGN(N), (((N)+?ALIGNMASK) band (bnot ?ALIGNMASK))).
+-define(NLA_PAD(N), ((?ALIGNTO-((N) band ?ALIGNMASK)) band
+ ?ALIGNMASK)).
+%% may need adjustment (NLA_ALIGN(sizeof(struct nlattr)))
+-define(NLA_HDRLEN, 4).
+%% -define(NLA_PAD(N), (ALIGN(N) - N)).
+
+%% prove that:
+%% ((N+3) band (bnot 3)) - N == (4 - (N band 3)) band 3
+%%
+
+encode_flags(Flags, Fun) ->
+ encode_flags(Flags, 0, Fun).
+
+encode_flags([], Mask, _Fun) -> Mask;
+encode_flags([Flag|Flags], Mask, Fun) ->
+ BitNum = Fun(Flag),
+ encode_flags(Flags, Mask+(1 bsl BitNum), Fun).
+
+
+decode_flags(Value, Fun) ->
+ decode_flags(0, Value, Fun).
+
+decode_flags(_I, 0, _Fun) -> [];
+decode_flags(I, Value, Fun) ->
+ Bit = (1 bsl I),
+ if Value band Bit =:= Bit ->
+ [Fun(I) | decode_flags(I+1, Value band (bnot Bit), Fun)];
+ true ->
+ decode_flags(I+1,Value,Fun)
+ end.
+
+decode_attr([{Ri,_Endian,Rv}|Ds], Fun) ->
+ [ Fun(Ri,Rv) | decode_attr(Ds, Fun)];
+decode_attr([], _Fun) ->
+ [].
+
+encode_tlv({Type0,Endian,Data}) ->
+ Payload = if is_list(Data) ->
+ encode_tlv_list(Data);
+ is_binary(Data) -> Data
+ end,
+ Type = if is_list(Data) ->
+ Type0 + 16#8000;
+ Endian =:= big ->
+ Type0 + 16#4000;
+ true ->
+ Type0
+ end,
+ Len = ?NLA_HDRLEN+byte_size(Payload),
+ Pad = ?NLA_PAD(Len),
+ <<Len:16/native-unsigned, Type:16/native-unsigned,
+ Payload/binary, 0:Pad/unit:8>>.
+
+encode_tlv_list(TLVs) ->
+ list_to_binary([encode_tlv(TLV) || TLV <- TLVs]).
+
+next_tlv(<<Len0:16/native-unsigned, _:16, Data/binary>>) ->
+ Len = Len0 - ?NLA_HDRLEN,
+ Pad = ?NLA_PAD(Len),
+ <<_:Len/binary, _:Pad/unit:8, Data1/binary>> = Data,
+ Data1.
+
+decode_tlv(<<Len0:16/native-unsigned, Type0:16/native-unsigned,
+ Rest/binary>>) ->
+ Len = Len0 - ?NLA_HDRLEN,
+ <<Payload:Len/binary, _/binary>> = Rest,
+ Type = Type0 band 16#3fff,
+ if Type0 band 16#8000 =:= 16#8000 ->
+ {Type, native, decode_tlv_list(Payload)};
+ Type0 band 16#4000 =:= 16#4000 ->
+ {Type, big, Payload};
+ true ->
+ {Type, native, Payload}
+ end.
+
+decode_tlv_list(<<>>) ->
+ [];
+decode_tlv_list(Data) ->
+ TLV = decode_tlv(Data),
+ Data1 = next_tlv(Data),
+ [TLV | decode_tlv_list(Data1)].
+
+
+decode(Part=
+ << Len:32/native-integer,
+ Type:16/native-integer,
+ Flags:16/native-integer,
+ Seq:32/native-integer,
+ Pid:32/native-integer,
+ Data/binary >>, Acc) ->
+ if Len >= byte_size(Part) ->
+ PayloadLen = Len - 16,
+ << Payload:PayloadLen/bytes, NextPart/binary >> = Data,
+ Msg = decode_(Type, Flags, Seq, Pid, Payload),
+ decode(NextPart, [Msg | Acc]);
+ true ->
+ decode(<<>>, [{ error, format} | Acc])
+ end;
+decode(_PadPart, Acc) ->
+ lists:reverse(Acc).
+
+decode_(Type,Flags,Seq,Pid,Payload) ->
+ MsgType = netl_codec:dec_nlmsg_type(Type),
+ FlagList = case msg_type(MsgType) of
+ new ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_new_flags/1);
+ get ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_get_flags/1);
+ _ ->
+ decode_flags(Flags, fun netl_codec:dec_nlm_flags/1)
+ end,
+ MsgPayload = apply(netl_codec,
+ list_to_atom("dec_"++atom_to_list(MsgType)),
+ [{native,Payload}]),
+ H = #nlmsghdr { type=MsgType, flags=FlagList, seq=Seq, pid=Pid },
+ #nlmsg { hdr = H, data=MsgPayload }.
+
+encode(#nlmsghdr { type=MsgType, flags=FlagList, seq=Seq, pid=Pid },
+ MsgPayload ) ->
+ Type = netl_codec:enc_nlmsg_type(MsgType),
+ Flags = case msg_type(MsgType) of
+ new ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_new_flags/1);
+ get ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_get_flags/1);
+ _ ->
+ encode_flags(FlagList, fun netl_codec:enc_nlm_flags/1)
+ end,
+ Payload = apply(netl_codec,
+ list_to_atom("enc_"++atom_to_list(MsgType)),
+ [{native,MsgPayload}]),
+ N = byte_size(Payload),
+ Pad = ?NLA_PAD(N),
+ Len = 16 + Pad + N,
+ << Len:32/native-integer,
+ Type:16/native-integer,
+ Flags:16/native-integer,
+ Seq:32/native-integer,
+ Pid:32/native-integer,
+ Payload/binary,
+ 0:Pad/unit:8 >>.
+
+msg_type(Type) ->
+ case Type of
+ noop -> misc;
+ error -> misc;
+ done -> misc;
+ overrun -> misc;
+ newlink -> new;
+ dellink -> del;
+ getlink -> get;
+ setlink -> set;
+ newaddr -> new;
+ deladdr -> del;
+ getaddr -> get;
+ newroute -> new;
+ delroute -> del;
+ getroute -> get;
+ newneigh -> new;
+ delneigh -> del;
+ getneigh -> get;
+ newrule -> new;
+ delrule -> del;
+ getrule -> get;
+ newdisc -> new;
+ delqdisc -> del;
+ getqdisc -> get;
+ newtclass -> new;
+ deltclass -> del;
+ gettclass -> get;
+ newtfilter -> new;
+ deltfilter -> del;
+ gettfilter -> get;
+ newaction -> new;
+ delaction -> del;
+ getaction -> get;
+ newprefix -> new;
+ getmulticast -> get;
+ getanycast -> get;
+ newneightbl -> new;
+ getneightbl -> get;
+ setneightbl -> set;
+ newnduseropt -> new;
+ newaddrlabel -> new;
+ deladdrlabel -> del;
+ getaddrlabel -> get;
+ getdcb -> get;
+ setdcb -> set
+ end.
diff --git a/deps/netlink/src/netlink_drv.erl b/deps/netlink/src/netlink_drv.erl
new file mode 100644
index 0000000..e390d12
--- /dev/null
+++ b/deps/netlink/src/netlink_drv.erl
@@ -0,0 +1,135 @@
+%%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%%
+%%% Copyright (C) 2012 Feuerlabs, Inc. All rights reserved.
+%%%
+%%% This Source Code Form is subject to the terms of the Mozilla Public
+%%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%%
+%%%---- END COPYRIGHT ---------------------------------------------------------
+%%% @author Tony Rogvall <tony@rogvall.se>
+%%% @doc
+%%% launch netlink_drv
+%%% @end
+%%% Created : 30 Nov 2011 by Tony Rogvall <tony@rogvall.se>
+
+-module(netlink_drv).
+-export([open/1, close/1, send/2]).
+-export([add_membership/2,
+ drop_membership/2,
+ set_rcvbuf/2, set_sndbuf/2,
+ get_rcvbuf/1, get_sndbuf/1,
+ get_sizeof/1,
+ deactivate/1,
+ activate/1,
+ activate/2,
+ debug/2]).
+
+%% deugging
+-compile(export_all).
+
+-include("netlink.hrl").
+
+-define(CMD_ADD_MEMBERSHIP, 1).
+-define(CMD_DROP_MEMBERSHIP, 2).
+-define(CMD_ACTIVE, 3).
+-define(CMD_DEBUG, 4).
+-define(CMD_SET_RCVBUF, 5).
+-define(CMD_SET_SNDBUF, 6).
+-define(CMD_GET_RCVBUF, 7).
+-define(CMD_GET_SNDBUF, 8).
+-define(CMD_GET_SIZEOF, 9).
+
+-define(DLOG_DEBUG, 7).
+-define(DLOG_INFO, 6).
+-define(DLOG_NOTICE, 5).
+-define(DLOG_WARNING, 4).
+-define(DLOG_ERROR, 3).
+-define(DLOG_CRITICAL, 2).
+-define(DLOG_ALERT, 1).
+-define(DLOG_EMERGENCY, 0).
+-define(DLOG_NONE, -1).
+
+add_membership(Port,Msg) when is_integer(Msg) ->
+ port_call(Port, ?CMD_ADD_MEMBERSHIP, <<Msg:32>>).
+
+drop_membership(Port,Msg) when is_integer(Msg) ->
+ port_call(Port, ?CMD_DROP_MEMBERSHIP, <<Msg:32>>).
+
+set_rcvbuf(Port,Size) when is_integer(Size), Size >= 0 ->
+ port_call(Port, ?CMD_SET_RCVBUF, <<Size:32>>).
+
+set_sndbuf(Port,Size) when is_integer(Size), Size >= 0 ->
+ port_call(Port, ?CMD_SET_SNDBUF, <<Size:32>>).
+
+get_rcvbuf(Port) ->
+ port_call(Port, ?CMD_GET_RCVBUF, <<>>).
+
+get_sndbuf(Port) ->
+ port_call(Port, ?CMD_GET_SNDBUF, <<>>).
+
+get_sizeof(Port) ->
+ port_call(Port, ?CMD_GET_SIZEOF, <<>>).
+
+deactivate(Port) ->
+ activate(Port, 0).
+
+activate(Port) ->
+ activate(Port, -1).
+
+activate(Port, N) when is_integer(N), N >= -1, N < 16#7fffffff ->
+ port_call(Port, ?CMD_ACTIVE, <<N:32>>).
+
+debug(Port,Level) when is_atom(Level) ->
+ L = level(Level),
+ port_call(Port, ?CMD_DEBUG, <<L:32>>).
+
+open(Protocol) when is_integer(Protocol), Protocol >= 0 ->
+ Driver = "netlink_drv",
+ Path = code:priv_dir(netlink),
+ io:format("load_driver '~s' from: '~s'\n", [Driver, Path]),
+ case erl_ddll:load_driver(Path, Driver) of
+ ok ->
+ Arg = integer_to_list(Protocol),
+ erlang:open_port({spawn_driver, Driver++" "++Arg}, [binary]);
+ {error,Error} ->
+ io:format("Error: ~s\n", [erl_ddll:format_error_int(Error)]),
+ erlang:error(Error)
+ end.
+
+close(Port) ->
+ erlang:port_close(Port).
+
+send(Port, Command) ->
+ erlang:port_command(Port, Command).
+
+port_call(Port, Cmd, Data) ->
+ case erlang:port_control(Port, Cmd, Data) of
+ <<0>> ->
+ ok;
+ <<255,E/binary>> ->
+ {error, erlang:binary_to_atom(E, latin1)};
+ <<254,E/binary>> ->
+ {error, binary_to_list(E)};
+ <<1,Y:8>> -> {ok,Y};
+ <<1,Y:16/native-unsigned>> -> {ok, Y};
+ <<1,Y:32/native-unsigned>> -> {ok, Y};
+ <<1,Y:64/native-unsigned>> -> {ok, Y};
+ <<2,X:32/native-unsigned,Y:32/native-unsigned>> -> {ok,{X,Y}};
+ <<3,X/binary>> -> {ok,X};
+ <<4,X/binary>> -> {ok,binary_to_list(X)}
+ end.
+
+%% convert symbolic to numeric level
+level(true) -> ?DLOG_DEBUG;
+level(false) -> ?DLOG_NONE;
+level(debug) -> ?DLOG_DEBUG;
+level(info) -> ?DLOG_INFO;
+level(notice) -> ?DLOG_NOTICE;
+level(warning) -> ?DLOG_WARNING;
+level(error) -> ?DLOG_ERROR;
+level(critical) -> ?DLOG_CRITICAL;
+level(alert) -> ?DLOG_ALERT;
+level(emergency) -> ?DLOG_EMERGENCY;
+level(none) -> ?DLOG_NONE.
+
diff --git a/deps/netlink/src/netlink_gen.erl b/deps/netlink/src/netlink_gen.erl
new file mode 100644
index 0000000..f0787c5
--- /dev/null
+++ b/deps/netlink/src/netlink_gen.erl
@@ -0,0 +1,798 @@
+%%% @author tony <tony@rogvall.se>
+%%% @copyright (C) 2013, tony
+%%% @doc
+%%% Generate netlink decoder & header files
+%%% @end
+%%% Created : 29 May 2013 by tony <tony@rogvall.se>
+
+-module(netlink_gen).
+
+-compile(export_all).
+
+-define(INFILE, "netlink.inc").
+-define(ERL_MOD, "netl_codec").
+
+-define(INT_SIZE_32, true).
+-define(LONG_SIZE_32, true).
+
+-ifdef(INT_SIZE_32).
+-define(int_t, int32_t).
+-define(uint_t, uint32_t).
+-else.
+-ifdef(INT_SIZE_64).
+-define(int_t, int64_t).
+-define(uint_t, uint64_t).
+-endif.
+-endif.
+
+-ifdef(LONG_SIZE_32).
+-define(long_t, int32_t).
+-define(ulong_t, uint32_t).
+-else.
+-ifdef(LONG_SIZE_64).
+-define(long_t, int64_t).
+-define(ulong_t, uint64_t).
+-endif.
+-endif.
+
+-define(short_t, int16_t).
+-define(ushort_t, uint16_t).
+
+-define(char_t, int8_t).
+-define(uchar_t, uint8_t).
+
+
+-record(gen,
+ {
+ error = 0 :: integer(), %% number of errors detected
+ defs :: term(), %% Symbol -> Value
+ enums :: term(), %% Name->[{atom(),integer()}]}
+ attrs :: term(), %% Name->[{atom(),integer(),type()}]
+ recs :: term() %% Name->[{atom(),integer(),type()}]
+ }).
+
+start() ->
+ G0 = #gen { defs = dict:new(),
+ enums = dict:new(),
+ attrs = dict:new(),
+ recs = dict:new() },
+ {ok,Fd} = file:open(?INFILE, [read]),
+ try fold_file_terms(fun load_term/3, G0, Fd) of
+ {ok,G1} ->
+ ok = emit_hrl(G1),
+ ok = emit_erl(G1);
+ Error -> Error
+ after
+ file:close(Fd)
+ end.
+
+load_term({define,Name,Value},Ln,G) ->
+ Value1 = lookup_value(Value, G),
+ D = case dict:find(Name, G#gen.defs) of
+ {ok,Value1} ->
+ G#gen.defs;
+ {ok,_Value2} ->
+ io:format("~s:~w: warning ~s redefined\n",
+ [?INFILE,Ln,Name]),
+ dict:store(Name,Value1,G#gen.defs);
+ error ->
+ dict:store(Name,Value1,G#gen.defs)
+ end,
+ G#gen { defs = D };
+load_term({enum,Name,Enums}, Ln, G) when is_atom(Name), is_list(Enums) ->
+ case dict:find(Name, G#gen.enums) of
+ {ok,_Enums} ->
+ io:format("~s:~w: error ~s allready defined\n",
+ [?INFILE,Ln,Name]),
+ G1 = inc_error(G),
+ load_enums(Name,Enums,Ln,G1);
+ error ->
+ load_enums(Name,Enums,Ln,G)
+ end;
+load_term({attribute,Name,Attrs}, Ln, G) when is_atom(Name), is_list(Attrs) ->
+ case dict:find(Name, G#gen.attrs) of
+ {ok,_Attrs} ->
+ io:format("~s:~w: error ~s allready defined\n",
+ [?INFILE,Ln,Name]),
+ G1 = inc_error(G),
+ load_attrs(Name,Attrs,Ln,G1);
+ error ->
+ load_attrs(Name,Attrs,Ln,G)
+ end;
+load_term({record,Name,Fields}, Ln, G) when is_atom(Name), is_list(Fields) ->
+ case dict:find(Name, G#gen.recs) of
+ {ok,_Attrs} ->
+ io:format("~s:~w: error ~s allready defined\n",
+ [?INFILE,Ln,Name]),
+ G1 = inc_error(G),
+ load_fields(Name,Fields,Ln,G1);
+ error ->
+ load_fields(Name,Fields,Ln,G)
+ end;
+load_term({record,Name,Type}, Ln, G) when is_atom(Name), is_atom(Type) ->
+ case dict:find(Type, G#gen.recs) of
+ error ->
+ io:format("~s:~w: error ~s not defined\n",
+ [?INFILE,Ln,Type]),
+ G1 = inc_error(G),
+ G2 = load_fields(Type,[],Ln,G1),
+ load_fields(Name,Type,Ln,G2);
+ {ok,_} ->
+ case dict:find(Name, G#gen.recs) of
+ {ok,_Attrs} ->
+ io:format("~s:~w: error ~s allready defined\n",
+ [?INFILE,Ln,Name]),
+ G1 = inc_error(G),
+ load_fields(Name,Type,Ln,G1);
+ error ->
+ load_fields(Name,Type,Ln,G)
+ end
+ end;
+load_term(Other, Ln, G) ->
+ io:format("~s:~w: error badly formed term ~p\n", [?INFILE,Ln,Other]),
+ inc_error(G).
+
+
+%%
+%% Load enums, enumerate warn about multiple usage of names and values!
+%%
+load_enums(Name,Enums0,Ln,G) ->
+ Enums = enumerate(Enums0,G),
+ G1 = check_enumeration(Name,Enums,Ln,G),
+ D = dict:store(Name, Enums, G1#gen.enums),
+ G1#gen { enums = D}.
+
+check_enumeration(Name,[{E,V}|Es],Ln,G) ->
+ case lists:keyfind(E,1,Es) of
+ false ->
+ case lists:keyfind(V,2,Es) of
+ false ->
+ check_enumeration(Name,Es,Ln,G);
+ {E1,V} ->
+ io:format("~s:~w: value for ~w also used by ~w\n",
+ [?INFILE,Ln,E,E1]),
+ G1 = inc_error(G),
+ check_enumeration(Name,Es,Ln,G1)
+ end;
+ {E,_V1} ->
+ io:format("~s:~w: enum ~s multiply defined\n",
+ [?INFILE,Ln,E]),
+ G1 = inc_error(G),
+ check_enumeration(Name,Es,Ln,G1)
+ end;
+check_enumeration(_Name, [], _Ln,G) ->
+ G.
+
+%% generate uniq values for names not assigne values
+enumerate(Enums,G) ->
+ Enums1 = lists:map(fun({E,V}) -> {E,lookup_value(V,G)};
+ (E) -> E
+ end, Enums),
+ Vs0 = lists:foldl(fun({_E,V},Acc) -> [V|Acc];
+ (_E,Acc) -> Acc
+ end, [], Enums1),
+ Vs1 = lists:usort(Vs0),
+ enumerate(Enums1, 0, Vs1).
+
+enumerate([{E,V}|Es], I, Vs) when is_atom(E) ->
+ [{E,V}|enumerate(Es, I, Vs)];
+enumerate(Es0=[E|Es], I, Vs) when is_atom(E) ->
+ case lists:member(I,Vs) of
+ true -> enumerate(Es0,I+1,Vs);
+ false -> [{E,I}|enumerate(Es,I+1,Vs)]
+ end;
+enumerate([],_I,_Vs) ->
+ [].
+
+%%
+%% Load record fields
+%%
+load_fields(Name,Type,_Ln,G) when is_atom(Type) ->
+ D = dict:store(Name, Type, G#gen.recs),
+ G#gen { recs = D };
+load_fields(Name,Fields,Ln,G) ->
+ Fields1 = [{F,I,T} ||
+ {I,{F,T}} <-
+ lists:zip(lists:seq(1,length(Fields)),Fields)],
+ G1 = check_fields(Name,Fields1,Ln,G),
+ D = dict:store(Name, Fields1, G1#gen.recs),
+ G1#gen { recs = D }.
+
+check_fields(Name,[{'_',_I,T}|Fs],Ln,G) ->
+ G1 = check_type({record,Name,'_'}, T, Ln, G),
+ check_fields(Name, Fs, Ln, G1);
+check_fields(Name,[{F,_I,T}|Fs],Ln,G) ->
+ case lists:keymember(F,1,Fs) of
+ true ->
+ io:format("~s:~w: field ~s multiply defined\n",
+ [?INFILE,Ln,F]),
+ G1 = inc_error(G),
+ G2 = check_type({record,Name,F}, T, Ln, G1),
+ check_fields(Name, Fs, Ln, G2);
+ false ->
+ G1 = check_type({record,Name,F}, T, Ln, G),
+ check_fields(Name, Fs, Ln, G1)
+ end;
+check_fields(_Name,[],_Ln,G) ->
+ G.
+%%
+%% Load attribute fields
+%%
+load_attrs(Name,Attrs,Ln,G) ->
+ Attrs1 = [{A,I,T} ||
+ {I,{A,T}} <- lists:zip(lists:seq(0,length(Attrs)-1),Attrs)],
+ G1 = check_attrs(Name,Attrs1,Ln,G),
+ D = dict:store(Name, Attrs1, G1#gen.attrs),
+ G1#gen { attrs = D }.
+
+check_attrs(Name,[{A,_I,T}|As],Ln,G) ->
+ case lists:keymember(A,1,As) of
+ true ->
+ io:format("~s:~w: attribute ~s multiply defined\n",
+ [?INFILE,Ln,A]),
+ G1 = inc_error(G),
+ G2 = check_type({attribute,Name,A}, T, Ln, G1),
+ check_attrs(Name, As, Ln, G2);
+ false ->
+ G1 = check_type({attribute,Name,A}, T, Ln, G),
+ check_attrs(Name, As, Ln, G1)
+ end;
+check_attrs(_Name,[],_Ln,G) ->
+ G.
+
+
+emit_hrl(G) ->
+ {ok,Fd} = file:open(?ERL_MOD++".hrl", [write]),
+ try
+ dict:fold(
+ fun(K,V,_A) ->
+ io:format(Fd, "-define(~s, ~w).\n", [K, V])
+ end, ok, G#gen.defs),
+ dict:fold(
+ fun(K,V,_A) ->
+ Fields = lookup_fields(V, G),
+ Fs = list_to_tuple([N || {N,_I,_Type} <- Fields, N =/= '_']),
+ io:format(Fd, "-record(~s, ~w).\n", [K, Fs])
+ end, ok, G#gen.recs)
+ of
+ R -> R
+ after
+ file:close(Fd)
+ end.
+
+
+emit_erl(G) ->
+ {ok,Fd} = file:open(?ERL_MOD++".erl", [write]),
+ io:format(Fd, "-module(~s).\n", [?ERL_MOD]),
+ io:format(Fd, "-include(~p).\n", [?ERL_MOD++".hrl"]),
+ try emit_codec_(Fd, G) of
+ ok -> ok
+ after
+ file:close(Fd)
+ end.
+
+emit_codec_(Fd, G) ->
+ dict:fold(
+ fun(Name,_Tab,_) ->
+ io:format(Fd, "-export([dec_~s/1, enc_~s/1]).\n",
+ [Name,Name])
+ end, ok, G#gen.enums),
+ dict:fold(
+ fun(Name,_Tab,_) ->
+ io:format(Fd, "-export([dec_~s/1, enc_~s/1]).\n",
+ [Name,Name])
+ end, ok, G#gen.attrs),
+ dict:fold(
+ fun(Name,_Tab,_) ->
+ io:format(Fd, "-export([dec_~s/1, enc_~s/1]).\n",
+ [Name,Name])
+ end, ok, G#gen.recs),
+
+
+ dict:fold(
+ fun(Name,Tab,_) ->
+ %% decode
+ lists:foreach(
+ fun({Enum,Value}) ->
+ io:format(Fd,"dec_~s(~w) -> ~s;\n", [Name,Value,Enum])
+ end, Tab),
+ io:format(Fd,"dec_~s(V) -> V.\n", [Name]),
+ %% encode
+ lists:foreach(
+ fun({Enum,Value}) ->
+ io:format(Fd,"enc_~s(~s) -> ~w;\n", [Name,Enum,Value])
+ end, Tab),
+ io:format(Fd,"enc_~s(V) when is_integer(V) -> V;\n", [Name]),
+ io:format(Fd,"enc_~s(E) -> erlang:error({undefined,E}).\n",
+ [Name])
+ end, ok, G#gen.enums),
+
+ dict:fold(
+ fun(Name,Tab0,_) ->
+ %% extend addr_t => ipv4_addr_t | ipv6_addr_t
+ Tab = lists:foldr(
+ fun({A,I,addr_t},Acc) ->
+ [{A,I,ipv4_addr_t},{A,I,ipv6_addr_t} | Acc];
+ (E,Acc) -> [E|Acc]
+ end, [], Tab0),
+ lists:foreach(
+ fun({Attr,Index,Type}) ->
+ {M1,R1} = match_code(Type,native,"X",G),
+ io:format(Fd,
+ "dec_~s({~w,native,<<~s>>}) ->\n"
+ " {~s,~s};\n",
+ [Name,Index,M1,Attr,R1]),
+ {M2,R2} = match_code(Type,big,"X",G),
+ io:format(Fd,
+ "dec_~s({~w,big,<<~s>>}) ->\n"
+ " {~s,~s};\n",
+ [Name,Index,M2,Attr,R2])
+ end, Tab),
+ io:format(Fd,"dec_~s({I,_Endian,Bin}) -> {I,Bin}.\n", [Name]),
+
+ lists:foreach(
+ fun({Attr,Index,Type}) ->
+ {M1,C1} = gen_code(Type,native,"X",G),
+ io:format(Fd,"enc_~s({~s,native,~s}) ->\n"
+ " {~w,native,<<~s>>};\n",
+ [Name,Attr,M1,Index,C1]),
+ {M2,C2} = gen_code(Type,big,"X",G),
+ io:format(Fd,"enc_~s({~s,big,~s}) ->\n"
+ " {~w,big,<<~s>>};\n",
+ [Name,Attr,M2,Index,C2])
+ end, Tab),
+ io:format(Fd,"enc_~s({I,Endian,X}) -> {I,Endian,X}.\n", [Name])
+ end, ok, G#gen.attrs),
+
+ dict:fold(
+ fun(Name,RecType,_) ->
+ Fields = lookup_fields(RecType, G),
+ Named = [{Fi,Ix,Ti} || {Fi,Ix,Ti} <- Fields, Fi =/= '_'],
+ {Ms,Rs} = match_record_code(Fields, native, "X", G),
+ M = io_list_join(Ms, ","),
+ Rs1 = lists:map(fun({{Fi,_,_Ti},Ri}) ->
+ [atom_to_list(Fi),"=",Ri]
+ end, lists:zip(Named,Rs)),
+ R1 = ["#",atom_to_list(Name),"{", io_list_join(Rs1,","), "}"],
+
+ io:format(Fd,"dec_~s({native,<<~s>>}) ->\n"
+ " ~s.\n",
+ [Name,M,R1]),
+
+ {Ts,Bs} = gen_record_code(Fields, native, "X", G),
+ Ts1 = lists:map(fun({{Fi,_,_Ti},Ri}) ->
+ [atom_to_list(Fi),"=",Ri]
+ end, lists:zip(Named,Ts)),
+ R2 = ["#",atom_to_list(Name),"{", io_list_join(Ts1,","), "}"],
+ B = io_list_join(Bs, ","),
+ io:format(Fd,"enc_~s({_Endian,~s}) -> <<~s>>.\n",
+ [Name,R2,B]),
+ ok
+ end, ok, G#gen.recs).
+
+
+check_type(Ctx, {array,T}, Ln, G) ->
+ case is_base_type(T) of
+ true ->
+ G;
+ false ->
+ io:format("~s:~w: type ~w not allowed as base type in ~w\n",
+ [?INFILE,Ln,T,Ctx]),
+ inc_error(G)
+ end;
+check_type(_Ctx, {enum,Type,Enum}, Ln, G)
+ when is_atom(Type), is_atom(Enum) ->
+ case is_integer_type(Type) of
+ true ->
+ case dict:find(Enum, G#gen.enums) of
+ {ok,_} -> G;
+ error ->
+ io:format("~s:~w: enum type ~s not defined\n",
+ [?INFILE,Ln,Enum]),
+ inc_error(G)
+ end;
+ false ->
+ io:format("~s:~w: enum must have an integer base type\n",
+ [?INFILE,Ln]),
+ inc_error(G)
+ end;
+check_type(_Ctx, {flags,Type,Enum}, Ln, G)
+ when is_atom(Type), is_atom(Enum) ->
+ case is_unsigned_type(Type) of
+ true ->
+ case dict:find(Enum, G#gen.enums) of
+ {ok,_} -> G;
+ error ->
+ io:format("~s:~w: enum type ~s not defined\n",
+ [?INFILE,Ln,Enum]),
+ inc_error(G)
+ end;
+ false ->
+ io:format("~s:~w: flags must have an unsigned base type\n",
+ [?INFILE,Ln]),
+ inc_error(G)
+ end;
+check_type(Ctx, {tlvs,Name}, Ln, G) ->
+ %% fixme, check that Ctx is {attribute,...}
+ case dict:find(Name, G#gen.attrs) of
+ error ->
+ io:format("~s:~w: attribute type ~s name not found in ~w\n",
+ [?INFILE,Ln,Name,Ctx]),
+ inc_error(G);
+ {ok,_} ->
+ G
+ end;
+check_type(Ctx, T, Ln, G) ->
+ case is_base_type(T) of
+ true -> G;
+ false ->
+ case T of
+ string_t -> G;
+ binary_t -> G;
+ Type when is_atom(Type) ->
+ case lookup_type(Type, G) of
+ false ->
+ io:format("~s:~w: type ~s name not found in ~w\n",
+ [?INFILE,Ln,Type,Ctx]),
+ inc_error(G);
+ _Typedef ->
+ G
+ end;
+ _ ->
+ io:format("~s:~w: type ~w not allowed in ~w\n",
+ [?INFILE,Ln,T,Ctx]),
+ inc_error(G)
+ end
+ end.
+
+is_base_type(T) ->
+ case is_integer_type(T) of
+ true -> true;
+ false ->
+ case T of
+ addr_t -> true;
+ ether_addr_t -> true;
+ ipv4_addr_t -> true;
+ ipv6_addr_t -> true;
+ _ -> false
+ end
+ end.
+
+is_integer_type(T) ->
+ is_unsigned_type(T) orelse is_signed_type(T).
+
+is_unsigned_type(T) ->
+ case T of
+ ulong_t -> true;
+ ushort_t -> true;
+ uchar_t -> true;
+ uint_t -> true;
+ uint8_t -> true;
+ uint16_t -> true;
+ uint32_t -> true;
+ uint64_t -> true;
+ _ -> false
+ end.
+
+is_signed_type(T) ->
+ case T of
+ long_t -> true;
+ int_t -> true;
+ short_t -> true;
+ char_t -> true;
+ int8_t -> true;
+ int16_t -> true;
+ int32_t -> true;
+ int64_t -> true;
+ _ -> false
+ end.
+%%
+%% generate match code
+%% {BitMatch, TermCode}
+%%
+match_code(int_t, E, X, G) -> match_code(?int_t, E, X, G);
+match_code(uint_t, E, X, G) -> match_code(?uint_t, E, X, G);
+match_code(long_t, E, X, G) -> match_code(?long_t, E, X, G);
+match_code(ulong_t, E, X, G) -> match_code(?ulong_t, E, X, G);
+match_code(short_t, E, X, G) -> match_code(?short_t, E, X, G);
+match_code(ushort_t, E, X, G) -> match_code(?ushort_t, E, X, G);
+match_code(char_t, E, X, G) -> match_code(?char_t, E, X, G);
+match_code(uchar_t, E, X, G) -> match_code(?uchar_t, E, X, G);
+
+match_code(uint64_t,native,X,_G) -> match_int_code(X,64,unsigned,native);
+match_code(uint32_t,native,X,_G) -> match_int_code(X,32,unsigned,native);
+match_code(uint16_t,native,X,_G) -> match_int_code(X,16,unsigned,native);
+match_code(uint8_t,native,X,_G) -> match_int_code(X,8,unsigned,native);
+match_code(uint64_t,big,X,_G) -> match_int_code(X,64,unsigned,big);
+match_code(uint32_t,big,X,_G) -> match_int_code(X,32,unsigned,big);
+match_code(uint16_t,big,X,_G) -> match_int_code(X,16,unsigned,big);
+match_code(uint8_t,big,X,_G) -> match_int_code(X,8,unsigned,big);
+match_code(uint64_t,little,X,_G) -> match_int_code(X,64,unsigned,little);
+match_code(uint32_t,little,X,_G) -> match_int_code(X,32,unsigned,little);
+match_code(uint16_t,little,X,_G) -> match_int_code(X,16,unsigned,little);
+match_code(uint8_t,little,X,_G) -> match_int_code(X,8,unsigned,little);
+
+match_code(int64_t,native,X,_G) -> match_int_code(X,64,signed,native);
+match_code(int32_t,native,X,_G) -> match_int_code(X,32,signed,native);
+match_code(int16_t,native,X,_G) -> match_int_code(X,16,signed,native);
+match_code(int8_t,native,X,_G) -> match_int_code(X,8,signed,native);
+match_code(int64_t,big,X,_G) -> match_int_code(X,64,signed,big);
+match_code(int32_t,big,X,_G) -> match_int_code(X,32,signed,big);
+match_code(int16_t,big,X,_G) -> match_int_code(X,16,signed,big);
+match_code(int8_t, big,X,_G) -> match_int_code(X,8,signed,big);
+match_code(int64_t,little,X,_G) -> match_int_code(X,64,signed,little);
+match_code(int32_t,little,X,_G) -> match_int_code(X,32,signed,little);
+match_code(int16_t,little,X,_G) -> match_int_code(X,16,signed,little);
+match_code(int8_t,little,X,_G) -> match_int_code(X,8,signed,little);
+match_code(binary_t,_Endian,X,_G) ->
+ {[X,"/binary"],X};
+match_code(string_t,_Endian,X,_G) ->
+ {[X,"/binary"], ["binary_to_list(hd(binary:split(",X,",","<<0>>)))"]};
+
+match_code({enum,BaseType,Name},Endian,X,G) ->
+ Xe = X++"e",
+ Decode = "dec_"++atom_to_list(Name),
+ {Match,Value} = match_code(BaseType,Endian,Xe,G),
+ {Match,[Decode,"(",Value,")"]};
+match_code({flags,BaseType,Name},Endian,X,G) ->
+ Xf = X++"f",
+ Decode = "dec_"++atom_to_list(Name),
+ {Match,Value} = match_code(BaseType,Endian,Xf,G),
+ {Match,["netlink_codec:decode_flags(",Value,",fun ",Decode,"/1)"]};
+match_code({array,BaseType},Endian,X,G) ->
+ %% [Xi || <<Xi:32/unsigned-big>> <= X ]
+ Xi = X++"i",
+ %% Well, Xi must be equal to Value here!
+ {Match,Value} = match_code(BaseType,Endian,Xi,G),
+ {[X,"/binary"], ["[",Value," || <<",Match,">> <= ",X,"]"] };
+match_code({tlvs,Name},_Endian,X,_G) ->
+ Xi = X++"i",
+ Decode = "dec_"++atom_to_list(Name),
+ {[X,"/binary"],
+ ["[",Decode,"(",Xi,") || ",
+ Xi," <- netlink_codec:decode_tlv_list(",X,")]"]};
+match_code(ether_addr_t, _, X,_G) ->
+ Xs = [X++integer_to_list(I) || I <- lists:seq(1,6)],
+ {string:join(Xs,","), ["{", string:join(Xs,","), "}"]};
+match_code(ipv4_addr_t, _, X,_G) ->
+ Xi = [X++integer_to_list(I) || I <- lists:seq(1,4)],
+ Xm = [J++":8" || J <- Xi],
+ {string:join(Xm,","),
+ ["{", string:join(Xi,","), "}"]};
+match_code(ipv6_addr_t,_,X,_G) ->
+ Xi = [X++integer_to_list(I) || I <- lists:seq(1,8)],
+ Xm = [J++":16" || J <- Xi],
+ {string:join(Xm,","),
+ ["{", string:join(Xi,","), "}"]};
+%% match_code(addr_t,_,X,_G) ->
+%% Xi = [X++integer_to_list(I) || I <- lists:seq(1,4)],
+%% Xm = [J++":8" || J <- Xi],
+%% {string:join(Xm,","),
+%% ["{", string:join(Xi,","), "}"]};
+match_code(Name,Endian,X,G) ->
+ case dict:find(Name, G#gen.recs) of
+ error ->
+ %% assume attribute!
+ {ok,_} = dict:find(Name, G#gen.attrs),
+ Decode = "dec_"++atom_to_list(Name),
+ {[X,"/binary"], [Decode,"(netlink_codec:decode_tlv(",X,"))"]};
+ {ok,RecType} ->
+ Fields = lookup_fields(RecType,G),
+ Named = [{Fi,Ix,Ti} || {Fi,Ix,Ti} <- Fields, Fi =/= '_'],
+ {Ms,Rs} = match_record_code(Fields, Endian, X, G),
+ M = io_list_join(Ms, ","),
+ Rs1 = lists:map(fun({{Fi,_,_Ti},Ri}) ->
+ [atom_to_list(Fi),"=",Ri]
+ end, lists:zip(Named,Rs)),
+ R = ["#",atom_to_list(Name),"{", io_list_join(Rs1,","), "}"],
+ {M, R}
+ end.
+
+match_record_code(Fs, Endian, X, G) ->
+ match_record_code_(Fs, Endian, X, G, [], []).
+
+match_record_code_([{'_',_Ix,Type}|Fs], Endian, X, G, Ms, Rs) ->
+ {M,_R} = match_code(Type, Endian, "_", G),
+ match_record_code_(Fs, Endian, X, G, [M|Ms], Rs);
+match_record_code_([{_Field,Ix,Type}|Fs], Endian, X, G, Ms, Rs) ->
+ Xi = X++integer_to_list(Ix),
+ {M,R} = match_code(Type, Endian, Xi, G),
+ match_record_code_(Fs, Endian, X, G, [M|Ms], [R|Rs]);
+match_record_code_([], _Endian, _X, _G, Ms, Rs) ->
+ {lists:reverse(Ms), lists:reverse(Rs)}.
+
+%%
+%% X:Size/<sign>-<endian> => Decode
+%% {BitMatch,Decode}
+%%
+match_int_code(X,Size,Sign,Endian) ->
+ {[X,":",integer_to_list(Size),"/",
+ atom_to_list(Sign),"-",atom_to_list(Endian)], X}.
+
+%%
+%% generate generate-code
+%% return {Encode, BitConstruct}
+%%
+gen_code(int_t, E, X, G) -> gen_code(?int_t, E, X, G);
+gen_code(uint_t, E, X, G) -> gen_code(?uint_t, E, X, G);
+gen_code(long_t, E, X, G) -> gen_code(?long_t, E, X, G);
+gen_code(ulong_t, E, X, G) -> gen_code(?ulong_t, E, X, G);
+gen_code(short_t, E, X, G) -> gen_code(?short_t, E, X, G);
+gen_code(ushort_t, E, X, G) -> gen_code(?ushort_t, E, X, G);
+gen_code(char_t, E, X, G) -> gen_code(?char_t, E, X, G);
+gen_code(uchar_t, E, X, G) -> gen_code(?uchar_t, E, X, G);
+
+gen_code(uint64_t,native,X,_G) -> gen_int_code(X,64,unsigned,native);
+gen_code(uint32_t,native,X,_G) -> gen_int_code(X,32,unsigned,native);
+gen_code(uint16_t,native,X,_G) -> gen_int_code(X,16,unsigned,native);
+gen_code(uint8_t,native,X,_G) -> gen_int_code(X,8,unsigned,native);
+gen_code(uint64_t,big,X,_G) -> gen_int_code(X,64,unsigned,big);
+gen_code(uint32_t,big,X,_G) -> gen_int_code(X,32,unsigned,big);
+gen_code(uint16_t,big,X,_G) -> gen_int_code(X,16,unsigned,big);
+gen_code(uint8_t,big,X,_G) -> gen_int_code(X,8,unsigned,big);
+gen_code(uint64_t,little,X,_G) -> gen_int_code(X,64,unsigned,little);
+gen_code(uint32_t,little,X,_G) -> gen_int_code(X,32,unsigned,little);
+gen_code(uint16_t,little,X,_G) -> gen_int_code(X,16,unsigned,little);
+gen_code(uint8_t,little,X,_G) -> gen_int_code(X,8,unsigned,little);
+
+gen_code(int64_t,native,X,_G) -> gen_int_code(X,64,signed,native);
+gen_code(int32_t,native,X,_G) -> gen_int_code(X,32,signed,native);
+gen_code(int16_t,native,X,_G) -> gen_int_code(X,16,signed,native);
+gen_code(int8_t,native,X,_G) -> gen_int_code(X,8,signed,native);
+gen_code(int64_t,big,X,_G) -> gen_int_code(X,64,signed,big);
+gen_code(int32_t,big,X,_G) -> gen_int_code(X,32,signed,big);
+gen_code(int16_t,big,X,_G) -> gen_int_code(X,16,signed,big);
+gen_code(int8_t,big,X,_G) -> gen_int_code(X,8,signed,big);
+gen_code(int64_t,little,X,_G) -> gen_int_code(X,64,signed,little);
+gen_code(int32_t,little,X,_G) -> gen_int_code(X,32,signed,little);
+gen_code(int16_t,little,X,_G) -> gen_int_code(X,16,signed,little);
+gen_code(int8_t,little,X,_G) -> gen_int_code(X,8,signed,little);
+
+gen_code(binary_t, _Endian, X,_G) ->
+ {X, X};
+gen_code(string_t, _Endian, X,_G) ->
+ {X, ["(erlang:iolist_to_binary([",X,",0","]))/binary"]};
+
+gen_code({enum,BaseType,Name},Endian,X,G) ->
+ Encode = "enc_"++atom_to_list(Name),
+ E = ["(",Encode,"(",X,"))"],
+ {_M,C} = gen_code(BaseType,Endian,E,G),
+ {X,C};
+
+gen_code({flags,BaseType,Name},Endian,X,G) ->
+ Encode = "enc_"++atom_to_list(Name),
+ E = ["(","netlink_codec:encode_flags(",X,",fun ",Encode,"/1))"],
+ {_M,C} = gen_code(BaseType,Endian,E,G),
+ {X,C};
+
+gen_code({array,BaseType},Endian,X,G) ->
+ Xi = X++"i",
+ {_M,C} = gen_code(BaseType,Endian,Xi,G), %% M=Xi! only simple base types!
+ {X, ["(<< <<",C,">>", " || ",Xi," <- ",X,">>)/binary"]};
+
+gen_code({tlvs,Name},_Endian,X,_G) ->
+ Xi = X++"i",
+ Encode = "enc_"++atom_to_list(Name),
+ {X, [ "(netlink_codec:encode_tlv_list(",
+ "[",Encode,"(",Xi,") || ", Xi," <- ",X,"]", "))/binary"]};
+
+gen_code(ether_addr_t,_,X,_G) ->
+ Xi = [X++integer_to_list(I) || I <- lists:seq(1,6)],
+ Xm = [J++":8" || J <- Xi],
+ {["{", string:join(Xi,","),"}"], string:join(Xm,",") };
+gen_code(ipv4_addr_t,_,X,_G) ->
+ Xi = [X++integer_to_list(I) || I <- lists:seq(1,4)],
+ Xm = [J++":8" || J <- Xi],
+ {["{", string:join(Xi,","),"}"], string:join(Xm,",")};
+gen_code(ipv6_addr_t,_,X,_G) ->
+ Xi = [X++integer_to_list(I) || I <- lists:seq(1,8)],
+ Xm = [J++":16" || J <- Xi],
+ {["{", string:join(Xi,","), "}"], string:join(Xm,",")};
+%% gen_code(addr_t,_,X,_G) ->
+%% %% FIXME: use address family from message ?
+%% Xi = [X++integer_to_list(I) || I <- lists:seq(1,4)],
+%% Xm = [J++":8" || J <- Xi],
+%% {["{", string:join(Xi,","),"}"], string:join(Xm,",")};
+gen_code(Name,Endian,X,G) ->
+ case dict:find(Name, G#gen.recs) of
+ error ->
+ %% assume attribute!
+ Encode = "enc_"++atom_to_list(Name),
+ {X, [ "(netlink_codec:encode_tlv(",Encode,"(",X,")))"]};
+ {ok,RecType} ->
+ Fields = lookup_fields(RecType,G),
+ Named = [{Fi,Ix,Ti} || {Fi,Ix,Ti} <- Fields, Fi =/= '_'],
+ %% must be record
+ {Ts,Bs} = gen_record_code(Fields, Endian, X, G),
+ Ts1 = lists:map(fun({{Fi,_,_Ti},Ri}) ->
+ [atom_to_list(Fi),"=",Ri]
+ end, lists:zip(Named,Ts)),
+ R = ["#",atom_to_list(Name),"{", io_list_join(Ts1,","), "}"],
+ B = io_list_join(Bs, ","),
+ {R, B}
+ end.
+
+
+
+gen_record_code(Fs, Endian, X, G) ->
+ gen_record_code_(Fs, Endian, X, G, [], []).
+
+gen_record_code_([{'_',_Ix,Type}|Fs], Endian, X, G, Ms, Bs) ->
+ {_M,B} = gen_code(Type, Endian, "0", G),
+ gen_record_code_(Fs, Endian, X, G, Ms, [B|Bs]);
+gen_record_code_([{_Field,Ix,Type}|Fs], Endian, X, G, Ms, Bs) ->
+ Xi = X++integer_to_list(Ix),
+ {M,B} = gen_code(Type, Endian, Xi, G),
+ gen_record_code_(Fs, Endian, X, G, [M|Ms], [B|Bs]);
+gen_record_code_([], _Endian, _X, _G, Ms, Bs) ->
+ {lists:reverse(Ms), lists:reverse(Bs)}.
+
+%% return {TermMatch,BitConstruct}
+gen_int_code(X,Size,Sign,Endian) ->
+ {X, [X,":",integer_to_list(Size),"/",
+ atom_to_list(Sign),"-",atom_to_list(Endian)]}.
+
+%%
+%% io_list_join like string:join but for io_lists
+%%
+io_list_join([], _Sep) -> [];
+io_list_join([A], _Sep) -> [A];
+io_list_join([A|As], Sep) -> [A,Sep|io_list_join(As,Sep)].
+
+%%
+%% Get record indirections
+%%
+lookup_fields(Name, G) when is_atom(Name) ->
+ case dict:find(Name, G#gen.recs) of
+ {ok,Name1} ->
+ lookup_fields(Name1, G)
+ end;
+lookup_fields(Fields,_G) when is_list(Fields) ->
+ Fields.
+
+%%
+%% Lookup defined value
+%%
+
+lookup_value(Value, _G) when is_integer(Value) ->
+ Value;
+lookup_value(Name, G) when is_atom(Name) ->
+ case dict:find(Name, G#gen.defs) of
+ {ok,Name} -> Name; %% recursive!
+ {ok,Value} when is_atom(Value) -> lookup_value(Value,G);
+ {ok,Value} when is_integer(Value) -> Value;
+ error -> Name
+ end.
+
+%% lookup named type (record / attribute)
+lookup_type(Name, G) when is_atom(Name) ->
+ case dict:find(Name, G#gen.attrs) of
+ error ->
+ case dict:find(Name, G#gen.recs) of
+ error ->
+ false;
+ {ok,Value} -> {attribute,Name,Value}
+ end;
+ {ok,Value} -> {record,Name,Value}
+ end.
+
+
+inc_error(G) ->
+ G#gen { error = G#gen.error + 1}.
+
+
+%% util to fold all terms in a file
+fold_file_terms(Fun, Acc, Fd) ->
+ fold_file_terms(Fun, Acc, 1, Fd).
+
+fold_file_terms(Fun, Acc, Line, Fd) ->
+ case io:read(Fd, '', Line) of
+ {ok,Term,EndLine} ->
+ fold_file_terms(Fun, Fun(Term,Line,Acc), EndLine,Fd);
+ {error,Error,Line} ->
+ io:format("parse error:~w: ~p\n", [Line,Error]),
+ {error,Error};
+ {eof,_Line} ->
+ {ok,Acc}
+ end.
+
diff --git a/deps/netlink/src/netlink_stat.erl b/deps/netlink/src/netlink_stat.erl
new file mode 100644
index 0000000..eb7775e
--- /dev/null
+++ b/deps/netlink/src/netlink_stat.erl
@@ -0,0 +1,115 @@
+%%% @author tony <tony@rogvall.se>
+%%% @copyright (C) 2013, tony
+%%% @doc
+%%% Get network statistics
+%%% @end
+%%% Created : 18 Aug 2013 by tony <tony@rogvall.se>
+
+-module(netlink_stat).
+
+-compile(export_all).
+
+-include("../include/netlink.hrl").
+
+get_value() ->
+ get_value("*").
+
+get_value("") ->
+ get_value("*");
+get_value(Counter) ->
+ case string:tokens(Counter, ".") of
+ [] -> get_all_counters();
+ ["*"] -> get_all_counters();
+ ["*","*"] -> get_all_counters();
+ [Name,"*"] -> get_all_counters(Name);
+ [Name] -> get_all_counters(Name);
+ ["*",Var] ->
+ Field = list_to_atom(Var),
+ Fi = index(Field, record_info(fields, rtnl_link_stats)),
+ if Fi =:= 0 ->
+ [];
+ true ->
+ {ok,Ifs} = inet:getiflist(),
+ select_counters_(Ifs, Fi+1, Var, [])
+ end;
+ [Name,Var] ->
+ Field = list_to_atom(Var),
+ {ok,S} = get_statistics(Name),
+ case index(Field, record_info(fields, rtnl_link_stats)) of
+ 0 -> [];
+ Fi -> [{Counter,element(Fi+1, S)}]
+ end
+ end.
+
+get_all_counters() ->
+ {ok,Ifs} = inet:getiflist(),
+ get_all_counters_(Ifs,[]).
+
+get_all_counters(Name) ->
+ {ok,S} = get_statistics(Name),
+ Acc = get_counters_(Name, 2, record_info(fields, rtnl_link_stats),S,[]),
+ lists:reverse(Acc).
+
+select_counters_([Name|As],Fi,Var,Acc) ->
+ {ok,S} = get_statistics(Name),
+ Value = element(Fi,S),
+ select_counters_(As,Fi,Var,[{Name++"."++Var,Value}|Acc]);
+select_counters_([], _Fi, _Var, Acc) ->
+ lists:reverse(Acc).
+
+get_all_counters_([Name|As],Acc) ->
+ {ok,S} = get_statistics(Name),
+ Acc1 = get_counters_(Name,2,record_info(fields, rtnl_link_stats),S,Acc),
+ get_all_counters_(As,Acc1);
+get_all_counters_([], Acc) ->
+ lists:reverse(Acc).
+
+get_counters_(Name, I, [F|Fs], S, Acc) ->
+ Var = atom_to_list(F),
+ get_counters_(Name, I+1, Fs, S, [{Name++"."++Var, element(I,S)} |Acc]);
+get_counters_(_Name, _I, [], _S, Acc) ->
+ Acc.
+
+%%
+%% Find first Key in Position Pos in the List
+%% return the position in the list or 0 if not found
+index(Value, List) ->
+ index_(1, Value, List).
+
+index_(I,Value,[Value|_List]) -> I;
+index_(I,Value,[_|List]) -> index_(I+1,Value,List);
+index_(_I,_Value,[]) -> 0.
+
+
+get_statistics(Interface) ->
+ netlink:start(),
+ {ok,Ref} = netlink:subscribe(Interface),
+ netlink:invalidate(Interface, [stats,stats64]),
+ ok = netlink:get_match(link, inet, [{stats,native,[]}]),
+ Res = get_stats64(Ref,1000),
+ flush_stats(Ref),
+ netlink:unsubscribe(Ref),
+ case Res of
+ {ok,Stats} ->
+ #rtnl_link_stats{} = R =list_to_tuple([rtnl_link_stats | Stats]),
+ {ok,R};
+ Error ->
+ Error
+ end.
+
+get_stats64(Ref,Timeout) ->
+ receive
+ {netlink,Ref,_Interface,stats64,_Old,New} ->
+ {ok,New}
+ after Timeout ->
+ {error,timeout}
+ end.
+
+flush_stats(Ref) ->
+ receive
+ _Msg={netlink,Ref,_Interface,_,_Old,_New} ->
+ %% io:format("flushed: ~p\n", [_Msg]),
+ flush_stats(Ref)
+ after 0 ->
+ ok
+ end.
diff --git a/deps/netlink/src/netlink_sup.erl b/deps/netlink/src/netlink_sup.erl
new file mode 100644
index 0000000..0d5a5d7
--- /dev/null
+++ b/deps/netlink/src/netlink_sup.erl
@@ -0,0 +1,36 @@
+%%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%%
+%%% Copyright (C) 2012 Feuerlabs, Inc. All rights reserved.
+%%%
+%%% This Source Code Form is subject to the terms of the Mozilla Public
+%%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%%
+%%%---- END COPYRIGHT ---------------------------------------------------------
+
+-module(netlink_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+%% ===================================================================
+%% API functions
+%% ===================================================================
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% ===================================================================
+%% Supervisor callbacks
+%% ===================================================================
+
+init([]) ->
+ C = {netlink, {netlink, start_link, []},
+ permanent, 5000, worker, [netlink]},
+ {ok, { {one_for_one, 5, 10}, [C]}}.
+
diff --git a/deps/netlink/tetrapak/build_drv.erl b/deps/netlink/tetrapak/build_drv.erl
new file mode 100644
index 0000000..b4359aa
--- /dev/null
+++ b/deps/netlink/tetrapak/build_drv.erl
@@ -0,0 +1,11 @@
+-task({"build:drv", "Build the netlink driver"}).
+-task({"clean:drv", "Clean the netlink driver"}).
+
+run("build:drv", _) ->
+ tetrapak:outputcmd(tetrapak:subdir("c_src"), "make", [cflags(), "all"]);
+
+run("clean:drv", _) ->
+ tetrapak:outputcmd(tetrapak:subdir("c_src"), "make", [cflags(), "clean"]).
+
+cflags() ->
+ ["CFLAGS=", "-O2 ", ["-I", code:root_dir(), "/erts-", erlang:system_info(version), "/include"]].
diff --git a/deps/netlink/tetrapak/config.ini b/deps/netlink/tetrapak/config.ini
new file mode 100644
index 0000000..0cd3ed4
--- /dev/null
+++ b/deps/netlink/tetrapak/config.ini
@@ -0,0 +1,8 @@
+[build]
+version = "~t.~o~~~c"
+
+[package]
+maintainer = "Tony Rogvall <tony@feuerlabs.com>"
+exclude = "\\.gitignore|README.md|libnl"
+architecture = host
+
diff --git a/deps/trace_runner/.gitignore b/deps/trace_runner/.gitignore
new file mode 100644
index 0000000..8e46d5a
--- /dev/null
+++ b/deps/trace_runner/.gitignore
@@ -0,0 +1,10 @@
+.eunit
+deps
+*.o
+*.beam
+*.plt
+erl_crash.dump
+ebin
+rel/example_project
+.concrete/DEV_MODE
+.rebar
diff --git a/deps/trace_runner/LICENSE b/deps/trace_runner/LICENSE
new file mode 100644
index 0000000..a612ad9
--- /dev/null
+++ b/deps/trace_runner/LICENSE
@@ -0,0 +1,373 @@
+Mozilla Public License Version 2.0
+==================================
+
+1. Definitions
+--------------
+
+1.1. "Contributor"
+ means each individual or legal entity that creates, contributes to
+ the creation of, or owns Covered Software.
+
+1.2. "Contributor Version"
+ means the combination of the Contributions of others (if any) used
+ by a Contributor and that particular Contributor's Contribution.
+
+1.3. "Contribution"
+ means Covered Software of a particular Contributor.
+
+1.4. "Covered Software"
+ means Source Code Form to which the initial Contributor has attached
+ the notice in Exhibit A, the Executable Form of such Source Code
+ Form, and Modifications of such Source Code Form, in each case
+ including portions thereof.
+
+1.5. "Incompatible With Secondary Licenses"
+ means
+
+ (a) that the initial Contributor has attached the notice described
+ in Exhibit B to the Covered Software; or
+
+ (b) that the Covered Software was made available under the terms of
+ version 1.1 or earlier of the License, but not also under the
+ terms of a Secondary License.
+
+1.6. "Executable Form"
+ means any form of the work other than Source Code Form.
+
+1.7. "Larger Work"
+ means a work that combines Covered Software with other material, in
+ a separate file or files, that is not Covered Software.
+
+1.8. "License"
+ means this document.
+
+1.9. "Licensable"
+ means having the right to grant, to the maximum extent possible,
+ whether at the time of the initial grant or subsequently, any and
+ all of the rights conveyed by this License.
+
+1.10. "Modifications"
+ means any of the following:
+
+ (a) any file in Source Code Form that results from an addition to,
+ deletion from, or modification of the contents of Covered
+ Software; or
+
+ (b) any new file in Source Code Form that contains any Covered
+ Software.
+
+1.11. "Patent Claims" of a Contributor
+ means any patent claim(s), including without limitation, method,
+ process, and apparatus claims, in any patent Licensable by such
+ Contributor that would be infringed, but for the grant of the
+ License, by the making, using, selling, offering for sale, having
+ made, import, or transfer of either its Contributions or its
+ Contributor Version.
+
+1.12. "Secondary License"
+ means either the GNU General Public License, Version 2.0, the GNU
+ Lesser General Public License, Version 2.1, the GNU Affero General
+ Public License, Version 3.0, or any later versions of those
+ licenses.
+
+1.13. "Source Code Form"
+ means the form of the work preferred for making modifications.
+
+1.14. "You" (or "Your")
+ means an individual or a legal entity exercising rights under this
+ License. For legal entities, "You" includes any entity that
+ controls, is controlled by, or is under common control with You. For
+ purposes of this definition, "control" means (a) the power, direct
+ or indirect, to cause the direction or management of such entity,
+ whether by contract or otherwise, or (b) ownership of more than
+ fifty percent (50%) of the outstanding shares or beneficial
+ ownership of such entity.
+
+2. License Grants and Conditions
+--------------------------------
+
+2.1. Grants
+
+Each Contributor hereby grants You a world-wide, royalty-free,
+non-exclusive license:
+
+(a) under intellectual property rights (other than patent or trademark)
+ Licensable by such Contributor to use, reproduce, make available,
+ modify, display, perform, distribute, and otherwise exploit its
+ Contributions, either on an unmodified basis, with Modifications, or
+ as part of a Larger Work; and
+
+(b) under Patent Claims of such Contributor to make, use, sell, offer
+ for sale, have made, import, and otherwise transfer either its
+ Contributions or its Contributor Version.
+
+2.2. Effective Date
+
+The licenses granted in Section 2.1 with respect to any Contribution
+become effective for each Contribution on the date the Contributor first
+distributes such Contribution.
+
+2.3. Limitations on Grant Scope
+
+The licenses granted in this Section 2 are the only rights granted under
+this License. No additional rights or licenses will be implied from the
+distribution or licensing of Covered Software under this License.
+Notwithstanding Section 2.1(b) above, no patent license is granted by a
+Contributor:
+
+(a) for any code that a Contributor has removed from Covered Software;
+ or
+
+(b) for infringements caused by: (i) Your and any other third party's
+ modifications of Covered Software, or (ii) the combination of its
+ Contributions with other software (except as part of its Contributor
+ Version); or
+
+(c) under Patent Claims infringed by Covered Software in the absence of
+ its Contributions.
+
+This License does not grant any rights in the trademarks, service marks,
+or logos of any Contributor (except as may be necessary to comply with
+the notice requirements in Section 3.4).
+
+2.4. Subsequent Licenses
+
+No Contributor makes additional grants as a result of Your choice to
+distribute the Covered Software under a subsequent version of this
+License (see Section 10.2) or under the terms of a Secondary License (if
+permitted under the terms of Section 3.3).
+
+2.5. Representation
+
+Each Contributor represents that the Contributor believes its
+Contributions are its original creation(s) or it has sufficient rights
+to grant the rights to its Contributions conveyed by this License.
+
+2.6. Fair Use
+
+This License is not intended to limit any rights You have under
+applicable copyright doctrines of fair use, fair dealing, or other
+equivalents.
+
+2.7. Conditions
+
+Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
+in Section 2.1.
+
+3. Responsibilities
+-------------------
+
+3.1. Distribution of Source Form
+
+All distribution of Covered Software in Source Code Form, including any
+Modifications that You create or to which You contribute, must be under
+the terms of this License. You must inform recipients that the Source
+Code Form of the Covered Software is governed by the terms of this
+License, and how they can obtain a copy of this License. You may not
+attempt to alter or restrict the recipients' rights in the Source Code
+Form.
+
+3.2. Distribution of Executable Form
+
+If You distribute Covered Software in Executable Form then:
+
+(a) such Covered Software must also be made available in Source Code
+ Form, as described in Section 3.1, and You must inform recipients of
+ the Executable Form how they can obtain a copy of such Source Code
+ Form by reasonable means in a timely manner, at a charge no more
+ than the cost of distribution to the recipient; and
+
+(b) You may distribute such Executable Form under the terms of this
+ License, or sublicense it under different terms, provided that the
+ license for the Executable Form does not attempt to limit or alter
+ the recipients' rights in the Source Code Form under this License.
+
+3.3. Distribution of a Larger Work
+
+You may create and distribute a Larger Work under terms of Your choice,
+provided that You also comply with the requirements of this License for
+the Covered Software. If the Larger Work is a combination of Covered
+Software with a work governed by one or more Secondary Licenses, and the
+Covered Software is not Incompatible With Secondary Licenses, this
+License permits You to additionally distribute such Covered Software
+under the terms of such Secondary License(s), so that the recipient of
+the Larger Work may, at their option, further distribute the Covered
+Software under the terms of either this License or such Secondary
+License(s).
+
+3.4. Notices
+
+You may not remove or alter the substance of any license notices
+(including copyright notices, patent notices, disclaimers of warranty,
+or limitations of liability) contained within the Source Code Form of
+the Covered Software, except that You may alter any license notices to
+the extent required to remedy known factual inaccuracies.
+
+3.5. Application of Additional Terms
+
+You may choose to offer, and to charge a fee for, warranty, support,
+indemnity or liability obligations to one or more recipients of Covered
+Software. However, You may do so only on Your own behalf, and not on
+behalf of any Contributor. You must make it absolutely clear that any
+such warranty, support, indemnity, or liability obligation is offered by
+You alone, and You hereby agree to indemnify every Contributor for any
+liability incurred by such Contributor as a result of warranty, support,
+indemnity or liability terms You offer. You may include additional
+disclaimers of warranty and limitations of liability specific to any
+jurisdiction.
+
+4. Inability to Comply Due to Statute or Regulation
+---------------------------------------------------
+
+If it is impossible for You to comply with any of the terms of this
+License with respect to some or all of the Covered Software due to
+statute, judicial order, or regulation then You must: (a) comply with
+the terms of this License to the maximum extent possible; and (b)
+describe the limitations and the code they affect. Such description must
+be placed in a text file included with all distributions of the Covered
+Software under this License. Except to the extent prohibited by statute
+or regulation, such description must be sufficiently detailed for a
+recipient of ordinary skill to be able to understand it.
+
+5. Termination
+--------------
+
+5.1. The rights granted under this License will terminate automatically
+if You fail to comply with any of its terms. However, if You become
+compliant, then the rights granted under this License from a particular
+Contributor are reinstated (a) provisionally, unless and until such
+Contributor explicitly and finally terminates Your grants, and (b) on an
+ongoing basis, if such Contributor fails to notify You of the
+non-compliance by some reasonable means prior to 60 days after You have
+come back into compliance. Moreover, Your grants from a particular
+Contributor are reinstated on an ongoing basis if such Contributor
+notifies You of the non-compliance by some reasonable means, this is the
+first time You have received notice of non-compliance with this License
+from such Contributor, and You become compliant prior to 30 days after
+Your receipt of the notice.
+
+5.2. If You initiate litigation against any entity by asserting a patent
+infringement claim (excluding declaratory judgment actions,
+counter-claims, and cross-claims) alleging that a Contributor Version
+directly or indirectly infringes any patent, then the rights granted to
+You by any and all Contributors for the Covered Software under Section
+2.1 of this License shall terminate.
+
+5.3. In the event of termination under Sections 5.1 or 5.2 above, all
+end user license agreements (excluding distributors and resellers) which
+have been validly granted by You or Your distributors under this License
+prior to termination shall survive termination.
+
+************************************************************************
+* *
+* 6. Disclaimer of Warranty *
+* ------------------------- *
+* *
+* Covered Software is provided under this License on an "as is" *
+* basis, without warranty of any kind, either expressed, implied, or *
+* statutory, including, without limitation, warranties that the *
+* Covered Software is free of defects, merchantable, fit for a *
+* particular purpose or non-infringing. The entire risk as to the *
+* quality and performance of the Covered Software is with You. *
+* Should any Covered Software prove defective in any respect, You *
+* (not any Contributor) assume the cost of any necessary servicing, *
+* repair, or correction. This disclaimer of warranty constitutes an *
+* essential part of this License. No use of any Covered Software is *
+* authorized under this License except under this disclaimer. *
+* *
+************************************************************************
+
+************************************************************************
+* *
+* 7. Limitation of Liability *
+* -------------------------- *
+* *
+* Under no circumstances and under no legal theory, whether tort *
+* (including negligence), contract, or otherwise, shall any *
+* Contributor, or anyone who distributes Covered Software as *
+* permitted above, be liable to You for any direct, indirect, *
+* special, incidental, or consequential damages of any character *
+* including, without limitation, damages for lost profits, loss of *
+* goodwill, work stoppage, computer failure or malfunction, or any *
+* and all other commercial damages or losses, even if such party *
+* shall have been informed of the possibility of such damages. This *
+* limitation of liability shall not apply to liability for death or *
+* personal injury resulting from such party's negligence to the *
+* extent applicable law prohibits such limitation. Some *
+* jurisdictions do not allow the exclusion or limitation of *
+* incidental or consequential damages, so this exclusion and *
+* limitation may not apply to You. *
+* *
+************************************************************************
+
+8. Litigation
+-------------
+
+Any litigation relating to this License may be brought only in the
+courts of a jurisdiction where the defendant maintains its principal
+place of business and such litigation shall be governed by laws of that
+jurisdiction, without reference to its conflict-of-law provisions.
+Nothing in this Section shall prevent a party's ability to bring
+cross-claims or counter-claims.
+
+9. Miscellaneous
+----------------
+
+This License represents the complete agreement concerning the subject
+matter hereof. If any provision of this License is held to be
+unenforceable, such provision shall be reformed only to the extent
+necessary to make it enforceable. Any law or regulation which provides
+that the language of a contract shall be construed against the drafter
+shall not be used to construe this License against a Contributor.
+
+10. Versions of the License
+---------------------------
+
+10.1. New Versions
+
+Mozilla Foundation is the license steward. Except as provided in Section
+10.3, no one other than the license steward has the right to modify or
+publish new versions of this License. Each version will be given a
+distinguishing version number.
+
+10.2. Effect of New Versions
+
+You may distribute the Covered Software under the terms of the version
+of the License under which You originally received the Covered Software,
+or under the terms of any subsequent version published by the license
+steward.
+
+10.3. Modified Versions
+
+If you create software not governed by this License, and you want to
+create a new license for such software, you may create and use a
+modified version of this License if you rename the license and remove
+any references to the name of the license steward (except to note that
+such modified license differs from this License).
+
+10.4. Distributing Source Code Form that is Incompatible With Secondary
+Licenses
+
+If You choose to distribute Source Code Form that is Incompatible With
+Secondary Licenses under the terms of this version of the License, the
+notice described in Exhibit B of this License must be attached.
+
+Exhibit A - Source Code Form License Notice
+-------------------------------------------
+
+ This Source Code Form is subject to the terms of the Mozilla Public
+ License, v. 2.0. If a copy of the MPL was not distributed with this
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+If it is not possible or desirable to put the notice in a particular
+file, then You may include the notice in a location (such as a LICENSE
+file in a relevant directory) where a recipient would be likely to look
+for such a notice.
+
+You may add additional accurate notices of copyright ownership.
+
+Exhibit B - "Incompatible With Secondary Licenses" Notice
+---------------------------------------------------------
+
+ This Source Code Form is "Incompatible With Secondary Licenses", as
+ defined by the Mozilla Public License, v. 2.0.
diff --git a/deps/trace_runner/Makefile b/deps/trace_runner/Makefile
new file mode 100644
index 0000000..a0c2cba
--- /dev/null
+++ b/deps/trace_runner/Makefile
@@ -0,0 +1,9 @@
+.PHONY: all clean compile
+
+all: compile
+
+compile:
+ rebar compile
+
+clean:
+ rebar clean
diff --git a/deps/trace_runner/README.md b/deps/trace_runner/README.md
new file mode 100644
index 0000000..51b9141
--- /dev/null
+++ b/deps/trace_runner/README.md
@@ -0,0 +1,120 @@
+# trace_runner
+A wrapper for tracing test runs using TTB.
+
+This component is based on [locks_ttb](https://github.com/uwiger/locks/blob/master/src/locks_ttb.erl), whose main purpose was to be used in complicated
+multi-node test cases: a wrapper around the test case sets up a multi-node
+trace using ttb; if the test case succeeds, the traces are discarded, but
+if it fails, the logs are fetched, merged and formatted for 'easy' viewing.
+
+The idea is complemented with the notion of using an `event()` function,
+whose only purpose is to be traced. This can serve as extremely lightweight
+runtime debugging statements. Since the `event()` function only returns
+`ok`, the whole operation is cheaper than any runtime test for debug level
+could be. the `include/trace_runner.hrl` include file defines `?event`
+macros that can be used, including one that tests whether the `event()`
+function is traced, before evaluating the argument expression. This can
+be used to 'pretty-print' the arguments to the `event()` function without
+incurring overhead when not tracing (obviously there is *some* overhead in
+checking the trace status).
+
+Example (from https://github.com/PDXOstc/rvi_core, although at the time of writing, the trace_runner support hasn't yet been merged)
+
+First, we create a callback module for the `tr_ttb` behavior, which
+lets us specify trace patterns and trace flags.
+
+```erlang
+patterns() ->
+ [{authorize_rpc , event, 3, []},
+ {service_edge_rpc , event, 3, []},
+ {service_discovery_rpc, event, 3, []},
+ {dlink_tcp_rpc , event, 3, []},
+ {connection , event, 3, []},
+ {dlink_tls_rpc , event, 3, []},
+ {dlink_tls_conn , event, 3, []},
+ {dlink_bt_rpc , event, 3, []},
+ {bt_connection , event, 3, []},
+ {dlink_sms_rpc , event, 3, []},
+ {schedule_rpc , event, 3, []},
+ {proto_json_rpc , event, 3, []},
+ {proto_msgpack_rpc , event, 3, []},
+ {rvi_common , event, 3, []},
+ {?MODULE , event, 3, []}
+ | tr_ttb:default_patterns()].
+
+flags() ->
+ {all, call}.
+```
+
+Then, we instrument our test suite(s):
+
+```erlang
+t_multicall_sota_service(Config) ->
+ with_trace(fun t_multicall_sota_service_/1, Config,
+ "t_multicall_sota_service").
+
+t_multicall_sota_service_(_Config) ->
+ %% the actual test case
+ Data = <<"abc">>,
+ ...
+```
+
+In the wrapper, we determine which nodes to include in the trace,
+give the trace a name, then call the test case within a try ... catch.
+If the test succeeds, we call `stop_nofetch()`, discarding the trace,
+otherwise, we fetch the trace logs and merge them, pretty-printing
+the result.
+
+```erlang
+with_trace(F, Config, File) ->
+ Nodes = [N || {N,_} <- get_nodes()],
+ rvi_ttb:on_nodes([node()|Nodes], File),
+ try F(Config)
+ catch
+ error:R ->
+ Stack = erlang:get_stacktrace(),
+ ttb_stop(),
+ ct:log("Error ~p; Stack = ~p", [R, Stack]),
+ erlang:error(R);
+ exit:R ->
+ ttb_stop(),
+ exit(R)
+ end,
+ rvi_ttb:stop_nofetch(),
+ ok.
+
+ttb_stop() ->
+ Dir = rvi_ttb:stop(),
+ Out = filename:join(filename:dirname(Dir),
+ filename:basename(Dir) ++ ".txt"),
+ rvi_ttb:format(Dir, Out),
+ ct:log("Formatted trace log in ~s~n", [Out]).
+```
+
+On test failure, this would result in the following output in the CT log:
+
+<img src="doc/images/ttb-log-snap-1.png" alt="trace log snapshot 2" style="width:800">
+
+The formatted text log has an emacs erlang-mode header, so is best
+viewed in emacs.
+
+<img src="doc/images/ttb-log-snap.png" alt="trace log snapshot" style="width:800">
+
+Note that the log formatter prefixes each message with the relative time
+(in ms) since the start of the trace, the name of the node where the
+trace event originated and the module/line of the traced call.
+It also tries to pretty-print records, looking for a
+`record_fields(RecName)` callback in the module named in the call trace.
+
+<img src="doc/images/ttb-log-snap-2.png" alt="trace log snapshot 2" style="width:800">
+
+A `record_fields/1` function might look like this:
+
+```erlang
+record_fields(service_entry) -> record_info(fields, service_entry);
+record_fields(st ) -> record_info(fields, st);
+record_fields(component_spec) -> record_info(fields, component_spec);
+record_fields(_) -> no.
+```
+
+In the future, more log formatting options may be added.
+Pull requests are welcome.
diff --git a/deps/trace_runner/doc/images/ttb-log-snap-1.png b/deps/trace_runner/doc/images/ttb-log-snap-1.png
new file mode 100644
index 0000000..e279ec4
--- /dev/null
+++ b/deps/trace_runner/doc/images/ttb-log-snap-1.png
Binary files differ
diff --git a/deps/trace_runner/doc/images/ttb-log-snap-2.png b/deps/trace_runner/doc/images/ttb-log-snap-2.png
new file mode 100644
index 0000000..75d502b
--- /dev/null
+++ b/deps/trace_runner/doc/images/ttb-log-snap-2.png
Binary files differ
diff --git a/deps/trace_runner/doc/images/ttb-log-snap.png b/deps/trace_runner/doc/images/ttb-log-snap.png
new file mode 100644
index 0000000..75cee87
--- /dev/null
+++ b/deps/trace_runner/doc/images/ttb-log-snap.png
Binary files differ
diff --git a/deps/trace_runner/include/trace_runner.hrl b/deps/trace_runner/include/trace_runner.hrl
new file mode 100644
index 0000000..353c258
--- /dev/null
+++ b/deps/trace_runner/include/trace_runner.hrl
@@ -0,0 +1,29 @@
+%% -*- mode: erlang; indent-tabs-mode: nil; -*-
+%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%
+%% Copyright (C) 2016 Ulf Wiger. All rights reserved.
+%%
+%% This Source Code Form is subject to the terms of the Mozilla Public
+%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%
+%%---- END COPYRIGHT ---------------------------------------------------------
+
+-ifndef(event).
+
+-define(costly_event(E),
+ case erlang:trace_info({MODULE,event,3}, traced) of
+ {_, false} -> ok;
+ _ -> event(?LINE, E, none)
+ end).
+
+-define(costly_event(E, S),
+ case erlang:trace_info({MODULE,event,3}, traced) of
+ {_, false} -> ok;
+ _ -> event(?LINE, E, S)
+ end).
+
+-define(event(E), event(?LINE, E, none)).
+-define(event(E, S), event(?LINE, E, S)).
+
+-endif. % ?event()
diff --git a/deps/trace_runner/src/tr_ttb.erl b/deps/trace_runner/src/tr_ttb.erl
new file mode 100644
index 0000000..339b28f
--- /dev/null
+++ b/deps/trace_runner/src/tr_ttb.erl
@@ -0,0 +1,213 @@
+%% -*- mode: erlang; indent-tabs-mode: nil; -*-
+%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%
+%% Copyright (C) 2016 Ulf Wiger. All rights reserved.
+%%
+%% This Source Code Form is subject to the terms of the Mozilla Public
+%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%
+%%---- END COPYRIGHT ---------------------------------------------------------
+-module(tr_ttb).
+
+-export([ event/1 ]).
+
+-export([
+ on_nodes/2,
+ on_nodes/3,
+ on_nodes/4,
+ default_patterns/0,
+ default_flags/0,
+ stop/0,
+ stop_nofetch/0,
+ format/1,
+ format/2,
+ format_opts/0,
+ format_opts/1,
+ handler/4,
+ pp/3,
+ record_print_fun/1
+ ]).
+
+-type trace_pat() :: any().
+-type pattern() :: {module(), atom(), arity(), trace_pat()}.
+
+-callback flags() -> [{atom(), any()}].
+-callback patterns() -> [pattern()].
+
+
+%% This function is also traced. Can be used to insert markers in the trace
+%% log.
+event(E) ->
+ event(?LINE, E, none).
+
+event(_, _, _) ->
+ ok.
+
+on_nodes(Ns, File) ->
+ on_nodes(Ns, default_patterns(), default_flags(), [{file, File}]).
+
+on_nodes(Ns, File, Mod) ->
+ on_nodes(Ns,
+ cb(Mod, patterns, [], default_patterns()),
+ cb(Mod, flags, [], default_flags()),
+ [{mod, Mod}, {file, File}]).
+
+on_nodes(Ns, Patterns, Flags, Opts) ->
+ ttb:start_trace(Ns, Patterns, Flags, lists:keydelete(mod, 1, Opts)).
+
+default_patterns() ->
+ [{?MODULE , event, 3, []}].
+
+default_flags() ->
+ {all, call}.
+
+stop() ->
+ {stopped, Dir} = ttb:stop([return_fetch_dir]),
+ Dir.
+
+stop_nofetch() ->
+ ttb:stop([nofetch]).
+
+format(Dir) ->
+ format(Dir, standard_io).
+
+format(Dir, OutFile) ->
+ ttb:format(Dir, format_opts(OutFile)).
+
+format_opts() ->
+ format_opts(standard_io).
+
+format_opts(OutFile) ->
+ [{out, OutFile}, {handler, {fun handler/4, {0,0}}}].
+
+handler(Fd, Trace, _, {Tp,Diff} = Acc) ->
+ if Acc == {0,0} ->
+ io:fwrite(Fd, "%% -*- erlang -*-~n", []);
+ true -> ok
+ end,
+ case Trace of
+ {trace_ts,{_, _, Node},
+ call,
+ {Mod, event, [Line, Evt, State]}, TS} when is_integer(Line) ->
+ Tdiff = tdiff(TS, Tp),
+ Diff1 = Diff + Tdiff,
+ print(Fd, Node, Mod, Line, Evt, State, Diff1),
+ case get_pids({Evt, State}) of
+ [] -> ok;
+ Pids ->
+ io:fwrite(Fd, " Nodes = ~p~n", [Pids])
+ end,
+ {TS, Diff1};
+ _ ->
+ io:fwrite(Fd, "~p~n", [Trace]),
+ {Tp, Diff}
+ end.
+
+-define(CHAR_MAX, 60).
+
+print(Fd, N, Mod, L, E, St, T) ->
+ Tstr = io_lib:fwrite("~w", [T]),
+ Indent = iolist_size(Tstr) + 3,
+ Head = io_lib:fwrite(" - ~w|~w/~w: ", [N, Mod, L]),
+ EvtCol = iolist_size(Head) + 1,
+ EvtCs = pp(E, EvtCol, Mod),
+ io:requests(Fd, [{put_chars, unicode, [Tstr, Head, EvtCs]}, nl
+ | print_tail(St, Mod, Indent)]).
+
+print_tail(none, _, _Col) -> [];
+print_tail(St, Mod, Col) ->
+ Cs = pp(St, Col+1, Mod),
+ [{put_chars, unicode, [lists:duplicate(Col,$\s), Cs]}, nl].
+
+pp(Term, Col, Mod) ->
+ io_lib_pretty:print(pp_term(Term),
+ [{column, Col},
+ {line_length, 80},
+ {depth, -1},
+ {max_chars, ?CHAR_MAX},
+ {record_print_fun, record_print_fun(Mod)}]).
+
+pp_term(D) when element(1,D) == dict ->
+ try {'$dict', dict:to_list(D)}
+ catch
+ error:_ ->
+ list_to_tuple([pp_term(T) || T <- tuple_to_list(D)])
+ end;
+pp_term(T) when is_tuple(T) ->
+ list_to_tuple([pp_term(Trm) || Trm <- tuple_to_list(T)]);
+pp_term(L) when is_list(L) ->
+ [pp_term(T) || T <- L];
+pp_term(T) ->
+ T.
+
+tdiff(_, 0) -> 0;
+tdiff(TS, T0) ->
+ %% time difference in milliseconds
+ timer:now_diff(TS, T0) div 1000.
+
+record_print_fun(Mod) ->
+ fun(Tag, NoFields) ->
+ try Mod:record_fields(Tag) of
+ Fields when is_list(Fields) ->
+ case length(Fields) of
+ NoFields -> Fields;
+ _ -> no
+ end;
+ no -> no
+ catch
+ _:_ ->
+ no
+ end
+ end.
+
+get_pids(Term) ->
+ Pids = dict:to_list(get_pids(Term, dict:new())),
+ [{node_prefix(P), N} || {N, P} <- Pids].
+
+get_pids(T, Acc) when is_tuple(T) ->
+ get_pids(tuple_to_list(T), Acc);
+get_pids(L, Acc) when is_list(L) ->
+ get_pids_(L, Acc);
+get_pids(P, Acc) when is_pid(P) ->
+ try ets:lookup(ttb, P) of
+ [{_, _, Node}] ->
+ dict:store(Node, P, Acc);
+ _ ->
+ Acc
+ catch
+ error:_ -> Acc
+ end;
+get_pids(_, Acc) ->
+ Acc.
+
+get_pids_([H|T], Acc) ->
+ get_pids_(T, get_pids(H, Acc));
+get_pids_(_, Acc) ->
+ Acc.
+
+
+node_prefix(P) ->
+ case re:run(pid_to_list(P), "[^<\\.]+", [{capture,first,list}]) of
+ {match, [Pfx]} ->
+ Pfx;
+ _ ->
+ P
+ end.
+
+cb(Mod, F, Args, Default) ->
+ ensure_loaded(Mod),
+ case erlang:function_exported(Mod, F, length(Args)) of
+ true ->
+ apply(Mod, F, Args);
+ false ->
+ Default
+ end.
+
+ensure_loaded(Mod) ->
+ case code:ensure_loaded(Mod) of
+ {module, _} ->
+ true;
+ {error, _} ->
+ false
+ end.
diff --git a/deps/trace_runner/src/trace_runner.app.src b/deps/trace_runner/src/trace_runner.app.src
new file mode 100644
index 0000000..0454c1f
--- /dev/null
+++ b/deps/trace_runner/src/trace_runner.app.src
@@ -0,0 +1,22 @@
+%% -*- mode: erlang; indent-tabs-mode: nil; -*-
+%%---- BEGIN COPYRIGHT -------------------------------------------------------
+%%
+%% Copyright (C) 2016 Ulf Wiger. All rights reserved.
+%%
+%% This Source Code Form is subject to the terms of the Mozilla Public
+%% License, v. 2.0. If a copy of the MPL was not distributed with this
+%% file, You can obtain one at http://mozilla.org/MPL/2.0/.
+%%
+%%---- END COPYRIGHT ---------------------------------------------------------
+{application, trace_runner,
+ [
+ {description, "A wrapper for tracing test runs using TTB"},
+ {vsn, "1"},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib,
+ observer
+ ]},
+ {env, []}
+ ]}.
diff --git a/rebar.config b/rebar.config
index f217849..6533c9e 100644
--- a/rebar.config
+++ b/rebar.config
@@ -38,13 +38,15 @@
%% given in gsms/rebar.config and uart/rebar.config, so
%% we'll specify them with a working reference here instead.
{bt, ".*", {git, "git://github.com/magnusfeuer/bt.git", "HEAD"}},
+ {netlink, ".*", {git, "git://github.com/Feuerlabs/netlink.git", "HEAD"}},
{dthread, ".*", {git, "git://github.com/tonyrog/dthread.git", "HEAD"}},
{uart, ".*", {git, "git://github.com/tonyrog/uart.git", "HEAD"}},
{gsms, ".*", {git, "git://github.com/tonyrog/gsms.git", {branch,"uw-session-behavior"}}},
{base64url, ".*", {git, "git://github.com/dvv/base64url.git", "HEAD"}},
{msgpack, ".*", {git, "git://github.com/msgpack/msgpack-erlang.git", "HEAD"}},
{exec, ".*", {git, "git://github.com/saleyn/erlexec.git", "HEAD"}},
- {gproc, ".*", {git, "git://github.com/uwiger/gproc.git", "HEAD"}}
+ {gproc, ".*", {git, "git://github.com/uwiger/gproc.git", "HEAD"}},
+ {trace_runner, ".*", {git, "git://github.com/uwiger/trace_runner.git", "HEAD"}}
]}.
{xref_checks,
diff --git a/test/rvi_core_SUITE.erl b/test/rvi_core_SUITE.erl
index b563755..93b518c 100644
--- a/test/rvi_core_SUITE.erl
+++ b/test/rvi_core_SUITE.erl
@@ -317,7 +317,11 @@ t_register_sota_service(_Config) ->
t_call_sota_service(_Config) ->
call_sota_service_(sota_client, sota_bin()).
-t_multicall_sota_service(_Config) ->
+t_multicall_sota_service(Config) ->
+ with_trace(fun t_multicall_sota_service_/1, Config,
+ "t_multicall_sota_service").
+
+t_multicall_sota_service_(_Config) ->
Data = <<"abc">>,
Pids = [spawn_monitor(fun() ->
exit({ok, call_sota_service_(N, Data)})
@@ -546,13 +550,17 @@ join_stdout_msgs_rev(L) ->
spawn_cmd(Cmd0) ->
Cmd = binary_to_list(iolist_to_binary(Cmd0)),
Me = self(),
- Pid = spawn(fun() ->
- Res = exec:run(Cmd, [stdin, stdout, stderr]),
- ct:log("~s ->~n~p~n", [Cmd, Res]),
- Me ! {self(), ok},
- cmd_loop()
- end),
+ {Pid, Ref} =
+ spawn_monitor(fun() ->
+ Res = exec:run(Cmd, [stdin, stdout, stderr]),
+ ct:log("~s ->~n~p~n", [Cmd, Res]),
+ Me ! {self(), ok},
+ cmd_loop()
+ end),
receive
+ {'DOWN', Ref, _, _, Reason} ->
+ error({spawn_cmd, [{cmd, Cmd},
+ {error, Reason}]});
{Pid, ok} ->
Pid
end.
@@ -644,7 +652,7 @@ generate_cred(sample, KeyDir, CredDir, _Config) ->
" --stop='", Stop, "'"
" --root_key=", root_keys(), "/root_key.pem"
" --receive='jlr.com/vin/abc/unlock jlr.com/vin/abc/lock'"
- " --invoke='jlr.com/backend/set_state'"
+ " --invoke='jlr.com/vin/abc/lock jlr.com/backend/set_state'"
" --jwt_out=", CredDir, "/lock_cred.jwt"
" --cred_out=", KeyDir, "/lock_cred.json"]),
ok;
@@ -677,7 +685,7 @@ generate_sota_cred(sample, KeyDir, CredDir, _Config) ->
" --stop='", Stop, "'"
" --root_key=", root_keys(), "/root_key.pem"
" --receive='jlr.com/vin/abc/store'"
- " --invoke='jlr.com/backend/set_state'"
+ " --invoke='jlr.com/vin/abc/sota jlr.com/backend/set_state'"
" --jwt_out=", CredDir, "/sota_cred.jwt"
" --cred_out=", KeyDir, "/sota_cred.json"]),
ok;
@@ -858,12 +866,16 @@ save_ospid(Node) ->
%% lookup({Node, pid}).
stop_nodes() ->
- Nodes = ets:select(?DATA, [{ {{'$1',pid},'$2'}, [], [{{'$1','$2'}}] }]),
+ Nodes = get_nodes(),
ct:log("Stopping, Nodes = ~p~n", [Nodes]),
rpc:multicall([N || {N,_} <- Nodes], init, stop, []),
[verify_killed(cmd_(["kill -9 ", P], [])) || {_,P} <- Nodes],
[delete_node(N) || {N,_} <- Nodes].
+get_nodes() ->
+ ets:select(?DATA, [{ {{'$1',pid},'$2'}, [], [{{'$1','$2'}}] }]).
+
+
stop_services() ->
Services =
ets:select(?DATA, [{ {{service,'_'},'_'}, [], ['$_'] },
@@ -948,3 +960,28 @@ log_is_empty(Log, F, Name) ->
ct:log("~s: Cannot read log ~s (~p)", [Name, Log, Reason]),
false
end.
+
+
+with_trace(F, Config, File) ->
+ Nodes = [N || {N,_} <- get_nodes()],
+ rvi_ttb:on_nodes([node()|Nodes], File),
+ try F(Config)
+ catch
+ error:R ->
+ Stack = erlang:get_stacktrace(),
+ ttb_stop(),
+ ct:log("Error ~p; Stack = ~p", [R, Stack]),
+ erlang:error(R);
+ exit:R ->
+ ttb_stop(),
+ exit(R)
+ end,
+ rvi_ttb:stop_nofetch(),
+ ok.
+
+ttb_stop() ->
+ Dir = rvi_ttb:stop(),
+ Out = filename:join(filename:dirname(Dir),
+ filename:basename(Dir) ++ ".txt"),
+ rvi_ttb:format(Dir, Out),
+ ct:log("Formatted trace log in ~s~n", [Out]).