diff --git a/src/confd/src/Makefile.am b/src/confd/src/Makefile.am index 37e32be9..4c381678 100644 --- a/src/confd/src/Makefile.am +++ b/src/confd/src/Makefile.am @@ -8,4 +8,5 @@ confd_plugin_la_CFLAGS = $(augeas_CFLAGS) $(jansson_CFLAGS) $(libite_CFLAGS) $( confd_plugin_la_LIBADD = $(augeas_LIBS) $(jansson_LIBS) $(libite_LIBS) $(sysrepo_LIBS) confd_plugin_la_LDFLAGS = -module -avoid-version -shared confd_plugin_la_SOURCES = core.c core.h helpers.c helpers.h srx_module.c srx_module.h srx_val.c srx_val.h \ - ietf-system.c ietf-interfaces.c systemv.c systemv.h lyx.c lyx.h dagger.c dagger.h + ietf-system.c ietf-interfaces.c systemv.c systemv.h lyx.c lyx.h dagger.c dagger.h \ + infix-dhcp.c diff --git a/src/confd/src/core.c b/src/confd/src/core.c index 2f877de4..1eeb5119 100644 --- a/src/confd/src/core.c +++ b/src/confd/src/core.c @@ -102,6 +102,9 @@ int sr_plugin_init_cb(sr_session_ctx_t *session, void **priv) if (rc) goto err; rc = ietf_system_init(&confd); + if (rc) + goto err; + rc = infix_dhcp_init(&confd); if (rc) goto err; diff --git a/src/confd/src/core.h b/src/confd/src/core.h index 3b436b03..353a6bde 100644 --- a/src/confd/src/core.h +++ b/src/confd/src/core.h @@ -137,4 +137,7 @@ int ietf_interfaces_init(struct confd *confd); /* ietf-system.c */ int ietf_system_init(struct confd *confd); +/* infix-dhcp.c */ +int infix_dhcp_init(struct confd *confd); + #endif /* CONFD_CORE_H_ */ diff --git a/src/confd/src/infix-dhcp.c b/src/confd/src/infix-dhcp.c new file mode 100644 index 00000000..7654dbc0 --- /dev/null +++ b/src/confd/src/infix-dhcp.c @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ + +#include +#include +#include +#include +#include +#include + +#include "core.h" +#include "lyx.h" +#include "srx_module.h" +#include "srx_val.h" + +static const struct srx_module_requirement infix_dhcp_reqs[] = { + { .dir = YANG_PATH_, .name = "infix-dhcp-client", .rev = "2023-05-22" }, + { NULL } +}; + +static int is_enabled(struct lyd_node *parent, const char *name) +{ + const char *attr; + + attr = lydx_get_cattr(parent, name); + if (!attr || !strcmp(attr, "true")) + return 1; + + return 0; +} + +static int client_change(sr_session_ctx_t *session, uint32_t sub_id, const char *module, + const char *xpath, sr_event_t event, unsigned request_id, void *_confd) +{ + struct lyd_node *global, *diff, *cifs, *difs, *cif, *dif; + sr_error_t err = 0; + sr_data_t *cfg; + int ena = 0; + + switch (event) { + case SR_EV_DONE: + break; + case SR_EV_CHANGE: + case SR_EV_ABORT: + default: + return SR_ERR_OK; + } + + ERROR("Got DHCP client change"); + err = sr_get_data(session, "/dhcp-client//.", 0, 0, 0, &cfg); + if (err) + goto err_abandon; + + err = srx_get_diff(session, (struct lyd_node **)&diff); + if (err) + goto err_release_data; + + global = lydx_get_descendant(cfg->tree, "dhcp-client", NULL); + ena = is_enabled(global, "enabled"); + + cifs = lydx_get_descendant(cfg->tree, "dhcp-client", "client-if", NULL); + difs = lydx_get_descendant(diff, "dhcp-client", "client-if", NULL); + + LYX_LIST_FOR_EACH(difs, dif, "client-if") { + /* find the modified one, delete or recreate only that */ + LYX_LIST_FOR_EACH(cifs, cif, "client-if") { + const char *ifname = lydx_get_cattr(dif, "if-name"); + FILE *fp; + + if (strcmp(ifname, lydx_get_cattr(cif, "if-name"))) + continue; + + if (!ena || !is_enabled(cif, "enabled")) { + systemf("initctl delete dhcp-%s", ifname); + continue; + } + + fp = fopenf("w", "/etc/finit.d/available/dhcp-%s.conf", ifname); + if (!fp) { + ERROR("failed creating DHCP client service for %s: %s", + ifname, strerror(errno)); + continue; + } + + fprintf(fp, "service name:dhcp :%s udhcpc -f -S -i %s -- DHCP client @%s", + ifname, ifname, ifname); + fclose(fp); + systemf("initctl enable dhcp-%s", ifname); + } + } + + lyd_free_tree(diff); +err_release_data: + sr_release_data(cfg); +err_abandon: + + return err; +} + + +int infix_dhcp_init(struct confd *confd) +{ + int rc; + + rc = srx_require_modules(confd->conn, infix_dhcp_reqs); + if (rc) + goto fail; + + ERROR("Loaded DHCP model"); + REGISTER_CHANGE(confd->session, "infix-dhcp-client", "/infix-dhcp-client:dhcp-client", + 0, client_change, confd, &confd->sub); + ERROR("Registered DHCP change callback"); + return SR_ERR_OK; +fail: + ERROR("init failed: %s", sr_strerror(rc)); + return rc; +} diff --git a/src/confd/yang/infix-dhcp-client@2023-05-22.yang b/src/confd/yang/infix-dhcp-client@2023-05-22.yang new file mode 100644 index 00000000..6b3e4abd --- /dev/null +++ b/src/confd/yang/infix-dhcp-client@2023-05-22.yang @@ -0,0 +1,56 @@ +module infix-dhcp-client { + yang-version 1.1; + namespace "urn:ietf:params:xml:ns:yang:infix-dhcp-client"; + prefix dhc4-clnt; + + import ietf-interfaces { + prefix "if"; + } + + contact "kernelkit@googlegroups.com"; + description "This module implements an IPv4 DHCP client"; + + revision 2023-05-22 { + description "Initial revision."; + reference "rfc2131 rfc7950"; + } + + /* + * Data Nodes + */ + + container dhcp-client { + description + "DHCPv4 client configuration"; + leaf enabled { + type boolean; + default "true"; + description + "Globally enables the DHCP client function."; + } + list client-if { + key "if-name"; + description + "The list of interfaces for which the client will + be requesting DHCPv4 configuration."; + leaf if-name { + type if:interface-ref; + mandatory true; + description + "Reference to the interface entry that the requested + configuration is relevant to."; + } + leaf enabled { + type boolean; + default "true"; + description + "Enables the DHCP client function for this interface."; + } + leaf client-id { + type string; + description + "DHCP client identifier"; + } + } + } +}