Skip to content

Commit

Permalink
Merge branch 'lacp' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
ydirson committed Jan 17, 2023
2 parents aec3f8f + 86090cd commit ee7f509
Show file tree
Hide file tree
Showing 11 changed files with 315 additions and 101 deletions.
30 changes: 30 additions & 0 deletions answerfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ def parseFreshInstall(self):
results.update(self.parseAssembleRaid())
results.update(self.parseRaid())
results.update(self.parseDisks())
results.update(self.parseBonding())
results.update(self.parseInterface())
results.update(self.parseRootPassword())
results.update(self.parseNSConfig())
Expand Down Expand Up @@ -391,6 +392,35 @@ def parseFCoEInterface(self):

return results

def parseBonding(self):
results = {}
nethw = netutil.scanConfiguration()

nodes = getElementsByTagName(self.top_node, ['bonding'])
if len(nodes) > 1:
raise AnswerfileException("<bonding> must appear only once")
if nodes:
node = nodes[0]
bond_name = getStrAttribute(node, ['name'], mandatory=True)
if bond_name != "bond0":
raise AnswerfileException("<bonding> name must be 'bond0'")

bond_mode = getStrAttribute(node, ['mode'], mandatory=True)
if bond_mode != "lacp":
raise AnswerfileException("<bonding> mode must be 'lacp'")

bond_members_str = getStrAttribute(node, ['members'], mandatory=True)
bond_members = bond_members_str.split(",")
if len(bond_members) < 2:
raise AnswerfileException("<bonding> members must be at least two")
for member in bond_members:
if member not in nethw:
raise AnswerfileException("<bonding> member %r not in detected NICs" % (member,))

results['bonding'] = dict(name=bond_name, mode=bond_mode, members=bond_members)

return results

