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 +++++++++++++++++++++++++++++++++++++++---------------- src/base/state.c | 76 +++-------------- src/base/state.h | 17 +--- 3 files changed, 191 insertions(+), 154 deletions(-) (limited to 'src') 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; diff --git a/src/base/state.c b/src/base/state.c index 652c943..acef753 100644 --- a/src/base/state.c +++ b/src/base/state.c @@ -103,50 +103,12 @@ error: return Error; } -int -FromString_link_type(char const *S, link_type *Type) -{ - for(link_type i = 0; i < link_type_COUNT; ++i) - { - if(strcmp(link_type_Names[i], S) == 0) - { - *Type = i; - return 0; - } - } - return -1; -} - -char * -Parse_link_type(link_type *E, ucl_object_t const *root, char const *Position) -{ - if(root == NULL) - { - *E = link_type_direct; - return NULL; - } - char *Error; - UCL_CHECK_ROOT(STRING); - char const *S = ucl_object_tostring(root); - if(FromString_link_type(S, E) == 0) return NULL; - asprintf(&Error, "%s invalid link type '%s'", Position, S); -error: - return Error; -} - char * Parse_link_configuration(link_configuration *E, ucl_object_t const *root, char const *Position) { char *Error; size_t EndpointAt = 0; UCL_CHECK_ROOT(OBJECT); - { - char *NewPosition; - asprintf(&NewPosition, "%s.type", Position); - Error = Parse_link_type(&E->Type, ucl_object_lookup(root, "type"), NewPosition); - free(NewPosition); - if(Error != NULL) goto error; - } ucl_object_t const *peer0 = ucl_object_lookup(root, "peer0"); { char *NewPosition; @@ -178,6 +140,8 @@ Parse_link(link_ *E, ucl_object_t const *root, char const *Position) size_t EndpointAt = 0; bool Configuration = false; UCL_CHECK_ROOT(OBJECT); + ucl_object_t const *id = ucl_object_lookup(root, "id"); + UCL_CHECK_OPTIONAL(id, INT); ucl_object_t const *configuration = ucl_object_lookup(root, "configuration"); { char *NewPosition; @@ -187,24 +151,15 @@ Parse_link(link_ *E, ucl_object_t const *root, char const *Position) if(Error != NULL) goto error; Configuration = true; } - switch(E->Configuration.Type) + if(id != NULL) { - case link_type_direct: break; - case link_type_pipe: + s64 ID = ucl_object_toint(id); + if(ID < 0 || ID > INT32_MAX) { - ucl_object_t const *id = ucl_object_lookup(root, "id"); - UCL_CHECK(id, INT); - s64 ID = ucl_object_toint(id); - if(ID < 0 || ID > INT32_MAX) - { - asprintf(&Error, "%s id invalid (%ld)", Position, ID); - goto error; - } - E->pipe.ID = (u32)ID; - break; + asprintf(&Error, "%s id invalid (%ld)", Position, ID); + goto error; } - case link_type_COUNT: - default: __builtin_unreachable(); + E->PipeID = (u32)ID; } ucl_object_t const *peer0 = ucl_object_lookup(root, "peer0"); { @@ -365,8 +320,6 @@ void Save_link_configuration(jprint_state *S, link_configuration const *E) { JPrintObjectBegin(S); - JPrintMember(S, "type"); - JPrint_string(S, link_type_Names[E->Type]); JPrintMember(S, "peer0"); Save_endpoint_configuration(S, E->Peer + 0); JPrintMember(S, "peer1"); @@ -380,17 +333,10 @@ Save_link(jprint_state *S, link_ const *E) JPrintObjectBegin(S); JPrintMember(S, "configuration"); Save_link_configuration(S, &E->Configuration); - switch(E->Configuration.Type) + if(E->PipeID != 0) { - case link_type_direct: break; - case link_type_pipe: - { - JPrintMember(S, "id"); - JPrint_ssize_t(S, E->pipe.ID); - break; - } - case link_type_COUNT: - default: __builtin_unreachable(); + JPrintMember(S, "id"); + JPrint_ssize_t(S, E->PipeID); } JPrintMember(S, "peer0"); Save_endpoint(S, E->Peer + 0); diff --git a/src/base/state.h b/src/base/state.h index 82db1e0..5aa29bd 100644 --- a/src/base/state.h +++ b/src/base/state.h @@ -14,12 +14,9 @@ struct char *Interface; } typedef endpoint_configuration; -NAMED_ENUM(link_type, direct, pipe, ); - struct { endpoint_configuration Peer[2]; - link_type Type; } typedef link_configuration; struct @@ -27,16 +24,7 @@ struct char *Name; link_configuration Configuration; endpoint Peer[2]; - union - { - struct - { - } direct; - struct - { - u32 ID; - } pipe; - }; + u32 PipeID; } typedef link_; struct @@ -60,8 +48,6 @@ struct link_ *Link; } typedef experiment; -int FromString_link_type(char const *, link_type *); - void Free_endpoint(endpoint *); void Free_endpoint_configuration(endpoint_configuration *); void Free_link_configuration(link_configuration *); @@ -72,7 +58,6 @@ void Free_experiment(experiment *); char *Parse_endpoint(endpoint *, ucl_object_t const *, char const *Position); char *Parse_endpoint_configuration(endpoint_configuration *, ucl_object_t const *, char const *Position); -char *Parse_link_type(link_type *, ucl_object_t const *, char const *Position); char *Parse_link_configuration(link_configuration *, ucl_object_t const *, char const *Position); char *Parse_link(link_ *, ucl_object_t const *, char const *Position); char *Parse_node_configuration(node_configuration *, ucl_object_t const *, char const *Position); -- cgit v1.2.3