Page MenuHomeVyOS Platform

interfaces-ethernet.py
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

interfaces-ethernet.py

#!/usr/bin/env python3
#
# Copyright (C) 2019-2020 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 copy import deepcopy
from netifaces import interfaces
from vyos.ifconfig import EthernetIf
from vyos.ifconfig_vlan import apply_all_vlans, verify_vlan_config
from vyos.configdict import list_diff, intf_to_dict, add_to_dict, interface_default_data
from vyos.validate import is_member
from vyos.config import Config
from vyos import ConfigError
from vyos import airbag
airbag.enable()
default_config_data = {
**interface_default_data,
'deleted': False,
'duplex': 'auto',
'flow_control': 'on',
'hw_id': '',
'ip_arp_cache_tmo': 30,
'ip_proxy_arp_pvlan': 0,
'is_bond_member': False,
'intf': '',
'offload_gro': 'off',
'offload_gso': 'off',
'offload_sg': 'off',
'offload_tso': 'off',
'offload_ufo': 'off',
'speed': 'auto',
'vif_s': {},
'vif_s_remove': [],
'vif': {},
'vif_remove': [],
'vrf': ''
}
def get_config():
# determine tagNode instance
if 'VYOS_TAGNODE_VALUE' not in os.environ:
raise ConfigError('Interface (VYOS_TAGNODE_VALUE) not specified')
ifname = os.environ['VYOS_TAGNODE_VALUE']
conf = Config()
# check if ethernet interface has been removed
cfg_base = ['interfaces', 'ethernet', ifname]
if not conf.exists(cfg_base):
eth = deepcopy(default_config_data)
eth['intf'] = ifname
eth['deleted'] = True
# we can not bail out early as ethernet interface can not be removed
# Kernel will complain with: RTNETLINK answers: Operation not supported.
# Thus we need to remove individual settings
return eth
# set new configuration level
conf.set_level(cfg_base)
eth, disabled = intf_to_dict(conf, default_config_data)
# disable ethernet flow control (pause frames)
if conf.exists('disable-flow-control'):
eth['flow_control'] = 'off'
# retrieve real hardware address
if conf.exists('hw-id'):
eth['hw_id'] = conf.return_value('hw-id')
# interface duplex
if conf.exists('duplex'):
eth['duplex'] = conf.return_value('duplex')
# ARP cache entry timeout in seconds
if conf.exists('ip arp-cache-timeout'):
eth['ip_arp_cache_tmo'] = int(conf.return_value('ip arp-cache-timeout'))
# Enable private VLAN proxy ARP on this interface
if conf.exists('ip proxy-arp-pvlan'):
eth['ip_proxy_arp_pvlan'] = 1
# check if we are a member of any bond
eth['is_bond_member'] = is_member(conf, eth['intf'], 'bonding')
# GRO (generic receive offload)
if conf.exists('offload-options generic-receive'):
eth['offload_gro'] = conf.return_value('offload-options generic-receive')
# GSO (generic segmentation offload)
if conf.exists('offload-options generic-segmentation'):
eth['offload_gso'] = conf.return_value('offload-options generic-segmentation')
# scatter-gather option
if conf.exists('offload-options scatter-gather'):
eth['offload_sg'] = conf.return_value('offload-options scatter-gather')
# TSO (TCP segmentation offloading)
if conf.exists('offload-options tcp-segmentation'):
eth['offload_tso'] = conf.return_value('offload-options tcp-segmentation')
# UDP fragmentation offloading
if conf.exists('offload-options udp-fragmentation'):
eth['offload_ufo'] = conf.return_value('offload-options udp-fragmentation')
# interface speed
if conf.exists('speed'):
eth['speed'] = conf.return_value('speed')
# remove default IPv6 link-local address if member of a bond
if eth['is_bond_member'] and 'fe80::/64' in eth['ipv6_eui64_prefix']:
eth['ipv6_eui64_prefix'].remove('fe80::/64')
eth['ipv6_eui64_prefix_remove'].append('fe80::/64')
add_to_dict(conf, disabled, eth, 'vif', 'vif')
add_to_dict(conf, disabled, eth, 'vif-s', 'vif_s')
return eth
def verify(eth):
if eth['deleted']:
return None
if eth['intf'] not in interfaces():
raise ConfigError(f"Interface ethernet {eth['intf']} does not exist")
if eth['speed'] == 'auto':
if eth['duplex'] != 'auto':
raise ConfigError('If speed is hardcoded, duplex must be hardcoded, too')
if eth['duplex'] == 'auto':
if eth['speed'] != 'auto':
raise ConfigError('If duplex is hardcoded, speed must be hardcoded, too')
if eth['dhcpv6_prm_only'] and eth['dhcpv6_temporary']:
raise ConfigError('DHCPv6 temporary and parameters-only options are mutually exclusive!')
memberof = eth['is_bridge_member'] if eth['is_bridge_member'] else eth['is_bond_member']
if ( memberof
and ( eth['address']
or eth['ipv6_eui64_prefix']
or eth['ipv6_autoconf'] ) ):
raise ConfigError((
f'Cannot assign address to interface "{eth["intf"]}" '
f'as it is a member of "{memberof}"!'))
if eth['vrf']:
if eth['vrf'] not in interfaces():
raise ConfigError(f'VRF "{eth["vrf"]}" does not exist')
if memberof:
raise ConfigError((
f'Interface "{eth["intf"]}" cannot be member of VRF "{eth["vrf"]}" '
f'and "{memberof}" at the same time!'))
if eth['mac'] and eth['is_bond_member']:
print('WARNING: "mac {0}" command will be ignored because {1} is a part of {2}'\
.format(eth['mac'], eth['intf'], eth['is_bond_member']))
# use common function to verify VLAN configuration
verify_vlan_config(eth)
return None
def generate(eth):
return None
def apply(eth):
e = EthernetIf(eth['intf'])
if eth['deleted']:
# apply all vlans to interface (they need removing too)
apply_all_vlans(e, eth)
# delete interface
e.remove()
else:
# update interface description used e.g. within SNMP
e.set_alias(eth['description'])
if eth['dhcp_client_id']:
e.dhcp.v4.options['client_id'] = eth['dhcp_client_id']
if eth['dhcp_hostname']:
e.dhcp.v4.options['hostname'] = eth['dhcp_hostname']
if eth['dhcp_vendor_class_id']:
e.dhcp.v4.options['vendor_class_id'] = eth['dhcp_vendor_class_id']
if eth['dhcpv6_prm_only']:
e.dhcp.v6.options['dhcpv6_prm_only'] = True
if eth['dhcpv6_temporary']:
e.dhcp.v6.options['dhcpv6_temporary'] = True
if eth['dhcpv6_pd_length']:
e.dhcp.v6.options['dhcpv6_pd_length'] = eth['dhcpv6_pd_length']
if eth['dhcpv6_pd_interfaces']:
e.dhcp.v6.options['dhcpv6_pd_interfaces'] = eth['dhcpv6_pd_interfaces']
# ignore link state changes
e.set_link_detect(eth['disable_link_detect'])
# disable ethernet flow control (pause frames)
e.set_flow_control(eth['flow_control'])
# configure ARP cache timeout in milliseconds
e.set_arp_cache_tmo(eth['ip_arp_cache_tmo'])
# configure ARP filter configuration
e.set_arp_filter(eth['ip_disable_arp_filter'])
# configure ARP accept
e.set_arp_accept(eth['ip_enable_arp_accept'])
# configure ARP announce
e.set_arp_announce(eth['ip_enable_arp_announce'])
# configure ARP ignore
e.set_arp_ignore(eth['ip_enable_arp_ignore'])
# Enable proxy-arp on this interface
e.set_proxy_arp(eth['ip_proxy_arp'])
# Enable private VLAN proxy ARP on this interface
e.set_proxy_arp_pvlan(eth['ip_proxy_arp_pvlan'])
# IPv6 accept RA
e.set_ipv6_accept_ra(eth['ipv6_accept_ra'])
# IPv6 address autoconfiguration
e.set_ipv6_autoconf(eth['ipv6_autoconf'])
# IPv6 forwarding
e.set_ipv6_forwarding(eth['ipv6_forwarding'])
# IPv6 Duplicate Address Detection (DAD) tries
e.set_ipv6_dad_messages(eth['ipv6_dup_addr_detect'])
# Delete old IPv6 EUI64 addresses before changing MAC
for addr in eth['ipv6_eui64_prefix_remove']:
e.del_ipv6_eui64_address(addr)
# Change interface MAC address - re-set to real hardware address (hw-id)
# if custom mac is removed. Skip if bond member.
if not eth['is_bond_member']:
if eth['mac']:
e.set_mac(eth['mac'])
elif eth['hw_id']:
e.set_mac(eth['hw_id'])
# Add IPv6 EUI-based addresses
for addr in eth['ipv6_eui64_prefix']:
e.add_ipv6_eui64_address(addr)
# Maximum Transmission Unit (MTU)
e.set_mtu(eth['mtu'])
# GRO (generic receive offload)
e.set_gro(eth['offload_gro'])
# GSO (generic segmentation offload)
e.set_gso(eth['offload_gso'])
# scatter-gather option
e.set_sg(eth['offload_sg'])
# TSO (TCP segmentation offloading)
e.set_tso(eth['offload_tso'])
# UDP fragmentation offloading
e.set_ufo(eth['offload_ufo'])
# Set physical interface speed and duplex
e.set_speed_duplex(eth['speed'], eth['duplex'])
# Enable/Disable interface
if eth['disable']:
e.set_admin_state('down')
else:
e.set_admin_state('up')
# Configure interface address(es)
# - not longer required addresses get removed first
# - newly addresses will be added second
for addr in eth['address_remove']:
e.del_addr(addr)
for addr in eth['address']:
e.add_addr(addr)
# assign/remove VRF (ONLY when not a member of a bridge or bond,
# otherwise 'nomaster' removes it from it)
if not ( eth['is_bridge_member'] or eth['is_bond_member'] ):
e.set_vrf(eth['vrf'])
# re-add ourselves to any bridge we might have fallen out of
if eth['is_bridge_member']:
e.add_to_bridge(eth['is_bridge_member'])
# apply all vlans to interface
apply_all_vlans(e, eth)
if __name__ == '__main__':
try:
c = get_config()
verify(c)
generate(c)
apply(c)
except ConfigError as e:
print(e)
exit(1)

File Metadata

Mime Type
text/x-script.python
Expires
Sat, Oct 17, 12:53 AM (1 d, 21 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4351287
Default Alt Text
interfaces-ethernet.py (10 KB)

Event Timeline