def parseInterface(self):
results = {}
node = getElementsByTagName(self.top_node, ['admin-interface'], mandatory=True)[0]
Expand Down
4 changes: 4 additions & 0 deletions backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,10 @@ def configureNetworking(mounts, admin_iface, admin_bridge, admin_config, hn_conf
print >>mc, "IPv6_GATEWAY='%s'" % admin_config.ipv6_gateway
if admin_config.vlan:
print >>mc, "VLAN='%d'" % admin_config.vlan
if admin_config.bond_mode is not None:
print >>mc, "BOND_MODE='%s'" % admin_config.bond_mode
print >>mc, "BOND_MEMBERS='%s'" % ','.join(admin_config.bond_members)

mc.close()

if network_backend == constants.NETWORK_BACKEND_VSWITCH:
Expand Down
8 changes: 8 additions & 0 deletions doc/answerfile.txt
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,14 @@ Common Elements
Specifies additional devices to be included in the local SR.


<bonding name="bond0" mode="lacp" members="eth,eth[,eth]*"/>

Join given ethernet interfaces using LACP bonding. Name of
resulting interface must be "bond0". It can be then be used with

<admin-interface name="bond0"/>


<admin-interface name="eth"/> | <admin-interface hwaddr="mac"/>

Specifies the initial management interface.
Expand Down
18 changes: 13 additions & 5 deletions doc/parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -122,29 +122,37 @@ Installer
Proceed with installation/upgrade.


--answerfile=ans
--answerfile=url

Read answerfile and perform a non-interactive installation
reporting status using screens.


--rt_answerfile=ans
--rt_answerfile=url

Read answerfile and perform a non-interactive installation
reporting status to the console as text.


--answerfile_generator=script
--answerfile_generator=url

Retrieve script, run it and use the output of it as an answerfile.


--answerfile_device[D]=eth|mac|all | --network_device=eth|mac|all
--network_device=eth|mac|lacp:members=eth,eth[,eth]*|all
--answerfile_device[D]=...

Bring up networking on the given interface to allow access to
answerfiles.

Default: all
Specification of LACP bonding configures a bond0 interfaces with
given members.

Default: "all" if a non-local URL is specified for any of the above
answerfile parameters, else no device is started

--answerfile_device is a deprecated alias, and accepts the same
parameters as --network_device.


--map_netdev=eth:d|s:mac|pci[[index]]|ppn
Expand Down
29 changes: 20 additions & 9 deletions init
Original file line number Diff line number Diff line change
Expand Up @@ -51,23 +51,34 @@ def configureNetworking(ui, device, config):

nethw = netutil.scanConfiguration()
netcfg = {}
for i in nethw:
if (device == i or device == nethw[i].hwaddr) and mode == 'static':
netcfg[i] = NetInterface(NetInterface.Static, nethw[i].hwaddr,
config_dict['ip'], config_dict['netmask'],
config_dict['gateway'], config_dict['dns'],
config_dict['domain'], config_dict['vlan'])

if device.startswith("lacp:"):
bond_mode, bond_config = device.split(":", 1)
device = "bond0"
assert bond_config.startswith("members=")
k, v = bond_config.split("=", 1)
bond_members = v.split(",")
netutil.configure_bonding_interface(nethw, device, "lacp", bond_members)

for devname, nic in nethw.items():
if (device == devname or device == nic.hwaddr) and mode == 'static':
netcfg[devname] = NetInterface(NetInterface.Static, nic.hwaddr,
config_dict['ip'], config_dict['netmask'],
config_dict['gateway'], config_dict['dns'],
config_dict['domain'], config_dict['vlan'],
bond_mode=nic.bond_mode, bond_members=nic.bond_members)
else:
netcfg[i] = NetInterface(NetInterface.DHCP, nethw[i].hwaddr,
vlan=config_dict['vlan'])
netcfg[devname] = NetInterface(NetInterface.DHCP, nic.hwaddr,
vlan=config_dict['vlan'],
bond_mode=nic.bond_mode, bond_members=nic.bond_members)

netutil.writeNetInterfaceFiles(netcfg)
netutil.writeResolverFile(netcfg, '/etc/resolv.conf')

iface_to_start = []
if device == 'all':
iface_to_start.extend(netcfg.keys())
elif device.startswith('eth'):
elif device.startswith('eth') or device.startswith('bond'):
if device in nethw:
iface_to_start.append(device)
else:
Expand Down
95 changes: 74 additions & 21 deletions netinterface.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class NetInterface:
Autoconf = 3

def __init__(self, mode, hwaddr, ipaddr=None, netmask=None, gateway=None,
dns=None, domain=None, vlan=None):
dns=None, domain=None, vlan=None, bond_mode=None, bond_members=None):
assert mode is None or mode == self.Static or mode == self.DHCP
if ipaddr == '':
ipaddr = None
Expand Down Expand Up @@ -61,6 +61,13 @@ def __init__(self, mode, hwaddr, ipaddr=None, netmask=None, gateway=None,
self.ipv6addr = None
self.ipv6_gateway = None

self.bond_mode = bond_mode
if bond_mode is not None:
# Not `balance-slb` because it's openvswitch specific
assert bond_mode in ["lacp", "active-backup"]
assert bond_members is not None
self.bond_members = bond_members

def __repr__(self):
hw = "hwaddr = '%s' " % self.hwaddr

Expand All @@ -83,7 +90,7 @@ def __repr__(self):
ipv6 = "autoconf"
else:
ipv6 = "None"
vlan = ("vlan = '%d' " % self.vlan) if self.vlan else ""
vlan = (" vlan='%d' " % self.vlan) if self.vlan else ""

return "<NetInterface: %s%s ipv4:%s ipv6:%s>" % (hw, vlan, ipv4, ipv6)

Expand Down Expand Up @@ -164,30 +171,76 @@ def writeRHStyleInterface(self, iface):
""" Write a RedHat-style configuration entry for this interface to
file object f using interface name iface. """

def writeBondMember(index, member):
""" Write a RedHat-style configuration entry for a bond member. """

with open('/etc/sysconfig/network-scripts/ifcfg-%s' % member, 'w') as f:
f.write("NAME=%s-slave%d\n" % (iface, index))
f.write("DEVICE=%s\n" % member)
f.write("ONBOOT=yes\n")
f.write("MASTER=%s\n" % iface)
f.write("SLAVE=yes\n")
f.write("BOOTPROTO=none\n")
f.write("Type=Ethernet\n")

def writeBondMaster():
""" Write a RedHat-style configuration entry for a bond master. """

with open('/etc/sysconfig/network-scripts/ifcfg-%s' % iface, 'w') as f:
f.write("NAME=%s\n" % iface)
f.write("DEVICE=%s\n" % iface)
f.write("ONBOOT=yes\n")
f.write("Type=Bond\n")
f.write("NOZEROCONF=yes\n")
f.write("BONDING_MASTER=yes\n")
if self.bond_mode == "lacp":
f.write("BONDING_OPTS=\"mode=4 miimon=100\"\n")
elif self.bond_mode == "active-backup":
f.write("BONDING_OPTS=\"mode=1 miimon=100\"\n")

if self.vlan:
f.write("BOOTPROTO=none\n")
else:
writeIpConfig(f)

def writeIface(iface_name):
with open('/etc/sysconfig/network-scripts/ifcfg-%s' % iface_name, 'w') as f:
f.write("NAME=%s\n" % iface_name)
f.write("DEVICE=%s\n" % iface_name)
f.write("ONBOOT=yes\n")
writeIpConfig(f)
if self.vlan:
f.write("VLAN=yes\n")

def writeIpConfig(f):
if self.mode == self.DHCP:
f.write("BOOTPROTO=dhcp\n")
f.write("PERSISTENT_DHCLIENT=1\n")
else:
# CA-11825: broadcast needs to be determined for non-standard networks
bcast = self.getBroadcast()
f.write("BOOTPROTO=none\n")
f.write("IPADDR=%s\n" % self.ipaddr)
if bcast is not None:
f.write("BROADCAST=%s\n" % bcast)
f.write("NETMASK=%s\n" % self.netmask)
if self.gateway:
f.write("GATEWAY=%s\n" % self.gateway)

assert self.modev6 is None
assert self.mode

iface_vlan = self.getInterfaceName(iface)

f = open('/etc/sysconfig/network-scripts/ifcfg-%s' % iface_vlan, 'w')
f.write("DEVICE=%s\n" % iface_vlan)
f.write("ONBOOT=yes\n")
if self.mode == self.DHCP:
f.write("BOOTPROTO=dhcp\n")
f.write("PERSISTENT_DHCLIENT=1\n")
if self.bond_mode:
# configuration of the bond interface
for idx, member in enumerate(self.bond_members):
writeBondMember(idx, member)
writeBondMaster() # ... includes IP config if not using VLAN ...
if self.vlan:
writeIface(iface_vlan) # ... but here when using VLAN
else:
# CA-11825: broadcast needs to be determined for non-standard networks
bcast = self.getBroadcast()
f.write("BOOTPROTO=none\n")
f.write("IPADDR=%s\n" % self.ipaddr)
if bcast is not None:
f.write("BROADCAST=%s\n" % bcast)
f.write("NETMASK=%s\n" % self.netmask)
if self.gateway:
f.write("GATEWAY=%s\n" % self.gateway)
if self.vlan:
f.write("VLAN=yes\n")
f.close()

writeIface(iface_vlan)

def waitUntilUp(self, iface):
if not self.isStatic():
Expand Down
Loading

0 comments on commit ee7f509

Please sign in to comment.