network/nix/lib/openwrt-models.nix

159 lines
4.8 KiB
Nix

{ self, openwrt }:
let
# the files that contain port definitions
defFiles = builtins.filter
(self.lib.hasSuffix "/etc/board.d/02_network")
(self.lib.filesystem.listFilesRecursive "${openwrt}/target/linux");
# files contents as one string
defSource = builtins.concatStringsSep "\n" (
map builtins.readFile defFiles
);
defSourceLines = builtins.filter (s: s != []) (
builtins.split "\n" (
builtins.replaceStrings
[ "\\\n" ] [ "" ] defSource
));
parseCommand = line:
let
tokens =
builtins.concatMap (frag:
if builtins.isString frag
then builtins.split "[[:space:]]+" frag
else frag
) (
builtins.split "\"([^\"]*)\"" line
);
words =
builtins.filter (word:
word != [] && word != ""
) tokens;
command = builtins.head words;
args = builtins.tail words;
makeLinkFromArg = port: arg:
builtins.foldl' (result: interface:
if port != []
then result // {
"${port}" = {
type = "phys";
inherit interface port;
};
}
else result
) {} (builtins.split "[[:space:]]+" arg);
commands = {
ucidef_add_switch.ports = builtins.foldl' (ports: arg:
let
switch = builtins.head args;
m1 = builtins.match "([[:digit:]]+):(.+)" arg;
m2 = builtins.match "([[:digit:]]+)([ut]?)@(.+)" arg;
m2flag = builtins.elemAt m2 1;
port = if m1 != null
then {
inherit switch;
type = "port";
index = builtins.elemAt m1 0;
port = builtins.elemAt m1 1;
}
else if m2 != null
then {
inherit switch;
type = "host";
index = builtins.elemAt m2 0;
interface = builtins.elemAt m2 2;
} // self.lib.optionalAttrs (m2flag == "u") {
only = "untagged";
} // self.lib.optionalAttrs (m2flag == "t") {
only = "tagged";
}
else throw "Unimplemented port scheme: ${arg}";
in if m1 != null || m2 != null
then ports // {
"${port.index}" = port;
}
else builtins.trace "Unimplemented port scheme: ${arg}" ports
) {} (builtins.tail args);
ucidef_set_interface_wan.ports = {
"${builtins.head args}" = {
type = "phys";
interface = builtins.head args;
port = "wan";
};
};
ucidef_set_interface_lan.ports =
makeLinkFromArg "lan" (builtins.elemAt args 0);
ucidef_set_interfaces_lan_wan.ports =
makeLinkFromArg "lan" (builtins.elemAt args 0) //
makeLinkFromArg "wan" (builtins.elemAt args 1);
};
in
if commands ? ${command}
then commands.${command}
else {
unknown."${command}" = args;
};
in (
builtins.foldl' ({ state, result, models ? null, data ? {} }: line:
if state == "start"
then
if builtins.match "[[:space:]]*case \"?\\$board\"? in" line != null
then { state = "case"; inherit result; }
else { inherit state result; }
else if state == "case"
then
if builtins.match "[[:space:]]*esac" line != null
then { state = "start"; inherit result; }
else
let
m = builtins.match "[[:space:]]*(.+)\\)" line;
in
if m == null
then { inherit state result; }
else {
inherit result;
state = "model";
models =
builtins.filter (m: m != null) (
map (s:
let
m = builtins.split "," s;
in
if s != [] &&
m != null &&
builtins.length m == 3
then {
vendor = builtins.elemAt m 0;
model = builtins.elemAt m 2;
}
else null
) (
builtins.split "[[:space:]]*\\|[[:space:]]*" (
builtins.head m
)));
}
else if state == "model"
then
if builtins.match "[[:space:]]*;;" line != null
then {
state = "case";
result = result ++ [ {
inherit models data;
} ];
}
else {
inherit result state models;
data = self.lib.recursiveUpdate data (parseCommand line);
}
else throw "Invalid state ${state}"
) { state = "start"; result = []; } defSourceLines
).result