Skip to content

Commit

Permalink
Merge pull request #1056 from javierbrk/babelnodes
Browse files Browse the repository at this point in the history
Links information module for shared state according to babeld
  • Loading branch information
G10h4ck authored Mar 12, 2024
2 parents f7d279e + a76d2b7 commit 7b7fcd7
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 0 deletions.
23 changes: 23 additions & 0 deletions packages/shared-state-babel_links_info/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#
# Copyright (c) 2023 Javier Jorge <[email protected]>
# Copyright (c) 2023 Instituto Nacional de Tecnología Industrial
# Copyright (C) 2023 Asociación Civil Altermundi <[email protected]>
# This is free software, licensed under the GNU Affero General Public License v3.
#

include ../../libremesh.mk

define Package/$(PKG_NAME)
CATEGORY:=LibreMesh
TITLE:=Babel links module for shared-state
MAINTAINER:=Asociación Civil Altermundi <[email protected]>
DEPENDS:=+lua +luci-lib-jsonc +ubus-lime-utils \
+libubus-lua +random-numgen shared-state-async
PKGARCH:=all
endef

define Package/$(PKG_NAME)/description
Synchronize Babel links information beween nodes.
endef

$(eval $(call BuildPackage,$(PKG_NAME)))
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/sh
unique_append()
{
grep -qF "$1" "$2" || echo "$1" >> "$2"
}


uci set shared-state.babel_links_info=dataType
uci set shared-state.babel_links_info.name='babel_links_info'
uci set shared-state.babel_links_info.scope='community'
uci set shared-state.babel_links_info.ttl='2400'
uci set shared-state.babel_links_info.update_interval='30'
uci commit shared-state

unique_append \
'*/30 * * * * ((sleep $(($RANDOM % 120)); shared-state-publish_babel_links_info &> /dev/null)&)' \
/etc/crontabs/root
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/lua

-- ! LibreMesh
-- ! Copyright (c) 2023 Javier Jorge <[email protected]>
-- ! Copyright (c) 2023 Instituto Nacional de Tecnología Industrial
-- ! Copyright (C) 2023 Asociación Civil Altermundi <[email protected]>
-- !
-- ! This program is free software: you can redistribute it and/or modify
-- ! it under the terms of the GNU Affero General Public License as
-- ! published by the Free Software Foundation, either version 3 of the
-- ! License, or (at your option) any later version.
-- !
-- ! This program is distributed in the hope that it will be useful,
-- ! but WITHOUT ANY WARRANTY; without even the implied warranty of
-- ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- ! GNU Affero General Public License for more details.
-- !
-- ! You should have received a copy of the GNU Affero General Public License
-- ! along with this program. If not, see <http://www.gnu.org/licenses/>.

local JSON = require("luci.jsonc")
local utils = require('lime.utils')
local ubus = require "ubus"

local ifaceip = {}

function get_interface_ip(ifname)
if ifaceip[ifname] == nil then
ifaceip[ifname] = string.gsub(utils.unsafe_shell("ip -6 address show "
.. ifname ..
" | awk '{if ($1 == \"inet6\") print $2}' | grep fe80 | awk -F/ '{print $1}'"),
"\n", "")
end
return ifaceip[ifname]
end

function get_babel_links_info()
local conn = ubus.connect()
local links = {}
babelneigt_obj = ubus.call(conn, "babeld", "get_neighbours", {})
if babelneigt_obj ~= nil then
for key, value in pairs(babelneigt_obj.IPv6) do
table.insert(links, {
src_ip = get_interface_ip(value.dev),
dst_ip = key,
iface = value.dev
})
end
end
return links
end

local hostname = io.input("/proc/sys/kernel/hostname"):read("*line")
local result = { [hostname] = get_babel_links_info() }
io.popen("shared-state-async insert babel_links_info", "w"):write(JSON.stringify(result))
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
local JSON = require("luci.jsonc")
local test_utils = require('tests.utils')
local utils = require('lime.utils')
local ubus = require "ubus"

