summaryrefslogtreecommitdiff
path: root/deps/netlink/src/netlink_stat.erl
blob: eb7775e0d7507a4b31537d8aecc5990d6404d0c4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
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.