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.
This commit is contained in:
Christian Goll
2022-03-15 11:42:15 +01:00
parent 399138c7c4
commit 55bf1695de
11 changed files with 102 additions and 15 deletions

View File

@@ -1,6 +1,9 @@
package add package add
import ( import (
"fmt"
"net"
"github.com/hpcng/warewulf/internal/pkg/node" "github.com/hpcng/warewulf/internal/pkg/node"
"github.com/hpcng/warewulf/internal/pkg/util" "github.com/hpcng/warewulf/internal/pkg/util"
"github.com/hpcng/warewulf/internal/pkg/warewulfd" "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) 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 { if SetDiscoverable {
wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get()) wwlog.Printf(wwlog.VERBOSE, "Node: %s, Setting node to discoverable\n", n.Id.Get())

View File

@@ -5,16 +5,17 @@ import "github.com/spf13/cobra"
var ( var (
baseCmd = &cobra.Command{ baseCmd = &cobra.Command{
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Use: "add [OPTIONS] NODENAME", Use: "add [OPTIONS] NODENAME",
Short: "Add new node to Warewulf", Short: "Add new node to Warewulf",
Long: "This command will add a new node named NODENAME to Warewulf.", Long: "This command will add a new node named NODENAME to Warewulf.",
RunE: CobraRunE, RunE: CobraRunE,
Args: cobra.MinimumNArgs(1), Args: cobra.MinimumNArgs(1),
} }
SetClusterName string SetClusterName string
SetNetName string SetNetName string
SetNetDev string SetNetDev string
SetIpaddr string SetIpaddr string
SetIpaddr6 string
SetNetmask string SetNetmask string
SetGateway string SetGateway string
SetHwaddr 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(&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(&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(&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(&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(&SetGateway, "gateway", "G", "", "Set the node's network device gateway")
baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address") baseCmd.PersistentFlags().StringVarP(&SetHwaddr, "hwaddr", "H", "", "Set the node's network device HW address")

View File

@@ -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+":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+":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+":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+":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+":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()) 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 { } 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)) fmt.Println(strings.Repeat("=", 80))
for _, node := range node.FilterByName(nodes, args) { for _, node := range node.FilterByName(nodes, args) {
if len(node.NetDevs) > 0 { if len(node.NetDevs) > 0 {
for name, dev := range node.NetDevs { 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 { } else {
fmt.Printf("%-22s %-6s %-18s %-15s %-15s\n", node.Id.Get(), "--", "--", "--", "--") fmt.Printf("%-22s %-6s %-18s %-15s %-15s %-15s\n", node.Id.Get(), "--", "--", "--", "--", "--")
} }
} }

View File

@@ -2,12 +2,15 @@ package node
import ( import (
"errors" "errors"
"fmt"
"io/ioutil" "io/ioutil"
"net"
"path" "path"
"sort" "sort"
"strings" "strings"
"github.com/hpcng/warewulf/internal/pkg/buildconfig" "github.com/hpcng/warewulf/internal/pkg/buildconfig"
"github.com/hpcng/warewulf/internal/pkg/warewulfconf"
"github.com/hpcng/warewulf/internal/pkg/wwlog" "github.com/hpcng/warewulf/internal/pkg/wwlog"
"gopkg.in/yaml.v2" "gopkg.in/yaml.v2"
@@ -43,7 +46,10 @@ func New() (nodeYaml, error) {
func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) { func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
var ret []NodeInfo var ret []NodeInfo
wwconfig, err := warewulfconf.New()
if err != nil {
return ret, err
}
wwlog.Printf(wwlog.DEBUG, "Finding all nodes...\n") wwlog.Printf(wwlog.DEBUG, "Finding all nodes...\n")
for nodename, node := range config.Nodes { for nodename, node := range config.Nodes {
var n NodeInfo var n NodeInfo
@@ -103,13 +109,28 @@ func (config *nodeYaml) FindAllNodes() ([]NodeInfo, error) {
} }
n.NetDevs[devname].Device.Set(netdev.Device) n.NetDevs[devname].Device.Set(netdev.Device)
n.NetDevs[devname].Ipaddr.Set(netdev.Ipaddr) 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].Netmask.Set(netdev.Netmask)
n.NetDevs[devname].Hwaddr.Set(netdev.Hwaddr) n.NetDevs[devname].Hwaddr.Set(netdev.Hwaddr)
n.NetDevs[devname].Gateway.Set(netdev.Gateway) n.NetDevs[devname].Gateway.Set(netdev.Gateway)
n.NetDevs[devname].Type.Set(netdev.Type) n.NetDevs[devname].Type.Set(netdev.Type)
n.NetDevs[devname].OnBoot.Set(netdev.OnBoot) n.NetDevs[devname].OnBoot.Set(netdev.OnBoot)
n.NetDevs[devname].Default.Set(netdev.Default) 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 { if len(node.NetDevs) == 1 {
n.NetDevs[devname].Default.Set("true") 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) wwlog.Printf(wwlog.DEBUG, "Updating profile (%s) netdev: %s\n", p, devname)
n.NetDevs[devname].Device.SetAlt(netdev.Device, p) 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].Netmask.SetAlt(netdev.Netmask, p)
n.NetDevs[devname].Hwaddr.SetAlt(netdev.Hwaddr, p) n.NetDevs[devname].Hwaddr.SetAlt(netdev.Hwaddr, p)
n.NetDevs[devname].Gateway.SetAlt(netdev.Gateway, p) n.NetDevs[devname].Gateway.SetAlt(netdev.Gateway, p)

View File

@@ -49,6 +49,7 @@ type NetDevs struct {
Hwaddr string `yaml:"hwaddr,omitempty"` Hwaddr string `yaml:"hwaddr,omitempty"`
Ipaddr string `yaml:"ipaddr,omitempty"` Ipaddr string `yaml:"ipaddr,omitempty"`
IpCIDR string `yaml:"ipcidr,omitempty"` IpCIDR string `yaml:"ipcidr,omitempty"`
Ipaddr6 string `yaml:"ip6addr,omitempty"`
Prefix string `yaml:"prefix,omitempty"` Prefix string `yaml:"prefix,omitempty"`
Netmask string `yaml:"netmask,omitempty"` Netmask string `yaml:"netmask,omitempty"`
Gateway string `yaml:"gateway,omitempty"` Gateway string `yaml:"gateway,omitempty"`
@@ -101,6 +102,7 @@ type NetDevEntry struct {
Device Entry Device Entry
Hwaddr Entry Hwaddr Entry
Ipaddr Entry Ipaddr Entry
Ipaddr6 Entry
IpCIDR Entry IpCIDR Entry
Prefix Entry Prefix Entry
Netmask Entry Netmask Entry

View File

@@ -33,8 +33,10 @@ type TemplateStruct struct {
BuildTime string BuildTime string
BuildSource string BuildSource string
Ipaddr string Ipaddr string
Ipaddr6 string
Netmask string Netmask string
Network string Network string
Ipv6 bool
Dhcp warewulfconf.DhcpConf Dhcp warewulfconf.DhcpConf
Nfs warewulfconf.NfsConf Nfs warewulfconf.NfsConf
Warewulf warewulfconf.WarewulfConf Warewulf warewulfconf.WarewulfConf

View File

@@ -205,7 +205,7 @@ func BuildOverlay(nodeInfo node.NodeInfo, overlayName string) error {
netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size() netPrefix, _ := net.IPMask(net.ParseIP(netdev.Netmask.Get()).To4()).Size()
tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix) tstruct.NetDevs[devname].Prefix = strconv.Itoa(netPrefix)
tstruct.NetDevs[devname].IpCIDR = netaddr.String() tstruct.NetDevs[devname].IpCIDR = netaddr.String()
tstruct.NetDevs[devname].Ipaddr6 = netdev.Ipaddr6.Get()
} }
// Backwards compatibility for templates using "Keys" // Backwards compatibility for templates using "Keys"
for keyname, key := range nodeInfo.Tags { for keyname, key := range nodeInfo.Tags {
@@ -219,8 +219,14 @@ func BuildOverlay(nodeInfo node.NodeInfo, overlayName string) error {
tstruct.Dhcp = *controller.Dhcp tstruct.Dhcp = *controller.Dhcp
tstruct.Warewulf = *controller.Warewulf tstruct.Warewulf = *controller.Warewulf
tstruct.Ipaddr = controller.Ipaddr tstruct.Ipaddr = controller.Ipaddr
tstruct.Ipaddr6 = controller.Ipaddr6
tstruct.Netmask = controller.Netmask tstruct.Netmask = controller.Netmask
tstruct.Network = controller.Network tstruct.Network = controller.Network
if controller.Ipaddr6 != "" {
tstruct.Ipv6 = true
} else {
tstruct.Ipv6 = false
}
hostname, _ := os.Hostname() hostname, _ := os.Hostname()
tstruct.BuildHost = hostname tstruct.BuildHost = hostname
dt := time.Now() dt := time.Now()

View File

@@ -62,7 +62,18 @@ func New() (ControllerConf, error) {
ret.Network = sub.GetNetworkPortion() 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 { if ret.Warewulf.Port == 0 {
ret.Warewulf.Port = defaultPort ret.Warewulf.Port = defaultPort
} }

View File

@@ -9,8 +9,10 @@ import (
type ControllerConf struct { type ControllerConf struct {
Comment string `yaml:"comment,omitempty"` Comment string `yaml:"comment,omitempty"`
Ipaddr string `yaml:"ipaddr"` Ipaddr string `yaml:"ipaddr"`
Ipaddr6 string `yaml:"ipaddr6,omitempty"`
Netmask string `yaml:"netmask"` Netmask string `yaml:"netmask"`
Network string `yaml:"network,omitempty"` Network string `yaml:"network,omitempty"`
Ipv6net string `yaml:"ipv6net,omitempty"`
Fqdn string `yaml:"fqdn,omitempty"` Fqdn string `yaml:"fqdn,omitempty"`
Warewulf *WarewulfConf `yaml:"warewulf"` Warewulf *WarewulfConf `yaml:"warewulf"`
Dhcp *DhcpConf `yaml:"dhcp"` Dhcp *DhcpConf `yaml:"dhcp"`

View File

@@ -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 NAME=default
BOOTPROTO=static BOOTPROTO=static
DEVTIMEOUT=10 DEVTIMEOUT=10
@@ -6,4 +10,11 @@ IPADDR={{$.NetDevs.default.Ipaddr}}
NETMASK={{$.NetDevs.default.Netmask}} NETMASK={{$.NetDevs.default.Netmask}}
GATEWAY={{$.NetDevs.default.Gateway}} GATEWAY={{$.NetDevs.default.Gateway}}
HWADDR={{$.NetDevs.default.Hwaddr}} HWADDR={{$.NetDevs.default.Hwaddr}}
ONBOOT=yes ONBOOT=yes
IPV6INIT=yes
IPV6_AUTOCONF=yes
IPV6_DEFROUTE=yes
IPV6_FAILURE_FATAL=no
{{- if $.NetDevs.default.Ipaddr6 }}
IPV6ADDR="{{ $.NetDevs.default.Ipaddr6 }}"
{{- end }}

View File

@@ -1,3 +1,9 @@
<!--
This file is autogenerated by warewulf
Host: {{.BuildHost}}
Time: {{.BuildTime}}
Source: {{.BuildSource}}
-->
<interface origin="static generated warewulf config"> <interface origin="static generated warewulf config">
<name>{{.NetDevs.default.Device}}</name> <name>{{.NetDevs.default.Device}}</name>
<control> <control>
@@ -24,4 +30,11 @@
<privacy>prefer-public</privacy> <privacy>prefer-public</privacy>
<accept-redirects>false</accept-redirects> <accept-redirects>false</accept-redirects>
</ipv6> </ipv6>
{{- if $.NetDevs.default.Ipaddr6 }}
<ipv6:static>
<address>
<local>{{ $.NetDevs.default.Ipaddr6 }}</local>
</address>
</ipv6:static>
{{- end }}
</interface> </interface>