From 55bf1695de2c565f700fc82c7e7746949d8078a5 Mon Sep 17 00:00:00 2001 From: Christian Goll Date: Tue, 15 Mar 2022 11:42:15 +0100 Subject: [PATCH] initial commit of simple ipv6 support As soon as in warewulf.conf a value for ipaddr6 is defined all nodes will get a derived ipv6 address if not the ipv6 is not explicitly set. --- internal/app/wwctl/node/add/main.go | 15 +++++++++++ internal/app/wwctl/node/add/root.go | 12 +++++---- internal/app/wwctl/node/list/main.go | 8 +++--- internal/pkg/node/constructors.go | 27 ++++++++++++++++--- internal/pkg/node/datastructure.go | 2 ++ internal/pkg/overlay/datastructure.go | 2 ++ internal/pkg/overlay/overlay.go | 8 +++++- internal/pkg/warewulfconf/constructors.go | 13 ++++++++- internal/pkg/warewulfconf/datastructure.go | 2 ++ .../network-scripts/ifcfg-default.ww | 15 +++++++++-- .../etc/wicked/ifconfig/ifcfg-default.xml.ww | 13 +++++++++ 11 files changed, 102 insertions(+), 15 deletions(-) diff --git a/internal/app/wwctl/node/add/main.go b/internal/app/wwctl/node/add/main.go index 39d43b95..43eae0b3 100644 --- a/internal/app/wwctl/node/add/main.go +++ b/internal/app/wwctl/node/add/main.go @@ -1,6 +1,9 @@ package add import ( + "fmt" + "net" + "github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/warewulfd" @@ -123,7 +126,19 @@ func CobraRunE(cmd *cobra.Command, args []string) error { n.NetDevs[SetNetName].Type.Set(SetType) } + if SetIpaddr6 != "" { + if SetNetName == "" { + return errors.New("you must include the '--netname' option") + } + if _, ok := n.NetDevs[SetNetName]; !ok { + return errors.New("network device does not exist: " + SetNetName) + } + // just check if address is a valid ipv6 CIDR address + if _, _, err := net.ParseCIDR(SetIpaddr6); err != nil { + return errors.New(fmt.Sprintf("%s is not a valid ipv6 address in CIDR notation\n", SetIpaddr6)) + } + } if SetDiscoverable { wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get()) diff --git a/internal/app/wwctl/node/add/root.go b/internal/app/wwctl/node/add/root.go index a3081965..a08caaf8 100644 --- a/internal/app/wwctl/node/add/root.go +++ b/internal/app/wwctl/node/add/root.go @@ -5,16 +5,17 @@ import "github.com/spf13/cobra" var ( baseCmd = &cobra.Command{ DisableFlagsInUseLine: true, - Use: "add [OPTIONS] NODENAME", - Short: "Add new node to Warewulf", - Long: "This command will add a new node named NODENAME to Warewulf.", - RunE: CobraRunE, - Args: cobra.MinimumNArgs(1), + Use: "add [OPTIONS] NODENAME", + Short: "Add new node to Warewulf", + Long: "This command will add a new node named NODENAME to Warewulf.", + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), } SetClusterName string SetNetName string SetNetDev string SetIpaddr string + SetIpaddr6 string SetNetmask string SetGateway string SetHwaddr string @@ -27,6 +28,7 @@ func init() { baseCmd.PersistentFlags().StringVarP(&SetNetName, "netname", "n", "default", "Define the network name to configure") baseCmd.PersistentFlags().StringVarP(&SetNetDev, "netdev", "N", "", "Define the network device to configure") baseCmd.PersistentFlags().StringVarP(&SetIpaddr, "ipaddr", "I", "", "Set the node's network device IP address") + baseCmd.PersistentFlags().StringVarP(&SetIpaddr6, "ipaddr6", "6", "", "Set the node's network device IPv6 address") baseCmd.PersistentFlags().StringVarP(&SetNetmask, "netmask", "M", "", "Set the node's network device netmask") baseCmd.PersistentFlags().StringVarP(&SetGateway, "gateway", "G", "", "Set the node's network device gateway") baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address") diff --git a/internal/app/wwctl/node/list/main.go b/internal/app/wwctl/node/list/main.go index 4fe66890..74bde638 100644 --- a/internal/app/wwctl/node/list/main.go +++ b/internal/app/wwctl/node/list/main.go @@ -65,6 +65,7 @@ func CobraRunE(cmd *cobra.Command, args []string) error { fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":DEVICE", netdev.Device.Source(), netdev.Device.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":HWADDR", netdev.Hwaddr.Source(), netdev.Hwaddr.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":IPADDR", netdev.Ipaddr.Source(), netdev.Ipaddr.Print()) + fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":IPADDR6", netdev.Ipaddr.Source(), netdev.Ipaddr6.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":NETMASK", netdev.Netmask.Source(), netdev.Netmask.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":GATEWAY", netdev.Gateway.Source(), netdev.Gateway.Print()) fmt.Printf("%-20s %-18s %-12s %s\n", node.Id.Get(), name+":TYPE", netdev.Type.Source(), netdev.Type.Print()) @@ -75,16 +76,17 @@ func CobraRunE(cmd *cobra.Command, args []string) error { } } else if ShowNet { - fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", "NODE NAME", "DEVICE", "HWADDR", "IPADDR", "GATEWAY") + fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", "NODE NAME", "DEVICE", "HWADDR", "IPADDR", "GATEWAY", "IPADDR6") fmt.Println(strings.Repeat("=", 80)) for _, node := range node.FilterByName(nodes, args) { if len(node.NetDevs) > 0 { for name, dev := range node.NetDevs { - fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Id.Get(), name, dev.Hwaddr.Print(), dev.Ipaddr.Print(), dev.Gateway.Print()) + fmt.Printf("%-22s %-6s %-18s %-15s %-15s %-15s\n", + node.Id.Get(), name, dev.Hwaddr.Print(), dev.Ipaddr.Print(), dev.Gateway.Print(), dev.Ipaddr6.Print()) } } else { - fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Id.Get(), "--", "--", "--", "--") + fmt.Printf("%-22s %-6s %-18s %-15s %-15s %-15s\n", node.Id.Get(), "--", "--", "--", "--", "--") } } diff --git a/internal/pkg/node/constructors.go b/internal/pkg/node/constructors.go index ed445901..789bc9d4 100644 --- a/internal/pkg/node/constructors.go +++ b/internal/pkg/node/constructors.go @@ -2,12 +2,15 @@ package node import ( "errors" + "fmt" "io/ioutil" + "net" "path" "sort" "strings" "github.com/hpcng/warewulf/internal/pkg/buildconfig" + "github.com/hpcng/warewulf/internal/pkg/warewulfconf" "github.com/hpcng/warewulf/internal/pkg/wwlog" "gopkg.in/yaml.v2" @@ -43,7 +46,10 @@ func New() (nodeYaml, error) { func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { var ret []NodeInfo - + wwconfig, err := warewulfconf.New() + if err != nil { + return ret, err + } wwlog.Printf(wwlog.DEBUG, "Finding all nodes...\n") for nodename, node := range config.Nodes { var n NodeInfo @@ -103,13 +109,28 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { } n.NetDevs[devname].Device.Set(netdev.Device) n.NetDevs[devname].Ipaddr.Set(netdev.Ipaddr) + n.NetDevs[devname].Ipaddr6.Set(netdev.Ipaddr6) + + // Derive value of ipv6 address from ipv4 if not explicitly set + if wwconfig.Ipaddr6 != "" { + ipv4Arr := strings.Split(netdev.Ipaddr, ".") + // error can be ignored as check was done at init + _, ipv6Net, _ := net.ParseCIDR(wwconfig.Ipaddr6) + mSize, _ := ipv6Net.Mask.Size() + ipv6str := fmt.Sprintf("%s%s:%s:%s:%s/%v", + ipv6Net.IP.String(), ipv4Arr[0], ipv4Arr[1], ipv4Arr[2], ipv4Arr[3], mSize) + if strings.Count(ipv6Net.IP.String(), ":") == 5 { + ipv6str = strings.Replace(ipv6str, "::", ":", -1) + } + n.NetDevs[devname].Ipaddr6.SetDefault(ipv6str) + } n.NetDevs[devname].Netmask.Set(netdev.Netmask) n.NetDevs[devname].Hwaddr.Set(netdev.Hwaddr) n.NetDevs[devname].Gateway.Set(netdev.Gateway) n.NetDevs[devname].Type.Set(netdev.Type) n.NetDevs[devname].OnBoot.Set(netdev.OnBoot) n.NetDevs[devname].Default.Set(netdev.Default) - // for just one netdeve, it is always the default + // for just one netdev, it is always the default if len(node.NetDevs) == 1 { n.NetDevs[devname].Default.Set("true") } @@ -174,7 +195,7 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { wwlog.Printf(wwlog.DEBUG, "Updating profile (%s) netdev: %s\n", p, devname) n.NetDevs[devname].Device.SetAlt(netdev.Device, p) - n.NetDevs[devname].Ipaddr.SetAlt(netdev.Ipaddr, p) + //n.NetDevs[devname].Ipaddr.SetAlt(netdev.Ipaddr, p) <- Ipaddr must be uniq n.NetDevs[devname].Netmask.SetAlt(netdev.Netmask, p) n.NetDevs[devname].Hwaddr.SetAlt(netdev.Hwaddr, p) n.NetDevs[devname].Gateway.SetAlt(netdev.Gateway, p) diff --git a/internal/pkg/node/datastructure.go b/internal/pkg/node/datastructure.go index b2e0e343..20610dfd 100644 --- a/internal/pkg/node/datastructure.go +++ b/internal/pkg/node/datastructure.go @@ -49,6 +49,7 @@ type NetDevs struct { Hwaddr string `yaml:"hwaddr,omitempty"` Ipaddr string `yaml:"ipaddr,omitempty"` IpCIDR string `yaml:"ipcidr,omitempty"` + Ipaddr6 string `yaml:"ip6addr,omitempty"` Prefix string `yaml:"prefix,omitempty"` Netmask string `yaml:"netmask,omitempty"` Gateway string `yaml:"gateway,omitempty"` @@ -101,6 +102,7 @@ type NetDevEntry struct { Device Entry Hwaddr Entry Ipaddr Entry + Ipaddr6 Entry IpCIDR Entry Prefix Entry Netmask Entry diff --git a/internal/pkg/overlay/datastructure.go b/internal/pkg/overlay/datastructure.go index 5f1f04e9..e0697883 100644 --- a/internal/pkg/overlay/datastructure.go +++ b/internal/pkg/overlay/datastructure.go @@ -33,8 +33,10 @@ type TemplateStruct struct { BuildTime string BuildSource string Ipaddr string + Ipaddr6 string Netmask string Network string + Ipv6 bool Dhcp warewulfconf.DhcpConf Nfs warewulfconf.NfsConf Warewulf warewulfconf.WarewulfConf diff --git a/internal/pkg/overlay/overlay.go b/internal/pkg/overlay/overlay.go index e91169b8..d452a8ab 100644 --- a/internal/pkg/overlay/overlay.go +++ b/internal/pkg/overlay/overlay.go @@ -205,7 +205,7 @@ func BuildOverlay(nodeInfo node.NodeInfo, overlayName string) error { netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size() tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix) tstruct.NetDevs[devname].IpCIDR = netaddr.String() - + tstruct.NetDevs[devname].Ipaddr6 = netdev.Ipaddr6.Get() } // Backwards compatibility for templates using "Keys" for keyname, key := range nodeInfo.Tags { @@ -219,8 +219,14 @@ func BuildOverlay(nodeInfo node.NodeInfo, overlayName string) error { tstruct.Dhcp = *controller.Dhcp tstruct.Warewulf = *controller.Warewulf tstruct.Ipaddr = controller.Ipaddr + tstruct.Ipaddr6 = controller.Ipaddr6 tstruct.Netmask = controller.Netmask tstruct.Network = controller.Network + if controller.Ipaddr6 != "" { + tstruct.Ipv6 = true + } else { + tstruct.Ipv6 = false + } hostname, _ := os.Hostname() tstruct.BuildHost = hostname dt := time.Now() diff --git a/internal/pkg/warewulfconf/constructors.go b/internal/pkg/warewulfconf/constructors.go index 932a3433..b3d91d1f 100644 --- a/internal/pkg/warewulfconf/constructors.go +++ b/internal/pkg/warewulfconf/constructors.go @@ -62,7 +62,18 @@ func New() (ControllerConf, error) { ret.Network = sub.GetNetworkPortion() } - + // check validity of ipv6 net + if ret.Ipaddr6 != "" { + _, ipv6net, err := net.ParseCIDR(ret.Ipaddr6) + if err != nil { + wwlog.Printf(wwlog.ERROR, "Invalid ipv6 address specified, mut be CIDR notation: %s\n", ret.Ipaddr6) + return ret, errors.New("invalid ipv6 network") + } + if msize, _ := ipv6net.Mask.Size(); msize > 64 { + wwlog.Printf(wwlog.ERROR, "ipv6 mask size must be smaller than 64\n") + return ret, errors.New("invalid ipv6 network size") + } + } if ret.Warewulf.Port == 0 { ret.Warewulf.Port = defaultPort } diff --git a/internal/pkg/warewulfconf/datastructure.go b/internal/pkg/warewulfconf/datastructure.go index 0ef1481e..a8a65ef3 100644 --- a/internal/pkg/warewulfconf/datastructure.go +++ b/internal/pkg/warewulfconf/datastructure.go @@ -9,8 +9,10 @@ import ( type ControllerConf struct { Comment string `yaml:"comment,omitempty"` Ipaddr string `yaml:"ipaddr"` + Ipaddr6 string `yaml:"ipaddr6,omitempty"` Netmask string `yaml:"netmask"` Network string `yaml:"network,omitempty"` + Ipv6net string `yaml:"ipv6net,omitempty"` Fqdn string `yaml:"fqdn,omitempty"` Warewulf *WarewulfConf `yaml:"warewulf"` Dhcp *DhcpConf `yaml:"dhcp"` diff --git a/overlays/wwinit/etc/sysconfig/network-scripts/ifcfg-default.ww b/overlays/wwinit/etc/sysconfig/network-scripts/ifcfg-default.ww index 3d499b00..da7e9e19 100644 --- a/overlays/wwinit/etc/sysconfig/network-scripts/ifcfg-default.ww +++ b/overlays/wwinit/etc/sysconfig/network-scripts/ifcfg-default.ww @@ -1,4 +1,8 @@ -DEVICE={{$.NetDevs.default.Device}} +# This file is autogenerated by warewulf +# Host: {{.BuildHost}} +# Time: {{.BuildTime}} +# Source: {{.BuildSource}} +# DEVICE={{$.NetDevs.default.Device}} NAME=default BOOTPROTO=static DEVTIMEOUT=10 @@ -6,4 +10,11 @@ IPADDR={{$.NetDevs.default.Ipaddr}} NETMASK={{$.NetDevs.default.Netmask}} GATEWAY={{$.NetDevs.default.Gateway}} HWADDR={{$.NetDevs.default.Hwaddr}} -ONBOOT=yes \ No newline at end of file +ONBOOT=yes +IPV6INIT=yes +IPV6_AUTOCONF=yes +IPV6_DEFROUTE=yes +IPV6_FAILURE_FATAL=no +{{- if $.NetDevs.default.Ipaddr6 }} +IPV6ADDR="{{ $.NetDevs.default.Ipaddr6 }}" +{{- end }} \ No newline at end of file diff --git a/overlays/wwinit/etc/wicked/ifconfig/ifcfg-default.xml.ww b/overlays/wwinit/etc/wicked/ifconfig/ifcfg-default.xml.ww index f1aa84e8..8f8e16db 100644 --- a/overlays/wwinit/etc/wicked/ifconfig/ifcfg-default.xml.ww +++ b/overlays/wwinit/etc/wicked/ifconfig/ifcfg-default.xml.ww @@ -1,3 +1,9 @@ + {{.NetDevs.default.Device}} @@ -24,4 +30,11 @@ prefer-public false +{{- if $.NetDevs.default.Ipaddr6 }} + +
+ {{ $.NetDevs.default.Ipaddr6 }} +
+
+{{- end }}