centos7 配置bond 脚本 python 配置bond bond子接口 多网口策略路由

15 篇文章 0 订阅
11 篇文章 1 订阅

需求

将多个网卡配置为 bond(模式mode 4 802.3ad,对接 lacp),并配置 bond子接口,为每个子接口都开启策略路由,实现源进源出的效果(ip rule + rp_filter = 0)。

适用于 CentOS 7 系列,系统自带 python2.7

多网卡都配置网关可能会造成断网,根据自己实际情况修改

使用方法:

python2 test.py -h
usage: 1.py [-h] [-b bond] [-d [eth0 [eth0 ...]]] [-s [SUBIF [SUBIF ...]]]

optional arguments:
  -h, --help            show this help message and exit
  -b bond, --bond bond  Input bond interface.
  -d [eth0 [eth0 ...]], --device [eth0 [eth0 ...]]
                        EXAMPLE: eth0 eth1.
  -s [SUBIF [SUBIF ...]], --subif [SUBIF [SUBIF ...]]
                        EXAMPLE: bond0.100 192.168.1.100 24 192.168.1.1
创建一个bond

python2 test.py -b <bond名称> -d <物理接口>
必须指定物理接口,且接口存在(如果出错脚本会检测列出当前网卡)

例如,将 em1 和 em2 配置为 bond2

python2 test.py -b bond2 -d em1 em2
# 若接口不存在,报以下错误
python2 test.py -b bond2 -d eth00
usage: test.py [-h] [-b bond] [-d [eth0 [eth0 ...]]] [-s [SUBIF [SUBIF ...]]]
test.py: error: argument -d/--device: invalid choice: 'eth000' (choose from 'bond0.1401@bond0', 'bond0', 'bond2', 'bond0.1401', 'bond0.1403', 'p6p2', 'em4', 'bond2.100', 'p6p1', 'em1', 'em3', 'em2', 'bond0.1403@bond0')
创建一个子接口并配置IP

默认掩码为 24 ,默认网关为 IP 地址 .1 ,bond 接口必须存在
例如,为 bond2 配置 bond2.100 子接口和 bond2.300 子接口

# 默认掩码是 24,网关是 .1
python2 test.py  -s bond2.100 2.2.2.2
# 可以指定掩码和网关
python2 test.py -s bond2.200 3.3.3.3 23 3.3.3.25

脚本没有对掩码和网关进行检测,例如你配置 1.1.1.100/24 的 IP,指定 2.2.2.1 的网关,也是可以配置成功的。

配置完成后,需要重启网络,并使策略路由立即生效,可以
python2 test.py restart

代码,可自行修改:

#!/usr/bin/env python
import os
import subprocess
import argparse
import re

INTERFACE = r'/etc/sysconfig/network-scripts/ifcfg-'
ip_pattern = re.compile(r'^((25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d{2}|[1-9]?\d)$')

DEV_CONF = '''
TYPE=Ethernet
BOOTPROTO=none
USERCTL=no
DEVICE={dev}
ONBOOT=yes
MASTER={bond_name}
SLAVE=yes
'''

BOND_CONF = '''
DEVICE={bond_name}
TYPE=Bond
BONDING_MASTER=yes
BOOTPROTO=none
ONBOOT=yes
USERCTL=no
NM_CONTROLLED=no
'''

SUB_IF_CONF = '''
DEVICE={dev}
USERCTL=no
BOOTPROTO=static
IPADDR={ip}
PREFIX={mask}
GATEWAY={gw}
BONDING_MASTER=yes
NM_CONTROLLED=no
ONBOOT=yes
VLAN=yes
'''

BONDING_CONF = '''
alias {bond_name} bonding
options {bond_name} miimon=100 mode={mode}
'''

IP_RULE_CONF = '''
ip route flush table {table_name}
ip route add default via {gw} dev {dev} src {ip} table {table_name}
ip rule add from {ip} table {table_name}
'''


def _separator(s=''):
    return s.center(60, '=')


def _cmd(cmd):
    return os.popen(cmd).read()


