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    case os:type() of
204	{unix, netbsd} ->
205	    {skip, "Host *may* not *properly* support IPV6"};
206	_ ->
207	    init_per_group_ipv6([inet6], Config)
208    end;
209init_per_group(ipv4_ipv6, Config) ->
210    case os:type() of
211	{unix, netbsd} ->
212	    {skip, "Host *may* not *properly* support IPV6"};
213	_ ->
214	    init_per_group_ipv6([inet, inet6], Config)
215    end;
216init_per_group(snmpget = Exec, Config) ->
217    %% From Ubuntu package snmp
218    init_per_group_agent(Exec, Config);
219init_per_group(snmptrapd = Exec, Config) ->
220    %% From Ubuntu package snmpd
221    init_per_group_agent(Exec, Config);
222init_per_group(snmpd_mt, Config) ->
223    %% From Ubuntu package snmp
224    init_per_group_manager(
225      snmpd,
226      [{manager_net_if_module, snmpm_net_if_mt} | Config]);
227init_per_group(snmpd = Exec, Config) ->
228    %% From Ubuntu package snmp
229    init_per_group_manager(
230      Exec,
231      [{manager_net_if_module, snmpm_net_if} | Config]);
232
233init_per_group(_, Config) ->
234    Config.
235
236init_per_group_ipv6(Families, Config) ->
237    case ?HAS_SUPPORT_IPV6() of
238        true ->
239            init_per_group_ip(Families, Config);
240        false ->
241            {skip, "Host does not support IPv6"}
242    end.
243
244init_per_group_ip(Families, Config) ->
245    AgentPort = ?config(agent_port, Config),
246    ManagerPort = ?config(manager_port, Config),
247    Transports =
248	[begin
249             Addr = ?LIB:localhost(Family),
250	     {domain(Family), {Addr, AgentPort}}
251	 end || Family <- Families],
252    Targets =
253	[begin
254             Addr = ?LIB:localhost(Family),
255	     {domain(Family), {Addr, ManagerPort}}
256	 end || Family <- Families],
257    [{transports, Transports}, {targets, Targets} | Config].
258
259init_per_group_agent(Exec, Config) ->
260    Versions = [v2],
261    Dir = ?config(priv_dir, Config),
262    Transports = ?config(transports, Config),
263    Targets = ?config(targets, Config),
264    agent_config(Dir, Transports, Targets, Versions),
265    find_executable(Exec, [{snmp_versions, Versions} | Config]).
266
267init_per_group_manager(Exec, Config) ->
268    Versions = [v2],
269    Dir = ?config(priv_dir, Config),
270    Targets = ?config(targets, Config),
271    manager_config(Dir, Targets),
272    find_executable(Exec, [{snmp_versions, Versions} | Config]).
273
274
275end_per_group(_GroupName, Config) ->
276    Config.
277
278
279
280%%
281%% -----
282%%
283
284init_per_testcase(_Case, Config) ->
285    ?IPRINT("init_per_testcase -> entry with"
286            "~n   Config: ~p", [Config]),
287
288    snmp_test_global_sys_monitor:reset_events(),
289
290    Dog = ct:timetrap(?SECS(20)),
291    application:stop(snmp),
292    application:unload(snmp),
293    Config1 = [{watchdog, Dog} | Config],
294
295    ?IPRINT("init_per_testcase -> done when"
296            "~n   Config: ~p", [Config1]),
297
298    Config1.
299
300end_per_testcase(_, Config) ->
301
302    ?IPRINT("end_per_testcase -> entry with"
303            "~n   Config:  ~p", [Config]),
304
305    ?IPRINT("system events during test: "
306            "~n   ~p", [snmp_test_global_sys_monitor:events()]),
307
308    case application:stop(snmp) of
309	ok ->
310	    ok;
311	E1 ->
312	    ct:pal("application:stop(snmp) -> ~p", [E1])
313    end,
314    case application:unload(snmp) of
315	ok ->
316	    ok;
317	E2 ->
318	    ct:pal("application:unload(snmp) -> ~p", [E2])
319    end,
320
321    ?IPRINT("end_per_testcase -> done with"
322            "~n   Config: ~p", [Config]),
323
324    Config.
325
326find_executable(Exec, Config) ->
327    ExecStr = atom_to_list(Exec),
328    case os:find_executable(ExecStr) of
329	false ->
330	    %% The sbin dirs are not in the PATH on all platforms...
331	    find_sys_executable(
332	      Exec, ExecStr,
333	      [["usr", "local", "sbin"],
334	       ["usr", "sbin"],
335	       ["sbin"]],
336	     Config);
337	Path ->
338	    [{Exec, Path} | Config]
339    end.
340
341find_sys_executable(_Exec, ExecStr, [], _Config) ->
342    {skip, ExecStr ++ " not found"};
343find_sys_executable(Exec, ExecStr, [Dir | Dirs], Config) ->
344    case os:find_executable(filename:join(["/" | Dir] ++ [ExecStr])) of
345	false ->
346	    find_sys_executable(Exec, ExecStr, Dirs, Config);
347	Path ->
348	    [{Exec, Path} | Config]
349    end.
350
351start_agent(Config) ->
352    ok = application:load(snmp),
353    ok = application:set_env(snmp, agent, agent_app_env(Config)),
354    ok = application:start(snmp).
355
356%% stop_agent(_Config) ->
357%%     case application:stop(snmp) of
358%% 	ok ->
359%% 	    ok;
360%% 	E1 ->
361%% 	    ct:pal("application:stop(snmp) -> ~p", [E1])
362%%     end,
363%%     case application:unload(snmp) of
364%% 	ok ->
365%% 	    ok;
366%% 	E2 ->
367%% 	    ct:pal("application:unload(snmp) -> ~p", [E2])
368%%     end.
369
370start_manager(Config) ->
371    ok = application:load(snmp),
372    ok = application:set_env(snmp, manager, manager_app_env(Config)),
373    ok = application:start(snmp).
374
375%% stop_manager(_Config) ->
376%%     case application:stop(snmp) of
377%% 	ok ->
378%% 	    ok;
379%% 	E1 ->
380%% 	    ct:pal("application:stop(snmp) -> ~p", [E1])
381%%     end,
382%%     case application:unload(snmp) of
383%% 	ok ->
384%% 	    ok;
385%% 	E2 ->
386%% 	    ct:pal("application:unload(snmp) -> ~p", [E2])
387%%     end.
388
389
390
391%%--------------------------------------------------------------------
392%% Test Cases --------------------------------------------------------
393%%--------------------------------------------------------------------
394erlang_agent_netsnmp_get() ->
395    [{doc,"Test that we can access erlang snmp agent "
396      "from snmpnet manager"}].
397
398erlang_agent_netsnmp_get(Config) when is_list(Config) ->
399    Transports = ?config(transports, Config),
400    start_agent(Config),
401    Oid = ?sysDescr_instance,
402    Expected = expected(Oid, get),
403    try
404        begin
405            [Expected = snmpget(Oid, Transport, Config)
406             || Transport <- Transports],
407            ok
408        end
409    catch
410        throw:{skip, _} = SKIP ->
411            SKIP
412    end.
413
414
415%%--------------------------------------------------------------------
416erlang_manager_netsnmp_get() ->
417    [{doc,"Test that the erlang snmp manager can access snmpnet agent"}].
418
419erlang_manager_netsnmp_get(Config) when is_list(Config) ->
420    Community  = "happy-testing",
421    SysDescr   = "Net-SNMP agent",
422    TargetName = "Target Net-SNMP agent",
423    Transports = ?config(transports, Config),
424    case start_snmpd(Community, SysDescr, Config) of
425        {skip, _} = SKIP ->
426            SKIP;
427        ProgHandle ->
428            start_manager(Config),
429            snmp_manager_user:start_link(self(), test_user),
430            [snmp_manager_user:register_agent(
431               TargetName++domain_suffix(Domain),
432               [{reg_type, target_name},
433                {tdomain, Domain}, {taddress, Addr},
434                {community, Community}, {engine_id, "EngineId"},
435                {version, v2}, {sec_model, v2c}, {sec_level, noAuthNoPriv}])
436             || {Domain, Addr} <- Transports],
437            Results =
438                [snmp_manager_user:sync_get2(
439                   TargetName++domain_suffix(Domain),
440                   [?sysDescr_instance], [])
441                 || {Domain, _} <- Transports],
442            ct:pal("sync_get -> ~p", [Results]),
443            snmp_manager_user:stop(),
444            stop_program(ProgHandle),
445            [{ok,
446              {noError, 0,
447               [{varbind, ?sysDescr_instance, 'OCTET STRING', SysDescr,1}] },
448              _} = R || R <- Results],
449            ok
450    end.
451
452
453%%--------------------------------------------------------------------
454erlang_agent_netsnmp_inform() ->
455    [{doc, "TBD"}].
456
457erlang_agent_netsnmp_inform(Config) when is_list(Config) ->
458    DataDir = ?config(data_dir, Config),
459    Mib = "TestTrapv2",
460
461    start_agent(Config),
462    ok = snmpa:load_mib(snmp_master_agent, filename:join(DataDir, Mib)),
463
464    case start_snmptrapd(Mib, Config) of
465        {skip, _} = SKIP ->
466            SKIP;
467        ProgHandle ->
468            snmpa:send_notification(
469              snmp_master_agent, testTrapv22, {erlang_agent_test, self()}),
470            receive
471                {snmp_targets, erlang_agent_test, Addresses} ->
472                    ct:pal("Notification sent to: ~p~n", [Addresses]),
473                    erlang_agent_netsnmp_inform_responses(Addresses)
474            end,
475            stop_program(ProgHandle)
476    end.
477
478erlang_agent_netsnmp_inform_responses([]) ->
479    receive
480	{snmp_notification, erlang_agent_test, _} = Unexpected ->
481	    ct:pal("Unexpected response: ~p", [Unexpected]),
482	    erlang_agent_netsnmp_inform_responses([])
483    after 0 ->
484	    ok
485    end;
486erlang_agent_netsnmp_inform_responses([Address | Addresses]) ->
487    receive
488	{snmp_notification, erlang_agent_test,
489	 {got_response, Address}} ->
490	    ct:pal("Got response from: ~p~n", [Address]),
491	    erlang_agent_netsnmp_inform_responses(Addresses);
492	{snmp_notification, erlang_agent_test,
493	 {no_response, _} = NoResponse} ->
494	    ct:fail(NoResponse)
495    end.
496
497%%--------------------------------------------------------------------
498%% Internal functions ------------------------------------------------
499%%--------------------------------------------------------------------
500
501snmpget(Oid, Transport, Config) ->
502    Versions = ?config(snmp_versions, Config),
503
504    Args =
505	["-c", "public", net_snmp_version(Versions),
506	 "-m", ":",
507	 "-Cf",
508	 net_snmp_addr_str(Transport),
509	 oid_str(Oid)],
510    case start_program(snmpget, Args, none, Config) of
511        {skip, _} = SKIP ->
512            throw(SKIP);
513        ProgHandle ->
514            {_, line, Line} = get_program_output(ProgHandle),
515            stop_program(ProgHandle),
516            Line
517    end.
518
519start_snmptrapd(Mibs, Config) ->
520    DataDir = ?config(data_dir, Config),
521    MibDir = filename:join(code:lib_dir(snmp), "mibs"),
522    Targets = ?config(targets, Config),
523    SnmptrapdArgs =
524	["-f", "-Lo", "-C",
525	 "-m", Mibs,
526	 "-M", MibDir++":"++DataDir,
527	 "--disableAuthorization=yes",
528	 "--snmpTrapdAddr=" ++ net_snmp_addr_str(Targets)],
529    {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]),
530    start_program(snmptrapd, SnmptrapdArgs, StartCheckMP, Config).
531
532start_snmpd(Community, SysDescr, Config) ->
533    DataDir = ?config(data_dir, Config),
534    Targets = ?config(targets, Config),
535    Transports = ?config(transports, Config),
536    Port = mk_port_number(),
537    CommunityArgs =
538	["--rocommunity"++domain_suffix(Domain)++"="
539	 ++Community++" "++inet_parse:ntoa(Ip)
540	 || {Domain, {Ip, _}} <- Targets],
541
542    SnmpdArgs =
543        ["-f", "-r", %"-Dverbose",
544         "-c", filename:join(DataDir, "snmpd.conf"),
545         "-C",
546         "-Lo",
547	 "-m", ":",
548	 "--sysDescr="++SysDescr,
549	 "--agentXSocket=tcp:localhost:"++integer_to_list(Port)]
550	++ CommunityArgs
551	++ [net_snmp_addr_str(Transports)],
552    {ok, StartCheckMP} = re:compile("NET-SNMP version ", [anchored]),
553    start_program(snmpd, SnmpdArgs, StartCheckMP, Config).
554
555start_program(Prog, Args, StartCheckMP, Config) ->
556    ct:pal("Starting program: ~w ~p", [Prog, Args]),
557    Path = ?config(Prog, Config),
558    DataDir = ?config(data_dir, Config),
559    StartWrapper = filename:join(DataDir, "start_stop_wrapper"),
560    Parent = self(),
561    %% process_flag(trap_exit, true),
562    {Pid, Mon} =
563	spawn_monitor(
564	  fun () ->
565		  run_program(Parent, StartWrapper, [Path | Args])
566	  end),
567    start_check(Pid, Mon, StartCheckMP).
568
569start_check(Pid, Mon, none) ->
570    {Pid, Mon};
571start_check(Pid, Mon, StartCheckMP) ->
572    receive
573	{Pid, line, Line} ->
574	    case re:run(Line, StartCheckMP, [{capture, none}]) of
575		match ->
576		    {Pid, Mon};
577		nomatch ->
578		    start_check(Pid, Mon, StartCheckMP)
579	    end;
580	{'DOWN', Mon, _, _Pid, {skip, Reason} = SKIP} ->
581	    ct:pal("Received DOWN from ~p"
582                   "~n   Skip Reason: ~p", [_Pid, Reason]),
583            SKIP;
584	{'DOWN', Mon, _, _, Reason} ->
585	    ct:fail("Prog ~p start failed: ~p", [Pid, Reason])
586    end.
587
588get_program_output({Pid, Mon}) ->
589    receive
590	{Pid, _, _} = Msg ->
591	    Msg;
592	{'DOWN', Mon, _, _, Reason} ->
593	    ct:fail("Prog ~p crashed: ~p", [Pid, Reason])
594    end.
595
596stop_program({Pid, _} = Handle) ->
597    Pid ! {self(), stop},
598    wait_program_stop(Handle).
599
600wait_program_stop({Pid, Mon}) ->
601    receive
602	{Pid, exit, ExitStatus} ->
603	    receive
604		{'DOWN', Mon, _, _, _} ->
605		    ExitStatus
606	    end;
607	{'DOWN', Mon, _, _, Reason} ->
608	    ct:fail("Prog stop: ~p", [Reason])
609    end.
610
611run_program(Parent, StartWrapper, ProgAndArgs) ->
612    [Prog | _] = ProgAndArgs,
613    Port =
614	open_port(
615	  {spawn_executable, StartWrapper},
616	  [{args, ProgAndArgs}, binary, stderr_to_stdout, {line, 80},
617	   exit_status]),
618    ct:pal("Prog ~p started: ~p", [Port, Prog]),
619    run_program_loop(Parent, Port, []).
620
621run_program_loop(Parent, Port, Buf) ->
622    receive
623	{Parent, stop} ->
624	    true = port_command(Port, <<"stop\n">>),
625	    ct:pal("Prog ~p stop", [Port]),
626	    run_program_loop(Parent, Port, Buf);
627	{Port, {data, {Flag, Data}}} ->
628	    case Flag of
629		eol ->
630		    Line  = iolist_to_binary(lists:reverse(Buf, Data)),
631                    ct:pal("Prog ~p output: ~s", [Port, Line]),
632                    %% There are potentially many different fail outputs,
633                    %% but for now we test for just this one: illegal option
634                    IOpt = "illegal option",
635                    case string:find(binary_to_list(Line), IOpt) of
636                        nomatch ->
637                            Parent ! {self(), line, Line},
638                            run_program_loop(Parent, Port, []);
639                        Line2 ->
640                            %% Try to extract the actual illegal option string
641                            IOpt2 =
642                                case string:take(
643                                       string:prefix(Line2, IOpt), [$-, $ ]) of
644                                    {_, Str} when length(Str) > 0 ->
645                                        Str;
646                                    _X ->
647                                        Line2
648                                end,
649                            ct:pal("Force program ~p stop", [Port]),
650                            true = port_command(Port, <<"stop\n">>),
651                            (catch port_close(Port)),
652                            exit({skip, {illegal_option, IOpt2}})
653                    end;
654		noeol ->
655		    run_program_loop(Parent, Port, [Data | Buf])
656	    end;
657	{Port, {exit_status, ExitStatus}} ->
658	    ct:pal("Prog ~p exit: ~p", [Port, ExitStatus]),
659	    catch port_close(Port),
660	    Parent ! {self(), exit, ExitStatus};
661	Unexpected ->
662	    ct:pal("run_program_loop Unexpected: ~p", [Unexpected]),
663	    run_program_loop(Parent, Port, Buf)
664    end.
665
666
667agent_app_env(Config) ->
668    Dir = ?config(priv_dir, Config),
669    Vsns = ?config(snmp_versions, Config),
670    [{versions,         Vsns},
671     {agent_type,       master},
672     {agent_verbosity,  trace},
673     {db_dir,           Dir},
674     {audit_trail_log,  [{type, read_write},
675			 {dir,  Dir},
676			 {size, {10240, 10}}]},
677     {config,           [{dir, Dir},
678			 {force_load, true},
679			 {verbosity,  trace}]},
680     {local_db,         [{repair,    true},
681			 {verbosity,  silence}]},
682     {mib_server,       [{verbosity, silence}]},
683     {symbolic_store,   [{verbosity, silence}]},
684     {note_store,       [{verbosity, silence}]},
685     {net_if,           [{verbosity, trace}]}].
686
687manager_app_env(Config) ->
688    Dir = ?config(priv_dir, Config),
689    Vsns = ?config(snmp_versions, Config),
690    NetIfModule = ?config(manager_net_if_module, Config),
691    [{versions,         Vsns},
692     {audit_trail_log,  [{type, read_write},
693			 {dir, Dir},
694			 {size, {10240, 10}}]},
695     {net_if,           [{module, NetIfModule}]},
696     {config,           [{dir, Dir},
697			 {db_dir, Dir},
698			 {verbosity, trace}]}
699    ].
700
701oid_str([1 | Ints]) ->
702    "iso." ++ oid_str_tl(Ints);
703oid_str(Ints) ->
704    oid_str_tl(Ints).
705
706oid_str_tl([]) ->
707    "";
708oid_str_tl([Int]) ->
709    integer_to_list(Int);
710oid_str_tl([Int | Ints]) ->
711    integer_to_list(Int) ++ "." ++ oid_str_tl(Ints).
712
713agent_config(Dir, Transports, Targets, Versions) ->
714    EngineID = ?AGENT_ENGINE_ID,
715    MMS = ?DEFAULT_MAX_MESSAGE_SIZE,
716    ok = snmp_config:write_agent_snmp_conf(Dir, Transports, EngineID, MMS),
717    ok = snmp_config:write_agent_snmp_context_conf(Dir),
718    ok = snmp_config:write_agent_snmp_community_conf(Dir),
719    ok =
720	snmp_config:write_agent_snmp_standard_conf(
721	  Dir, "snmp_to_snmpnet_SUITE"),
722    ok =
723	snmp_config:write_agent_snmp_target_addr_conf(
724	  Dir, Targets, Versions),
725    ok = snmp_config:write_agent_snmp_target_params_conf(Dir, Versions),
726    ok = snmp_config:write_agent_snmp_notify_conf(Dir, inform),
727    ok = snmp_config:write_agent_snmp_vacm_conf(Dir, Versions, none).
728
729manager_config(Dir, Targets) ->
730    EngineID = ?MANAGER_ENGINE_ID,
731    MMS = ?DEFAULT_MAX_MESSAGE_SIZE,
732    ok = snmp_config:write_manager_snmp_conf(Dir, Targets, MMS, EngineID).
733
734net_snmp_version([v3 | _]) ->
735    "-v3";
736net_snmp_version([v2 | _]) ->
737    "-v2c";
738net_snmp_version([v1 | _]) ->
739    "-v1".
740
741domain(inet) ->
742    transportDomainUdpIpv4;
743domain(inet6) ->
744    transportDomainUdpIpv6.
745
746net_snmp_addr_str([Target | Targets]) ->
747    net_snmp_addr_str(Target) ++
748	case Targets of
749	    [] ->
750		[];
751	    [_ | _] ->
752		"," ++ net_snmp_addr_str(Targets)
753	end;
754net_snmp_addr_str({transportDomainUdpIpv4, {Addr, Port}}) ->
755    "udp:" ++
756	inet_parse:ntoa(Addr) ++ ":" ++
757	integer_to_list(Port);
758net_snmp_addr_str({transportDomainUdpIpv6, {Addr, Port}}) ->
759    "udp6:[" ++
760	inet_parse:ntoa(Addr) ++ "]:" ++
761	integer_to_list(Port).
762
763domain_suffix(transportDomainUdpIpv4) ->
764    "";
765domain_suffix(transportDomainUdpIpv6) ->
766    "6".
767
768mk_port_number() ->
769    {ok, Socket} = gen_udp:open(0, [{reuseaddr, true}]),
770    {ok, PortNum} = inet:port(Socket),
771    ok = gen_udp:close(Socket),
772    PortNum.
773
774