diff --git a/board/common/rootfs/etc/avahi/avahi-autoipd.action b/board/common/rootfs/etc/avahi/avahi-autoipd.action index 239d7853..20912b82 100755 --- a/board/common/rootfs/etc/avahi/avahi-autoipd.action +++ b/board/common/rootfs/etc/avahi/avahi-autoipd.action @@ -7,38 +7,49 @@ # STOP: The daemon is terminating # $2 interface name # $3 IP adddress -# -# For details on the distance adjustment below, please see the following -# section in the Frr documentation on distance + prefence => to metric. -# https://docs.frrouting.org/en/stable-8.0/zebra.html#administrative-distance PATH="$PATH:/usr/bin:/usr/sbin:/bin:/sbin" +NAME="/etc/frr/static.d/$2-zeroconf.conf" +NEXT="${NAME}+" log() { logger -I $$ -t zeroconf -p user.notice "$*" } -# Use a different metric for each interface as tie breaker, to ensure we -# can set identical routes to multiple interfaces. -IFINDEX=$(cat "/sys/class/net/$2/ifindex" 2>/dev/null || echo 0) +# Reduce changes needed by comparing with previous route(s) +act() +{ + case $1 in + add) + echo "! Generated by avahi-autoipd" > "$NEXT" + echo "ip route 0.0.0.0/0 $2 254" >> "$NEXT" + cmp -s "$NAME" "$NEXT" && return + mv "$NEXT" "$NAME" + ;; + del) + [ -f "$NAME" ] || return + rm "$NAME" + ;; + *) + return + ;; + esac -# Distance adjustment to ensure that static routes set by Zebra and any -# routes learned from DHCP take precedence over these interface routes. -# A distance of 255 ensures these routes are never redistributed. -METRIC=$(((255 << 24) + 1000 + IFINDEX)) + initctl -nbq restart staticd +} case "$1" in BIND) - ip addr flush dev "$2" label "$2:avahi" - ip addr add "$3"/16 brd 169.254.255.255 label "$2:avahi" scope link dev "$2" proto random - ip route add default dev "$2" metric "$METRIC" scope link proto zeroconf + ip addr flush dev "$2" proto random + ip addr add "$3"/16 brd 169.254.255.255 scope link dev "$2" proto random + act add "$2" log "set ipv4ll $3 on iface $2" ;; CONFLICT|UNBIND|STOP) - ip route del default dev "$2" metric "$METRIC" scope link - ip addr flush dev "$2" label "$2:avahi" + act del "$2" + ip addr flush dev "$2" proto random log "clr ipv4ll on iface $2" ;; diff --git a/board/common/rootfs/etc/frr/static.d/.empty b/board/common/rootfs/etc/frr/static.d/.empty new file mode 100644 index 00000000..e69de29b diff --git a/board/common/rootfs/etc/frr/static.d/00default.conf b/board/common/rootfs/etc/frr/static.d/00default.conf new file mode 100644 index 00000000..c23631f5 --- /dev/null +++ b/board/common/rootfs/etc/frr/static.d/00default.conf @@ -0,0 +1,9 @@ +! Default settings for staticd, used for both +! confd generated routes, udhcpc and zeroconf +frr defaults traditional +hostname Router +password zebra +enable password zebra +no log unique-id +log syslog informational +log facility local2 diff --git a/board/common/rootfs/usr/sbin/staticd-helper b/board/common/rootfs/usr/sbin/staticd-helper new file mode 100755 index 00000000..744b2cd3 --- /dev/null +++ b/board/common/rootfs/usr/sbin/staticd-helper @@ -0,0 +1,15 @@ +#!/bin/sh +# Sort and collate all /etc/frr/static.d/*.conf files managed by confd, +# udhcpc, and avahi-autoipd before starting staticd. + +DIRD=/etc/frr/static.d +NAME=/etc/frr/staticd.conf +NEXT=${NAME}+ + +rm -f "$NEXT" +find "$DIRD" -type f -name '*.conf' ! -name '*~' | sort | while read -r file; do + cat "$file" >> "$NEXT" +done + +cmp -s "$NAME" "$NEXT" && exit 0 +mv "$NEXT" "$NAME" diff --git a/board/common/rootfs/usr/share/udhcpc/default.script b/board/common/rootfs/usr/share/udhcpc/default.script index 73e4c78b..1917e790 100755 --- a/board/common/rootfs/usr/share/udhcpc/default.script +++ b/board/common/rootfs/usr/share/udhcpc/default.script @@ -1,9 +1,5 @@ #!/bin/sh # This script expect a system with resolvconf (openresolv) and iproute2 -# -# For details on the distance adjustment below, please see the following -# section in the Frr documentation on distance + prefence => to metric. -# https://docs.frrouting.org/en/stable-8.0/zebra.html#administrative-distance [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1 @@ -11,13 +7,12 @@ ACTION="$1" IP_CACHE="/var/lib/misc/${interface}.cache" RESOLV_CONF="/run/resolvconf/interfaces/${interface}.conf" NTPFILE="/run/chrony/dhcp-sources.d/${interface}.sources" +NAME="/etc/frr/static.d/${interface}-dhcp.conf" +NEXT="${NAME}+" + [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" [ -n "$subnet" ] || subnet=32 -[ -n "$metric" ] || metric=100 - -# Distance adjustment to ensure that static routes set by Zebra -# can take precedence over routes learned from DHCP. -metric=$(((5 << 24) + metric)) +[ -n "$metric" ] || metric=5 # Handle stateful DHCPv6 like DHCPv4 [ -n "$ipv6" ] && ip="$ipv6/128" @@ -31,7 +26,7 @@ log() logger -I $$ -t udhcpc -p user.notice "$*" } -wwait_for_ipv6_default_route() +wait_for_ipv6_default_route() { log "waiting for IPv6 default route to be installed." while [ $IF_WAIT_DELAY -gt 0 ]; do @@ -50,28 +45,35 @@ wwait_for_ipv6_default_route() # client MUST ignore the Router option. set_dhcp_routes() { + echo "! Generated by udhcpc" > "$NEXT" if [ -n "$staticroutes" ]; then # format: dest1/mask gw1 ... destn/mask gwn set -- $staticroutes while [ -n "$1" -a -n "$2" ]; do log "adding route $1 via $2 dev $interface proto dhcp" - ip route add "$1" via "$2" dev $interface metric $metric proto dhcp + echo "ip route $1 $2 $metric tag 100" >> "$NEXT" shift 2 done elif [ -n "$router" ] ; then for i in $router ; do - ip route add default via $i dev $interface metric $((metric++)) proto dhcp + echo "ip route 0.0.0.0/0 $i $metric tag 100" >> "$NEXT" done fi + + # Reduce changes needed by comparing with previous route(s) + cmp -s "$NAME" "$NEXT" && return + mv "$NEXT" "$NAME" + + initctl -nbq restart staticd } clr_dhcp_routes() { log "deleting DHCP routes from $interface" - ip route show proto dhcp dev $interface | while read rt via nh dev dev; do - log "removing $rt nh $nh on $dev" - ip route del $rt via $nh dev $dev proto dhcp - done + [ -f "$NAME" ] || return + rm "$NAME" + + initctl -nbq restart staticd } clr_dhcp_addresses() @@ -120,7 +122,6 @@ case "$ACTION" in wait_for_ipv6_default_route fi - clr_dhcp_routes set_dhcp_routes # set hostname if given diff --git a/package/skeleton-init-finit/skeleton-init-finit.mk b/package/skeleton-init-finit/skeleton-init-finit.mk index c1339e22..30088ec0 100644 --- a/package/skeleton-init-finit/skeleton-init-finit.mk +++ b/package/skeleton-init-finit/skeleton-init-finit.mk @@ -89,6 +89,7 @@ define SKELETON_INIT_FINIT_SET_FRR for svc in babeld bfdd bgpd eigrpd isisd ldpd ospfd ospf6d pathd ripd ripng staticd vrrpd zebra; do \ cp $(SKELETON_INIT_FINIT_AVAILABLE)/frr/$$svc.conf $(FINIT_D)/available/$$svc.conf; \ done + ln -sf ../available/staticd.conf $(FINIT_D)/enabled/staticd.conf ln -sf ../available/zebra.conf $(FINIT_D)/enabled/zebra.conf endef SKELETON_INIT_FINIT_POST_INSTALL_TARGET_HOOKS += SKELETON_INIT_FINIT_SET_FRR diff --git a/package/skeleton-init-finit/skeleton/etc/finit.d/available/frr/staticd.conf b/package/skeleton-init-finit/skeleton/etc/finit.d/available/frr/staticd.conf index d6fae1ae..e3af6b5f 100644 --- a/package/skeleton-init-finit/skeleton/etc/finit.d/available/frr/staticd.conf +++ b/package/skeleton-init-finit/skeleton/etc/finit.d/available/frr/staticd.conf @@ -1 +1,4 @@ -service [2345] log:null staticd -A 127.0.0.1 -u frr -g frr -f /etc/frr/staticd.conf -- Static routing daemon +# Run staticd-helper to collate /etc/static.d/*.conf before starting staticd +service log:null pre:/usr/sbin/staticd-helper \ + [2345] staticd -A 127.0.0.1 -u frr -g frr -f /etc/frr/staticd.conf \ + -- Static routing daemon diff --git a/src/confd/src/ietf-routing.c b/src/confd/src/ietf-routing.c index de6aacfb..b3fc4dea 100644 --- a/src/confd/src/ietf-routing.c +++ b/src/confd/src/ietf-routing.c @@ -8,7 +8,7 @@ #define XPATH_BASE_ "/ietf-routing:routing/control-plane-protocols/control-plane-protocol" #define XPATH_OSPF_ XPATH_BASE_ "/ietf-ospf:ospf" -#define STATICD_CONF "/etc/frr/staticd.conf" +#define STATICD_CONF "/etc/frr/static.d/confd.conf" #define STATICD_CONF_NEXT STATICD_CONF "+" #define STATICD_CONF_PREV STATICD_CONF "-" #define OSPFD_CONF "/etc/frr/ospfd.conf" @@ -245,7 +245,7 @@ static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t su const char *xpath, sr_event_t event, unsigned request_id, void *priv) { int staticd_enabled = 0, ospfd_enabled = 0, bfdd_enabled = 0; - bool ospfd_running, staticd_running, bfdd_running; + bool ospfd_running, bfdd_running; struct lyd_node *cplane, *tmp; bool restart_zebra = false; int rc = SR_ERR_OK; @@ -260,7 +260,7 @@ static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t su ERROR("Failed to open %s", STATICD_CONF_NEXT); return SR_ERR_INTERNAL; } - fputs(FRR_STATIC_CONFIG, fp); + fputs("! Generated by Infix confd\n", fp); break; case SR_EV_ABORT: /* User abort, or other plugin failed */ @@ -272,18 +272,8 @@ static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t su staticd_enabled = fexist(STATICD_CONF_NEXT); ospfd_enabled = fexist(OSPFD_CONF_NEXT); bfdd_enabled = fexist(BFDD_CONF_NEXT); - staticd_running = !systemf("initctl -bfq status staticd"); ospfd_running = !systemf("initctl -bfq status ospfd"); bfdd_running = !systemf("initctl -bfq status bfdd"); - if (staticd_running && !staticd_enabled) { - if (systemf("initctl -bfq disable staticd")) { - ERROR("Failed to disable static routing daemon"); - rc = SR_ERR_INTERNAL; - goto err_abandon; - } - /* Remove all generated files */ - (void)remove(STATICD_CONF); - } if (bfdd_running && !bfdd_enabled) { if (systemf("initctl -bfq disable bfdd")) { @@ -337,15 +327,10 @@ static int change_control_plane_protocols(sr_session_ctx_t *session, uint32_t su (void)remove(STATICD_CONF_PREV); (void)rename(STATICD_CONF, STATICD_CONF_PREV); (void)rename(STATICD_CONF_NEXT, STATICD_CONF); - if (!staticd_running) { - if (systemf("initctl -bfq enable staticd")) { - ERROR("Failed to enable static routing daemon"); - rc = SR_ERR_INTERNAL; - goto err_abandon; - } - } else { + restart_zebra = true; + } else { + if (!remove(STATICD_CONF)) restart_zebra = true; - } } if (restart_zebra) {