def _popen(cmd):
    popen = subprocess.Popen(cmd, shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
    popen.wait()
    return popen.returncode, popen.stdout.read(), popen.stderr.read()


def _init_bond(bond_name, mode='4'):
    with open(r'/etc/modprobe.d/bonding.conf', 'a+') as f:
        f.write(BONDING_CONF.format(bond_name=bond_name, mode=mode))
    _popen(r'modprobe --first-time bonding')
    _popen(r'modprobe --first-time 8021q')


def _get_interface_list():
    cmd1 = 'ip link | grep ^[0-9] | awk -F": " \'{print $2}\' | grep -v "lo"'
    cmd2 = 'ls /etc/sysconfig/network-scripts/ | grep -E "ifcfg" | awk -F"-" \'{print $2}\' | grep -v "lo"'
    dev1 = _cmd(cmd1).split()
    dev2 = _cmd(cmd2).split()
    return list(set(dev1 + dev2))


def _config_phy_if(bond_name, dev_names):
    for dev in dev_names:
        with open(INTERFACE + dev, 'w') as f:
            f.write(DEV_CONF.format(dev=dev, bond_name=bond_name))
    with open(INTERFACE + bond_name, 'w') as f:
        f.write(BOND_CONF.format(bond_name=bond_name))


def _config_bond_subif(dev, ip, mask, gw):
    with open(INTERFACE + dev, 'w') as f:
        f.write(SUB_IF_CONF.format(dev=dev, ip=ip, mask=mask, gw=gw))


def _disable_rp_filter(dev):
    cmd = r'echo net.ipv4.conf.{dev}.rp_filter=0 >> /etc/sysctl.conf'.format(dev=dev)
    code, _, err = _popen(cmd)
    if code != 0:
        print 'Disable {dev} rp_filter Failed.'.format(dev=dev), '\n', err


def _config_ip_rule(dev, ip, gw):
    table_name = 'cloud-' + dev.split('.')[-1]
    num_list = []
    with open('/etc/iproute2/rt_tables', 'a+') as f:
        for line in f.readlines():
            if not (line.startswith("#") or line.startswith('0')):
                num_list.append(line.strip().split()[0])
        num = int(min(num_list)) - 1
        f.write('{num} {table_name}\n'.format(num=num, table_name=table_name, ))
    with open(r'/etc/rc.local', 'a+') as f:
        f.write(IP_RULE_CONF.format(
            ip=ip, gw=gw, dev=dev, table_name=table_name))


def bond(bond_name, dev_names):
    _config_phy_if(bond_name, dev_names)
    _init_bond(bond_name)
    for dev in dev_names:
        _disable_rp_filter(dev)
    _disable_rp_filter(bond_name)
    print bond_name + ' config done'


def sub_if(dev, ip, mask='24', gw=''):
    if not gw:
        gw = '.'.join(ip.split('.')[0:3]) + '.1'
    if not re.findall(ip_pattern, ip) or not re.findall(ip_pattern, gw):
        print 'ERROR: IP or GW wrong'
    if not 2 < int(mask) < 30:
        print 'ERROR: MASK wrong'
    _config_bond_subif(dev=dev, ip=ip, mask=mask, gw=gw)
    _disable_rp_filter(dev=dev)
    _config_ip_rule(dev=dev, ip=ip, gw=gw)
    print dev + ' config done.'


parser = argparse.ArgumentParser()
parser.add_argument('-b', '--bond', metavar='bond', help='Input bond interface.')
parser.add_argument('-d', '--device', nargs='*', metavar='eth0', choices=_get_interface_list(),
                    help='EXAMPLE: eth0 eth1.')
parser.add_argument('-s', '--subif', nargs='*', help='EXAMPLE: bond0.100 192.168.1.100 24 192.168.1.1')
parser.add_argument('-r', '--restart', action='store_true', help="Restart Network")
parsed_args = parser.parse_args()

if __name__ == '__main__':
    if parsed_args.bond or parsed_args.device:
        if parsed_args.bond and parsed_args.device:
            bond(parsed_args.bond, parsed_args.device)
            # print parsed_args.bond, parsed_args.device
        else:
            print 'ERROR: Argument Error, both "-b bond" and "-d phy-if" is required.'

    if parsed_args.subif:
        subif_lis = parsed_args.subif[0].split('.')
        if subif_lis[0] not in _get_interface_list():
            print 'ERROR: No bond interface. Use "-b bond" and "-d phy-if" to create'
        elif len(subif_lis) != 2:
            print 'ERROR: Sub-if name wrong,it must be <bond if>.<vlan id> Example: bond1.1024'
        else:
            sub_if(*parsed_args.subif)
            # print parsed_args.subif
    if parsed_args.restart:
        _popen(r'echo net.ipv4.conf.all.rp_filter=0 >> /etc/sysctl.conf')
        _popen(r'echo net.ipv4.conf.default.rp_filter=0 >> /etc/sysctl.conf')
        _popen(r'sysctl -p')
        _popen(r'systemctl restart network')
        _popen(r'chmod +x /etc/rc.local && source /etc/rc.local')

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

某呆啊

赏个糖吃吧~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值