From ec241a43c51dc0c8355bc7def98649d23ed49f77 Mon Sep 17 00:00:00 2001 From: dautor Date: Sun, 17 Nov 2024 17:20:16 +0100 Subject: Implement ng_pipe link functionality Links are just netgraph connections by default. To convert a link to a ng_pipe, use setcfg command. To go back to a direct link, use clrcfg command. --- src/base/main.c | 252 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 179 insertions(+), 73 deletions(-) (limited to 'src/base/main.c') diff --git a/src/base/main.c b/src/base/main.c index 60d76b4..6721701 100644 --- a/src/base/main.c +++ b/src/base/main.c @@ -1,5 +1,6 @@ #include "state.h" #include +#include #include "../util.h" static char const *Arg0; @@ -215,28 +216,7 @@ start_link_(link_ *R) fprintf(stderr, "Failed to create netgraph socket: %s\n", strerror(errno)); return -1; } - int Result; - switch(R->Configuration.Type) - { - case link_type_direct: - { - Result = - ng_connect(Control, R->Peer[0].Address, R->Peer[1].Address, R->Peer[0].Hook, R->Peer[1].Hook); - break; - } - case link_type_pipe: - { - Result = Create_pipe(&R->pipe.ID, - Control, - R->Peer[0].Address, - R->Peer[1].Address, - R->Peer[0].Hook, - R->Peer[1].Hook); - break; - } - case link_type_COUNT: - default: __builtin_unreachable(); - } + int Result = ng_connect(Control, R->Peer[0].Address, R->Peer[1].Address, R->Peer[0].Hook, R->Peer[1].Hook); close(Control); return Result; } @@ -250,31 +230,25 @@ stop_link_(link_ *R) fprintf(stderr, "Failed to create netgraph socket: %s\n", strerror(errno)); return -1; } - switch(R->Configuration.Type) + if(R->PipeID) { - case link_type_direct: - { - struct ngm_rmhook D; - char Path0[NG_PATHSIZ]; - strncpy(Path0, R->Peer[0].Address, sizeof(Path0)); - strncpy(D.ourhook, R->Peer[0].Hook, sizeof(D.ourhook)); - if(NgSendMsg(Control, Path0, NGM_GENERIC_COOKIE, NGM_RMHOOK, &D, sizeof(D)) == -1) - { - fprintf(stderr, "ngctl rmhook %s %s: %s\n", Path0, D.ourhook, strerror(errno)); - close(Control); - return -1; - } - close(Control); - return 0; - } - case link_type_pipe: + int Result = DestroyNetgraphNode(R->PipeID, Control); + close(Control); + return Result; + } else + { + struct ngm_rmhook D; + char Path0[NG_PATHSIZ]; + strncpy(Path0, R->Peer[0].Address, sizeof(Path0)); + strncpy(D.ourhook, R->Peer[0].Hook, sizeof(D.ourhook)); + if(NgSendMsg(Control, Path0, NGM_GENERIC_COOKIE, NGM_RMHOOK, &D, sizeof(D)) == -1) { - int Result = DestroyNetgraphNode(R->pipe.ID, Control); + fprintf(stderr, "ngctl rmhook %s %s: %s\n", Path0, D.ourhook, strerror(errno)); close(Control); - return Result; + return -1; } - case link_type_COUNT: - default: __builtin_unreachable(); + close(Control); + return 0; } } @@ -284,8 +258,7 @@ start_link(experiment *E, char const *NodeA, char const *InterfaceA, char const *NodeB, - char const *InterfaceB, - link_type Type) + char const *InterfaceB) { if(FindLinkIndex(E, Name) != SIZE_MAX) { @@ -298,7 +271,6 @@ start_link(experiment *E, C.Peer[0].Interface = strdup(InterfaceA); C.Peer[1].Node = strdup(NodeB); C.Peer[1].Interface = strdup(InterfaceB); - C.Type = Type; } link_ R; { // Start @@ -622,16 +594,30 @@ LoadState(experiment *E, fd FD) static void __attribute__((noreturn)) usage(void) { + // NOTE: I couldn't find a way to make string precision work with '$'. + // We could skip all this buffer nonsense that way. + size_t Length = strlen(Arg0); + char Buffer[PATH_MAX]; + if(Length > sizeof(Buffer)) Length = sizeof(Buffer) - 1; + memset(Buffer, ' ', Length); + Buffer[Length] = 0; fprintf( stderr, "usage: %1$s show\n" - " %1$s node start [node-name] [configuration]\n" - " %1$s node stop [node-name]\n" - " %1$s link start [link-name] [node-A-name] [interface-A-name] [node-B-name] [interface-B-name] [?type]\n" - " %1$s link stop [link-name]\n" - " %1$s node cmd [node-name] [command...]\n" - " %1$s node mod [node-name] [command...]\n", - Arg0); + " %1$s node start [node-name] [configuration]\n" + " %2$s stop [node-name]\n" + " %2$s cmd [node-name] [command...]\n" + " %2$s mod [node-name] [command...]\n" + " %1$s link start [link-name] [node-A-name] [interface-A-name] [node-B-name] [interface-B-name]\n" + " %2$s stop [link-name]\n" + " %2$s setcfg [link-name] [configuration]\n" + " %2$s getcfg [link-name]\n" + " %2$s clrcfg [link-name]\n" + " %2$s getstats [link-name]\n" + " %2$s clrstats [link-name]\n" + " %2$s getclrstats [link-name]\n", + Arg0, + Buffer); exit(EX_USAGE); } @@ -722,6 +708,101 @@ Command_node(experiment *E, fd StateFD, int ArgCount, char **Arg) } } +static int +link_unpipe(link_ *E, fd Control) +{ + if(E->PipeID == 0) return 0; + if(DestroyNetgraphNode(E->PipeID, Control) == -1) return -1; + E->PipeID = 0; + if(ng_connect(Control, E->Peer[0].Address, E->Peer[1].Address, E->Peer[0].Hook, E->Peer[1].Hook) == -1) + return -1; + return 0; +} + +static int +link_pipe(link_ *E, fd Control) +{ + if(E->PipeID != 0) return 0; + struct ngm_rmhook D; + char Path0[NG_PATHSIZ]; + strncpy(Path0, E->Peer[0].Address, sizeof(Path0)); + strncpy(D.ourhook, E->Peer[0].Hook, sizeof(D.ourhook)); + if(NgSendMsg(Control, Path0, NGM_GENERIC_COOKIE, NGM_RMHOOK, &D, sizeof(D)) == -1) + { + fprintf(stderr, "ngctl rmhook %s %s: %s\n", Path0, D.ourhook, strerror(errno)); + return -1; + } + return Create_pipe(&E->PipeID, + Control, + E->Peer[0].Address, + E->Peer[1].Address, + E->Peer[0].Hook, + E->Peer[1].Hook); +} + +static int +link_setcfg(link_ *E, fd Control, char const *Config) +{ + if(link_pipe(E, Control) == -1) goto error; + if(*Config == '\0') return 0; + char Path[NG_PATHSIZ]; + snprintf(Path, sizeof(Path), "[%x]:", E->PipeID); + if(NgSendAsciiMsg(Control, Path, "setcfg {%s}", Config) < 0) + { + // NOTE: We do not save if return code is not 0. + // We should probably always save configuration. + // We do not want to create a node and not save it. + fprintf(stderr, "NgSendAsciiMsg failed: %s\n", strerror(errno)); + } + return 0; +error: + return -1; +} + +static int +link_get(link_ *E, fd Control, char const *What) +{ + if(E->PipeID == 0) + { + fprintf(stderr, "link is not a pipe\n"); + return -1; + } + char Path[NG_PATHSIZ]; + snprintf(Path, sizeof(Path), "[%x]:", E->PipeID); + if(NgSendAsciiMsg(Control, Path, "%s", What) < 0) + { + fprintf(stderr, "NgSendAsciiMsg failed: %s\n", strerror(errno)); + return -1; + } + struct ng_mesg *Message; + if(NgAllocRecvAsciiMsg(Control, &Message, Path) < 0) + { + fprintf(stderr, "NgAllocRecvAsciiMsg failed: %s\n", strerror(errno)); + return -1; + } + printf("%s", Message->data); + free(Message); + return 0; +} + +static int +link_clrstats(link_ *E, fd Control) +{ + if(E->PipeID == 0) + { + fprintf(stderr, "link is not a pipe\n"); + return -1; + } + char Path[NG_PATHSIZ]; + snprintf(Path, sizeof(Path), "[%x]:", E->PipeID); + if(NgSendAsciiMsg(Control, Path, "clrstats") < 0) + { + fprintf(stderr, "NgSendAsciiMsg failed: %s\n", strerror(errno)); + return -1; + } + return 0; +} + static int Command_link(experiment *E, fd StateFD, int ArgCount, char **Arg) { @@ -738,32 +819,57 @@ Command_link(experiment *E, fd StateFD, int ArgCount, char **Arg) int Result; if(strcmp(Command, "start") == 0) { - if(ArgCount == 4) - { - Result = start_link(E, LinkName, Arg[0], Arg[1], Arg[2], Arg[3], link_type_direct); - } else if(ArgCount == 5) - { - link_type Type; - if(FromString_link_type(Arg[4], &Type) == -1) - { - fprintf(stderr, "Unknown link type '%s'\n", Arg[4]); - Result = -1; - } else - { - Result = start_link(E, LinkName, Arg[0], Arg[1], Arg[2], Arg[3], Type); - } - } else - { - usage(); - } + if(ArgCount != 4) usage(); + Result = start_link(E, LinkName, Arg[0], Arg[1], Arg[2], Arg[3]); } else if(strcmp(Command, "stop") == 0) { if(ArgCount != 0) usage(); Result = stop_link(E, LinkName); } else { - fprintf(stderr, "unknown argument: %s\n", Command); - usage(); + size_t LinkIndex = FindLinkIndex(E, LinkName); + if(LinkIndex == SIZE_MAX) + { + fprintf(stderr, "Link %s does not exists\n", LinkName); + return -1; + } + link_ *R = E->Link + LinkIndex; + fd Control; + if(NgMkSockNode(NULL, &Control, NULL) == -1) + { + fprintf(stderr, "Failed to create netgraph socket: %s\n", strerror(errno)); + return -1; + } + if(strcmp(Command, "setcfg") == 0) + { + if(ArgCount != 1) usage(); + Result = link_setcfg(R, Control, Arg[0]); + } else if(strcmp(Command, "getcfg") == 0) + { + if(ArgCount != 0) usage(); + Result = link_get(R, Control, "getcfg"); + } else if(strcmp(Command, "clrcfg") == 0) + { + if(ArgCount != 0) usage(); + Result = link_unpipe(R, Control); + } else if(strcmp(Command, "getstats") == 0) + { + if(ArgCount != 0) usage(); + Result = link_get(R, Control, "getstats"); + } else if(strcmp(Command, "clrstats") == 0) + { + if(ArgCount != 0) usage(); + Result = link_clrstats(R, Control); + } else if(strcmp(Command, "getclrstats") == 0) + { + if(ArgCount != 0) usage(); + Result = link_get(R, Control, "getclrstats"); + } else + { + fprintf(stderr, "unknown argument: %s\n", Command); + usage(); + } + close(Control); } if(Result == 0) SaveState(E, StateFD); return Result; -- cgit v1.2.3