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:
parent
033c8d352f
commit
d6a0d0908c
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user