Git Product home page Git Product logo

bonding's Introduction

Linux Bonding Script

This script is used to configure bonding on Linux machines, and to determine which interface groups (peers) are available for bonding.

Features

  • Determination of interface groups (peers)
  • Configuration of interface bonding on Linux

Supported Operating Systems

  • Red Hat Enterprise Linux (Versions >= 5)
  • CentOS (Versions >= 5)
  • Fedora (Versions >= 10)
  • Debian (Versions >= 5)
  • Ubuntu (Versions >= 10.04)

Usage

$ python bonding.py --help
Usage:
  bonding.py [--nopeers]
  bonding.py --onlypeers
  bonding.py --automated
  bonding.py --unattend --bond=BOND --ip=ADDR --netmask=MASK --iface=IFACE1 
             --iface=IFACE2 [--iface=IFACE3 ...] [--gateway=GW] [--mode=MODE]

A script used to configure bonding on Linux machines, and to determine which
interface groups (peers) are available for bonding.
------------------------------------------------------------------------------
https://github.com/sivel/bonding

Options:
  -h, --help           show this help message and exit
  --version            Show the version number and exit

  Peers:
    --onlypeers        Only run the peers portion of this utility, to identify
                       bonded peer interfaces
    --nopeers          Do not run the peers portion of this utility
    --peerswait=SECS   The number of seconds to wait for switch port
                       negotiation. Default 5

  Unattended:
    --automated        Whether to run this command automated, this is
                       different from unattended which requires information
                       about how to configure the bond. This option requires
                       no additional options and will ignore them
    --unattend         Whether to run this command unattended
    --bond=BOND        The bonded master interface name. Required when using
                       --unattend
    --ip=IP            The IP address to use in the bond. Required when using
                       --unattend
    --netmask=NETMASK  The Netmask to use in the bond. Required when using
                       --unattend
    --iface=IFACE      The interfaces to be used in the bond, specify multiple
                       times for multiple interfaces. Required when using
                       --unattend
    --gateway=GATEWAY  The default gateway to use for the system, if this is
                       specified, the gateway and gateway dev will be updated.
                       default: none
    --mode=MODE        The bonding mode to be used. default: active-backup

Exit Codes

Generic

1: Generic Error
2: Not all options provided for an unattended configuration

Automated

100: There are no interfaces that contain the default route
101: The gateway device is already a master/bonded interface
102: There is no IP Address configured on the device containing the default route.
103: There is no Network Mask configured on the device containing the default route.
104: Automated bonding will only work when there are exactly 2 peer interfaces, more than 2 found.
105: Interface is already part of a bond

Operating System

200: OS Unsupported
201: Backup directory already exists
202: Red Hat Network Manager enabled
203: Debian ifenslave package is not installed or cannot be located
204: Interface(s) starting with __tmp exist, indicative of misconfigured network interfaces

Bugs

Submit bugs, feature requests, etc as Issues

Contributing

  1. Fork it
  2. Branch it
  3. Commit it
  4. Push it
  5. Pull request it

bonding's People

Contributors

davidwittman avatar robert-thompson avatar sivel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bonding's Issues

Support RHEL7 / CentOS7 using pure nmcli

The new RHEL7 / CentOS7 methodology is to prefer using NetworkManager's nmcli based operation over direct editing of config files; we need to support building bonding using the new vendor methodology, and it's actually simpler.

Groundwork: the systemd unit NetworkManager.service is preconfigured in /etc/NetworkManager/NetworkManager.conf with this:

[main]
plugins=ifcfg-rh

This plugin is fully detailed in the man page nm-settings-ifcfg-rh which is part of the NetworkManager RPM. It provides a comprehensive set of tables of the old FOO=bar values to the new settings along with the nmcli man page. I have wirtten a proof of concept script using VirtualBox and two interfaces on the same network:

https://github.com/troyengel/scripts/blob/master/nm4bond.sh

