mirror of
https://github.com/kernelkit/infix.git
synced 2026-08-02 13:53:01 +02:00
src/net: fixes after spec. audit by wkz
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -1,8 +1,12 @@
|
||||
LDLIBS = -lite
|
||||
EXEC = net
|
||||
|
||||
net: main.o
|
||||
$(CC) -o $@ $^ $(LDLIBS)
|
||||
|
||||
check: $(EXEC)
|
||||
./test.sh
|
||||
|
||||
clean:
|
||||
$(RM) net
|
||||
|
||||
|
||||
+80
-37
@@ -7,24 +7,35 @@ a previously configured state to the next while attempting to keep the
|
||||
amount of changes needed to a minimum.
|
||||
|
||||
|
||||
Overview
|
||||
--------
|
||||
Concept Overview
|
||||
----------------
|
||||
|
||||
net applies a configuration from `/run/net/next`, where `next` is a file
|
||||
that holds the number of the current generation. It is up to the user
|
||||
to create the below structure with commands to run. Consider the case
|
||||
when `next` contains `0`, net reads all interfaces, in dependency order,
|
||||
from `/run/net/0/` and runs all the `ip-link` and `ip-addr` commands.
|
||||
When it is done, it writes `0` to the file `/run/net/gen` and removes
|
||||
the `next` file to confirm the next generation has been activated.
|
||||
that holds the number of the current generation. It is up to the user,
|
||||
i.e., sysrepo, to create the below tree structure with commands to run.
|
||||
|
||||
Note: it is currently up to the user to remove any old generation.
|
||||
The setup we start with and later move `eth4` from `lag0` to `br0`.
|
||||
|
||||
vlan1
|
||||
______/____
|
||||
[____br0____]
|
||||
/ / \ \
|
||||
eth1 eth2 eth3 lag0
|
||||
/ \
|
||||
eth4 eth5
|
||||
|
||||
Consider the case when `next` contains `0`, net reads all interfaces, in
|
||||
dependency order, from `/run/net/0/` running all `ip-link` and `ip-addr`
|
||||
commands. When done, it writes `0` to the file `/run/net/gen` and then
|
||||
removes the `next` file to confirm the generation has been activated.
|
||||
|
||||
**Note:** it is currently up to the user to remove any old generation.
|
||||
|
||||
/run/net/0/
|
||||
|-- lo/
|
||||
| |-- deps/
|
||||
| |-- ip-link
|
||||
| `-- ip-addr
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- br0/
|
||||
| |-- deps/
|
||||
| | |-- eth1 -> ../../eth1
|
||||
@@ -37,6 +48,9 @@ Note: it is currently up to the user to remove any old generation.
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- ethX/
|
||||
| |-- ...
|
||||
: :
|
||||
|-- lag0/
|
||||
| |-- deps/
|
||||
| | |-- eth4 -> ../../eth4
|
||||
@@ -50,30 +64,67 @@ Note: it is currently up to the user to remove any old generation.
|
||||
`-- ip-addr.up
|
||||
|
||||
The `deps/` sub-directory for each of the interfaces contains symlinks
|
||||
to all interfaces that this interface depends on. I.e., when bringing
|
||||
networking up or down these dependent interfaces are evaluated in order
|
||||
creating a dependency tree:
|
||||
to any interfaces this interface may depend on. I.e., those interfaces
|
||||
are evaluated first.
|
||||
|
||||
vlan1
|
||||
_____/____
|
||||
[___br0____]
|
||||
/ / \ \
|
||||
eth1 eth2 eth3 lag0
|
||||
/ \
|
||||
eth4 eth5
|
||||
|
||||
Essentially, all leaves must be set up before their parents.
|
||||
Essentially, all leaves must be set up before their parents. Moving a
|
||||
leaf from one parent to another, e.g., from lag0 to br0, is tricky, it
|
||||
involves traversing the previous dependency order when removing leaves,
|
||||
and traversing the next dependency order when addning, see next section
|
||||
for an example.
|
||||
|
||||
|
||||
Concepts
|
||||
--------
|
||||
Example
|
||||
-------
|
||||
|
||||
Conceptually, net is built to complement sysrepo. The idea is to listen
|
||||
to added, deleted, modified states in sysrepo changes to a candidate
|
||||
configuration and generate the `next` generation.
|
||||
net is built to complement sysrepo. The idea is to listen to any added,
|
||||
deleted, modified states in sysrepo changes to a candidate configuration
|
||||
and generate the `next` generation. However, as mentioned previously,
|
||||
when moving leaves between parents we must do so in the dependency order
|
||||
of the current generation.
|
||||
|
||||
So, the user (sysrepo) needs to add `.dn` scripts in the current tree,
|
||||
and `.up` scripts in the next.
|
||||
|
||||
/run/net/<NUM+1>/
|
||||
In our example, interface `eth4` is moved from `lag0` to `br0`, so we
|
||||
need to run `eth4/ip-link.dn` in the current generation first to remove
|
||||
`eth4` from `lag0` before its `ip-link.up` script in the next generation
|
||||
sets `eth4` as a bridge member instead.
|
||||
|
||||
We traverse the current generation and execute all `.dn` scripts:
|
||||
|
||||
/run/net/<GEN>/
|
||||
|-- lo/
|
||||
| `-- deps/
|
||||
|-- br0/
|
||||
| |-- deps/
|
||||
| | |-- eth1 -> ../../eth1
|
||||
| | |-- eth2 -> ../../eth2
|
||||
| | |-- eth3 -> ../../eth3
|
||||
| | `-- lag0 -> ../../lag0
|
||||
| `-- ip-link.up
|
||||
|-- eth0/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
| `-- ip-addr.up
|
||||
|-- eth4/
|
||||
| |-- deps/
|
||||
| |-- ip-link.dn
|
||||
| `-- ip-link.up
|
||||
|-- lag0/
|
||||
| |-- deps/
|
||||
| | |-- eth4 -> ../../eth4
|
||||
| | `-- eth5 -> ../../eth5
|
||||
| `-- ip-link.up
|
||||
`-- vlan1/
|
||||
|-- deps/
|
||||
| `-- br0 -> ../../br0
|
||||
|-- ip-link.up
|
||||
`-- ip-addr.up
|
||||
|
||||
Now we can run all the `.up` scripts in the next generation:
|
||||
|
||||
/run/net/<GEN+1>/
|
||||
|-- lo/
|
||||
| |-- deps/
|
||||
| |-- ip-link.up
|
||||
@@ -105,11 +156,3 @@ configuration and generate the `next` generation.
|
||||
`-- ip-addr.up
|
||||
|
||||
|
||||
Interfaces can be evaluated in any order. The `deps/` directory of each
|
||||
is interface is always evaluated first. For each dependency, `foo.dn`
|
||||
is evaluated first and `foo.up` is evaluated last. Any `ip-link` script
|
||||
is also evaluated before any `ip-addr` script.
|
||||
|
||||
In the case above, interface `eth4` has been moved from `lag0` to `br0`,
|
||||
so we need to run `eth4/ip-link.dn` to remove `eth4` from `lag0` before
|
||||
its `ip-link.up` script sets `eth4` as a bridge member instead.
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
#!/bin/sh
|
||||
# Generate test directory structure for verifying the net tool
|
||||
|
||||
gensh()
|
||||
{
|
||||
cat <<-EOF >"$1"
|
||||
#!/bin/sh
|
||||
echo "Running \$0 ..."
|
||||
EOF
|
||||
chmod +x "$1"
|
||||
}
|
||||
|
||||
mkdir -p /tmp/net/1
|
||||
echo 1 > /tmp/net/next
|
||||
|
||||
mkdir -p /tmp/net/1/lo/deps
|
||||
mkdir -p /tmp/net/1/eth0/deps
|
||||
mkdir -p /tmp/net/1/eth1/deps
|
||||
mkdir -p /tmp/net/1/eth2/deps
|
||||
|
||||
mkdir -p /tmp/net/1/br0/deps
|
||||
ln -sf ../../eth1 /tmp/net/1/br0/deps/
|
||||
ln -sf ../../eth2 /tmp/net/1/br0/deps/
|
||||
|
||||
mkdir -p /tmp/net/1/vlan1/deps
|
||||
ln -sf ../../br0 /tmp/net/1/vlan1/deps/
|
||||
|
||||
gensh /tmp/net/1/lo/ip-link.up
|
||||
gensh /tmp/net/1/eth0/ip-link.up
|
||||
gensh /tmp/net/1/eth1/ip-link.up
|
||||
gensh /tmp/net/1/eth2/ip-link.up
|
||||
gensh /tmp/net/1/br0/ip-link.up
|
||||
gensh /tmp/net/1/vlan1/ip-link.up
|
||||
+93
-38
@@ -1,11 +1,12 @@
|
||||
#include <err.h>
|
||||
#include <libgen.h>
|
||||
#include <stdlib.h>
|
||||
#include <sysexits.h>
|
||||
#include <net/if.h>
|
||||
#include <libite/lite.h>
|
||||
|
||||
#define _PATH_NET "/run/net"
|
||||
#define DEBUG 1
|
||||
#define DEBUG 0
|
||||
#define dbg(fmt, args...) if (DEBUG) warnx(fmt, ##args)
|
||||
|
||||
static char **handled;
|
||||
@@ -51,7 +52,7 @@ static int if_find(char *ifname)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int deps(char *ipath, char *ifname, char *action)
|
||||
static int deps(char *ipath, char *ifname, const char *action)
|
||||
{
|
||||
char path[strlen(ipath) + 42];
|
||||
int num, rc = -1;
|
||||
@@ -94,47 +95,94 @@ done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int activate(const char *net, char *gen)
|
||||
static int iter(char *path, size_t len, const char *action)
|
||||
{
|
||||
char **files;
|
||||
int rc = 0;
|
||||
int num;
|
||||
|
||||
num = dir(path, NULL, NULL, &files, 0);
|
||||
if_alloc(num);
|
||||
|
||||
for (int j = 0; j < num; j++) {
|
||||
char *ifname = files[j];
|
||||
char ipath[len];
|
||||
|
||||
snprintf(ipath, sizeof(ipath), "%s/%s", path, ifname);
|
||||
dbg("Calling deps(%s, %s, %s)", ipath, ifname, action);
|
||||
rc += deps(ipath, ifname, action);
|
||||
free(ifname);
|
||||
}
|
||||
|
||||
if_free();
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int deactivate(const char *net, char *gen)
|
||||
{
|
||||
char path[strlen(net) + strlen(gen) + 5 + IFNAMSIZ];
|
||||
char *action[] = {
|
||||
"ip-addr.dn",
|
||||
"ip-link.dn",
|
||||
"ip-link.up",
|
||||
"ip-addr.up",
|
||||
};
|
||||
char **files;
|
||||
int rc = 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", net, gen);
|
||||
|
||||
for (size_t i = 0; i < NELEMS(action); i++) {
|
||||
char *act = action[i];
|
||||
int num;
|
||||
|
||||
num = dir(path, NULL, NULL, &files, 0);
|
||||
if_alloc(num);
|
||||
|
||||
for (int j = 0; j < num; j++) {
|
||||
char ipath[sizeof(path)];
|
||||
char *ifname = files[j];
|
||||
|
||||
snprintf(ipath, sizeof(ipath), "%s/%s", path, ifname);
|
||||
rc += deps(ipath, ifname, act);
|
||||
free(ifname);
|
||||
}
|
||||
|
||||
if_free();
|
||||
}
|
||||
for (size_t i = 0; i < NELEMS(action); i++)
|
||||
rc += iter(path, sizeof(path), action[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int activate(const char *net, char *gen)
|
||||
{
|
||||
char path[strlen(net) + strlen(gen) + 5 + IFNAMSIZ];
|
||||
char *action[] = {
|
||||
"ip-link.up",
|
||||
"ip-addr.up",
|
||||
};
|
||||
int rc = 0;
|
||||
|
||||
snprintf(path, sizeof(path), "%s/%s", net, gen);
|
||||
for (size_t i = 0; i < NELEMS(action); i++)
|
||||
rc += iter(path, sizeof(path), action[i]);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int load_gen(const char *net, char *gen, char *buf, size_t len)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("r", "%s/%s", net, gen);
|
||||
if (!fp)
|
||||
return EX_OSFILE;
|
||||
if (!fgets(buf, len, fp))
|
||||
return EX_IOERR;
|
||||
fclose(fp);
|
||||
chomp(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int save_gen(const char *net, char *gen, char *buf)
|
||||
{
|
||||
FILE *fp;
|
||||
|
||||
fp = fopenf("w", "%s/%s", net, gen);
|
||||
if (!fp)
|
||||
return -1;
|
||||
fprintf(fp, "%s\n", buf);
|
||||
fclose(fp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const char *net = _PATH_NET;
|
||||
char next[512];
|
||||
FILE *fp;
|
||||
char curr[512], next[512];
|
||||
int rc;
|
||||
|
||||
if (getenv("NET_DIR"))
|
||||
@@ -144,24 +192,31 @@ int main(void)
|
||||
err(1, "makedir");
|
||||
}
|
||||
|
||||
fp = fopenf("r", "%s/next", net);
|
||||
if (!fp)
|
||||
if ((rc = load_gen(net, "next", next, sizeof(next)))) {
|
||||
if (rc == EX_IOERR)
|
||||
warnx("missing next generation");
|
||||
exit(0); /* nothing to do */
|
||||
}
|
||||
|
||||
if (!fgets(next, sizeof(next), fp))
|
||||
err(1, "missing next generation");
|
||||
fclose(fp);
|
||||
if ((rc = load_gen(net, "gen", curr, sizeof(curr)))) {
|
||||
if (rc == EX_IOERR)
|
||||
errx(rc, "missing current generation");
|
||||
/* no current generation */
|
||||
} else {
|
||||
rc = deactivate(net, curr);
|
||||
if (rc)
|
||||
err(1, "failed deactivating current generation");
|
||||
}
|
||||
|
||||
rc = activate(net, chomp(next));
|
||||
rc = activate(net, next);
|
||||
if (rc)
|
||||
err(1, "failed activating next generation");
|
||||
|
||||
fp = fopenf("w", "%s/gen", net);
|
||||
if (!fp)
|
||||
if (save_gen(net, "gen", next))
|
||||
err(1, "next generation applied, failed current");
|
||||
|
||||
fprintf(fp, "%s\n", next);
|
||||
fclose(fp);
|
||||
if (fremove("%s/next", net))
|
||||
err(1, "failed removing %s/next", net);
|
||||
|
||||
return fremove("%s/next", net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Executable
+101
@@ -0,0 +1,101 @@
|
||||
#!/bin/sh
|
||||
# Generate test directory structure for verifying the net tool
|
||||
set -e
|
||||
|
||||
NET_DIR=/tmp/net
|
||||
export NET_DIR
|
||||
|
||||
gensh()
|
||||
{
|
||||
cat <<-EOF >"$1"
|
||||
#!/bin/sh
|
||||
echo "Running \$0 ..."
|
||||
EOF
|
||||
chmod +x "$1"
|
||||
}
|
||||
|
||||
check()
|
||||
{
|
||||
if ./net; then
|
||||
printf "\n[\033[1;32m OK \033[0m] Checking %s\n" "$1"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf "\n[\033[1;31FAIL\033[0m] Checking %s\n" "$1"
|
||||
return 1
|
||||
}
|
||||
|
||||
echo "Verify that all leaves and dependencies are"
|
||||
echo "evaluated first:"
|
||||
echo " vlan1"
|
||||
echo " ______/____"
|
||||
echo " [____br0____]"
|
||||
echo " / / \\ \\"
|
||||
echo "lo eth0 eth1 eth2 eth3 lag0"
|
||||
echo " / \\"
|
||||
echo " eth4 eth5"
|
||||
printf "_______________________________________________\n\n"
|
||||
|
||||
mkdir -p $NET_DIR/0
|
||||
echo 0 > $NET_DIR/next
|
||||
|
||||
mkdir -p $NET_DIR/0/lo/deps
|
||||
gensh $NET_DIR/0/lo/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/eth0/deps
|
||||
mkdir -p $NET_DIR/0/eth1/deps
|
||||
mkdir -p $NET_DIR/0/eth2/deps
|
||||
mkdir -p $NET_DIR/0/eth3/deps
|
||||
mkdir -p $NET_DIR/0/eth4/deps
|
||||
|
||||
gensh $NET_DIR/0/eth0/ip-link.up
|
||||
gensh $NET_DIR/0/eth1/ip-link.up
|
||||
gensh $NET_DIR/0/eth2/ip-link.up
|
||||
gensh $NET_DIR/0/eth3/ip-link.up
|
||||
gensh $NET_DIR/0/eth4/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/lag0/deps
|
||||
ln -sf ../../eth3 $NET_DIR/0/lag0/deps/
|
||||
ln -sf ../../eth4 $NET_DIR/0/lag0/deps/
|
||||
gensh $NET_DIR/0/lag0/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/br0/deps
|
||||
ln -sf ../../eth1 $NET_DIR/0/br0/deps/
|
||||
ln -sf ../../eth2 $NET_DIR/0/br0/deps/
|
||||
ln -sf ../../lag0 $NET_DIR/0/br0/deps/
|
||||
gensh $NET_DIR/0/br0/ip-link.up
|
||||
|
||||
mkdir -p $NET_DIR/0/vlan1/deps
|
||||
ln -sf ../../br0 $NET_DIR/0/vlan1/deps/
|
||||
gensh $NET_DIR/0/vlan1/ip-link.up
|
||||
|
||||
check "initial startup, gen 0"
|
||||
|
||||
printf "_______________________________________________\n\n"
|
||||
mkdir -p $NET_DIR/1
|
||||
|
||||
mkdir -p $NET_DIR/1/lo/deps
|
||||
mkdir -p $NET_DIR/1/eth0/deps
|
||||
mkdir -p $NET_DIR/1/eth1/deps
|
||||
mkdir -p $NET_DIR/1/eth2/deps
|
||||
mkdir -p $NET_DIR/1/eth3/deps
|
||||
mkdir -p $NET_DIR/1/eth4/deps
|
||||
|
||||
mkdir -p $NET_DIR/1/lag0/deps
|
||||
ln -sf ../../eth4 $NET_DIR/1/lag0/deps/
|
||||
|
||||
mkdir -p $NET_DIR/1/br0/deps
|
||||
ln -sf ../../eth1 $NET_DIR/1/br0/deps/
|
||||
ln -sf ../../eth2 $NET_DIR/1/br0/deps/
|
||||
ln -sf ../../eth3 $NET_DIR/1/br0/deps/
|
||||
|
||||
mkdir -p $NET_DIR/1/vlan1/deps
|
||||
ln -sf ../../br0 $NET_DIR/1/vlan1/deps/
|
||||
|
||||
gensh $NET_DIR/0/eth3/ip-link.dn
|
||||
gensh $NET_DIR/1/eth3/ip-link.up
|
||||
echo 1 > $NET_DIR/next
|
||||
|
||||
check "move eth3 from lag0 to br0"
|
||||
|
||||
exit 0
|
||||
Reference in New Issue
Block a user