1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 2014-2020. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
21%% This test suite uses the following external programs:
22%%     snmpget    From packet 'snmp' (in Ubuntu 12.04)
23%%     snmpd      From packet 'snmpd' (in Ubuntu 12.04)
24%%     snmptrapd  From packet 'snmpd' (in Ubuntu 12.04)
25%% They originate from the Net-SNMP applications, see:
26%%     http://net-snmp.sourceforge.net/
27
28
29-module(snmp_to_snmpnet_SUITE).
30
31-export([
32         suite/0, all/0, groups/0,
33         init_per_suite/1,    end_per_suite/1,
34         init_per_group/2,    end_per_group/2,
35         init_per_testcase/2, end_per_testcase/2,
36
37         erlang_agent_netsnmp_get/0,    erlang_agent_netsnmp_get/1,
38         erlang_agent_netsnmp_inform/0, erlang_agent_netsnmp_inform/1,
39         erlang_manager_netsnmp_get/0,  erlang_manager_netsnmp_get/1
40
41        ]).
42
43-include("snmp_test_lib.hrl").
44-include_lib("common_test/include/ct.hrl").
45-include_lib("snmp/include/STANDARD-MIB.hrl").
46
47-define(AGENT_ENGINE_ID, "ErlangSnmpAgent").
48-define(MANAGER_ENGINE_ID, "ErlangSnmpManager").
49-define(AGENT_PORT, 4000).
50-define(MANAGER_PORT, 8989).
51-define(DEFAULT_MAX_MESSAGE_SIZE, 484).
52
53expected(?sysDescr_instance = Oid, get) ->
54    OidStr = oid_str(Oid),
55    iolist_to_binary([OidStr | " = STRING: \"Erlang SNMP agent\""]).
56
57
58%%--------------------------------------------------------------------
59%% Common Test interface functions -----------------------------------
60%%--------------------------------------------------------------------
61
62suite() -> [{ct_hooks,[ts_install_cth]}].
63
64all() ->
65    [
66     {group, ipv4},
67     {group, ipv6},
68     {group, ipv4_ipv6}
69    ].
70
71groups() ->
72    [
73     {ipv4,      [], ipv4_cases()},
74     {ipv6,      [], ipv6_cases()},
75     {ipv4_ipv6, [], ipv4_ipv6_cases()},
76
77     {snmpget,   [], snmpget_cases()},
78     {snmptrapd, [], snmptrapd_cases()},
79     {snmpd_mt,  [], snmpd_mt_cases()},
80     {snmpd,     [], snmpd_cases()}
81    ].
82
83ipv4_cases() ->
84    [
85     {group, snmpget},
86     {group, snmptrapd},
87     {group, snmpd_mt},
88     {group, snmpd}
89    ].
90
91ipv6_cases() ->
92    [
93     {group, snmpget},
94     {group, snmptrapd},
95     {group, snmpd_mt},
96     {group, snmpd}
97    ].
98
99ipv4_ipv6_cases() ->
100     [
101      {group, snmpget},
102      {group, snmptrapd},
103      {group, snmpd_mt},
104      {group, snmpd}
105     ].
106
107snmpget_cases() ->
108    [
109     erlang_agent_netsnmp_get
110    ].
111
112snmptrapd_cases() ->
113    [
114     erlang_agent_netsnmp_inform
115    ].
116
117snmpd_mt_cases() ->
118    [
119     erlang_manager_netsnmp_get
120    ].
121
122snmpd_cases() ->
123    [
124     erlang_manager_netsnmp_get
125    ].
126
127
128
129%%
130%% -----
131%%
132
133init_per_suite(Config0) ->
134    ?IPRINT("init_per_suite -> entry with"
135            "~n   Config: ~p", [Config0]),
136
137    case netsnmp_init(Config0) of
138        {skip, _} = SKIP ->
139            SKIP;
140
141        Config1 ->
142            case ?LIB:init_per_suite(Config1) of
143                {skip, _} = SKIP ->
144                    SKIP;
145
146                Config2 when is_list(Config2) ->
147                    snmp_test_sys_monitor:start(),
148
149                    ?IPRINT("init_per_suite -> end when"
150                            "~n      Config: ~p", [Config2]),
151
152                    Config2
153            end
154    end.
155
156netsnmp_init(Config) ->
157    case has_netsnmp() of
158        true ->
159            case proper_netsnmp_version() of
160                true ->
161                    [{agent_port,   ?AGENT_PORT},
162                     {manager_port, ?MANAGER_PORT} | Config];
163                false ->
164                    {skip, "Buggy NetSNMP"}
165            end;
166        false ->
167            {skip, "No NetSNMP"}
168    end.
169
170has_netsnmp() ->
171    netsnmp_check("NET-SNMP").
172
173proper_netsnmp_version() ->
174    not netsnmp_check("5.4|5.6.2.1").
175
176netsnmp_check(RE) ->
177    case re:run(os:cmd("snmpd -v"), RE, [{capture, first}]) of
178        nomatch ->
179            false;
180        {match, _} ->
181            true
182    end.
183
184
185end_per_suite(Config) ->
186    ?IPRINT("end_per_suite -> entry with"
187            "~n   Config: ~p", [Config]),
188
189    snmp_test_sys_monitor:stop(),
190    ?LIB:end_per_suite(Config),
191
192    ?IPRINT("end_per_suite -> end"),
193
194    Config.
195
196%%
197%% -----
198%%
199
200init_per_group(ipv4, Config) ->
201    init_per_group_ip([inet], Config);
202init_per_group(ipv6, Config) ->
203    init_per_group_ipv6([inet6], Config);
204init_per_group(ipv4_ipv6, Config) ->
205    init_per_group_ipv6([inet, inet6], Config);
206
207init_per_group(snmpget = Exec, Config) ->
208    %% From Ubuntu package snmp
209    init_per_group_agent(Exec, Config);
210init_per_group(snmptrapd = Exec, Config) ->
211    %% From Ubuntu package snmpd
212    init_per_group_agent(Exec, Config);
213init_per_group(snmpd_mt, Config) ->
214    %% From Ubuntu package snmp
215    init_per_group_manager(
216      snmpd,
217      [{manager_net_if_module, snmpm_net_if_mt} | Config]);
218init_per_group(snmpd = Exec, Config) ->
219    %% From Ubuntu package snmp
220    init_per_group_manager(
221      Exec,
222      [{manager_net_if_module, snmpm_net_if} | Config]);
223
224init_per_group(_, Config) ->
225    Config.
226
227init_per_group_ipv6(Families, Config) ->
228    case ?HAS_SUPPORT_IPV6() of
229        true ->
230            init_per_group_ip(Families, Config);
231        false ->
232            {skip, "Host does not support IPv6"}
233    end.
234
235init_per_group_ip(Families, Config) ->
236    AgentPort = ?config(agent_port, Config),
237    ManagerPort = ?config(manager_port, Config),
238    Transports =
239	[begin
240             Addr = ?LIB:localhost(Family),
241	     {domain(Family), {Addr, AgentPort}}
242	 end || Family <- Families],
243    Targets =
244	[begin
245             Addr = ?LIB:localhost(Family),
246	     {domain(Family), {Addr, ManagerPort}}
247	 end || Family <- Families],
248    [{transports, Transports}, {targets, Targets} | Config].
249
250init_per_group_agent(Exec, Config) ->
251    Versions = [v2],
252    Dir = ?config(priv_dir, Config),
253    Transports = ?config(transports, Config),
254    Targets = ?config(targets, Config),
255    agent_config(Dir, Transports, Targets, Versions),
256    find_executable(Exec, [{snmp_versions, Versions} | Config]).
257
258init_per_group_manager(Exec, Config) ->
259    Versions = [v2],
260    Dir = ?config(priv_dir, Config),
261    Targets = ?config(targets, Config),
262    manager_config(Dir, Targets),
263    find_executable(Exec, [{snmp_versions, Versions} | Config]).
264
265
266end_per_group(_GroupName, Config) ->
267    Config.
268
269
270
271%%
272%% -----
273%%
274
275init_per_testcase(_Case, Config) ->
276    ?IPRINT("init_per_testcase -> entry with"
277            "~n   Config: ~p", [Config]),
278
279    snmp_test_global_sys_monitor:reset_events(),
280
281    Dog = ct:timetrap(?SECS(20)),
282    application:stop(snmp),
283    application:unload(snmp),
284    Config1 = [{watchdog, Dog} | Config],
285
286    ?IPRINT("init_per_testcase -> done when"
287            "~n   Config: ~p", [Config1]),
288
289    Config1.
290
291end_per_testcase(_, Config) ->
292
293    ?IPRINT("end_per_testcase -> entry with"
294            "~n   Config:  ~p", [Config]),
295
296    ?IPRINT("system events during test: "
297            "~n   ~p", [snmp_test_global_sys_monitor:events()]),
298
299    case application:stop(snmp) of
300	ok ->
301	    ok;
302	E1 ->
303	    ct:pal("application:stop(snmp) -> ~p", [E1])
304    end,
305    case application:unload(snmp) of
306	ok ->
307	    ok;
308	E2 ->
309	    ct:pal("application:unload(snmp) -> ~p", [E2])
310    end,
311
312    ?IPRINT("end_per_testcase -> done with"
313            "~n   Config: ~p", [Config]),
314
315    Config.
316
317find_executable(Exec, Config) ->
318    ExecStr = atom_to_list(Exec),
319    case os:find_executable(ExecStr) of
320	false ->
321	    %% The sbin dirs are not in the PATH on all platforms...
322	    find_sys_executable(
323	      Exec, ExecStr,
324	      [["usr", "local", "sbin"],
325	       ["usr", "sbin"],
326	       ["sbin"]],
327	     Config);
328	Path ->
329	    [{Exec, Path} | Config]
330    end.
331
332find_sys_executable(_Exec, ExecStr, [], _Config) ->
333    {skip, ExecStr ++ " not found"};
334find_sys_executable(Exec, ExecStr, [Dir | Dirs], Config) ->
335    case os:find_executable(filename:join(["/" | Dir] ++ [ExecStr])) of
336	false ->
337	    find_sys_executable(Exec, ExecStr, Dirs, Config);
338	Path ->
339	    [{Exec, Path} | Config]
340    end.
341
342start_agent(Config) ->
343    ok = application:load(snmp),
344    ok = application:set_env(snmp, agent, agent_app_env(Config)),
345    ok = application:start(snmp).
346
347start_manager(Config) ->
348    ok = application:load(snmp),
349    ok = application:set_env(snmp, manager, manager_app_env(Config)),
350    ok = application:start(snmp).
351
352
353
354%%--------------------------------------------------------------------
355%% Test Cases --------------------------------------------------------
356%%--------------------------------------------------------------------
357erlang_agent_netsnmp_get() ->
358    [{doc,"Test that we can access erlang snmp agent "
359      "from snmpnet manager"}].
360
361erlang_agent_netsnmp_get(Config) when is_list(Config) ->
362    Transports = ?config(transports, Config),
363    start_agent(Config),
364    Oid = ?sysDescr_instance,
365    Expected = expected(Oid, get),
366    try
367        begin
368            [Expected = snmpget(Oid, Transport, Config)
369             || Transport <- Transports],
370            ok
371        end
372    catch
373        throw:{skip, _} = SKIP ->
374            SKIP
375    end.
376
377
378%%--------------------------------------------------------------------
379erlang_manager_netsnmp_get() ->
380    [{doc,"Test that the erlang snmp manager can access snmpnet agent"}].
381
382erlang_manager_netsnmp_get(Config) when is_list(Config) ->
383    Community  = "happy-testing",
384    SysDescr   = "Net-SNMP agent",
385    TargetName = "Target Net-SNMP agent",
386    Transports = ?config(transports, Config),
387    case start_snmpd(Community, SysDescr, Config) of
388        {skip, _} = SKIP ->
389            SKIP;
390        ProgHandle ->
391            start_manager(Config),
392            snmp_manager_user:start_link(self(), test_user),
393            [snmp_manager_user:register_agent(
394               TargetName++domain_suffix(Domain),
395               [{reg_type, target_name},
396                {tdomain, Domain}, {taddress, Addr},
397                {community, Community}, {engine_id, "EngineId"},
398                {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
399             || {Domain, Addr} <- Transports],
400            Results =
401                [snmp_manager_user:sync_get(
402                   TargetName++domain_suffix(Domain),
403                   [?sysDescr_instance])
404                 || {Domain, _} <- Transports],
405            ct:pal("sync_get -> ~p", [Results]),
406            snmp_manager_user:stop(),
407            stop_program(ProgHandle),
408            [{ok,
409              {noError, 0,
410               [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
411              _} = R || R <- Results],
412            ok
413    end.
414
415
416%%--------------------------------------------------------------------
417erlang_agent_netsnmp_inform() ->
418    [{doc, "TBD"}].
419
420erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
421    DataDir = ?config(data_dir, Config),
422    Mib = "TestTrapv2",
423
424    start_agent(Config),
425    ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)),
426
427    case start_snmptrapd(Mib, Config) of
428        {skip, _} = SKIP ->
429            SKIP;
430        ProgHandle ->
431            snmpa:send_notification(
432              snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
433            receive
434                {snmp_targets, erlang_agent_test, Addresses} ->
435                    ct:pal("Notification sent to: ~p~n", [Addresses]),
436                    erlang_agent_netsnmp_inform_responses(Addresses)
437            end,
438            stop_program(ProgHandle)
439    end.
440
441erlang_agent_netsnmp_inform_responses([]) ->
442    receive
443	{snmp_notification, erlang_agent_test, _} = Unexpected ->
444	    ct:pal("Unexpected response: ~p", [Unexpected]),
445	    erlang_agent_netsnmp_inform_responses([])
446    after 0 ->
447	    ok
448    end;
449erlang_agent_netsnmp_inform_responses([Address | Addresses]) ->
450    receive
451	{snmp_notification, erlang_agent_test,
452	 {got_response, Address}} ->
453	    ct:pal("Got response from: ~p~n", [Address]),
454	    erlang_agent_netsnmp_inform_responses(Addresses);
455	{snmp_notification, erlang_agent_test,
456	 {no_response, _} = NoResponse} ->
457	    ct:fail(NoResponse)
458    end.
459
460%%--------------------------------------------------------------------
461%% Internal functions ------------------------------------------------
462%%--------------------------------------------------------------------
463
464snmpget(Oid, Transport, Config) ->
465    Versions = ?config(snmp_versions, Config),
466
467    Args =
468	["-c", "public", net_snmp_version(Versions),
469	 "-m", ":",
470	 "-Cf",
471	 net_snmp_addr_str(Transport),
472	 oid_str(Oid)],
473    case start_program(snmpget, Args, none, Config) of
474        {skip, _} = SKIP ->
475            throw(SKIP);
476        ProgHandle ->
477            {_, line, Line} = get_program_output(ProgHandle),
478            stop_program(ProgHandle),
479            Line
480    end.
481
482start_snmptrapd(Mibs, Config) ->
483    DataDir = ?config(data_dir, Config),
484    MibDir = filename:join(code:lib_dir(snmp), "mibs"),
485    Targets = ?config(targets, Config),
486    SnmptrapdArgs =
487	["-f", "-Lo", "-C",
488	 "-m", Mibs,
489	 "-M", MibDir++":"++DataDir,
490	 "--disableAuthorization=yes",
491	 "--snmpTrapdAddr=" ++ net_snmp_addr_str(Targets)],
492    {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]),
493    start_program(snmptrapd, SnmptrapdArgs, StartCheckMP, Config).
494
495start_snmpd(Community, SysDescr, Config) ->
496    DataDir = ?config(data_dir, Config),
497    Targets = ?config(targets, Config),
498    Transports = ?config(transports, Config),
499    Port = mk_port_number(),
500    CommunityArgs =
501	["--rocommunity"++domain_suffix(Domain)++"="
502	 ++Community++" "++inet_parse:ntoa(Ip)
503	 || {Domain, {Ip, _}} <- Targets],
504
505    SnmpdArgs =
506        ["-f", "-r", %"-Dverbose",
507         "-c", filename:join(DataDir, "snmpd.conf"),
508         "-C",
509         "-Lo",
510	 "-m", ":",
511	 "--sysDescr="++SysDescr,
512	 "--agentXSocket=tcp:localhost:"++integer_to_list(Port)]
513	++ CommunityArgs
514	++ [net_snmp_addr_str(Transports)],
515    {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]),
516    start_program(snmpd, SnmpdArgs, StartCheckMP, Config).
517
518start_program(Prog, Args, StartCheckMP, Config) ->
519    ct:pal("Starting program: ~w ~p", [Prog, Args]),
520    Path = ?config(Prog, Config),
521    DataDir = ?config(data_dir, Config),
522    StartWrapper = filename:join(DataDir, "start_stop_wrapper"),
523    Parent = self(),
524    %% process_flag(trap_exit, true),
525    {Pid, Mon} =
526	spawn_monitor(
527	  fun () ->
528		  run_program(Parent, StartWrapper, [Path | Args])
529	  end),
530    start_check(Pid, Mon, StartCheckMP).
531
532start_check(Pid, Mon, none) ->
533    {Pid, Mon};
534start_check(Pid, Mon, StartCheckMP) ->
535    receive
536	{Pid, line, Line} ->
537	    case re:run(Line, StartCheckMP, [{capture, none}]) of
538		match ->
539		    {Pid, Mon};
540		nomatch ->
541		    start_check(Pid, Mon, StartCheckMP)
542	    end;
543	{'DOWN', Mon, _, _Pid, {skip, Reason} = SKIP} ->
544	    ct:pal("Received DOWN from ~p"
545                   "~n   Skip Reason: ~p", [_Pid, Reason]),
546            SKIP;
547	{'DOWN', Mon, _, _, Reason} ->
548	    ct:fail("Prog ~p start failed: ~p", [Pid, Reason])
549    end.
550
551get_program_output({Pid, Mon}) ->
552    receive
553	{Pid, _, _} = Msg ->
554	    Msg;
555	{'DOWN', Mon, _, _, Reason} ->
556	    ct:fail("Prog ~p crashed: ~p", [Pid, Reason])
557    end.
558
559stop_program({Pid, _} = Handle) ->
560    Pid ! {self(), stop},
561    wait_program_stop(Handle).
562
563wait_program_stop({Pid, Mon}) ->
564    receive
565	{Pid, exit, ExitStatus} ->
566	    receive
567		{'DOWN', Mon, _, _, _} ->
568		    ExitStatus
569	    end;
570	{'DOWN', Mon, _, _, Reason} ->
571	    ct:fail("Prog stop: ~p", [Reason])
572    end.
573
574run_program(Parent, StartWrapper, ProgAndArgs) ->
575    [Prog | _] = ProgAndArgs,
576    Port =
577	open_port(
578	  {spawn_executable, StartWrapper},
579	  [{args, ProgAndArgs}, binary, stderr_to_stdout, {line, 80},
580	   exit_status]),
581    ct:pal("Prog ~p started: ~p", [Port, Prog]),
582    run_program_loop(Parent, Port, []).
583
584run_program_loop(Parent, Port, Buf) ->
585    receive
586	{Parent, stop} ->
587	    true = port_command(Port, <<"stop\n">>),
588	    ct:pal("Prog ~p stop", [Port]),
589	    run_program_loop(Parent, Port, Buf);
590	{Port, {data, {Flag, Data}}} ->
591	    case Flag of
592		eol ->
593		    Line  = iolist_to_binary(lists:reverse(Buf, Data)),
594                    ct:pal("Prog ~p output: ~s", [Port, Line]),
595                    %% There are potentially many different fail outputs,
596                    %% but for now we test for just this one: illegal option
597                    IOpt = "illegal option",
598                    case string:find(binary_to_list(Line), IOpt) of
599                        nomatch ->
600                            Parent ! {self(), line, Line},
601                            run_program_loop(Parent, Port, []);
602                        Line2 ->
603                            %% Try to extract the actual illegal option string
604                            IOpt2 =
605                                case string:take(
606                                       string:prefix(Line2, IOpt), [$-, $ ]) of
607                                    {_, Str} when length(Str) > 0 ->
608                                        Str;
609                                    _X ->
610                                        Line2
611                                end,
612                            ct:pal("Force program ~p stop", [Port]),
613                            true = port_command(Port, <<"stop\n">>),
614                            (catch port_close(Port)),
615                            exit({skip, {illegal_option, IOpt2}})
616                    end;
617		noeol ->
618		    run_program_loop(Parent, Port, [Data | Buf])
619	    end;
620	{Port, {exit_status, ExitStatus}} ->
621	    ct:pal("Prog ~p exit: ~p", [Port, ExitStatus]),
622	    catch port_close(Port),
623	    Parent ! {self(), exit, ExitStatus};
624	Unexpected ->
625	    ct:pal("run_program_loop Unexpected: ~p", [Unexpected]),
626	    run_program_loop(Parent, Port, Buf)
627    end.
628
629
630agent_app_env(Config) ->
631    Dir = ?config(priv_dir, Config),
632    Vsns = ?config(snmp_versions, Config),
633    [{versions,         Vsns},
634     {agent_type,       master},
635     {agent_verbosity,  trace},
636     {db_dir,           Dir},
637     {audit_trail_log,  [{type, read_write},
638			 {dir,  Dir},
639			 {size, {10240, 10}}]},
640     {config,           [{dir, Dir},
641			 {force_load, true},
642			 {verbosity,  trace}]},
643     {local_db,         [{repair,    true},
644			 {verbosity,  silence}]},
645     {mib_server,       [{verbosity, silence}]},
646     {symbolic_store,   [{verbosity, silence}]},
647     {note_store,       [{verbosity, silence}]},
648     {net_if,           [{verbosity, trace}]}].
649
650manager_app_env(Config) ->
651    Dir = ?config(priv_dir, Config),
652    Vsns = ?config(snmp_versions, Config),
653    NetIfModule = ?config(manager_net_if_module, Config),
654    [{versions,         Vsns},
655     {audit_trail_log,  [{type, read_write},
656			 {dir, Dir},
657			 {size, {10240, 10}}]},
658     {net_if,           [{module, NetIfModule}]},
659     {config,           [{dir, Dir},
660			 {db_dir, Dir},
661			 {verbosity, trace}]}
662    ].
663
664oid_str([1 | Ints]) ->
665    "iso." ++ oid_str_tl(Ints);
666oid_str(Ints) ->
667    oid_str_tl(Ints).
668
669oid_str_tl([]) ->
670    "";
671oid_str_tl([Int]) ->
672    integer_to_list(Int);
673oid_str_tl([Int | Ints]) ->
674    integer_to_list(Int) ++ "." ++ oid_str_tl(Ints).
675
676agent_config(Dir, Transports, Targets, Versions) ->
677    EngineID = ?AGENT_ENGINE_ID,
678    MMS = ?DEFAULT_MAX_MESSAGE_SIZE,
679    ok = snmp_config:write_agent_snmp_conf(Dir, Transports, EngineID, MMS),
680    ok = snmp_config:write_agent_snmp_context_conf(Dir),
681    ok = snmp_config:write_agent_snmp_community_conf(Dir),
682    ok =
683	snmp_config:write_agent_snmp_standard_conf(
684	  Dir, "snmp_to_snmpnet_SUITE"),
685    ok =
686	snmp_config:write_agent_snmp_target_addr_conf(
687	  Dir, Targets, Versions),
688    ok = snmp_config:write_agent_snmp_target_params_conf(Dir, Versions),
689    ok = snmp_config:write_agent_snmp_notify_conf(Dir, inform),
690    ok = snmp_config:write_agent_snmp_vacm_conf(Dir, Versions, none).
691
692manager_config(Dir, Targets) ->
693    EngineID = ?MANAGER_ENGINE_ID,
694    MMS = ?DEFAULT_MAX_MESSAGE_SIZE,
695    ok = snmp_config:write_manager_snmp_conf(Dir, Targets, MMS, EngineID).
696
697net_snmp_version([v3 | _]) ->
698    "-v3";
699net_snmp_version([v2 | _]) ->
700    "-v2c";
701net_snmp_version([v1 | _]) ->
702    "-v1".
703
704domain(inet) ->
705    transportDomainUdpIpv4;
706domain(inet6) ->
707    transportDomainUdpIpv6.
708
709net_snmp_addr_str([Target | Targets]) ->
710    net_snmp_addr_str(Target) ++
711	case Targets of
712	    [] ->
713		[];
714	    [_ | _] ->
715		"," ++ net_snmp_addr_str(Targets)
716	end;
717net_snmp_addr_str({transportDomainUdpIpv4, {Addr, Port}}) ->
718    "udp:" ++
719	inet_parse:ntoa(Addr) ++ ":" ++
720	integer_to_list(Port);
721net_snmp_addr_str({transportDomainUdpIpv6, {Addr, Port}}) ->
722    "udp6:[" ++
723	inet_parse:ntoa(Addr) ++ "]:" ++
724	integer_to_list(Port).
725
726domain_suffix(transportDomainUdpIpv4) ->
727    "";
728domain_suffix(transportDomainUdpIpv6) ->
729    "6".
730
731mk_port_number() ->
732    {ok, Socket} = gen_udp:open(0, [{reuseaddr, true}]),
733    {ok, PortNum} = inet:port(Socket),
734    ok = gen_udp:close(Socket),
735    PortNum.
736
737