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 {
|
type InterfaceGenerator interface {
|
||||||
Name() string
|
Name() string
|
||||||
|
Filename() string
|
||||||
Netdev() string
|
Netdev() string
|
||||||
Link() string
|
Link() string
|
||||||
Network() string
|
Network() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type networkInterface interface {
|
||||||
|
InterfaceGenerator
|
||||||
|
Children() []networkInterface
|
||||||
|
setConfigDepth(int)
|
||||||
|
}
|
||||||
|
|
||||||
type logicalInterface struct {
|
type logicalInterface struct {
|
||||||
name string
|
name string
|
||||||
config configMethod
|
config configMethod
|
||||||
children []InterfaceGenerator
|
children []networkInterface
|
||||||
|
configDepth int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (i *logicalInterface) Network() string {
|
func (i *logicalInterface) Network() string {
|
||||||
@ -52,6 +60,18 @@ func (i *logicalInterface) Link() string {
|
|||||||
return ""
|
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 {
|
type physicalInterface struct {
|
||||||
logicalInterface
|
logicalInterface
|
||||||
}
|
}
|
||||||
@ -104,8 +124,20 @@ func (v *vlanInterface) Netdev() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
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 {
|
for _, iface := range stanzas {
|
||||||
switch iface.kind {
|
switch iface.kind {
|
||||||
case interfaceBond:
|
case interfaceBond:
|
||||||
@ -113,7 +145,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: iface.name,
|
name: iface.name,
|
||||||
config: iface.configMethod,
|
config: iface.configMethod,
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
},
|
},
|
||||||
iface.options["slaves"],
|
iface.options["slaves"],
|
||||||
}
|
}
|
||||||
@ -123,7 +155,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: slave,
|
name: slave,
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +169,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: iface.name,
|
name: iface.name,
|
||||||
config: iface.configMethod,
|
config: iface.configMethod,
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +183,7 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: rawDevice,
|
name: rawDevice,
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,14 +192,17 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: iface.name,
|
name: iface.name,
|
||||||
config: iface.configMethod,
|
config: iface.configMethod,
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
},
|
},
|
||||||
id,
|
id,
|
||||||
rawDevice,
|
rawDevice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return interfaceMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func linkAncestors(interfaceMap map[string]networkInterface) {
|
||||||
for _, iface := range interfaceMap {
|
for _, iface := range interfaceMap {
|
||||||
switch i := iface.(type) {
|
switch i := iface.(type) {
|
||||||
case *vlanInterface:
|
case *vlanInterface:
|
||||||
@ -192,11 +227,27 @@ func buildInterfaces(stanzas []*stanzaInterface) []InterfaceGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interfaces := make([]InterfaceGenerator, 0, len(interfaceMap))
|
func markConfigDepths(interfaceMap map[string]networkInterface) {
|
||||||
for _, iface := range interfaceMap {
|
rootInterfaceMap := make(map[string]networkInterface)
|
||||||
interfaces = append(interfaces, iface)
|
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) {
|
func TestPhysicalInterfaceNetwork(t *testing.T) {
|
||||||
p := physicalInterface{logicalInterface{
|
p := physicalInterface{logicalInterface{
|
||||||
name: "testname",
|
name: "testname",
|
||||||
children: []InterfaceGenerator{
|
children: []networkInterface{
|
||||||
&bondInterface{
|
&bondInterface{
|
||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "testbond1",
|
name: "testbond1",
|
||||||
@ -96,7 +96,7 @@ func TestBondInterfaceNetwork(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "testname",
|
name: "testname",
|
||||||
config: configMethodDHCP{},
|
config: configMethodDHCP{},
|
||||||
children: []InterfaceGenerator{
|
children: []networkInterface{
|
||||||
&bondInterface{
|
&bondInterface{
|
||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "testbond1",
|
name: "testbond1",
|
||||||
@ -251,7 +251,8 @@ func TestBuildInterfacesBlindBond(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "bond0",
|
name: "bond0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
|
configDepth: 1,
|
||||||
},
|
},
|
||||||
[]string{"eth0"},
|
[]string{"eth0"},
|
||||||
}
|
}
|
||||||
@ -259,7 +260,8 @@ func TestBuildInterfacesBlindBond(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "eth0",
|
name: "eth0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{bond0},
|
children: []networkInterface{bond0},
|
||||||
|
configDepth: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expect := []InterfaceGenerator{bond0, eth0}
|
expect := []InterfaceGenerator{bond0, eth0}
|
||||||
@ -286,7 +288,8 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "vlan0",
|
name: "vlan0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
|
configDepth: 1,
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
"eth0",
|
"eth0",
|
||||||
@ -295,7 +298,8 @@ func TestBuildInterfacesBlindVLAN(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "eth0",
|
name: "eth0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{vlan0},
|
children: []networkInterface{vlan0},
|
||||||
|
configDepth: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expect := []InterfaceGenerator{eth0, vlan0}
|
expect := []InterfaceGenerator{eth0, vlan0}
|
||||||
@ -357,7 +361,8 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "vlan1",
|
name: "vlan1",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
|
configDepth: 2,
|
||||||
},
|
},
|
||||||
1,
|
1,
|
||||||
"bond0",
|
"bond0",
|
||||||
@ -366,7 +371,8 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "vlan0",
|
name: "vlan0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
|
configDepth: 1,
|
||||||
},
|
},
|
||||||
0,
|
0,
|
||||||
"eth0",
|
"eth0",
|
||||||
@ -375,7 +381,8 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "bond1",
|
name: "bond1",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{},
|
children: []networkInterface{},
|
||||||
|
configDepth: 2,
|
||||||
},
|
},
|
||||||
[]string{"bond0"},
|
[]string{"bond0"},
|
||||||
}
|
}
|
||||||
@ -383,7 +390,8 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "bond0",
|
name: "bond0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{bond1, vlan1},
|
children: []networkInterface{bond1, vlan1},
|
||||||
|
configDepth: 1,
|
||||||
},
|
},
|
||||||
[]string{"eth0"},
|
[]string{"eth0"},
|
||||||
}
|
}
|
||||||
@ -391,7 +399,8 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
logicalInterface{
|
logicalInterface{
|
||||||
name: "eth0",
|
name: "eth0",
|
||||||
config: configMethodManual{},
|
config: configMethodManual{},
|
||||||
children: []InterfaceGenerator{bond0, vlan0},
|
children: []networkInterface{bond0, vlan0},
|
||||||
|
configDepth: 0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1}
|
expect := []InterfaceGenerator{eth0, bond0, bond1, vlan0, vlan1}
|
||||||
@ -399,3 +408,19 @@ func TestBuildInterfaces(t *testing.T) {
|
|||||||
t.FailNow()
|
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 {
|
func WriteNetworkdConfigs(interfaces []network.InterfaceGenerator) error {
|
||||||
for _, iface := range interfaces {
|
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 {
|
if err := writeConfig(filename, iface.Netdev()); err != nil {
|
||||||
return err
|
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 {
|
if err := writeConfig(filename, iface.Link()); err != nil {
|
||||||
return err
|
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 {
|
if err := writeConfig(filename, iface.Network()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user