summaryrefslogtreecommitdiff
path: root/src/conf_mode/interfaces-bonding.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode/interfaces-bonding.py')
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py294
1 files changed, 0 insertions, 294 deletions
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
deleted file mode 100755
index 8184d8415..000000000
--- a/src/conf_mode/interfaces-bonding.py
+++ /dev/null
@@ -1,294 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-
-from sys import exit
-from netifaces import interfaces
-from vyos.config import Config
-from vyos.configdict import get_interface_dict
-from vyos.configdict import is_node_changed
-from vyos.configdict import leaf_node_changed
-from vyos.configdict import is_member
-from vyos.configdict import is_source_interface
-from vyos.configverify import verify_address
-from vyos.configverify import verify_bridge_delete
-from vyos.configverify import verify_dhcpv6
-from vyos.configverify import verify_mirror_redirect
-from vyos.configverify import verify_mtu_ipv6
-from vyos.configverify import verify_source_interface
-from vyos.configverify import verify_vlan_config
-from vyos.configverify import verify_vrf
-from vyos.ifconfig import BondIf
-from vyos.ifconfig.ethernet import EthernetIf
-from vyos.ifconfig import Section
-from vyos.template import render_to_string
-from vyos.utils.dict import dict_search
-from vyos.utils.dict import dict_to_paths_values
-from vyos.configdict import has_address_configured
-from vyos.configdict import has_vrf_configured
-from vyos.configdep import set_dependents, call_dependents
-from vyos import ConfigError
-from vyos import frr
-from vyos import airbag
-airbag.enable()
-
-def get_bond_mode(mode):
- if mode == 'round-robin':
- return 'balance-rr'
- elif mode == 'active-backup':
- return 'active-backup'
- elif mode == 'xor-hash':
- return 'balance-xor'
- elif mode == 'broadcast':
- return 'broadcast'
- elif mode == '802.3ad':
- return '802.3ad'
- elif mode == 'transmit-load-balance':
- return 'balance-tlb'
- elif mode == 'adaptive-load-balance':
- return 'balance-alb'
- else:
- raise ConfigError(f'invalid bond mode "{mode}"')
-
-def get_config(config=None):
- """
- Retrive CLI config as dictionary. Dictionary can never be empty, as at least the
- interface name will be added or a deleted flag
- """
- if config:
- conf = config
- else:
- conf = Config()
- base = ['interfaces', 'bonding']
- ifname, bond = get_interface_dict(conf, base)
-
- # To make our own life easier transfor the list of member interfaces
- # into a dictionary - we will use this to add additional information
- # later on for each member
- if 'member' in bond and 'interface' in bond['member']:
- # convert list of member interfaces to a dictionary
- bond['member']['interface'] = {k: {} for k in bond['member']['interface']}
-
- if 'mode' in bond:
- bond['mode'] = get_bond_mode(bond['mode'])
-
- tmp = is_node_changed(conf, base + [ifname, 'mode'])
- if tmp: bond['shutdown_required'] = {}
-
- tmp = is_node_changed(conf, base + [ifname, 'lacp-rate'])
- if tmp: bond['shutdown_required'] = {}
-
- # determine which members have been removed
- interfaces_removed = leaf_node_changed(conf, base + [ifname, 'member', 'interface'])
- # Reset config level to interfaces
- old_level = conf.get_level()
- conf.set_level(['interfaces'])
-
- if interfaces_removed:
- bond['shutdown_required'] = {}
- if 'member' not in bond:
- bond['member'] = {}
-
- tmp = {}
- for interface in interfaces_removed:
- # if member is deleted from bond, add dependencies to call
- # ethernet commit again in apply function
- # to apply options under ethernet section
- set_dependents('ethernet', conf, interface)
- section = Section.section(interface) # this will be 'ethernet' for 'eth0'
- if conf.exists([section, interface, 'disable']):
- tmp[interface] = {'disable': ''}
- else:
- tmp[interface] = {}
-
- # also present the interfaces to be removed from the bond as dictionary
- bond['member']['interface_remove'] = tmp
-
- # Restore existing config level
- conf.set_level(old_level)
-
- if dict_search('member.interface', bond):
- for interface, interface_config in bond['member']['interface'].items():
-
- interface_ethernet_config = conf.get_config_dict(
- ['interfaces', 'ethernet', interface],
- key_mangling=('-', '_'),
- get_first_key=True,
- no_tag_node_value_mangle=True,
- with_defaults=False,
- with_recursive_defaults=False)
-
- interface_config['config_paths'] = dict_to_paths_values(interface_ethernet_config)
-
- # Check if member interface is a new member
- if not conf.exists_effective(base + [ifname, 'member', 'interface', interface]):
- bond['shutdown_required'] = {}
- interface_config['new_added'] = {}
-
- # Check if member interface is disabled
- conf.set_level(['interfaces'])
-
- section = Section.section(interface) # this will be 'ethernet' for 'eth0'
- if conf.exists([section, interface, 'disable']):
- interface_config['disable'] = ''
-
- conf.set_level(old_level)
-
- # Check if member interface is already member of another bridge
- tmp = is_member(conf, interface, 'bridge')
- if tmp: interface_config['is_bridge_member'] = tmp
-
- # Check if member interface is already member of a bond
- tmp = is_member(conf, interface, 'bonding')
- for tmp in is_member(conf, interface, 'bonding'):
- if bond['ifname'] == tmp:
- continue
- interface_config['is_bond_member'] = tmp
-
- # Check if member interface is used as source-interface on another interface
- tmp = is_source_interface(conf, interface)
- if tmp: interface_config['is_source_interface'] = tmp
-
- # bond members must not have an assigned address
- tmp = has_address_configured(conf, interface)
- if tmp: interface_config['has_address'] = {}
-
- # bond members must not have a VRF attached
- tmp = has_vrf_configured(conf, interface)
- if tmp: interface_config['has_vrf'] = {}
- return bond
-
-
-def verify(bond):
- if 'deleted' in bond:
- verify_bridge_delete(bond)
- return None
-
- if 'arp_monitor' in bond:
- if 'target' in bond['arp_monitor'] and len(bond['arp_monitor']['target']) > 16:
- raise ConfigError('The maximum number of arp-monitor targets is 16')
-
- if 'interval' in bond['arp_monitor'] and int(bond['arp_monitor']['interval']) > 0:
- if bond['mode'] in ['802.3ad', 'balance-tlb', 'balance-alb']:
- raise ConfigError('ARP link monitoring does not work for mode 802.3ad, ' \
- 'transmit-load-balance or adaptive-load-balance')
-
- if 'primary' in bond:
- if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']:
- raise ConfigError('Option primary - mode dependency failed, not'
- 'supported in mode {mode}!'.format(**bond))
-
- verify_mtu_ipv6(bond)
- verify_address(bond)
- verify_dhcpv6(bond)
- verify_vrf(bond)
- verify_mirror_redirect(bond)
-
- # use common function to verify VLAN configuration
- verify_vlan_config(bond)
-
- bond_name = bond['ifname']
- if dict_search('member.interface', bond):
- for interface, interface_config in bond['member']['interface'].items():
- error_msg = f'Can not add interface "{interface}" to bond, '
-
- if interface == 'lo':
- raise ConfigError('Loopback interface "lo" can not be added to a bond')
-
- if interface not in interfaces():
- raise ConfigError(error_msg + 'it does not exist!')
-
- if 'is_bridge_member' in interface_config:
- tmp = next(iter(interface_config['is_bridge_member']))
- raise ConfigError(error_msg + f'it is already a member of bridge "{tmp}"!')
-
- if 'is_bond_member' in interface_config:
- tmp = next(iter(interface_config['is_bond_member']))
- raise ConfigError(error_msg + f'it is already a member of bond "{tmp}"!')
-
- if 'is_source_interface' in interface_config:
- tmp = interface_config['is_source_interface']
- raise ConfigError(error_msg + f'it is the source-interface of "{tmp}"!')
-
- if 'has_address' in interface_config:
- raise ConfigError(error_msg + 'it has an address assigned!')
-
- if 'has_vrf' in interface_config:
- raise ConfigError(error_msg + 'it has a VRF assigned!')
-
- if 'new_added' in interface_config and 'config_paths' in interface_config:
- for option_path, option_value in interface_config['config_paths'].items():
- if option_path in EthernetIf.get_bond_member_allowed_options() :
- continue
- if option_path in BondIf.get_inherit_bond_options():
- continue
- raise ConfigError(error_msg + f'it has a "{option_path.replace(".", " ")}" assigned!')
-
- if 'primary' in bond:
- if bond['primary'] not in bond['member']['interface']:
- raise ConfigError(f'Primary interface of bond "{bond_name}" must be a member interface')
-
- if bond['mode'] not in ['active-backup', 'balance-tlb', 'balance-alb']:
- raise ConfigError('primary interface only works for mode active-backup, ' \
- 'transmit-load-balance or adaptive-load-balance')
-
- return None
-
-def generate(bond):
- bond['frr_zebra_config'] = ''
- if 'deleted' not in bond:
- bond['frr_zebra_config'] = render_to_string('frr/evpn.mh.frr.j2', bond)
- return None
-
-def apply(bond):
- ifname = bond['ifname']
- b = BondIf(ifname)
- if 'deleted' in bond:
- # delete interface
- b.remove()
- else:
- b.update(bond)
-
- if dict_search('member.interface_remove', bond):
- try:
- call_dependents()
- except ConfigError:
- raise ConfigError('Error in updating ethernet interface '
- 'after deleting it from bond')
-
- zebra_daemon = 'zebra'
- # Save original configuration prior to starting any commit actions
- frr_cfg = frr.FRRConfig()
-
- # The route-map used for the FIB (zebra) is part of the zebra daemon
- frr_cfg.load_configuration(zebra_daemon)
- frr_cfg.modify_section(f'^interface {ifname}', stop_pattern='^exit', remove_stop_mark=True)
- if 'frr_zebra_config' in bond:
- frr_cfg.add_before(frr.default_add_before, bond['frr_zebra_config'])
- frr_cfg.commit_configuration(zebra_daemon)
-
- return None
-
-if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- exit(1)