The takeaways I gained from this:

  1. the /etc/sysconfig/network file will respect a global GATEWAY and GATEWAYDEV setting, however this is not how Red Hat would like for it to be done now; they prefer the values be set as part of the interface. the file is empty by default.
  2. given the above, determining the default route methodology was interesting until I found this posting from Dan Williams at Red Hat: https://mail.gnome.org/archives/networkmanager-list/2014-July/msg00080.html -- you'll see in my PoC script that I'm setting 'connection.autoconnect-priority 99' based on his post and the man page.
  3. unlike earlier releases, we want to leave NM_CONTROLLED alone and not set it to 'no'; the NetworkManager service runs along with the traditional /etc/init.d/network script.
  4. the 'route', 'netstat' and other tools part of RPM net-tools is not installed on a default Miniman installation; the ifenslave binary is now part of RPM iputils, so no longer a unique RPM.
  5. I think NOZEROCONF is deprecated now, we should probably just ignore doing anything with it (but I could be wrong - insifficient information)
  6. the new 'ipv4.ignore-auto-dns' is what causes NM to write out the DNS*= lines from ifcfg-? to /etc/resolv.conf; you'll see I'm setting that to 'no' to cause the writes to happen, we want that file populated.

A few quotes I found handy - partially from Red hat's website docs, part from the man pages:

"The default gateway is determined by the network scripts which parse the /etc/sysconfig/network file first and then the network interface ifcfg files for interfaces that are โ€œupโ€. The ifcfg files are parsed in numerically ascending order, and the last GATEWAY directive to be read is used to compose a default route in the routing table."

"The default route can thus be indicated by means of the GATEWAY directive and can be specified either globally or in interface-specific configuration files. Specifying the gateway globally has certain advantages in static networking environments, especially if more than one network interface is present. It can make fault finding simpler if applied consistently. "

"Each NetworkManager connection maps to one ifcfg-* file, with possible usage of keys-* for passwords, route-* for static IPv4 routes and route6-* for static IPv6 routes."

"The UUID values in the config files must be unique. You can use uuidgen command line tool to generate such values. Alternatively, you can leave out UUID entirely. In that case NetworkManager will generate a UUID based on the file name."

And lastly, even though I'm not sure it's a part of bonding.py -- the route-? files will accept both the 'ip' style and NM style route configurations (so somehow it knows which one is which):

ADDRESS0=192.168.0.0
NETMASK0=255.255.255.0
GATEWAY0=10.0.2.1

vs.

192.168.0.0/24 via 10.0.2.1 dev eth0

The former/first is what's created when you use the nmcli tool to set the routes, which is preferred. The latter seems to be for backwards compatibility; likewise, the /etc/sysconfig/static-routes is still respected but only by the add-on /etc/init.d/network script and not NM.

Oracle Linux support

Oracle Linux is a RHEL clone that adheres exactly to the design as CentOS does, even more closely - they do not even change /etc/redhat-release and instead provide /etc/oracle-release. The bonding code runs fine if we allow oracle in the distro array as well. (PR coming)

Missing default route on RHEL7.5

We ran into an issue running the script on RHEL 7.5 which uses NetworkManager-1.10.2. This new version of NetworkManager has code for the ifcfg-rh plugin that when adding the new interface it will compare if the GATEWAYDEV entry in /etc/sysconfig/network and the DEVICE entry in /etc/sysconfig/network-scripts/ifcfg-bond0 are the same, if they are different it will ignore the GATEWAY entry.

The consequence of ignoring the GATEWAY is that the server will be missing the default route and loose remote access through the public interface until the network service is manually restarted through a console.

The solution I found is to update the /etc/sysconfig/network file before running the nmcli connection add for the bond interface that way the GATEWAYDEV and GATEWAY will match and we can retain remote public access.

The new code in 1.10.2 can be found between lines 1288 - 1351 in the following link:
https://github.com/NetworkManager/NetworkManager/blob/7ebc9258452623679b9f1c27aee94c528c14b273/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c

