Skip to content
Draft

Yangerd #1536

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ updates:
directory: /src/netbrowse
schedule:
interval: weekly

- package-ecosystem: gomod
directory: /src/yangerd
schedule:
interval: weekly
2 changes: 1 addition & 1 deletion board/common/rootfs/etc/finit.d/available/firewalld.conf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
service [2345] <!pid/syslogd> reload:'firewall-cmd -q --reload' \
service [2345] <!pid/syslogd> reload:'firewall reload' \
firewalld --nofork --log-target syslog \
-- Firewall daemon
1 change: 1 addition & 0 deletions configs/aarch64_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ BR2_PACKAGE_CURIOS_NFTABLES=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT_ENCRYPT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/aarch64_minimal_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/arm_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT_ENCRYPT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/arm_minimal_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/riscv64_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ BR2_PACKAGE_NETD=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT_ENCRYPT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/x86_64_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ BR2_PACKAGE_CURIOS_NFTABLES=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT_ENCRYPT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions configs/x86_64_minimal_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ BR2_PACKAGE_CONFD_TEST_MODE=y
BR2_PACKAGE_GENCERT=y
BR2_PACKAGE_STATD=y
BR2_PACKAGE_SUPPORT=y
BR2_PACKAGE_YANGERD=y
BR2_PACKAGE_FACTORY=y
BR2_PACKAGE_FINIT_PLUGIN_HOTPLUG=y
BR2_PACKAGE_FINIT_PLUGIN_HOOK_SCRIPTS=y
Expand Down
1 change: 1 addition & 0 deletions package/Config.in
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/curios-nftables/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/gencert/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/statd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/support/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/yangerd/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/factory/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/faux/Config.in"
source "$BR2_EXTERNAL_INFIX_PATH/package/finit/Config.in"
Expand Down
2 changes: 2 additions & 0 deletions package/statd/Config.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
config BR2_PACKAGE_STATD
bool "statd"
depends on BR2_PACKAGE_HOST_GO_TARGET_ARCH_SUPPORTS # yangerd
select BR2_PACKAGE_YANGERD
select BR2_PACKAGE_JANSSON
select BR2_PACKAGE_LIBEV
select BR2_PACKAGE_SYSREPO
Expand Down
7 changes: 7 additions & 0 deletions package/yangerd/Config.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
config BR2_PACKAGE_YANGERD
bool "yangerd"
depends on BR2_PACKAGE_HOST_GO_TARGET_ARCH_SUPPORTS
help
Operational data daemon for YANG/NETCONF/RESTCONF.
Replaces Python yanger scripts with a persistent Go daemon
serving operational data over a Unix socket IPC protocol.
3 changes: 3 additions & 0 deletions package/yangerd/yangerd.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
service <> name:yangerd notify:pid log:prio:daemon.notice,tag:yangerd \
env:-/etc/default/yangerd \
[2345] yangerd -- Operational data daemon
50 changes: 50 additions & 0 deletions package/yangerd/yangerd.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
################################################################################
#
# yangerd
#
################################################################################

YANGERD_VERSION = 1.0.0
YANGERD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/yangerd
YANGERD_SITE_METHOD = local
YANGERD_GOMOD = github.com/kernelkit/infix/src/yangerd
YANGERD_LICENSE = BSD-2-Clause
YANGERD_LICENSE_FILES = LICENSE
YANGERD_REDISTRIBUTE = NO

YANGERD_BUILD_TARGETS = cmd/yangerd cmd/yangerctl
YANGERD_INSTALL_BINS = yangerd yangerctl

