c820f2b1cf
Until support for bonding params is added to networkd, this will be neccessary in order to use bonding parameters (i.e. miimon, mode). This also makes it such that the 8012q module will only be loaded if the network config makes use of VLANs.
290 lines
6.4 KiB
Go
290 lines
6.4 KiB
Go
package network
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type InterfaceGenerator interface {
|
|
Name() string
|
|
Filename() string
|
|
Netdev() string
|
|
Link() string
|
|
Network() string
|
|
Type() string
|
|
ModprobeParams() string
|
|
}
|
|
|
|
type networkInterface interface {
|
|
InterfaceGenerator
|
|
Children() []networkInterface
|
|
setConfigDepth(int)
|
|
}
|
|
|
|
type logicalInterface struct {
|
|
name string
|
|
config configMethod
|
|
children []networkInterface
|
|
configDepth int
|
|
}
|
|
|
|
func (i *logicalInterface) Network() string {
|
|
config := fmt.Sprintf("[Match]\nName=%s\n\n[Network]\n", i.name)
|
|
|
|
for _, child := range i.children {
|
|
switch iface := child.(type) {
|
|
case *vlanInterface:
|
|
config += fmt.Sprintf("VLAN=%s\n", iface.name)
|
|
case *bondInterface:
|
|
config += fmt.Sprintf("Bond=%s\n", iface.name)
|
|
}
|
|
}
|
|
|
|
switch conf := i.config.(type) {
|
|
case configMethodStatic:
|
|
for _, nameserver := range conf.nameservers {
|
|
config += fmt.Sprintf("DNS=%s\n", nameserver)
|
|
}
|
|
if conf.address.IP != nil {
|
|
config += fmt.Sprintf("\n[Address]\nAddress=%s\n", conf.address.String())
|
|
}
|
|
for _, route := range conf.routes {
|
|
config += fmt.Sprintf("\n[Route]\nDestination=%s\nGateway=%s\n", route.destination.String(), route.gateway)
|
|
}
|
|
case configMethodDHCP:
|
|
config += "DHCP=true\n"
|
|
}
|
|
|
|
return config
|
|
}
|
|
|
|
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) ModprobeParams() string {
|
|
return ""
|
|
}
|
|
|
|
func (i *logicalInterface) setConfigDepth(depth int) {
|
|
i.configDepth = depth
|
|
}
|
|
|
|
type physicalInterface struct {
|
|
logicalInterface
|
|
}
|
|
|
|
func (p *physicalInterface) Name() string {
|
|
return p.name
|
|
}
|
|
|
|
func (p *physicalInterface) Netdev() string {
|
|
return ""
|
|
}
|
|
|
|
func (p *physicalInterface) Type() string {
|
|
return "physical"
|
|
}
|
|
|
|
type bondInterface struct {
|
|
logicalInterface
|
|
slaves []string
|
|
options map[string]string
|
|
}
|
|
|
|
func (b *bondInterface) Name() string {
|
|
return b.name
|
|
}
|
|
|
|
func (b *bondInterface) Netdev() string {
|
|
return fmt.Sprintf("[NetDev]\nKind=bond\nName=%s\n", b.name)
|
|
}
|
|
|
|
func (b *bondInterface) Type() string {
|
|
return "bond"
|
|
}
|
|
|
|
func (b *bondInterface) ModprobeParams() string {
|
|
params := ""
|
|
for name, val := range b.options {
|
|
params += fmt.Sprintf("%s=%s ", name, val)
|
|
}
|
|
params = strings.TrimSuffix(params, " ")
|
|
return params
|
|
}
|
|
|
|
type vlanInterface struct {
|
|
logicalInterface
|
|
id int
|
|
rawDevice string
|
|
}
|
|
|
|
func (v *vlanInterface) Name() string {
|
|
return v.name
|
|
}
|
|
|
|
func (v *vlanInterface) Netdev() string {
|
|
config := fmt.Sprintf("[NetDev]\nKind=vlan\nName=%s\n", v.name)
|
|
switch c := v.config.(type) {
|
|
case configMethodStatic:
|
|
if c.hwaddress != nil {
|
|
config += fmt.Sprintf("MACAddress=%s\n", c.hwaddress)
|
|
}
|
|
case configMethodDHCP:
|
|
if c.hwaddress != nil {
|
|
config += fmt.Sprintf("MACAddress=%s\n", c.hwaddress)
|
|
}
|
|
}
|
|
config += fmt.Sprintf("\n[VLAN]\nId=%d\n", v.id)
|
|
return config
|
|
}
|
|
|
|
func (v *vlanInterface) Type() string {
|
|
return "vlan"
|
|
}
|
|
|
|
func buildInterfaces(stanzas []*stanzaInterface) []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:
|
|
bondOptions := make(map[string]string)
|
|
for _, k := range []string{"mode", "miimon", "lacp-rate"} {
|
|
if v, ok := iface.options["bond-"+k]; ok && len(v) > 0 {
|
|
bondOptions[k] = v[0]
|
|
}
|
|
}
|
|
interfaceMap[iface.name] = &bondInterface{
|
|
logicalInterface{
|
|
name: iface.name,
|
|
config: iface.configMethod,
|
|
children: []networkInterface{},
|
|
},
|
|
iface.options["bond-slaves"],
|
|
bondOptions,
|
|
}
|
|
for _, slave := range iface.options["bond-slaves"] {
|
|
if _, ok := interfaceMap[slave]; !ok {
|
|
interfaceMap[slave] = &physicalInterface{
|
|
logicalInterface{
|
|
name: slave,
|
|
config: configMethodManual{},
|
|
children: []networkInterface{},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
case interfacePhysical:
|
|
if _, ok := iface.configMethod.(configMethodLoopback); ok {
|
|
continue
|
|
}
|
|
interfaceMap[iface.name] = &physicalInterface{
|
|
logicalInterface{
|
|
name: iface.name,
|
|
config: iface.configMethod,
|
|
children: []networkInterface{},
|
|
},
|
|
}
|
|
|
|
case interfaceVLAN:
|
|
var rawDevice string
|
|
id, _ := strconv.Atoi(iface.options["id"][0])
|
|
if device := iface.options["raw_device"]; len(device) == 1 {
|
|
rawDevice = device[0]
|
|
if _, ok := interfaceMap[rawDevice]; !ok {
|
|
interfaceMap[rawDevice] = &physicalInterface{
|
|
logicalInterface{
|
|
name: rawDevice,
|
|
config: configMethodManual{},
|
|
children: []networkInterface{},
|
|
},
|
|
}
|
|
}
|
|
}
|
|
interfaceMap[iface.name] = &vlanInterface{
|
|
logicalInterface{
|
|
name: iface.name,
|
|
config: iface.configMethod,
|
|
children: []networkInterface{},
|
|
},
|
|
id,
|
|
rawDevice,
|
|
}
|
|
}
|
|
}
|
|
return interfaceMap
|
|
}
|
|
|
|
func linkAncestors(interfaceMap map[string]networkInterface) {
|
|
for _, iface := range interfaceMap {
|
|
switch i := iface.(type) {
|
|
case *vlanInterface:
|
|
if parent, ok := interfaceMap[i.rawDevice]; ok {
|
|
switch p := parent.(type) {
|
|
case *physicalInterface:
|
|
p.children = append(p.children, iface)
|
|
case *bondInterface:
|
|
p.children = append(p.children, iface)
|
|
}
|
|
}
|
|
case *bondInterface:
|
|
for _, slave := range i.slaves {
|
|
if parent, ok := interfaceMap[slave]; ok {
|
|
switch p := parent.(type) {
|
|
case *physicalInterface:
|
|
p.children = append(p.children, iface)
|
|
case *bondInterface:
|
|
p.children = append(p.children, iface)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func markConfigDepths(interfaceMap map[string]networkInterface) {
|
|
rootInterfaceMap := make(map[string]networkInterface)
|
|
for k, v := range interfaceMap {
|
|
rootInterfaceMap[k] = v
|
|
}
|
|
|
|
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)
|
|
}
|
|
}
|