fix(network): Generate prefixes to ensure proper lexicographical ordering

In order for networkd to properly configure the network interfaces, the configs must be
prefixed to ensure that they load in the correct order (parent interfaces have a lower
prefix than their children).
This commit is contained in:
Alex Crawford 2014-06-12 18:13:19 -05:00
parent 033c8d352f
commit d6a0d0908c
3 changed files with 121 additions and 45 deletions

View File

@ -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
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)
}
}

View File

@ -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",
@ -251,7 +251,8 @@ func TestBuildInterfacesBlindBond(t *testing.T) {
logicalInterface{
name: "bond0",
config: configMethodManual{},
children: []InterfaceGenerator{},
children: []networkInterface{},
configDepth: 1,
},
[]string{"eth0"},
}
@ -259,7 +260,8 @@ func TestBuildInterfacesBlindBond(t *testing.T) {
logicalInterface{
name: "eth0",
config: configMethodManual{},
children: []InterfaceGenerator{bond0},
children: []networkInterface{bond0},
configDepth: 0,
},
}
expect := []InterfaceGenerator{bond0, eth0}
@ -286,7 +288,8 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) {
logicalInterface{
name: "vlan0",
config: configMethodManual{},
children: []InterfaceGenerator{},
children: []networkInterface{},
configDepth: 1,
},
0,
"eth0",
@ -295,7 +298,8 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) {
logicalInterface{
name: "eth0",
config: configMethodManual{},
children: []InterfaceGenerator{vlan0},
children: []networkInterface{vlan0},
configDepth: 0,
},
}
expect := []InterfaceGenerator{eth0, vlan0}
@ -357,7 +361,8 @@ func TestBuildInterfaces(t *testing.T) {
logicalInterface{
name: "vlan1",
config: configMethodManual{},
children: []InterfaceGenerator{},
children: []networkInterface{},
configDepth: 2,
},
1,
"bond0",
@ -366,7 +371,8 @@ func TestBuildInterfaces(t *testing.T) {
logicalInterface{
name: "vlan0",
config: configMethodManual{},
children: []InterfaceGenerator{},
children: []networkInterface{},
configDepth: 1,
},
0,
"eth0",
@ -375,7 +381,8 @@ func TestBuildInterfaces(t *testing.T) {
logicalInterface{
name: "bond1",
config: configMethodManual{},
children: []InterfaceGenerator{},
children: []networkInterface{},
configDepth: 2,
},
[]string{"bond0"},
}
@ -383,7 +390,8 @@ func TestBuildInterfaces(t *testing.T) {
logicalInterface{
name: "bond0",
config: configMethodManual{},
children: []InterfaceGenerator{bond1, vlan1},
children: []networkInterface{bond1, vlan1},
configDepth: 1,
},
[]string{"eth0"},
}
@ -391,7 +399,8 @@ func TestBuildInterfaces(t *testing.T) {
logicalInterface{
name: "eth0",
config: configMethodManual{},
children: []InterfaceGenerator{bond0, vlan0},
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)
}
}
}

View File

@ -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
}