More specifically in lines 1341 - 1345 where it ignores the GATEWAY entry after GATEWAYDEV and DEVICE did not match:

			if (never_default)
				PARSE_WARNING ("GATEWAY will be ignored when DEFROUTE is disabled");
			gateway = g_strdup (nm_utils_inet4_ntop (gw, inet_buf));
			g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, gateway, NULL);
}

I have a pull request on the way, while it keeps the exact same code, it just updates the /etc/sysconfig/network file before running the nmcli connection add commands. This solution has been tested on RHEL6.9, RHEL7.4, RHEL7.5 and Ubuntu 16.04 to ensure compatibility.

Failure when there are more than 10 interfaces

When using this script to set up bonding on a server with 12 interfaces, I got the following traceback:

Scanning for bonding peers...
Enabling interfaces............
Sleeping 5 seconds for switch port negotiation...
Scanning....Traceback (most recent call last):
File "/home/rack/.adc/bonding/bonding.py", line 949, in
handleArgs()
File "/home/rack/.adc/bonding/bonding.py", line 934, in handleArgs
groups = peers(False)
File "/home/rack/.adc/bonding/bonding.py", line 286, in peers
data = s2.recv(60)
socket.error: [Errno 100] Network is down

Looking into this, it appears that the script enabled interfaces eth0-9, but did not enable eth10 or eth11 and then failed while scanning for peers.

The first 8 interfaces (eth0-7) are standard gigabit ethernet and eth8-11 are 10G fiber ethernet, but that does not seem to matter. The bonding script worked after I manually enabled the interfaces. Please let me know if you need any more info.

Thanks,
Danny

MTU configuration

Would it be possible to add MTU support to this script ?
I'm testing it for usage in ORACLE RAC configurations where the MTU on the interconnect needs to be configured for Jumbo Frames

Thanks it's a great script and if I knew a little more python than I do I would have put up a pull request instead of this :)

Request for devel -> master PR merge for EL7

We added the EL7 nmcli support in the devel branch 9 months ago; it's been working in Production for all out internal builds since then without error. I would like to get this merged into master so we can make it easier for the end user to get the 'right' code.

Bad interface name crashes on IOError

A server that has a messed up udev and an interface "rename8" listed causes bonding.py to crash with an exception:

# python bonding.py --onlypeers
Enabling interfaces..........Traceback (most recent call last):
  File "bonding.py", line 986, in <module>
    handleArgs()
  File "bonding.py", line 959, in handleArgs
    groups = peers(False)
  File "bonding.py", line 259, in peers
    set_iface_flag(iface, IFF_UP)
  File "bonding.py", line 148, in set_iface_flag
    fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifreq)
IOError: [Errno 19] No such device

I attempted to do a little debugging to gather data on where the exception handler can be added; I added a pdb.set_trace() in set_iface_flag() and stepped through it:

.> bonding.py(143)set_iface_flag()
-> s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
(Pdb) p ifname
'rename8'
(Pdb) n
> bonding.py(144)set_iface_flag()
-> if not flags:
(Pdb) n
> bonding.py(145)set_iface_flag()
-> flags = 0
(Pdb) n
> bonding.py(146)set_iface_flag()
-> ifreq = fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, struct.pack('256s', ifname[:15]))
(Pdb) n
> bonding.py(147)set_iface_flag()
-> (flags,) = struct.unpack('16xH', ifreq[:18])
(Pdb) n
> bonding.py(148)set_iface_flag()
-> flags |= flag
(Pdb) n
> bonding.py(149)set_iface_flag()
-> ifreq = struct.pack('4s12xH', ifname, flags)
(Pdb) n
> bonding.py(150)set_iface_flag()
-> fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifreq)
(Pdb) n
IOError: (19, 'No such device')
> bonding.py(150)set_iface_flag()
-> fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifreq)

(Pdb) list
145         flags = 0
146         ifreq = fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, struct.pack('256s', ifname[:15]))
147         (flags,) = struct.unpack('16xH', ifreq[:18])
148       flags |= flag
149       ifreq = struct.pack('4s12xH', ifname, flags)
150  ->   fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifreq)
151       s.close()
152       return flags
153     
154     def get_iface_list():
155       ifaces = []


