network: Add support for multiple addresses and HW addresses

Logical Interfaces can be assigned a hardware address allowing them
to match on MAC address. The static config method also needs to
support specifying multiple addresses.
This commit is contained in:
Alex Crawford 2014-08-18 12:26:27 -07:00
parent 604ef7ecb4
commit 4a2e417781
4 changed files with 28 additions and 14 deletions

View File

@ -2,6 +2,7 @@ package network
import ( import (
"fmt" "fmt"
"net"
"sort" "sort"
"strconv" "strconv"
"strings" "strings"
@ -25,13 +26,21 @@ type networkInterface interface {
type logicalInterface struct { type logicalInterface struct {
name string name string
hwaddr net.HardwareAddr
config configMethod config configMethod
children []networkInterface children []networkInterface
configDepth int configDepth int
} }
func (i *logicalInterface) Network() string { func (i *logicalInterface) Network() string {
config := fmt.Sprintf("[Match]\nName=%s\n\n[Network]\n", i.name) config := fmt.Sprintln("[Match]")
if i.name != "" {
config += fmt.Sprintf("Name=%s\n", i.name)
}
if i.hwaddr != nil {
config += fmt.Sprintf("MACAddress=%s\n", i.hwaddr)
}
config += "\n[Network]\n"
for _, child := range i.children { for _, child := range i.children {
switch iface := child.(type) { switch iface := child.(type) {
@ -47,8 +56,8 @@ func (i *logicalInterface) Network() string {
for _, nameserver := range conf.nameservers { for _, nameserver := range conf.nameservers {
config += fmt.Sprintf("DNS=%s\n", nameserver) config += fmt.Sprintf("DNS=%s\n", nameserver)
} }
if conf.address.IP != nil { for _, addr := range conf.addresses {
config += fmt.Sprintf("\n[Address]\nAddress=%s\n", conf.address.String()) config += fmt.Sprintf("\n[Address]\nAddress=%s\n", addr.String())
} }
for _, route := range conf.routes { for _, route := range conf.routes {
config += fmt.Sprintf("\n[Route]\nDestination=%s\nGateway=%s\n", route.destination.String(), route.gateway) config += fmt.Sprintf("\n[Route]\nDestination=%s\nGateway=%s\n", route.destination.String(), route.gateway)

View File

@ -181,9 +181,11 @@ func TestVLANInterfaceNetwork(t *testing.T) {
logicalInterface{ logicalInterface{
name: "testname", name: "testname",
config: configMethodStatic{ config: configMethodStatic{
address: net.IPNet{ addresses: []net.IPNet{
IP: []byte{192, 168, 1, 100}, {
Mask: []byte{255, 255, 255, 0}, IP: []byte{192, 168, 1, 100},
Mask: []byte{255, 255, 255, 0},
},
}, },
nameservers: []net.IP{ nameservers: []net.IP{
[]byte{8, 8, 8, 8}, []byte{8, 8, 8, 8},

View File

@ -37,7 +37,7 @@ type route struct {
type configMethod interface{} type configMethod interface{}
type configMethodStatic struct { type configMethodStatic struct {
address net.IPNet addresses []net.IPNet
nameservers []net.IP nameservers []net.IP
routes []route routes []route
hwaddress net.HardwareAddr hwaddress net.HardwareAddr
@ -193,20 +193,21 @@ func parseInterfaceStanza(attributes []string, options []string) (*stanzaInterfa
switch confMethod { switch confMethod {
case "static": case "static":
config := configMethodStatic{ config := configMethodStatic{
addresses: make([]net.IPNet, 1),
routes: make([]route, 0), routes: make([]route, 0),
nameservers: make([]net.IP, 0), nameservers: make([]net.IP, 0),
} }
if addresses, ok := optionMap["address"]; ok { if addresses, ok := optionMap["address"]; ok {
if len(addresses) == 1 { if len(addresses) == 1 {
config.address.IP = net.ParseIP(addresses[0]) config.addresses[0].IP = net.ParseIP(addresses[0])
} }
} }
if netmasks, ok := optionMap["netmask"]; ok { if netmasks, ok := optionMap["netmask"]; ok {
if len(netmasks) == 1 { if len(netmasks) == 1 {
config.address.Mask = net.IPMask(net.ParseIP(netmasks[0]).To4()) config.addresses[0].Mask = net.IPMask(net.ParseIP(netmasks[0]).To4())
} }
} }
if config.address.IP == nil || config.address.Mask == nil { if config.addresses[0].IP == nil || config.addresses[0].Mask == nil {
return nil, fmt.Errorf("malformed static network config for %q", iface) return nil, fmt.Errorf("malformed static network config for %q", iface)
} }
if gateways, ok := optionMap["gateway"]; ok { if gateways, ok := optionMap["gateway"]; ok {

View File

@ -194,9 +194,11 @@ func TestParseVLANStanzas(t *testing.T) {
func TestParseInterfaceStanzaStaticAddress(t *testing.T) { func TestParseInterfaceStanzaStaticAddress(t *testing.T) {
options := []string{"address 192.168.1.100", "netmask 255.255.255.0"} options := []string{"address 192.168.1.100", "netmask 255.255.255.0"}
expect := net.IPNet{ expect := []net.IPNet{
IP: net.IPv4(192, 168, 1, 100), {
Mask: net.IPv4Mask(255, 255, 255, 0), IP: net.IPv4(192, 168, 1, 100),
Mask: net.IPv4Mask(255, 255, 255, 0),
},
} }
iface, err := parseInterfaceStanza([]string{"eth", "inet", "static"}, options) iface, err := parseInterfaceStanza([]string{"eth", "inet", "static"}, options)
@ -207,7 +209,7 @@ func TestParseInterfaceStanzaStaticAddress(t *testing.T) {
if !ok { if !ok {
t.FailNow() t.FailNow()
} }
if !reflect.DeepEqual(static.address, expect) { if !reflect.DeepEqual(static.addresses, expect) {
t.FailNow() t.FailNow()
} }
} }