netifd: update to Git HEAD (2026-02-15)

Adds ucode proto handler support

51fa9ed6d4d6 interface-ip: fix fortify build error
ca33316f8552 proto-ext: extract shared protocol handler code from proto-shell.c
2098f29810e8 proto: add config_load callback to proto_handler
aaf5b194b15d proto-ucode: add ucode protocol handler infrastructure
3fc8b83c8b62 proto-ucode: add ucode proto handler scripts
c6122254eb70 examples: sync wireless scripts with openwrt

Signed-off-by: Felix Fietkau <nbd@nbd.name>
This commit is contained in:
Felix Fietkau 2026-02-15 08:27:59 +00:00
parent f2a532ec09
commit c504cbd47c
5 changed files with 208 additions and 8 deletions

View file

@ -1,13 +1,13 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=netifd
PKG_RELEASE:=3
PKG_RELEASE:=1
PKG_SOURCE_PROTO:=git
PKG_SOURCE_URL=$(PROJECT_GIT)/project/netifd.git
PKG_SOURCE_DATE:=2025-10-20
PKG_SOURCE_VERSION:=777f5942fa7d6245f6ad29daa1daecc400344d37
PKG_MIRROR_HASH:=7fc56f436faa1a5b05a147febed52c6f58c479125a38c9737736b352cd8d4409
PKG_SOURCE_DATE:=2026-02-15
PKG_SOURCE_VERSION:=c6122254eb7003377b67a6ad14d284b69725bbee
PKG_MIRROR_HASH:=feb62dba4dfecba1e3e758e5e4e822e9776b4104ee133dccfc3feb7ae6c5182d
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
PKG_LICENSE:=GPL-2.0

View file

@ -1,6 +1,6 @@
import * as uci from "uci";
import * as uloop from "uloop";
import * as ubus from "ubus";
import * as libubus from "ubus";
import { access, dirname } from "fs";
function ex_handler(e)
@ -9,9 +9,11 @@ function ex_handler(e)
}
uloop.guard(ex_handler);
ubus.guard(ex_handler);
libubus.guard(ex_handler);
let ubus = netifd.ubus = libubus.connect();
let wireless;
let proto_mod;
function uci_ctx()
{
@ -26,8 +28,13 @@ function config_init()
{
let ctx = uci_ctx();
if (wireless)
wireless.config_init(ctx);
for (let mod in [ wireless, proto_mod ]) {
try {
mod?.config_init(ctx);
} catch (e) {
netifd.log(netifd.L_WARNING, `${e}\n${e.stacktrace[0].context}`);
}
}
}
function config_start()
@ -77,3 +84,12 @@ if (access(wireless_module, "r")) {
} else {
netifd.log(netifd.L_WARNING, `Wireless module not found\n`);
}
const proto_module = dirname(sourcepath()) + "/proto.uc";
if (access(proto_module, "r")) {
try {
proto_mod = loadfile(proto_module)();
} catch (e) {
netifd.log(netifd.L_WARNING, `Error loading proto module: ${e}\n${e.stacktrace[0].context}\n`);
}
}

View file

@ -0,0 +1,112 @@
#!/usr/bin/env ucode
import * as libubus from "ubus";
let script_path = ARGV[0];
let proto_name = ARGV[1];
let action = ARGV[2];
let iface_name = ARGV[3];
let config_json = ARGV[4];
let device = ARGV[5];
let config;
try {
let blob = json(config_json);
let inner = blob?._ucode_config;
config = inner ? json(inner) : blob;
} catch (e) {
warn(`Failed to parse config JSON: ${e}\n${e.stacktrace[0].context}\n`);
exit(1);
}
let ubus = libubus.connect();
if (!ubus) {
warn(`Failed to connect to ubus\n`);
exit(1);
}
let notify_path = `network.interface.${iface_name}`;
function proto_notify(data)
{
return ubus.call(notify_path, "notify_proto", data);
}
let proto = {
iface: iface_name,
proto: proto_name,
config,
device,
notify: proto_notify,
update_link: function(up, data) {
let msg = { action: 0, "link-up": up, ...(data ?? {}) };
return proto_notify(msg);
},
run_command: function(argv, env) {
let msg = { action: 1, command: argv };
if (env)
msg.env = env;
return proto_notify(msg);
},
kill_command: function(signal) {
return proto_notify({ action: 2, signal: signal ?? 15 });
},
error: function(errors) {
return proto_notify({ action: 3, error: errors });
},
block_restart: function() {
return proto_notify({ action: 4 });
},
set_available: function(available) {
return proto_notify({ action: 5, available });
},
add_host_dependency: function(host, ifname) {
let msg = { action: 6 };
if (host)
msg.host = host;
if (ifname)
msg.ifname = ifname;
return proto_notify(msg);
},
setup_failed: function() {
return proto_notify({ action: 7 });
},
};
let handlers = {};
let netifd_stub = {
add_proto: function(handler) {
if (handler?.name)
handlers[handler.name] = handler;
},
};
try {
include(script_path, { netifd: netifd_stub });
} catch (e) {
warn(`Failed to load proto handler script '${script_path}': ${e}\n${e.stacktrace[0].context}\n`);
exit(1);
}
let handler = handlers[proto_name];
if (!handler) {
warn(`No handler found for protocol '${proto_name}'\n`);
exit(1);
}
if (!handler[action]) {
warn(`Handler '${proto_name}' has no '${action}' function\n`);
exit(1);
}
handler[action](proto);

View file

@ -0,0 +1,52 @@
import { sorted_json } from "./utils.uc";
import { dirname, glob } from "fs";
let ctx;
function proto_config_load(config_fn, section_name)
{
if (!ctx)
return null;
let section_data = ctx.get_all("network", section_name);
if (!section_data)
return null;
let config_obj = {
iface: section_name,
section: section_name,
data: section_data,
uci: ctx,
};
let result;
if (config_fn)
result = config_fn(config_obj);
else
result = section_data;
return sorted_json(result);
}
netifd.cb.proto_config_load = proto_config_load;
let base = dirname(sourcepath());
for (let script in glob(base + "/proto/*.uc")) {
try {
loadfile(script)();
} catch (e) {
netifd.log(netifd.L_WARNING,
`Error loading proto handler ${script}: ${e}\n${e.stacktrace[0].context}\n`);
}
}
function config_init(uci)
{
ctx = uci;
if (!ctx.load("network"))
netifd.log(netifd.L_WARNING, `Failed to load network config\n`);
}
return {
config_init,
};

View file

@ -102,6 +102,26 @@ export function parse_attribute_list(data, spec)
return ret;
};
export function sorted_json(value) {
let t = type(value);
if (t == "object") {
let parts = [];
for (let key in sort(keys(value)))
push(parts, sprintf("%J", key) + ":" + sorted_json(value[key]));
return "{" + join(",", parts) + "}";
}
if (t == "array") {
let parts = [];
for (let item in value)
push(parts, sorted_json(item));
return "[" + join(",", parts) + "]";
}
return sprintf("%J", value);
};
export function is_equal(val1, val2) {
let t1 = type(val1);