local uci = nil

local ubus_babel_hosts = [[{"IPv6":{"fe80::16cc:20ff:feda:4eac":{"uhello-reach":
0,"hello-reach":65535,"txcost":256,"channel":255,"if_up":true,"rxcost":256,
"dev":"wlan1-mesh_17","rtt":"0.000"},"fe80::a2f3:c1ff:fe46:2896":
{"uhello-reach":0,"hello-reach":64511,"txcost":264,"channel":255,"if_up":true,
"rxcost":264,"dev":"wlan0-mesh_17","rtt":"0.000"},"fe80::16cc:20ff:feda:4eab":
{"uhello-reach":0,"hello-reach":65535,"txcost":438,"channel":255,"if_up":true,
"rxcost":256,"dev":"wlan0-mesh_17","rtt":"0.000"},"fe80::a2f3:c1ff:fe46:2897":
{"uhello-reach":0,"hello-reach":65535,"txcost":256,"channel":255,"if_up":true,
"rxcost":256,"dev":"wlan1-mesh_17","rtt":"0.000"}},"IPv4":[]}]]

describe('Tests network_nodes #network_nodes', function()
before_each('', function()
stub(ubus, "call", function(arg)
return JSON.parse(ubus_babel_hosts)
end)

stub(utils, "unsafe_shell", function(cmd)
return "fe80::c24a:ff:fefc:3abd"
end)
end)

it('a simple test to get babel info and assert requiered fields are present', function()
package.path = package.path .. ";packages/shared-state-babel_links_info/files/usr/bin/?;;"
require("shared-state-publish_babel_links_info")

babelinfo = get_babel_links_info()
assert.are.equal('fe80::16cc:20ff:feda:4eac', babelinfo[1].dst_ip)
assert.are.equal("wlan1-mesh_17",babelinfo[1].iface)
assert.are.equal("fe80::c24a:ff:fefc:3abd",babelinfo[1].src_ip)
end)
end)

describe('Test get interface local ipv6', function()
before_each('', function()
local ifaces = {'lo', 'eth0-1_250', 'bat0', 'anygw'}
unsafe_shell_calls =0
stub(utils, "get_ifnames", function () return ifaces end)

--this function returns an output similar to the command invoked in get_interface_ip
stub(utils, "unsafe_shell", function (cmd)
unsafe_shell_calls=unsafe_shell_calls+1
if string.match(cmd, 'lo') then
--the loopback interface tipically dont have an ipv6 ip
return ""
end
if string.match(cmd, 'eth0%-1_250') then
return "fe80::db:d6ff:fefc:3abd"
end
if string.match(cmd, 'bat0') then
--the bat0 interface may not have an ipv6 ip
return ""
end
if string.match(cmd, 'anygw') then
return "fe80::a8aa:aaff:feea:d2aa"
end
return "not expected command: ".. cmd
end)

end)
it('a simple test to get get interface local ipv6 address', function()
local unsafe_shell_spy = spy.on(utils, "unsafe_shell")
ifs = utils.get_ifnames()

assert.are.equal("",get_interface_ip(ifs[1]))
assert.are.equal("fe80::db:d6ff:fefc:3abd",get_interface_ip(ifs[2]))
assert.are.equal("",get_interface_ip(ifs[3]))
assert.are.equal("fe80::a8aa:aaff:feea:d2aa",get_interface_ip(ifs[4]))
assert.are.equal("fe80::a8aa:aaff:feea:d2aa",get_interface_ip(ifs[4]))
assert.are.equal("fe80::a8aa:aaff:feea:d2aa",get_interface_ip(ifs[4]))
--cached values shoud be used instead of making the os call
assert.spy(unsafe_shell_spy).was.called(4)
end)
end)

0 comments on commit 7b7fcd7

Please sign in to comment.