(Pdb) locals()
{'ifreq': 'rena\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03\x10', 'flag': 1, 's': <socket._socketobject object at 0x276d980>, '__exception__': (<type 'exceptions.IOError'>, (19, 'No such device')), 'flags': 4099, 'ifname': 'rename8'}

(Pdb) p s.fileno()
4

The server itself needed to be fixed (delete udev rules, reboot, etc.) but the bonding.py should probably have an exception handler added if this crashes. It's somewhat analogous to the __tmpXXXX interfaces from udev.

Ubuntu 14.04.1: AttributeError: 'module' object has no attribute 'SO_BINDTODEVICE'

I pulled the latest mainline bonding.py and uploaded to a server; attempting to run ends up with this error:

# python bonding.py --onlypeers
Enabling interfaces........
Sleeping 5 seconds for switch port negotiation...
Scanning..Traceback (most recent call last):
  File "bonding.py", line 988, in <module>
    handleArgs()
  File "bonding.py", line 961, in handleArgs
    groups = peers(False)
  File "bonding.py", line 291, in peers
    s1.setsockopt(socket.SOL_SOCKET, IN.SO_BINDTODEVICE, send_iface + '\0')
AttributeError: 'module' object has no attribute 'SO_BINDTODEVICE'

# cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.1 LTS"

# python -V
Python 2.7.6

It appears that in /usr/lib/python2.7/plat-x86_64-linux-gnu/IN.py this definition is missing, however on my Fedora 19 workstation with python 2.7.5 it's there and '25':

$ python -V
Python 2.7.5

$ grep BIND /usr/lib64/python2.7/plat-linux2/IN.py
SO_BINDTODEVICE = 25

I hacked the bonding.py and replaced IN.SO_BINDTODEVICE with 25 and it allowed the script to work (as expected) on this Ubuntu server.

Problems with interface names longer than 4 characters

In several places there is code similar to this:

ifreq = struct.pack('4s12xH', ifname, flags)

The '4s' assumes that ifname will be 4 characters long (for example "eth0"), but if ifname is 5 characters long (for example "eth11"), then the interface name gets truncated to 4 characters and the operation gets applied the incorrect interface. (ie: "eth1" instead of "eth11").

Could this code be generalized to handle interface names of any (reasonable) length?

Ignore interfaces that begin with __tmp

Misconfigured interfaces show up as __tmp in /proc/net/dev and do not react correctly:

Enabling interfaces.Traceback (most recent call last):
  File "./bonding.py", line 980, in ?
    handleArgs()
  File "./bonding.py", line 953, in handleArgs
    groups = peers(False)
  File "./bonding.py", line 253, in peers
    set_iface_flag(iface, IFF_UP)
  File "./bonding.py", line 148, in set_iface_flag
    fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifreq)
IOError: [Errno 19] No such device

A patch to ignore those - it might be better to expand this to output some error to screen letting the admin know that they have an incorrectly configured network interface and it's being skipped during the test...

From 9cf45c1c00d61f89c552991140c2cd8007d51f8e Mon Sep 17 00:00:00 2001
From: troyengel <[email protected]>
Date: Fri, 22 Mar 2013 16:51:28 -0500
Subject: [PATCH 1/1] ignore misconfigured __tmp interfaces

---
 bonding.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/bonding.py b/bonding.py
index e3e5e56..ba11980 100644
--- a/bonding.py
+++ b/bonding.py
@@ -155,7 +155,8 @@ def get_iface_list():
     fields = line.strip().split()
     if ':' in fields[0]:
       iface = fields[0].split(':')
-      ifaces.append(iface[0])
+      if not iface[0].startswith('__tmp'):
+        ifaces.append(iface[0])
   return sorted(ifaces)

 def get_iface_link_status(ifname):
-- 
1.7.11.7

Python Packaging

Could we get this distributed as a PyPI package for ease of install?

I don't mind being the one to package it up, but just wanted to confirm that this is the most recent version etc.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.