Separate repositories
This commit is contained in:
parent
67a3c648ce
commit
a7e5c7629a
1
.gitignore
vendored
1
.gitignore
vendored
@ -0,0 +1 @@
|
||||
workstation/
|
@ -1,7 +0,0 @@
|
||||
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.
|
@ -1,3 +0,0 @@
|
||||
# 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.
|
30
bundle.go
30
bundle.go
@ -1,30 +0,0 @@
|
||||
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
|
||||
}
|
314
configuration.go
314
configuration.go
@ -1,314 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"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) NetdevConfigureIfaceMAC(iface Iface, addr net.HardwareAddr) *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.String()),
|
||||
"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.Run = 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 netip.Prefix) 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 netip.Prefix) *S6Svc {
|
||||
ipv := NetdevIPAddrVer(addr.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, "ip.route"}
|
||||
ipv = route.IPver
|
||||
|
||||
header = []string{
|
||||
NETDEV_EXECLINE_HEADER,
|
||||
ExeclineXDGConfig(),
|
||||
}
|
||||
)
|
||||
for _, v := range []netip.Addr{route.Net.Addr(), route.Via} {
|
||||
if ipv != 0 {
|
||||
break
|
||||
}
|
||||
if v.IsValid() {
|
||||
ipv = NetdevIPAddrVer(v)
|
||||
}
|
||||
}
|
||||
if ipv == 0 {
|
||||
// Assume IPv6 if cannot derive
|
||||
ipv = 6
|
||||
}
|
||||
svcname = append(svcname, fmt.Sprintf("%d", ipv))
|
||||
|
||||
var cmd = []string{
|
||||
"ip",
|
||||
fmt.Sprintf("-%d", ipv), // IP version
|
||||
"route",
|
||||
"%s",
|
||||
}
|
||||
|
||||
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.IsValid() {
|
||||
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")
|
||||
svcname = append(svcname, "vrf", route.Vrf.Name)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
41
execline.go
41
execline.go
@ -1,41 +0,0 @@
|
||||
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, "")
|
||||
}
|
@ -4,7 +4,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
4
go.mod
4
go.mod
@ -1,3 +1,5 @@
|
||||
module git.redxen.eu/caskd/s6-netdev
|
||||
|
||||
go 1.22.5
|
||||
go 1.22.8
|
||||
|
||||
require git.redxen.eu/nnd/s6-netdev v0.0.0-20241106103743-03b649623f4e
|
||||
|
2
go.sum
Normal file
2
go.sum
Normal file
@ -0,0 +1,2 @@
|
||||
git.redxen.eu/nnd/s6-netdev v0.0.0-20241106103743-03b649623f4e h1:t4/qeNtyQNYFcWQMw7akxafvWJT8+8yErqNiu/Y/1/o=
|
||||
git.redxen.eu/nnd/s6-netdev v0.0.0-20241106103743-03b649623f4e/go.mod h1:3P2jgoez/bos+RdMFoDCs63PlCKFw1POQz/TfE1dq5g=
|
@ -1,72 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
type IfMap map[string]*Iface
|
||||
|
||||
func (im IfMap) AddIf(i *Iface) {
|
||||
im[i.Name] = i
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceAddAddr(addr string) (err error) {
|
||||
var (
|
||||
a netip.Prefix
|
||||
)
|
||||
if a, err = netip.ParsePrefix(addr); err != nil {
|
||||
err = fmt.Errorf("Failed to parse address %s, %w", addr, err)
|
||||
}
|
||||
i.Addresses = append(i.Addresses, a)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceAddRoute(def bool, route, r_type, via string, vrf *Iface, table *RouteTable, metric Metric) (err error) {
|
||||
var (
|
||||
r = Route{
|
||||
Default: def,
|
||||
Type: r_type,
|
||||
Vrf: vrf,
|
||||
Table: table,
|
||||
Metric: metric,
|
||||
}
|
||||
)
|
||||
|
||||
if via != "" {
|
||||
if r.Via, err = netip.ParseAddr(via); err != nil {
|
||||
err = fmt.Errorf("Failed to parse via %s, %w", via, err)
|
||||
}
|
||||
}
|
||||
|
||||
if !def {
|
||||
if r.Net, err = netip.ParsePrefix(route); err != nil {
|
||||
err = fmt.Errorf("Failed to parse via %s, %w", via, err)
|
||||
}
|
||||
}
|
||||
|
||||
i.Routes = append(i.Routes, r)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceMAC(mac string) (err error) {
|
||||
i.MACAddr, err = net.ParseMAC(mac)
|
||||
return
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceEnslave(s ...*Iface) {
|
||||
i.Slaves = append(i.Slaves, s...)
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceSysctl(ipv int, key, value, def string) {
|
||||
l := &i.Sysctls.V4
|
||||
if ipv == 6 {
|
||||
l = &i.Sysctls.V6
|
||||
}
|
||||
*l = append(*l, Property{Key: key, Value: value, Default: def})
|
||||
}
|
||||
|
||||
func (i *Iface) NetdevIfaceProperty(key, value, def string) {
|
||||
i.Properties = append(i.Properties, Property{Key: key, Value: value, Default: def})
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
@ -7,7 +7,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
@ -5,7 +5,7 @@ import (
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@ -59,20 +59,24 @@ func main() {
|
||||
{ifn: "tristan-travel", ll: "fe80::1/64", route: "2a04:5b81:201f::/48"},
|
||||
{ifn: "gustav", ll: "fe80::1/64", route: "2a04:5b81:2011::/48"},
|
||||
{ifn: "caskd-lakewood", ll: "fe80::1/64", route: "2a04:5b81:2060::/48"},
|
||||
{ifn: "caskd-thetford", ll: "fe80::1/64", route: ""},
|
||||
} {
|
||||
ifs.AddIf(&s6netdev.Iface{
|
||||
iface := s6netdev.Iface{
|
||||
Name: v.ifn,
|
||||
Type: &s6netdev.NetdevIfTypes.Wireguard,
|
||||
Addresses: []netip.Prefix{netip.MustParsePrefix(v.ll)},
|
||||
Routes: []s6netdev.Route{
|
||||
{Net: netip.MustParsePrefix(v.route), Vrf: ifs["vrf-wgate"]},
|
||||
},
|
||||
Sysctls: s6netdev.Sysctl_IP{
|
||||
V6: []s6netdev.Property{
|
||||
{Key: "forwarding", Value: "1", Default: "0"},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
if v.route != "" {
|
||||
iface.Routes: []s6netdev.Route{
|
||||
{Net: netip.MustParsePrefix(v.route), Vrf: ifs["vrf-wgate"]},
|
||||
},
|
||||
}
|
||||
ifs.AddIf(&iface)
|
||||
}
|
||||
|
||||
for _, m := range []struct {
|
60
misc.go
60
misc.go
@ -1,60 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/netip"
|
||||
"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 netip.Addr) int {
|
||||
if IP.Is6() {
|
||||
return 6
|
||||
}
|
||||
return 4
|
||||
}
|
||||
|
||||
func NetdevIsDummy(s S6SvcName) (r bool) {
|
||||
_, r = dummy_svc_blacklist[s]
|
||||
return
|
||||
}
|
||||
|
||||
func NetdevOnlyMAC(x net.HardwareAddr, _ error) net.HardwareAddr {
|
||||
return x
|
||||
}
|
9
nnd.go
9
nnd.go
@ -1,9 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func NNDLibExec(name string) string {
|
||||
return fmt.Sprintf("/usr/libexec/nnd/s6/%s", name)
|
||||
}
|
204
s6.go
204
s6.go
@ -1,204 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type S6SvcTree struct {
|
||||
s map[S6SvcName]*S6Svc
|
||||
rcdir, envdir string
|
||||
root string
|
||||
}
|
||||
|
||||
type kv_file struct {
|
||||
name, value string
|
||||
perm int
|
||||
}
|
||||
|
||||
type S6Svc struct {
|
||||
Name S6SvcName
|
||||
Type S6SvcType
|
||||
Children []*S6Svc // Either dependencies or contents depending on type
|
||||
ProducerFor, ConsumerFor *S6Svc
|
||||
NotifFd int
|
||||
FlagEssential bool
|
||||
Up, Down, Run string
|
||||
env map[string]string
|
||||
}
|
||||
|
||||
type S6SvcName string
|
||||
|
||||
func (s S6SvcName) Sanitize() S6SvcName {
|
||||
// Only sanitize slashes for now
|
||||
return S6SvcName(strings.ReplaceAll(string(s), "/", "_"))
|
||||
}
|
||||
|
||||
type S6SvcType *string
|
||||
|
||||
var S6SvcTypes = struct {
|
||||
Oneshot, Longrun, Bundle string
|
||||
}{
|
||||
Oneshot: "oneshot",
|
||||
Longrun: "longrun",
|
||||
Bundle: "bundle",
|
||||
}
|
||||
|
||||
func S6NewTree() *S6SvcTree {
|
||||
t := new(S6SvcTree)
|
||||
t.s = make(map[S6SvcName]*S6Svc)
|
||||
t.root = "/etc/s6"
|
||||
t.rcdir = "rc"
|
||||
t.envdir = "env"
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) S6New(name S6SvcName, svc_type S6SvcType) *S6Svc {
|
||||
if name == "" || svc_type == nil {
|
||||
return nil
|
||||
}
|
||||
if e, ok := t.s[name]; ok && e.Type == svc_type {
|
||||
return e
|
||||
}
|
||||
s := new(S6Svc)
|
||||
s.Name = name
|
||||
s.Type = svc_type
|
||||
t.s[name] = s
|
||||
return s
|
||||
}
|
||||
func S6Pipe(src, dst *S6Svc) {
|
||||
src.ProducerFor = dst
|
||||
dst.ConsumerFor = src
|
||||
}
|
||||
|
||||
func (s *S6Svc) S6Children(children ...*S6Svc) {
|
||||
s.Children = append(s.Children, children...)
|
||||
}
|
||||
|
||||
func (s *S6Svc) S6AddEnv(key, value string) {
|
||||
s.env[key] = value
|
||||
}
|
||||
|
||||
func (s *S6Svc) S6DelEnv(key string) {
|
||||
delete(s.env, key)
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) S6AddSvc(s *S6Svc) {
|
||||
t.s[s.Name] = s
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) S6GetSvc(name S6SvcName) *S6Svc {
|
||||
return t.s[name]
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) S6Services() (r []*S6Svc) {
|
||||
for _, v := range t.s {
|
||||
r = append(r, v)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) S6CommitService(s *S6Svc) (err error) {
|
||||
if err = os.Mkdir(t.rcdir, fs.ModeDir|0777); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
|
||||
sdir := filepath.Join(t.rcdir, string(s.Name))
|
||||
if err = os.Mkdir(sdir, fs.ModeDir|0777); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
|
||||
var kvfiles []kv_file
|
||||
kvfiles = append(kvfiles, kv_file{"type", *s.Type, 0666})
|
||||
if s.FlagEssential {
|
||||
kvfiles = append(kvfiles, kv_file{"flag-essential", "", 0666})
|
||||
}
|
||||
if s.ProducerFor != nil {
|
||||
kvfiles = append(kvfiles, kv_file{"producer-for", string(s.ProducerFor.Name), 0666})
|
||||
}
|
||||
if s.ConsumerFor != nil {
|
||||
kvfiles = append(kvfiles, kv_file{"consumer-for", string(s.ConsumerFor.Name), 0666})
|
||||
}
|
||||
if s.NotifFd != 0 {
|
||||
kvfiles = append(kvfiles, kv_file{"notification-fd", fmt.Sprintf("%d", s.NotifFd), 0666})
|
||||
}
|
||||
|
||||
// Scripts
|
||||
switch s.Type {
|
||||
case &S6SvcTypes.Longrun:
|
||||
{
|
||||
if s.Run != "" {
|
||||
kvfiles = append(kvfiles, kv_file{"run", s.Run, 0777})
|
||||
}
|
||||
}
|
||||
case &S6SvcTypes.Oneshot:
|
||||
{
|
||||
if s.Up != "" {
|
||||
kvfiles = append(kvfiles, kv_file{"up", s.Up, 0777})
|
||||
}
|
||||
if s.Down != "" {
|
||||
kvfiles = append(kvfiles, kv_file{"down", s.Down, 0777})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range kvfiles {
|
||||
var f *os.File
|
||||
if f, err = os.OpenFile(filepath.Join(sdir, v.name), os.O_CREATE|os.O_RDWR, fs.FileMode(v.perm)); err != nil {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintln(f, v.value)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Children
|
||||
var dirname string
|
||||
switch s.Type {
|
||||
case &S6SvcTypes.Bundle:
|
||||
dirname = "contents.d"
|
||||
default:
|
||||
dirname = "dependencies.d"
|
||||
}
|
||||
cdir := filepath.Join(sdir, dirname)
|
||||
if err = os.Mkdir(cdir, fs.ModeDir|0777); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
|
||||
for _, v := range s.Children {
|
||||
var f *os.File
|
||||
if f, err = os.Create(filepath.Join(cdir, string(v.Name))); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
f.Close()
|
||||
}
|
||||
|
||||
if len(s.env) != 0 {
|
||||
if err = os.Mkdir(t.envdir, fs.ModeDir|0777); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
sdir := filepath.Join(t.envdir, string(s.Name))
|
||||
if err = os.Mkdir(sdir, fs.ModeDir|0777); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
for k, v := range s.env {
|
||||
var f *os.File
|
||||
if f, err = os.Create(filepath.Join(sdir, string(k))); err != nil && !errors.Is(err, os.ErrExist) {
|
||||
return
|
||||
}
|
||||
_, err = fmt.Fprintln(f, v)
|
||||
f.Close()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
147
services.go
147
services.go
@ -1,147 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func (t *S6SvcTree) CreateIfaceService(iface string) *S6Svc {
|
||||
return t.S6New(S6SvcName(fmt.Sprintf("interface.%s.create", iface)), &S6SvcTypes.Oneshot)
|
||||
}
|
||||
|
||||
func (t *S6SvcTree) LinkIfaceService(iface string) *S6Svc {
|
||||
return t.S6New(S6SvcName(fmt.Sprintf("interface.%s.link", iface)), &S6SvcTypes.Oneshot)
|
||||
}
|
||||
|
||||
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(512)
|
||||
}
|
||||
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:
|
||||
{
|
||||
t.NetdevDependBundleStage(i.Name, "configure", t.NetdevWireguardConfig(i))
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
if i.MACAddr != nil {
|
||||
r = append(r, t.NetdevConfigureIfaceMAC(i, i.MACAddr))
|
||||
}
|
||||
|
||||
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.netdevCreateBundleStage(i.Name, "configure"))
|
||||
|
||||
bundle_ready := t.NetdevDependBundleStage(i.Name, "ready", svc_link)
|
||||
r = append(r, bundle_ready)
|
||||
|
||||
return
|
||||
}
|
@ -6,7 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
@ -7,7 +7,7 @@ import (
|
||||
"net/netip"
|
||||
"os"
|
||||
|
||||
"git.redxen.eu/caskd/s6-netdev"
|
||||
"git.redxen.eu/nnd/s6-netdev"
|
||||
)
|
||||
|
||||
func main() {
|
74
types.go
74
types.go
@ -1,74 +0,0 @@
|
||||
package s6netdev
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/netip"
|
||||
)
|
||||
|
||||
type (
|
||||
RouteTable uint16
|
||||
Metric uint32
|
||||
VLAN uint16
|
||||
)
|
||||
|
||||
type Property struct {
|
||||
Key, Value, Default string
|
||||
}
|
||||
|
||||
type Sysctl_IP struct {
|
||||
V4, V6 []Property
|
||||
}
|
||||
|
||||
type DHCP_IP struct {
|
||||
V4, V6 bool // Should we start dhcp on this interface?
|
||||
}
|
||||
|
||||
type Iface struct {
|
||||
Name string // Interface name
|
||||
Type *NetdevIfType // Type of interface
|
||||
Slaves []*Iface // Slaves for VRFs, Bridges and Bonds etc...
|
||||
|
||||
VlanId VLAN // VLAN id for VLAN interfaces
|
||||
Parent *Iface // Parent interface for VLAN interfaces
|
||||
|
||||
Table RouteTable // Routing table, for VRF
|
||||
|
||||
MACAddr net.HardwareAddr // MAC address of interface (only valid for physical, bridges and VLAN)
|
||||
|
||||
Addresses []netip.Prefix // Addresses to be assigned to interface
|
||||
Routes []Route // Routes to be assigned to interface
|
||||
|
||||
DHCP DHCP_IP // Should we start dhcp on this interface?
|
||||
|
||||
Properties []Property // List of properties of the interface, valid for many
|
||||
Sysctls Sysctl_IP // Sysctls associated with this interface
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
Default bool
|
||||
// VRF would be a field but it can be derived from parent
|
||||
Type string // unicast default, can be others
|
||||
IPver int // if 0, will guess based on Net
|
||||
Net netip.Prefix
|
||||
Via netip.Addr
|
||||
Vrf *Iface
|
||||
Table *RouteTable
|
||||
Metric Metric // Should be explicitly initialised to 1024
|
||||
}
|
||||
|
||||
type NetdevIfType struct {
|
||||
str string
|
||||
deps []S6SvcName
|
||||
}
|
||||
|
||||
var NetdevIfTypes = struct {
|
||||
Phys, Loopback, Bridge, Vlan, Wireguard, Bond, Vrf NetdevIfType
|
||||
}{
|
||||
Phys: NetdevIfType{"", []S6SvcName{"bundle.hw-coldplug"}},
|
||||
Loopback: NetdevIfType{"loopback", []S6SvcName{}},
|
||||
Bridge: NetdevIfType{"bridge", []S6SvcName{"module.bridge"}},
|
||||
Vlan: NetdevIfType{"vlan", []S6SvcName{"module.8021q"}},
|
||||
Wireguard: NetdevIfType{"wireguard", []S6SvcName{"module.wireguard"}},
|
||||
Bond: NetdevIfType{"bond", []S6SvcName{"module.bonding"}},
|
||||
Vrf: NetdevIfType{"vrf", []S6SvcName{"module.vrf"}},
|
||||
}
|
Loading…
Reference in New Issue
Block a user