define YANGERD_INSTALL_EXTRA
$(INSTALL) -D -m 0644 $(YANGERD_PKGDIR)/yangerd.conf \
$(FINIT_D)/available/yangerd.conf
ln -sf ../available/yangerd.conf $(FINIT_D)/enabled/yangerd.conf
$(INSTALL) -d $(TARGET_DIR)/etc/default
echo '# yangerd build-time feature flags (generated by yangerd.mk)' \
> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_WIFI=$(if $(BR2_PACKAGE_IW),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_CONTAINERS=$(if $(BR2_PACKAGE_PODMAN),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_GPS=$(if $(BR2_PACKAGE_GPSD),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_LLDP=$(if $(BR2_PACKAGE_LLDPD),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_FIREWALL=$(if $(BR2_PACKAGE_FIREWALLD),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_DHCP=$(if $(BR2_PACKAGE_DNSMASQ),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_ENABLE_FRR=$(if $(BR2_PACKAGE_FRR),true,false)' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'YANGERD_LOG_LEVEL=info' >> $(TARGET_DIR)/etc/default/yangerd
echo '# Soft heap limit, the live data is well under 1 MiB and the' \
>> $(TARGET_DIR)/etc/default/yangerd
echo '# rest is garbage; without it RSS drifts past 100 MiB on a' \
>> $(TARGET_DIR)/etc/default/yangerd
echo '# 512 MiB box and the OOM killer picks yangerd during upgrades' \
>> $(TARGET_DIR)/etc/default/yangerd
echo 'GOMEMLIMIT=64MiB' >> $(TARGET_DIR)/etc/default/yangerd
endef
YANGERD_POST_INSTALL_TARGET_HOOKS += YANGERD_INSTALL_EXTRA

$(eval $(golang-package))
39 changes: 39 additions & 0 deletions src/confd/bin/firewall
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
DEST="org.fedoraproject.FirewallD1"
OBJECT="/org/fedoraproject/FirewallD1"
INTERFACE="org.fedoraproject.FirewallD1"
ADDRSET_DIR="/run/confd/address-sets"
VERBOSE=0

print() {
Expand Down Expand Up @@ -117,6 +118,42 @@ ipset_call()
fi
}

# Dynamic address-set entries only exist in the runtime config; a reload
# rebuilds the sets from the generated ipset XML, which holds static
# entries only. Re-apply the dynamic entries tracked by confd's
# add/remove action handlers, so they survive the reload without being
# baked into the XML (which would resurrect entries removed while the
# reload was in flight).
#
# An entry firewalld rejects as invalid, e.g., one now overlapping a
# static entry, is dropped from the shadow file, or it could never be
# removed with the remove action again.
addrset_resync()
{
for file in "$ADDRSET_DIR"/*; do
case "$file" in *.resync) continue ;; esac
[ -f "$file" ] || continue
name=$(basename "$file")
keep="$file.resync"
: > "$keep"

while IFS= read -r entry; do
[ -n "$entry" ] || continue
if ! ipset_call addEntry "$name" "$entry"; then
case "$output" in
*INVALID_ENTRY*)
logger -t firewall -p daemon.warn "ipset $name: dropping rejected dynamic entry $entry"
continue
;;
esac
fi
printf '%s\n' "$entry" >> "$keep"
done < "$file"

mv "$keep" "$file"
done
}

panic_status()
{
if is_panic_enabled; then
Expand Down Expand Up @@ -377,6 +414,8 @@ main()
exit 1
fi
fi

addrset_resync
;;
panic)
if ! check_firewalld; then
Expand Down
4 changes: 4 additions & 0 deletions src/confd/src/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -805,6 +805,10 @@ static int change_cb(sr_session_ctx_t *session, uint32_t sub_id, const char *mod
return SR_ERR_SYS;
}

/* Nudge yangerd to re-poll, best effort: it may not be installed */
if (systemf("initctl -bq reload yangerd"))
DEBUG("yangerd not reloaded, not running?");

AUDIT("The new configuration has been applied.");
}

Expand Down
84 changes: 15 additions & 69 deletions src/confd/src/firewall.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,29 +106,6 @@ static int prefix_parse(const char *str, struct prefix *p)
return -1;
}

static bool prefix_overlap(const char *a, const char *b)
{
struct prefix pa, pb;
int len, i;

if (prefix_parse(a, &pa) || prefix_parse(b, &pb) || pa.af != pb.af)
return false;

len = pa.len < pb.len ? pa.len : pb.len;
for (i = 0; i < len / 8; i++) {
if (pa.addr[i] != pb.addr[i])
return false;
}
if (len % 8) {
uint8_t mask = 0xff << (8 - len % 8);

if ((pa.addr[i] & mask) != (pb.addr[i] & mask))
return false;
}

return true;
}

static bool shadow_has(const char *name, const char *entry)
{
char line[ENTRY_STRLEN];
Expand Down Expand Up @@ -371,47 +348,12 @@ static int generate_zone(struct lyd_node *cfg, const char *name, char **ifaces)
}

/*
* Dynamic entries, added at runtime with the add action, are folded
* into the generated ipset as regular entries so they survive the
* firewalld reload triggered by configuration changes. Entries that
* overlap new static configuration are dropped -- config wins, and
* nftables refuses overlapping elements in interval sets.
* Only static entries go into the generated ipset. Dynamic entries,
* added at runtime with the add action, are re-applied from the shadow
* files by 'firewall reload' after firewalld has reloaded. Baking them
* into the XML would resurrect entries removed while a reload was in
* flight -- the reload is asynchronous to the action handlers.
*/
static void merge_dynamic(FILE *fp, struct lyd_node *cfg, const char *name)
{
char line[ENTRY_STRLEN];
FILE *sf;

sf = fopenf("r", ADDRSET_RUNDIR "/%s", name);
if (!sf)
return;

while (fgets(line, sizeof(line), sf)) {
struct lyd_node *node;
bool skip = false;

chomp(line);
if (!line[0])
continue;

LYX_LIST_FOR_EACH(lyd_child(cfg), node, "entry") {
if (prefix_overlap(line, lyd_get_value(node))) {
skip = true;
break;
}
}

if (skip) {
NOTE("address-set %s: dropping dynamic entry %s, overlaps static entry",
name, line);
continue;
}

fprintf(fp, " <entry>%s</entry>\n", line);
}
fclose(sf);
}

static int generate_ipset(struct lyd_node *cfg, const char *name)
{
const char *family, *timeout, *desc;
Expand Down Expand Up @@ -441,9 +383,6 @@ static int generate_ipset(struct lyd_node *cfg, const char *name)
LYX_LIST_FOR_EACH(lyd_child(cfg), node, "entry")
fprintf(fp, " <entry>%s</entry>\n", lyd_get_value(node));

if (!timeout)
merge_dynamic(fp, cfg, name);

fprintf(fp, "</ipset>\n");

return close_file(fp);
Expand Down Expand Up @@ -745,10 +684,17 @@ int firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
return SR_ERR_OK;
}

/* Drop dynamic state of deleted address-sets */
/*
* Drop dynamic state of deleted address-sets, and of sets
* that got a timeout: their entries expire on their own and
* must not be re-applied on reload.
*/
clist = lydx_get_descendant(diff, "firewall", "address-set", NULL);
LYX_LIST_FOR_EACH(clist, cnode, "address-set") {
if (lydx_get_op(cnode) == LYDX_OP_DELETE)
struct lyd_node *timeout = lydx_get_child(cnode, "timeout");

if (lydx_get_op(cnode) == LYDX_OP_DELETE ||
(timeout && lydx_get_op(timeout) != LYDX_OP_DELETE))
erasef(ADDRSET_RUNDIR "/%s", lydx_get_cattr(cnode, "name"));
}

Expand Down Expand Up @@ -861,7 +807,7 @@ int firewall_change(sr_session_ctx_t *session, struct lyd_node *config, struct l
LYX_LIST_FOR_EACH(clist, cnode, "service")
generate_service(cnode, lydx_get_cattr(cnode, "name"));

/* Regenerate all address-sets, incl. dynamic entries */
/* Regenerate all address-sets (static entries only) */
clist = lydx_get_descendant(tree, "firewall", "address-set", NULL);
LYX_LIST_FOR_EACH(clist, cnode, "address-set")
generate_ipset(cnode, lydx_get_cattr(cnode, "name"));
Expand Down
2 changes: 1 addition & 1 deletion src/statd/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ DISTCLEANFILES = *~ *.d
ACLOCAL_AMFLAGS = -I m4

sbin_PROGRAMS = statd
statd_SOURCES = statd.c shared.c shared.h journal.c journal_retention.c journal.h avahi.c avahi.h iface.c iface.h
statd_SOURCES = statd.c shared.c shared.h journal.c journal_retention.c journal.h avahi.c avahi.h iface.c iface.h yangerd.c yangerd.h
statd_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE
statd_CPPFLAGS += -DSTATD_VERSION=\"$(PACKAGE_VERSION)\"
statd_CFLAGS = -W -Wall -Wextra
Expand Down
Loading
Loading