With the caveat that this isn't necessarily pretty and I was just trying to get it working and even newer to elixir than I still am, and the doc comments were not written with others in mind, and I should probably clean it up, and un-hardcode things, this is the gist of what I came up with:
def sysOid, do: [1,3,6,1,2,1,1,2,0]
def ospfLsdbEntry, do: [1,3,6,1,2,1,14,4,1]
def ospfLsdbAdvertisement, do: [1,3,6,1,2,1,14,4,1,8]
def start do
:snmpm.start
:snmpm.register_user :me, :snmpm_user_default, self
:snmpm.register_agent :me, 'targetname',
[engine_id: 'myengine', address: [192,168,1,1], community: 'public']
end
def stop, do: :snmpm.stop
@doc """
do the leading elements in the first list match all of the elements in the
second list?
"""
def starts_with([_|_], []), do: true
def starts_with([head|tail1], [head|tail2]), do: starts_with(tail1, tail2)
def starts_with([], []), do: true
def starts_with(_, _), do: false
@doc """
walk an smnp oid, call func on each element with arguments (oid, value, state)
get the next (oid, value) after oid, if oid starts with prefix call
func with (oid, value, state), and repeat with next oid as the new oid.
state will be replaced with the return value of func.
returns state.
"""
defp walk(oid, prefix, func, state) do
{:ok, snmpReply, _remaining} = :snmpm.sync_get_next2 :me, 'targetname', [oid]
{:noError, _errorIndex, varBinds} = snmpReply
[varBind|_T] = varBinds
{:varbind, newoid, _type, value, index} = varBind
if starts_with newoid, prefix do
state = func.(oid, value, state)
if is_list index do
state = walk newoid ++ index, prefix, func, state
else
state = walk newoid ++ [index], prefix, func, state
end
end
state
end
@doc """
walk an smnp oid, call func on each element with arguments (oid, value, state).
state will be replaced with the return value of func each time it is called.
returns state.
"""
def walk(oid, func, state), do: walk(oid, oid, func, state)
an example walk function:
# debugging
# pass to walk to print the walked values, which are assumed to be OSPF LSAs
def walkfunc_print(_oid, value, state) do
lsa = value |> :erlang.list_to_binary |> ospf_lsa
IO.puts inspect lsa
state
end
walk ospfLsdbAdvertisement, &walkfunc_print/3, nil
(and I just realized, my walk function may not work if you happen to walk the last table in an agent, as it needs to check for a "there is no next" return).