diff --git a/network/interface.go b/network/interface.go index 070c4ea..be0b04b 100644 --- a/network/interface.go +++ b/network/interface.go @@ -7,15 +7,23 @@ import ( type InterfaceGenerator interface { Name() string + Filename() string Netdev() string Link() string Network() string } +type networkInterface interface { + InterfaceGenerator + Children() []networkInterface + setConfigDepth(int) +} + type logicalInterface struct { - name string - config configMethod - children []InterfaceGenerator + name string + config configMethod + children []networkInterface + configDepth int } func (i *logicalInterface) Network() string { @@ -52,6 +60,18 @@ func (i *logicalInterface) Link() string { return "" } +func (i *logicalInterface) Filename() string { + return fmt.Sprintf("%02x-%s", i.configDepth, i.name) +} + +func (i *logicalInterface) Children() []networkInterface { + return i.children +} + +func (i *logicalInterface) setConfigDepth(depth int) { + i.configDepth = depth +} + type physicalInterface struct { logicalInterface } @@ -104,8 +124,20 @@ func (v *vlanInterface) Netdev() string { } func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { - interfaceMap := make(map[string]InterfaceGenerator) + interfaceMap := createInterfaces(stanzas) + linkAncestors(interfaceMap) + markConfigDepths(interfaceMap) + interfaces := make([]InterfaceGenerator, 0, len(interfaceMap)) + for _, iface := range interfaceMap { + interfaces = append(interfaces, iface) + } + + return interfaces +} + +func createInterfaces(stanzas []*stanzaInterface) map[string]networkInterface { + interfaceMap := make(map[string]networkInterface) for _, iface := range stanzas { switch iface.kind { case interfaceBond: @@ -113,7 +145,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { logicalInterface{ name: iface.name, config: iface.configMethod, - children: []InterfaceGenerator{}, + children: []networkInterface{}, }, iface.options["slaves"], } @@ -123,7 +155,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { logicalInterface{ name: slave, config: configMethodManual{}, - children: []InterfaceGenerator{}, + children: []networkInterface{}, }, } } @@ -137,7 +169,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { logicalInterface{ name: iface.name, config: iface.configMethod, - children: []InterfaceGenerator{}, + children: []networkInterface{}, }, } @@ -151,7 +183,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { logicalInterface{ name: rawDevice, config: configMethodManual{}, - children: []InterfaceGenerator{}, + children: []networkInterface{}, }, } } @@ -160,14 +192,17 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { logicalInterface{ name: iface.name, config: iface.configMethod, - children: []InterfaceGenerator{}, + children: []networkInterface{}, }, id, rawDevice, } } } + return interfaceMap +} +func linkAncestors(interfaceMap map[string]networkInterface) { for _, iface := range interfaceMap { switch i := iface.(type) { case *vlanInterface: @@ -192,11 +227,27 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator { } } } +} - interfaces := make([]InterfaceGenerator, 0, len(interfaceMap)) - for _, iface := range interfaceMap { - interfaces = append(interfaces, iface) +func markConfigDepths(interfaceMap map[string]networkInterface) { + rootInterfaceMap := make(map[string]networkInterface) + for k, v := range interfaceMap { + rootInterfaceMap[k] = v } - return interfaces + for _, iface := range interfaceMap { + for _, child := range iface.Children() { + delete(rootInterfaceMap, child.Name()) + } + } + for _, iface := range rootInterfaceMap { + setDepth(iface, 0) + } +} + +func setDepth(iface networkInterface, depth int) { + iface.setConfigDepth(depth) + for _, child := range iface.Children() { + setDepth(child, depth+1) + } } diff --git a/network/interface_test.go b/network/interface_test.go index 25b4c3b..c98bf60 100644 --- a/network/interface_test.go +++ b/network/interface_test.go @@ -30,7 +30,7 @@ func TestPhysicalInterfaceLink(t *testing.T) { func TestPhysicalInterfaceNetwork(t *testing.T) { p := physicalInterface{logicalInterface{ name: "testname", - children: []InterfaceGenerator{ + children: []networkInterface{ &bondInterface{ logicalInterface{ name: "testbond1", @@ -96,7 +96,7 @@ func TestBondInterfaceNetwork(t *testing.T) { logicalInterface{ name: "testname", config: configMethodDHCP{}, - children: []InterfaceGenerator{ + children: []networkInterface{ &bondInterface{ logicalInterface{ name: "testbond1", @@ -249,17 +249,19 @@ func TestBuildInterfacesBlindBond(t *testing.T) { interfaces := buildInterfaces(stanzas) bond0 := &bondInterface{ logicalInterface{ - name: "bond0", - config: configMethodManual{}, - children: []InterfaceGenerator{}, + name: "bond0", + config: configMethodManual{}, + children: []networkInterface{}, + configDepth: 1, }, []string{"eth0"}, } eth0 := &physicalInterface{ logicalInterface{ - name: "eth0", - config: configMethodManual{}, - children: []InterfaceGenerator{bond0}, + name: "eth0", + config: configMethodManual{}, + children: []networkInterface{bond0}, + configDepth: 0, }, } expect := []InterfaceGenerator{bond0, eth0} @@ -284,18 +286,20 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) { interfaces := buildInterfaces(stanzas) vlan0 := &vlanInterface{ logicalInterface{ - name: "vlan0", - config: configMethodManual{}, - children: []InterfaceGenerator{}, + name: "vlan0", + config: configMethodManual{}, + children: []networkInterface{}, + configDepth: 1, }, 0, "eth0", } eth0 := &physicalInterface{ logicalInterface{ - name: "eth0", - config: configMethodManual{}, - children: []InterfaceGenerator{vlan0}, + name: "eth0", + config: configMethodManual{}, + children: []networkInterface{vlan0}, + configDepth: 0, }, } expect := []InterfaceGenerator{eth0, vlan0} @@ -355,43 +359,48 @@ func TestBuildInterfaces(t *testing.T) { interfaces := buildInterfaces(stanzas) vlan1 := &vlanInterface{ logicalInterface{ - name: "vlan1", - config: configMethodManual{}, - children: []InterfaceGenerator{}, + name: "vlan1", + config: configMethodManual{}, + children: []networkInterface{}, + configDepth: 2, }, 1, "bond0", } vlan0 := &vlanInterface{ logicalInterface{ - name: "vlan0", - config: configMethodManual{}, - children: []InterfaceGenerator{}, + name: "vlan0", + config: configMethodManual{}, + children: []networkInterface{}, + configDepth: 1, }, 0, "eth0", } bond1 := &bondInterface{ logicalInterface{ - name: "bond1", - config: configMethodManual{}, - children: []InterfaceGenerator{}, + name: "bond1", + config: configMethodManual{}, + children: []networkInterface{}, + configDepth: 2, }, []string{"bond0"}, } bond0 := &bondInterface{ logicalInterface{ - name: "bond0", - config: configMethodManual{}, - children: []InterfaceGenerator{bond1, vlan1}, + name: "bond0", + config: configMethodManual{}, + children: []networkInterface{bond1, vlan1}, + configDepth: 1, }, []string{"eth0"}, } eth0 := &physicalInterface{ logicalInterface{ - name: "eth0", - config: configMethodManual{}, - children: []InterfaceGenerator{bond0, vlan0}, + name: "eth0", + config: configMethodManual{}, + children: []networkInterface{bond0, vlan0}, + configDepth: 0, }, } expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1} @@ -399,3 +408,19 @@ func TestBuildInterfaces(t *testing.T) { t.FailNow() } } + +func TestFilename(t *testing.T) { + for _, tt := range []struct { + i logicalInterface + f string + }{ + {logicalInterface{name: "iface", configDepth: 0}, "00-iface"}, + {logicalInterface{name: "iface", configDepth: 9}, "09-iface"}, + {logicalInterface{name: "iface", configDepth: 10}, "0a-iface"}, + {logicalInterface{name: "iface", configDepth: 53}, "35-iface"}, + } { + if tt.i.Filename() != tt.f { + t.Fatalf("bad filename (%q): got %q, want %q", tt.i, tt.i.Filename(), tt.f) + } + } +} diff --git a/system/networkd.go b/system/networkd.go index f49a15d..a982869 100644 --- a/system/networkd.go +++ b/system/networkd.go @@ -66,15 +66,15 @@ func restartNetworkd() error { func WriteNetworkdConfigs(interfaces []network.InterfaceGenerator) error { for _, iface := range interfaces { - filename := path.Join(runtimeNetworkPath, fmt.Sprintf("%s.netdev", iface.Name())) + filename := path.Join(runtimeNetworkPath, fmt.Sprintf("%s.netdev", iface.Filename())) if err := writeConfig(filename, iface.Netdev()); err != nil { return err } - filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.link", iface.Name())) + filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.link", iface.Filename())) if err := writeConfig(filename, iface.Link()); err != nil { return err } - filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.network", iface.Name())) + filename = path.Join(runtimeNetworkPath, fmt.Sprintf("%s.network", iface.Filename())) if err := writeConfig(filename, iface.Network()); err != nil { return err }