Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

APuP support for LibreMesh #1134

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
662 changes: 662 additions & 0 deletions packages/lime-curtigghio/README.adoc

Large diffs are not rendered by default.

502 changes: 502 additions & 0 deletions packages/lime-curtigghio/test.sh

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,6 @@ protocol direct {
return base_conf
end

function anygw.runOnDevice(linuxDev, args) end

return anygw
14 changes: 14 additions & 0 deletions packages/lime-proto-babeld/files/usr/lib/lua/lime/proto/babeld.lua
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,18 @@ function babeld.setup_interface(ifname, args)
uci:save("babeld")
end

function babeld.runOnDevice(linuxDev, args)
utils.log("lime.proto.babeld.runOnDevice(%s, ...)", linuxDev)

local vlanId = args[2] or 17
local vlanProto = args[3] or "8021ad"

local vlanDev = network.createVlan(linuxDev, vlanId, vlanProto)
network.createStatic(vlanDev)

local libubus = require("ubus")
local ubus = libubus.connect()
ubus:call('babeld', 'add_interface', { ifname = vlanDev })
end

return babeld
37 changes: 37 additions & 0 deletions packages/lime-proto-batadv/files/usr/lib/lua/lime/proto/batadv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,42 @@ function batadv.setup_interface(ifname, args)
uci:save("network")
end

function batadv.runOnDevice(linuxDev, args)
args = args or {}
local vlanId = args[2] or "%N1"
local vlanProto = args[3] or "8021ad"

utils.log("lime.proto.batadv.runOnDevice(%s, ...)", linuxDev)


local mtu = 1532

if not tonumber(vlanId) then
vlanId = 29 + (utils.applyNetTemplate10(vlanId) - 13) % 256
end

local devName = network.createVlan(linuxDev, vlanId, vlanProto)
local ifName = network.limeIfNamePrefix..linuxDev .. "_batadv"

local ifaceConf = {
name = ifName,
proto = "batadv_hardif",
auto = "1",
device = devName,
master = "bat0"
}

local libubus = require("ubus");
local ubus = libubus.connect()
ubus:call('network', 'add_dynamic', ifaceConf)
ubus:call('network.interface.'..ifName, 'up', {})


--! TODO: as of today ubus silently fails to properly setting up a linux network
--! device for batman ADV usage dinamycally work around it by using
--! shell commands instead
network.createStatic(devName)
utils.unsafe_shell("batctl if add "..devName)
end

return batadv
5 changes: 3 additions & 2 deletions packages/lime-system/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ LIME_DESCRIPTION:=$(LIME_ID) $(LIME_RELEASE) $(LIME_CODENAME) ($(LIME_BRANCH) re
include $(INCLUDE_DIR)/package.mk

define Package/$(PKG_NAME)
TITLE:=libremesh system files
TITLE:=LibreMesh system core
CATEGORY:=LibreMesh
MAINTAINER:=Gioacchino Mazzurco <gio@eigenlab.org>
URL:=http://libremesh.org
Expand All @@ -32,7 +32,8 @@ define Package/$(PKG_NAME)
endef

define Package/$(PKG_NAME)/description
Basic system files for LiMe node
LibreMesh is a modular meta-firmare this package provide the core of it
which articulates all LiMe modules around it
endef

define Build/Compile
Expand Down
1 change: 1 addition & 0 deletions packages/lime-system/files/etc/config/lime-defaults
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ config lime wifi
option apname_ssid 'LibreMesh.org/%H'
option adhoc_ssid 'LiMe'
option adhoc_bssid 'ca:fe:00:c0:ff:ee'
option apup_ssid 'LibreMesh.org'
option ieee80211s_mesh_fwding '0'
option ieee80211s_mesh_id 'LiMe'
option unstuck_interval '10'
Expand Down
14 changes: 14 additions & 0 deletions packages/lime-system/files/etc/init.d/limed
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh /etc/rc.common

USE_PROCD=1
START=15

start_service()
{
procd_open_instance
procd_set_param command /usr/bin/limed
## procd_set_param respawn
procd_set_param stderr 1
procd_set_param term_timeout 10
procd_close_instance
}
106 changes: 106 additions & 0 deletions packages/lime-system/files/usr/bin/limed
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/lua

--! LibreMesh community mesh networks meta-firmware
--!
--! Copyright (C) 2024 Gioacchino Mazzurco <gio@polymathes.cc>
--! Copyright (C) 2024 Asociación Civil Altermundi <info@altermundi.net>
--!
--! SPDX-License-Identifier: AGPL-3.0-only

local config = require("lime.config")
local utils = require("lime.utils")

local limed = {};

limed.__PRIVATE_APUP_ENABLED = nil

function limed.APUP_ENABLED()
if limed.__PRIVATE_APUP_ENABLED ~= nil then
return limed.__PRIVATE_APUP_ENABLED
end

function check_apup_mode_cb(section)
if(section['modes'] == null) then return end

for _,mode in pairs(section['modes']) do
if(mode == 'apup') then
limed.__PRIVATE_APUP_ENABLED = true;
return limed.__PRIVATE_APUP_ENABLED;
end
end
end

config.foreach(nil, check_apup_mode_cb)
return limed.__PRIVATE_APUP_ENABLED
end

-- No need to run if APuP is not enabled in configuration
if not limed.APUP_ENABLED() then os.exit(0) end;

local uloop = require("uloop");
local network = require("lime.network")

local function dumptable(table, nesting)
local nesting = nesting or 1
if type(table) ~= "table" then
print("dumptable: first argument is expected to be a table but you passed a", type(table), table)
else
if next(table) == nil then
print(table, "empty")
else
for k,v in pairs(table) do
print(string.rep('\t', nesting), k, ' = ', v)
if type(v) == 'table' then dumptable(v, nesting+1) end
end
end
end
end

local libubus = require("ubus")
local ubus = libubus.connect()

local peerSubscriber = {
notify = function(nData, nType)
if nType ~= "apup-newpeer" then return end

utils.log("peerSubscriber:", nType, nData.ifname)
network.createStatic(nData.ifname)
network.runProtocols(nData.ifname)
end
}

local apupSubscriber = {
notify = function(nData, nType)
if nType ~= "bss.add" then return end

local apupDev = string.match(nData["name"], "wlan%d+%-apup");
if not apupDev then return end

local evPath = "hostapd." .. apupDev

utils.log("Subscribing:", evPath)
ubus:subscribe(evPath, peerSubscriber)
end
}
function limed.waitForHostapd()
local found = false
while not found do
local namespaces = ubus:objects()
for _, namespace in ipairs(namespaces) do
if namespace == "hostapd" then
found = true
break
end
end
if not found then
utils.log("Waiting for 'hostapd' namespace...")
os.execute("sleep 1") -- Wait for 1 second before retrying
else
utils.log(" 'hostapd' namespace exists...")
end
end
end
limed.waitForHostapd()
uloop.init();
ubus:subscribe("hostapd", apupSubscriber)
uloop.run();
41 changes: 41 additions & 0 deletions packages/lime-system/files/usr/lib/lua/lime/mode/apup.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#!/usr/bin/lua

--! LibreMesh community mesh networks meta-firmware
--!
--! Copyright (C) 2024 Gioacchino Mazzurco <gio@polymathes.cc>
--! Copyright (C) 2024 Asociación Civil Altermundi <info@altermundi.net>
--!
--! SPDX-License-Identifier: AGPL-3.0-only

local wireless = require("lime.wireless")

local apup = {}

function apup.WIFI_MODE()
return "ap"
end

function apup.WIFI_MODE_SUFFIX()
return "up"
end

function apup.PEER_SUFFIX()
return "peer"
end

function apup.setup_radio(radio, args)
--! checks("table", "?table")

args["network"] = "lan"
args["apup"] = "1"
args["apup_peer_ifname_prefix"] =
wireless.calcIfname(radio[".name"], apup.PEER_SUFFIX(), "")

return wireless.createBaseWirelessIface(
radio, apup.WIFI_MODE(), apup.WIFI_MODE_SUFFIX(), args )
end

--! TODO: port all modes to .WIFI_MODE()
apup.wifi_mode="ap"

return apup
110 changes: 104 additions & 6 deletions packages/lime-system/files/usr/lib/lua/lime/network.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

--! LibreMesh community mesh networks meta-firmware
--!
--! Copyright (C) 2013-2023 Gioacchino Mazzurco <gio@eigenlab.org>
--! Copyright (C) 2023 Asociación Civil Altermundi <info@altermundi.net>
--! Copyright (C) 2013-2024 Gioacchino Mazzurco <gio@polymathes.cc>
--! Copyright (C) 2023-2024 Asociación Civil Altermundi <info@altermundi.net>
--!
--! SPDX-License-Identifier: AGPL-3.0-only

Expand All @@ -15,13 +15,21 @@ local fs = require("nixio.fs")
local config = require("lime.config")
local utils = require("lime.utils")

network.limeIfNamePrefix="lm_net_"
network.protoParamsSeparator=":"
network.protoVlanSeparator="_"

function network.PROTO_PARAM_SEPARATOR() return ":" end
function network.PROTO_VLAN_SEPARATOR() return "_" end
function network.LIME_UCI_IFNAME_PREFIX() return "lm_net_" end


network.MTU_ETH = 1500
network.MTU_ETH_WITH_VLAN = network.MTU_ETH - 4

-- Deprecated use corresponding functions instead
network.protoParamsSeparator=":"
network.protoVlanSeparator="_"
network.limeIfNamePrefix="lm_net_"


function network.get_mac(ifname)
local _, macaddr = next(network.get_own_macs(ifname))
return utils.split(macaddr, ":")
Expand Down Expand Up @@ -268,7 +276,7 @@ function network.scandevices()
end
end

if dev:match("^wlan%d+"..wireless.wifiModeSeparator.."%w+$") then
if dev:match("^wlan%d+"..wireless.WIFI_MODE_SEPARATOR().."%w+$") then
devices[dev] = {}
utils.log( "network.scandevices.dev_parser found WiFi device %s",
dev )
Expand Down Expand Up @@ -550,4 +558,94 @@ function network.createMacvlanIface(baseIfname, linuxName, argsDev, argsIf)
return owrtInterfaceName, linuxName, owrtDeviceName
end

--! Create a static interface at runtime via ubus
function network.createStatic(linuxBaseIfname)
local ipv4, ipv6 = network.primary_address()
local ubusIfaceName = network.sanitizeIfaceName(
network.LIME_UCI_IFNAME_PREFIX()..linuxBaseIfname.."_static")
local ifaceConf = {
name = ubusIfaceName,
proto = "static",
auto = "1",
ifname = linuxBaseIfname,
ipaddr = ipv4:host():string(),
netmask = "255.255.255.255"
}

print('network', 'add_dynamic')
utils.dumptable(ifaceConf)

local libubus = require("ubus")
local ubus = libubus.connect()
ubus:call('network', 'add_dynamic', ifaceConf)
ubus:call('network.interface.'..ifaceConf.name, 'up', {})

--! TODO: As of today ubus silently fails to properly setup the interface,
--! subsequent status query return NO_DEVICE error
--! ubus -v call network.interface.lm_net_lm_net_wlan0_peer1_static status
--! {
--! "up": false,
--! "pending": false,
--! "available": false,
--! "autostart": true,
--! "dynamic": true,
--! "proto": "static",
--! "data": {
--!
--! },
--! "errors": [
--! {
--! "subsystem": "interface",
--! "code": "NO_DEVICE"
--! }
--! ]
--! }
--!
--! ATM work around the problem configuring IP addresses via ip command

utils.unsafe_shell("ip link set up dev "..ifaceConf.ifname)
utils.unsafe_shell("ip address add "..ifaceConf.ipaddr.."/32 dev "..ifaceConf.ifname)

return ifaceConf.name
end

--! Create a vlan at runtime via ubus
function network.createVlan(linuxBaseIfname, vid, vlanProtocol)
local vlanConf = {
name = linuxBaseIfname .. network.PROTO_VLAN_SEPARATOR() .. vid,
type = vlanProtocol or "8021ad",
ifname = linuxBaseIfname,
vid = vid
}

utils.log("lime.network.createVlan(%s, ...)", linuxBaseIfname)
utils.dumptable(vlanConf)

local libubus = require("ubus")
local ubus = libubus.connect()
ubus:call('network', 'add_dynamic_device', vlanConf)

--! TODO: as of today ubus silently fails to properly creating a device
--! dinamycally work around it by using ip command instead
utils.unsafe_shell("ip link add name "..vlanConf.name.." link "..vlanConf.ifname.." type vlan proto 802.1ad id "..vlanConf.vid)

return vlanConf.name
end

--! Run protocols at runtime on top of linux network devices
-- TODO: probably some code between here and configure might be deduplicaded
function network.runProtocols(linuxBaseIfname)
utils.log("lime.network.runProtocols(%s, ...)", linuxBaseIfname)
local protoConfs = config.get("network", "protocols")
for _,protoConf in pairs(protoConfs) do
local args = utils.split(protoConf, network.PROTO_PARAM_SEPARATOR())
local protoModule = "lime.proto."..args[1]
if utils.isModuleAvailable(protoModule) then
local proto = require(protoModule)
xpcall(function() proto.runOnDevice(linuxBaseIfname, args) end,
function(errmsg) print(errmsg) ; print(debug.traceback()) end)
end
end
end

return network
Loading
Loading