From 0bcad8a5c6e1763545cc2c029dad6841e0627917 Mon Sep 17 00:00:00 2001 From: Alex Denes Date: Wed, 4 Sep 2024 12:22:10 +0000 Subject: [PATCH] Switch to golang version --- .gitignore | 1 + LICENSE.md | 7 + NOTES.md | 4 - README.md | 3 + bundle.go | 30 ++ configuration.go | 297 +++++++++++++ execline.go | 41 ++ generic.sh | 25 -- go.mod | 3 + hosts/dongguan.china.sh | 27 -- hosts/izmaylovo.russia.sh | 42 -- hosts/lakewood.united-states.sh | 151 ------- hosts/magong.taiwan.sh | 32 -- hosts/mika.frankfurt.vultr.sh | 65 --- hosts/san-jorge.argentina.sh | 22 - hosts/tarui.japan.sh | 39 -- hosts/thetford-mines.canada.sh | 113 ----- interfaces.go | 137 ++++++ netdev.go | 55 +++ netdev.sh | 719 -------------------------------- nnd.go | 9 + s6.go | 204 +++++++++ services.go | 13 + types.go | 68 +++ 24 files changed, 868 insertions(+), 1239 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE.md delete mode 100644 NOTES.md create mode 100644 README.md create mode 100644 bundle.go create mode 100644 configuration.go create mode 100644 execline.go delete mode 100755 generic.sh create mode 100644 go.mod delete mode 100755 hosts/dongguan.china.sh delete mode 100755 hosts/izmaylovo.russia.sh delete mode 100755 hosts/lakewood.united-states.sh delete mode 100755 hosts/magong.taiwan.sh delete mode 100755 hosts/mika.frankfurt.vultr.sh delete mode 100755 hosts/san-jorge.argentina.sh delete mode 100755 hosts/tarui.japan.sh delete mode 100755 hosts/thetford-mines.canada.sh create mode 100644 interfaces.go create mode 100644 netdev.go delete mode 100755 netdev.sh create mode 100644 nnd.go create mode 100644 s6.go create mode 100644 services.go create mode 100644 types.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0375e81 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +hosts/ diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..ea06888 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,7 @@ +Copyright 2024 Alex Denes + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/NOTES.md b/NOTES.md deleted file mode 100644 index 756b4ef..0000000 --- a/NOTES.md +++ /dev/null @@ -1,4 +0,0 @@ -# KNOWN BUGS - -- Currently the static address adds don't check if interface is a wireguard interface - - wg tool doesn't lock the interface when it loads the config and the static address gets swallowed away without any error message diff --git a/README.md b/README.md new file mode 100644 index 0000000..4996a16 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# s6-netdev + +This is a project which can generate s6 service definitions based on a structured definition. It's intended to be used together with nnd but can be adapted to be used with any other distribution based on s6. diff --git a/bundle.go b/bundle.go new file mode 100644 index 0000000..74eb25c --- /dev/null +++ b/bundle.go @@ -0,0 +1,30 @@ +package s6netdev + +import ( + "fmt" +) + +func (t *S6SvcTree) netdevCreateBundleAll(ifsvc *S6Svc) *S6Svc { + bundle_name := S6SvcName("bundle.s6netdev") + b := t.S6New(bundle_name, &S6SvcTypes.Bundle) + b.S6Children(ifsvc) + return b +} + +func (t *S6SvcTree) netdevCreateBundleStage(iface, stage string) *S6Svc { + bundle_name := S6SvcName(fmt.Sprintf("bundle.interface.%s", iface)) + stage_name := S6SvcName(fmt.Sprintf("%s.%s", bundle_name, stage)) + + b := t.S6New(bundle_name, &S6SvcTypes.Bundle) + t.netdevCreateBundleAll(b) + + s := t.S6New(stage_name, &S6SvcTypes.Bundle) + b.S6Children(s) + return s +} + +func (t *S6SvcTree) NetdevDependBundleStage(iface, stage string, svcs ...*S6Svc) *S6Svc { + b := t.netdevCreateBundleStage(iface, stage) + b.S6Children(svcs...) + return b +} diff --git a/configuration.go b/configuration.go new file mode 100644 index 0000000..f3cd7bd --- /dev/null +++ b/configuration.go @@ -0,0 +1,297 @@ +package s6netdev + +import ( + "fmt" + "net" + "strings" +) + +func (t *S6SvcTree) NetdevIfaceCreate(iface Iface, iftype *NetdevIfType) *S6Svc { + l := t.CreateIfaceService(iface.Name) + + // Defaults to be overridden + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + fmt.Sprintf("ip link add $INTERFACE type %s", iface.Type.str), + }, "\n") + l.Down = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + "ip link del dev $INTERFACE", + }, "\n") + + for _, v := range iftype.deps { + // External dummy services, should be ignored at commit + cs := t.S6New(S6SvcName(v), &S6SvcTypes.Oneshot) + l.S6Children(cs) + } + + // Overrides + switch iftype { + case &NetdevIfTypes.Phys: + { + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + "bcnm-waitif 1 $INTERFACE", + }, "\n") + l.Down = "" + } + case &NetdevIfTypes.Vlan: + { + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + ExeclineDefine("PARENT", iface.Parent.Name), + ExeclineDefine("VLAN", fmt.Sprintf("%d", iface.VlanId)), + fmt.Sprintf("ip link add link $PARENT name $INTERFACE type %s id $VLAN", iface.Type.str), + }, "\n") + l.S6Children(t.CreateIfaceService(iface.Parent.Name)) + } + case &NetdevIfTypes.Vrf: + { + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + ExeclineDefine("TABLE", fmt.Sprintf("%d", iface.Table)), + fmt.Sprintf("ip link add $INTERFACE type %s table $TABLE", iface.Type.str), + }, "\n") + } + } + + return l +} + +func (t *S6SvcTree) NetdevIfaceIpSysctl(iface Iface, ipv int, p Property) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("sysctl.net-ipv%d-conf-%s-%s", ipv, iface.Name, p.Key)).Sanitize() + sysctl_path := fmt.Sprintf("net/ipv%d/conf/%s/%s", ipv, iface.Name, p.Key) + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + l.S6Children(t.S6New("mount.proc", &S6SvcTypes.Oneshot)) + if ipv == 6 { + l.S6Children(t.S6New("module.ipv6", &S6SvcTypes.Oneshot)) + } + + for _, v := range []struct { + prop *string + val string + }{ + {&l.Up, p.Value}, + {&l.Down, p.Default}, + } { + *v.prop = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineXDGConfig(), + ExeclineXDGEnvdirConfig(l.Name), + ExeclineExport("SYSCTL", sysctl_path), + // Set default if not exported + ExeclineImportas("VAL", false, v.val), + ExeclineExport("VAL", "$VAL"), + NNDLibExec("sysctl"), + }, "\n") + } + + l.S6Children(t.CreateIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "configure", l) + + return l +} + +func (t *S6SvcTree) NetdevIfaceProp(iface Iface, p Property) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("interface.%s.property.%s", iface.Name, p.Key)).Sanitize() + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + + for _, v := range []struct { + prop *string + val string + }{ + {&l.Up, p.Value}, + {&l.Down, p.Default}, + } { + *v.prop = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineXDGConfig(), + ExeclineXDGEnvdirConfig(l.Name), + ExeclineDefine("INTERFACE", iface.Name), + ExeclineDefine("PROP", p.Key), + ExeclineImportas("TYPE", false, iface.Type.str), + ExeclineImportas("VAL", false, v.val), + "ip link set dev $INTERFACE type $TYPE $PROP $VAL", + }, "\n") + } + + l.S6Children(t.CreateIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "configure", l) + + return l +} + +func (t *S6SvcTree) ConfigureIfaceAddr(iface Iface, addr string) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("interface.%s.ether.addr", iface.Name)).Sanitize() + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineXDGConfig(), + ExeclineXDGEnvdirConfig(l.Name), + ExeclineDefine("INTERFACE", iface.Name), + ExeclineImportas("ADDRESS", false, addr), + "ip link set $INTERFACE address $ADDRESS", + }, "\n") + + l.S6Children(t.CreateIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "configure", l) + + return l +} + +func (t *S6SvcTree) NetdevWireguardConfig(iface Iface) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("interface.%s.wg.config", iface.Name)).Sanitize() + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineXDGConfig(), + ExeclineXDGEnvdirConfig(l.Name), + ExeclineDefine("INTERFACE", iface.Name), + ExeclineImportas("CONFIG", false, "/etc/wireguard/${INTERFACE}"), + "wg setconf $INTERFACE $CONFIG", + }, "\n") + + l.S6Children(t.CreateIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "configure", l) + + return l +} + +func (t *S6SvcTree) NetdevIfaceDHCP(iface Iface, ipv int) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("interface.%s.dhcp", iface.Name)).Sanitize() + + l := t.S6New(svc_name, &S6SvcTypes.Longrun) + + var daemon = "udhcpc" + if ipv == 6 { + daemon = fmt.Sprintf("%s%d", daemon, ipv) + } + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface.Name), + "fdmove -c 2 1", + fmt.Sprintf("%s -i $INTERFACE -f -S", daemon), + }, "\n") + l.ProducerFor = t.S6New("logger.udhcpc", &S6SvcTypes.Longrun) + + l.S6Children(t.LinkIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "ready", l) + + return l +} + +func (t *S6SvcTree) netdevIfaceAddrTemplate(action, iface string, ipv int, addr net.IP) string { + return strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface), + ExeclineDefine("ADDRESS", addr.String()), + ExeclineDefine("FAMILY", fmt.Sprintf("%d", ipv)), + fmt.Sprintf("ip -${FAMILY} address %s $ADDRESS dev $INTERFACE", action), + }, "\n") +} + +func (t *S6SvcTree) NetdevIfaceAddr(iface Iface, addr net.IP) *S6Svc { + ipv := NetdevIPAddrVer(addr) + svc_name := S6SvcName(fmt.Sprintf("interface.%s.ip.addr.%d.%s", iface.Name, ipv, addr)).Sanitize() + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + + l.Up = t.netdevIfaceAddrTemplate("add", iface.Name, ipv, addr) + l.Down = t.netdevIfaceAddrTemplate("del", iface.Name, ipv, addr) + + l.S6Children(t.LinkIfaceService(iface.Name)) + t.NetdevDependBundleStage(iface.Name, "ready", l) + + return l +} + +func (t *S6SvcTree) netdevRouteTemplate(iface Iface, route Route) (up, down string, name S6SvcName) { + var ( + lines []string + svcname = []string{"interface", iface.Name, "route"} + + cmd = []string{ + "ip", + fmt.Sprintf("-%d", NetdevIPAddrVer(route.Net.IP)), // IP version + "route", + "%s", + } + header = []string{ + NETDEV_EXECLINE_HEADER, + ExeclineXDGConfig(), + } + ) + + if route.Type != "" { + lines = append(lines, ExeclineDefine("TYPE", route.Type)) + cmd = append(cmd, "$TYPE") + svcname = append(svcname, route.Type) + } + + var r = "default" + if !route.Default { + r = route.Net.String() + } + lines = append(lines, ExeclineDefine("ROUTE", r)) + cmd = append(cmd, "$ROUTE") + svcname = append(svcname, r) + + if route.Via != nil { + lines = append(lines, ExeclineImportas("VIA", false, route.Via.String())) + cmd = append(cmd, "via", "$VIA") + } + + lines = append(lines, ExeclineDefine("DEV", iface.Name)) + cmd = append(cmd, "dev", "$DEV") + + if route.Metric != 0 { + lines = append(lines, ExeclineImportas("METRIC", false, fmt.Sprintf("%d", route.Metric))) + cmd = append(cmd, "metric", "$METRIC") + } + + if route.Vrf != nil && route.Vrf.Type == &NetdevIfTypes.Vrf { + // Parent is VRF + lines = append(lines, ExeclineImportas("VRF", false, route.Vrf.Name)) + cmd = append(cmd, "vrf", "$VRF") + } + + name = S6SvcName(strings.Join(svcname, ".")) + // Merge + header = append(header, ExeclineXDGEnvdirConfig(name)) + + lines = append(lines, strings.Join(cmd, " ")) + full := append(header, lines...) + + up = fmt.Sprintf(strings.Join(full, "\n"), "add") + down = fmt.Sprintf(strings.Join(full, "\n"), "del") + + return +} + +func (t *S6SvcTree) NetdevRoute(iface Iface, route Route) *S6Svc { + up, down, name := t.netdevRouteTemplate(iface, route) + + l := t.S6New(name.Sanitize(), &S6SvcTypes.Oneshot) + + l.Up = up + l.Down = down + + l.S6Children(t.LinkIfaceService(iface.Name)) + if route.Vrf != nil { + l.S6Children(t.LinkIfaceService(route.Vrf.Name)) + } + t.NetdevDependBundleStage(iface.Name, "ready", l) + + return l +} diff --git a/execline.go b/execline.go new file mode 100644 index 0000000..7d11856 --- /dev/null +++ b/execline.go @@ -0,0 +1,41 @@ +package s6netdev + +import ( + "fmt" + "strings" +) + +const ( + NETDEV_EXECLINE_HEADER = "#!/bin/execlineb -P" +) + +func ExeclineDefine(param, value string) string { + return fmt.Sprintf("define %s %s", param, value) +} + +func ExeclineExport(param, value string) string { + return fmt.Sprintf("export %s %s", param, value) +} + +func ExeclineXDGEnvdirConfig(name S6SvcName) string { + return fmt.Sprintf("s6-envdir -I ${XDG_CONFIG_HOME}/env/%s", name.Sanitize()) +} + +func ExeclineImportas(name string, strict bool, def string) string { + var s = []string{ + "importas", + } + if strict { + s = append(s, "-i") + } + if def != "" { + s = append(s, "-D", def) + } + // Always assume we import to same name + s = append(s, name, name) + return strings.Join(s, " ") +} + +func ExeclineXDGConfig() string { + return ExeclineImportas("XDG_CONFIG_HOME", true, "") +} diff --git a/generic.sh b/generic.sh deleted file mode 100755 index 7a17efb..0000000 --- a/generic.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/netdev.sh" - -# Handle loopback specially -# - addresses are assigned automatically when brought up -# - interface is created automatically by the kernel -IFACE="lo" -new_if_phys "$IFACE" - #if_ip_addr "$IFACE" '127.0.0.1/8' - #if_ip_addr "$IFACE" '::1/128' - - -BRIDGE="br0" -new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - if_dhcpv6 "$BRIDGE" - - IFACE="eth0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..54cc1b2 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.redxen.eu/caskd/s6-netdev + +go 1.22.5 diff --git a/hosts/dongguan.china.sh b/hosts/dongguan.china.sh deleted file mode 100755 index 999ddaa..0000000 --- a/hosts/dongguan.china.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -BRIDGE="br-main" -new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - - IFACE="enp1s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - -BRIDGE="br-home" -new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - if_accept_ra "$BRIDGE" '0' # Disable IPv6 on home net, only ipv4 - - IFACE="enp11s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" diff --git a/hosts/izmaylovo.russia.sh b/hosts/izmaylovo.russia.sh deleted file mode 100755 index 46d95c7..0000000 --- a/hosts/izmaylovo.russia.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -IFACE="home-66" -new_if_vlan "$IFACE" - -VRF="vrf-home" -new_if_vrf "$VRF" 20 - if_route_vrf_default_unreach "$VRF" - - BRIDGE="home" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'priority' "$BRIDGE" '16384' '32768' - if_bridge_property 'stp_state' "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - - IFACE="enp2s0f0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - IFACE="enp8s0f0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - IFACE="enp4s0f0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - IFACE="enp4s0f1" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - -# Wireguard -IFACE="wg-tunnel" -new_if_wg "$IFACE" - if_ip_addr "$IFACE" "172.22.12.7/32" - if_ip_addr "$IFACE" "fd42:42:42::2:7/128" - if_route_addr "$IFACE" "172.22.12.0/24" - if_route_addr "$IFACE" "fd42:42:42::2:0/120" diff --git a/hosts/lakewood.united-states.sh b/hosts/lakewood.united-states.sh deleted file mode 100755 index 1cc128a..0000000 --- a/hosts/lakewood.united-states.sh +++ /dev/null @@ -1,151 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -# VRFs -VRF="vrf-dn42" -new_if_vrf "$VRF" 20 - if_route_vrf_default_unreach "$VRF" - - BRIDGE="br-dn42" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - - IFACE="home-42" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - IFACE="enp2s0" - if_slave "$VRF" "$IFACE" - new_if_phys "$IFACE" - - - IFACE="famfo" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::1422:1/64" - - IFACE="mark22k" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::4546/64" - - IFACE="highdef" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - - IFACE="kioubit" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - - IFACE="lare" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - - IFACE="haktron" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - -VRF="vrf-v6" -new_if_vrf "$VRF" 10 - if_route_vrf_sink_unreach "$VRF" "2a04:5b81:2060::/44" - - IFACE="intersix" - #if_route_vrf_default_interface "$VRF" "$IFACE" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - if_ip_addr "$IFACE" "2a04:5b80:ffff:ff0b::2/64" - - IFACE="vultrbgp" - if_route_vrf_default_interface "$VRF" "$IFACE" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - - BRIDGE="b00b" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_stats_enabled' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:00:b0:0b' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:b00b::1/64" - - IFACE="enp16s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="home-66" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - BRIDGE="f33d" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:00:f3:3d' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:f33d::1/64" - - IFACE="enp17s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="home-100" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - BRIDGE="d00d" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:00:d0:0d' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:d00d::1/64" - - IFACE="enp18s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="home-101" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - -# NO-vrf -BRIDGE="home" -new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - if_forward "$BRIDGE" - - IFACE="enp13s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" diff --git a/hosts/magong.taiwan.sh b/hosts/magong.taiwan.sh deleted file mode 100755 index ab85ad6..0000000 --- a/hosts/magong.taiwan.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -VRF="vrf-v6" -new_if_vrf "$VRF" 20 - if_route_vrf_default_unreach "$VRF" - - BRIDGE="br-v6" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - - IFACE="enp1s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - -BRIDGE="br-home" -new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - - IFACE="enp9s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" diff --git a/hosts/mika.frankfurt.vultr.sh b/hosts/mika.frankfurt.vultr.sh deleted file mode 100755 index bf1becb..0000000 --- a/hosts/mika.frankfurt.vultr.sh +++ /dev/null @@ -1,65 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -# VRFs -VRF="vrf-wgate" -new_if_vrf "$VRF" 20 - if_route_vrf_sink_unreach "$VRF" "2a04:5b81:2060::/44" - if_route_vrf_sink_unreach "$VRF" "2a04:5b81:2010::/44" - if_route_vrf_default_unreach "$VRF" - - # Bridges - IFACE="br-uplink" - if_slave "$VRF" "$IFACE" - new_if_bridge "$IFACE" - if_bridge_property 'stp_state' "$IFACE" - if_bridge_property 'forward_delay' "$IFACE" '400' # 4 seconds, 8 seconds total (listen>learn) - if_bridge_property 'hello_time' "$IFACE" '100' # every 1 second - if_bridge_property 'mcast_router' "$IFACE" - if_bridge_property 'mcast_snooping' "$IFACE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$IFACE" - if_bridge_property 'mcast_mld_version' "$IFACE" '2' '' - if_forward "$IFACE" - if_accept_ra "$IFACE" - if_dhcp "$IFACE" - - if_slave "$IFACE" "enp1s0" - new_if_phys "enp1s0" - - - # Wireguard - IFACE="tristan" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_forward "$IFACE" - if_ip_addr "$IFACE" "fe80::1/64" - if_route_vrf_addr "$VRF" "$IFACE" "2a04:5b81:2010::/48" - - IFACE="tristan-travel" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_forward "$IFACE" - if_ip_addr "$IFACE" "fe80::1/64" - if_route_vrf_addr "$VRF" "$IFACE" "2a04:5b81:201f::/48" - - IFACE="gustav" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_forward "$IFACE" - if_ip_addr "$IFACE" "fe80::1/64" - if_route_vrf_addr "$VRF" "$IFACE" "2a04:5b81:2011::/48" - - IFACE="caskd-lakewood" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_forward "$IFACE" - if_ip_addr "$IFACE" "fe80::1/64" - if_route_vrf_addr "$VRF" "$IFACE" "2a04:5b81:2060::/48" - - IFACE="caskd-thetford" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_forward "$IFACE" - if_ip_addr "$IFACE" "fe80::1/64" - if_route_vrf_addr "$VRF" "$IFACE" "2a04:5b81:2060::/48" diff --git a/hosts/san-jorge.argentina.sh b/hosts/san-jorge.argentina.sh deleted file mode 100755 index 7b045fc..0000000 --- a/hosts/san-jorge.argentina.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -BRIDGE="br-v6" -new_if_bridge "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - - IFACE="enp1s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - -IFACE="wg-tunnel" -new_if_wg "$IFACE" - if_ip_addr "$IFACE" "172.22.12.8/32" - if_ip_addr "$IFACE" "fd42:42:42::2:8/128" - if_route_addr "$IFACE" "172.22.12.0/24" - if_route_addr "$IFACE" "fd42:42:42::2:0/120" diff --git a/hosts/tarui.japan.sh b/hosts/tarui.japan.sh deleted file mode 100755 index d446283..0000000 --- a/hosts/tarui.japan.sh +++ /dev/null @@ -1,39 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -IFACE="home-66" -new_if_vlan "$IFACE" - -VRF="vrf-home" -new_if_vrf "$VRF" 20 - if_route_vrf_default_unreach "$VRF" - - BRIDGE="home" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'priority' "$BRIDGE" '16384' '32768' - if_bridge_property 'stp_state' "$BRIDGE" - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - - IFACE="eno1" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - IFACE="enp129s0f0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - IFACE="enp129s0f1" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - -# Wireguard -IFACE="wg-tunnel" -new_if_wg "$IFACE" - if_ip_addr "$IFACE" "172.22.12.5/32" - if_ip_addr "$IFACE" "fd42:42:42::2:5/128" - if_route_addr "$IFACE" "172.22.12.0/24" - if_route_addr "$IFACE" "fd42:42:42::2:0/120" diff --git a/hosts/thetford-mines.canada.sh b/hosts/thetford-mines.canada.sh deleted file mode 100755 index 6b66bb3..0000000 --- a/hosts/thetford-mines.canada.sh +++ /dev/null @@ -1,113 +0,0 @@ -#!/bin/sh - -. "$(dirname -- "$0")/../netdev.sh" - -VRF="vrf-dn42" -new_if_vrf "$VRF" 20 - if_route_vrf_default_unreach "$VRF" - - BRIDGE="br-dn42" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - - IFACE="enp15s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="phys-42" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - -VRF="vrf-v6" -new_if_vrf "$VRF" 10 - #if_route_vrf_sink_unreach "$VRF" "2a04:5b81:2060::/44" - - IFACE="vultrbgp" - #if_route_vrf_default_interface "$VRF" "$IFACE" - if_slave "$VRF" "$IFACE" - new_if_wg "$IFACE" - if_ip_addr "$IFACE" "fe80::2/64" - - BRIDGE="b00b" - if_slave "$VRF" "$BRIDGE" - if_sysctl "$BRIDGE" 'forwarding' '0' - if_sysctl "$BRIDGE" 'autoconf' '0' - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_stats_enabled' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:01:b0:0b' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:b00b::2/64" - - IFACE="enp9s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="phys-66" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - BRIDGE="f33d" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:01:f3:3d' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:f33d::2/64" - - IFACE="enp14s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="phys-100" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - - BRIDGE="d00d" - if_slave "$VRF" "$BRIDGE" - new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" '0' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_ether_address "$BRIDGE" '02:00:00:01:d0:0d' - if_ip_addr "$BRIDGE" "2a04:5b81:2060:d00d::2/64" - - IFACE="enp13s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" - - IFACE="phys-101" - if_linkdepend "$IFACE" "${IFACE%-*}" - if_slave "$BRIDGE" "$IFACE" - new_if_vlan "$IFACE" - -BRIDGE="phys" -new_if_bridge "$BRIDGE" - if_bridge_property 'stp_state' "$BRIDGE" - if_ether_address "$BRIDGE" '52:54:00:81:cb:62' - if_bridge_property 'mcast_router' "$BRIDGE" - if_bridge_property 'mcast_snooping' "$BRIDGE" '0' '' # TODO: Remove such entries when bridges play well with multicasting - if_bridge_property 'mcast_querier' "$BRIDGE" - if_bridge_property 'mcast_mld_version' "$BRIDGE" '2' '' - if_dhcp "$BRIDGE" - if_forward "$BRIDGE" - - IFACE="enp12s0" - if_slave "$BRIDGE" "$IFACE" - new_if_phys "$IFACE" diff --git a/interfaces.go b/interfaces.go new file mode 100644 index 0000000..505f593 --- /dev/null +++ b/interfaces.go @@ -0,0 +1,137 @@ +package s6netdev + +import ( + "fmt" + "strings" +) + +func (t *S6SvcTree) Services(i Iface) (r []*S6Svc) { + r = append(r, t.ConfigureServices(i)...) + r = append(r, t.ReadyServices(i)...) + return +} + +func (t *S6SvcTree) ConfigureServices(i Iface) (r []*S6Svc) { + svc_create := t.CreateIfaceService(i.Name) + r = append(r, svc_create) + + // Defaults to be overridden + svc_create.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + fmt.Sprintf("ip link add $INTERFACE type %s", i.Type.str), + }, "\n") + svc_create.Down = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + "ip link del dev $INTERFACE", + }, "\n") + + for _, v := range i.Type.deps { + // External dummy services, should be ignored at commit + cs := t.S6New(S6SvcName(v), &S6SvcTypes.Oneshot) + svc_create.S6Children(cs) + } + + // Overrides + switch i.Type { + case &NetdevIfTypes.Phys: + fallthrough + case &NetdevIfTypes.Loopback: + { + svc_create.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + "bcnm-waitif 1 $INTERFACE", + }, "\n") + svc_create.Down = "" + } + case &NetdevIfTypes.Vlan: + { + svc_create.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + ExeclineDefine("PARENT", i.Parent.Name), + ExeclineDefine("VLAN", fmt.Sprintf("%d", i.VlanId)), + fmt.Sprintf("ip link add link $PARENT name $INTERFACE type %s id $VLAN", i.Type.str), + }, "\n") + svc_create.S6Children(t.CreateIfaceService(i.Parent.Name)) + } + case &NetdevIfTypes.Vrf: + { + // Default if no table defined + if i.Table == 0 { + i.Table = RouteTable(500) + } + svc_create.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + ExeclineDefine("TABLE", fmt.Sprintf("%d", i.Table)), + fmt.Sprintf("ip link add $INTERFACE type %s table $TABLE", i.Type.str), + }, "\n") + } + case &NetdevIfTypes.Wireguard: + { + wg_cfg := t.NetdevWireguardConfig(i) + svc_create.S6Children(wg_cfg) + r = append(r, wg_cfg) + } + } + + for _, v := range i.Slaves { + r = append(r, t.NetdevEnslaveInterface(v.Name, i.Name)) + } + + for _, v := range i.Properties { + r = append(r, t.NetdevIfaceProp(i, v)) + } + + if i.DHCP.V4 { + r = append(r, t.NetdevIfaceDHCP(i, 4)) + } + if i.DHCP.V6 { + r = append(r, t.NetdevIfaceDHCP(i, 6)) + } + + for _, v := range i.Sysctls.V4 { + r = append(r, t.NetdevIfaceIpSysctl(i, 4, v)) + } + for _, v := range i.Sysctls.V6 { + r = append(r, t.NetdevIfaceIpSysctl(i, 6, v)) + } + + for _, v := range i.Addresses { + r = append(r, t.NetdevIfaceAddr(i, v)) + } + for _, v := range i.Routes { + r = append(r, t.NetdevRoute(i, v)) + } + + bundle_configure := t.NetdevDependBundleStage(i.Name, "configure", svc_create) + r = append(r, bundle_configure) + r = append(r, svc_create.Children...) + + return +} + +func (t *S6SvcTree) ReadyServices(i Iface) (r []*S6Svc) { + svc_link := t.S6New(S6SvcName(fmt.Sprintf("interface.%s.link", i.Name)), &S6SvcTypes.Oneshot) + r = append(r, svc_link) + + svc_link.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + "ip link set dev $INTERFACE up", + }, "\n") + svc_link.Down = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", i.Name), + "ip link set dev $INTERFACE down", + }, "\n") + svc_link.S6Children(t.CreateIfaceService(i.Name)) + + bundle_ready := t.NetdevDependBundleStage(i.Name, "ready", svc_link) + r = append(r, bundle_ready) + + return +} diff --git a/netdev.go b/netdev.go new file mode 100644 index 0000000..4b49368 --- /dev/null +++ b/netdev.go @@ -0,0 +1,55 @@ +package s6netdev + +import ( + "fmt" + "net" + "strings" +) + +var ( + dummy_svc_blacklist = map[S6SvcName]interface{}{ + "bundle.hw-coldplug": nil, + "module.8021q": nil, + "module.bonding": nil, + "module.bridge": nil, + "module.vrf": nil, + "module.ipv6": nil, + "module.wireguard": nil, + "mount.proc": nil, + "logger.udhcpc": nil, + } +) + +func (t *S6SvcTree) NetdevEnslaveInterface(iface, master string) *S6Svc { + svc_name := S6SvcName(fmt.Sprintf("interface.%s.master.%s", iface, master)) + + l := t.S6New(svc_name, &S6SvcTypes.Oneshot) + l.Up = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface), + ExeclineDefine("MASTER", master), + "ip link set dev $INTERFACE master $MASTER", + }, "\n") + l.Down = strings.Join([]string{ + NETDEV_EXECLINE_HEADER, + ExeclineDefine("INTERFACE", iface), + "ip link set dev $INTERFACE nomaster", + }, "\n") + + l.S6Children(t.CreateIfaceService(iface), t.CreateIfaceService(master)) + t.NetdevDependBundleStage(iface, "configure", l) + + return l +} + +func NetdevIPAddrVer(IP net.IP) int { + if IP.To4() == nil { + return 6 + } + return 4 +} + +func NetdevIsDummy(s S6SvcName) (r bool) { + _, r = dummy_svc_blacklist[s] + return +} diff --git a/netdev.sh b/netdev.sh deleted file mode 100755 index 7a44993..0000000 --- a/netdev.sh +++ /dev/null @@ -1,719 +0,0 @@ -#!/bin/sh -# -# Generate s6 network definitions - -set -ex - -header_eb() { - echo '#!/bin/execlineb -P' -} - -header_if() { - local if="${1:?missing if}" - echo "define INTERFACE $if" -} - -header_addr() { - local addr="${1:?missing addr}" - echo "define ADDR $addr" -} - -header_fam() { - local fam="${1:?missing family}" - echo "define FAMILY $fam" -} - -header_vlan() { - local vlan="${1:?missing vlan}" - local parent="${2:?missing parent}" - echo "define VLAN $vlan" - echo "define PARENT $parent" -} - -header_vrf() { - local vrf="${1:?missing vrf}" - echo "define VRF $vrf" -} - -header_prop() { - local prop="${1:?missing prop}" - echo "define PROP $prop" -} - -addrfam() { - # Use ipv6 if cannot autodetect of if no semicolons are present - local addr="$1" - local fam='6' - if which grep >/dev/null 2>&1 && echo "$addr" | grep -v ':' >/dev/null 2>&1; then - fam='4' - fi - echo "$fam" -} - -linkdel() { - local if="${1:?missing if}" - header_eb - header_if "$if" - echo 'ip link del $INTERFACE' -} - -depends() { - echo "$@" - local svcname="${1:?missing sname}" - - shift 1 - local sname # God i fucking hate global contexts by default - for sname in $@; do - install -Dm644 /dev/null rc/"$svcname"/dependencies.d/"$sname" - done -} - -contains() { - local svcname="${1:?missing sname}" - - shift 1 - local sname # God i fucking hate global contexts by default - for sname in $@; do - install -Dm644 /dev/null rc/"$svcname"/contents.d/"$sname" - done -} - -# -# Bundle management -# - -bundle_deps() { - local if="${1:?missing if}" - - local svcname="bundle.interface.$if" - [ -r "rc/$svcname/type" ] || install -Dm644 <(echo bundle) rc/"$svcname"/type - - shift 1 - contains "$svcname" $@ -} - -# Currently used stages -# > configure -# - create -# - enslave -# - configure (anything that must be configured before interface is up) -# > ready -# - link -# - configure (anything that may be configured after interface is up) -bundle_stage_create() { - local if="${1:?missing if}" - local stage="${2:?missing stage}" - - local svcname="bundle.interface.$if.$stage" - [ -r "rc/$svcname/type" ] || install -Dm644 <(echo bundle) rc/"$svcname"/type - - # Add to parent bundle - bundle_deps "$if" "$svcname" - - shift 2 - contains "$svcname" $@ -} - -bundle_stage_depend_on() { - local if="${1:?missing if}" - local stage="${2:?missing stage}" - - local svcname="bundle.interface.$if.$stage" - - shift 2 - local sname - for sname in $@; do - depends "$sname" "$svcname" - done -} - -bundle_stage_step_configure() { - local if="$1" - local stage="configure" - - shift 1 - bundle_stage_create "$if" "$stage" $@ -} - -bundle_stage_step_ready() { - local if="$1" - local stage="ready" - - shift 1 - bundle_stage_create "$if" "$stage" $@ -} - -# -# Interface creation -# - -new_link() { - local if="${1:?missing if}" - shift 1 - - local sname="interface.$if.link" - bundle_stage_step_ready "$if" "$sname" - - install -Dm644 <( - header_eb - header_if "$if" - echo 'ip link set dev $INTERFACE up' - ) rc/"$sname"/up - install -Dm644 <( - header_eb - header_if "$if" - echo 'ip link set dev $INTERFACE down' - ) rc/"$sname"/down - install -Dm644 <(echo oneshot) rc/"$sname"/type - - bundle_stage_depend_on "$if" "configure" "$sname" -} - -new_if_bridge() { - local if="${1:?missing if}" - - local sname="interface.$if.create" - bundle_stage_step_configure "$if" "$sname" - new_link "$if" - - install -Dm644 <( - header_eb - header_if "$if" - echo 'ip link add $INTERFACE type bridge' - ) rc/"$sname"/up - install -Dm644 <(linkdel "$if") rc/"$sname"/down - install -Dm644 <(echo oneshot) rc/"$sname"/type - - depends "$sname" module.bridge -} - -new_if_phys() { - local if="${1:?missing if}" - - local sname="interface.$if.create" - bundle_stage_step_configure "$if" "$sname" - new_link "$if" - - install -Dm644 <( - header_eb - header_if "$if" - echo 'bcnm-waitif 1 $INTERFACE' - ) rc/"$sname"/up - install -Dm644 <(echo oneshot) rc/"$sname"/type - - depends "$sname" bundle.hw-coldplug -} - -new_if_lo() { - local if="${1:?missing if}" - - local sname="interface.$if.create" - bundle_stage_step_configure "$if" "$sname" - new_link "$if" - - install -Dm644 <( - header_eb - header_if "$if" - echo 'ip link add $INTERFACE type loopback' - ) rc/"$sname"/up - install -Dm644 <(linkdel "$if") rc/"$sname"/down - install -Dm644 <(echo oneshot) rc/"$sname"/type -} - -new_if_wg() { - local if="${1:?missing if}" - - # Main service for creating interface - local sname="interface.$if.create" - bundle_stage_step_configure "$if" "$sname" - - install -Dm644 <( - header_eb - header_if "$if" - echo 'ip link add $INTERFACE type wireguard' - ) rc/"$sname"/up - install -Dm644 <(linkdel "$if") rc/"$sname"/down - install -Dm644 <(echo oneshot) rc/"$sname"/type - - depends "$sname" module.wireguard - - new_link "$if" - # Secondary service for loading config - if_wg_conf "$if" -} - -new_if_vrf() { - local if="${1:?missing if}" - local table="${2:?missing table}" - - local sname="interface.$if.create" - bundle_stage_step_configure "$if" "$sname" - - install -Dm644 <( - header_eb - header_if "$if" - cat <