From 4ae44c074e15fa102718d5a4512c23db447d6dc8 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 7 Sep 2019 14:24:30 +0200 Subject: Python/ifconfig: T1557: rename EthernetIf -> VLANIf An Ethernet Interface will provide additional functionality (link speed/duplex) which is not available for a Bond Interface, but both share the same VLAN capabilities. --- python/vyos/ifconfig.py | 15 +++++++++------ src/conf_mode/interface-bonding.py | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 750a7cc70..524c0f276 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -997,8 +997,11 @@ class BridgeIf(Interface): .format(self._ifname, interface), priority) -class EthernetIf(Interface): - +class VLANIf(Interface): + """ + This class handels the creation and removal of a VLAN interface. It serves + as base class for BondIf and EthernetIf. + """ def __init__(self, ifname, type=None): super().__init__(ifname, type) @@ -1012,7 +1015,7 @@ class EthernetIf(Interface): This function creates both 802.1q and 802.1ad (Q-in-Q) interfaces. Proto parameter is used to indicate VLAN type. - A new object of type EthernetIf is returned once the interface has been + A new object of type VLANIf is returned once the interface has been created. """ vlan_ifname = self._ifname + '.' + str(vlan_id) @@ -1031,7 +1034,7 @@ class EthernetIf(Interface): # return new object mapping to the newly created interface # we can now work on this object for e.g. IP address setting # or interface description and so on - return EthernetIf(vlan_ifname) + return VLANIf(vlan_ifname) def del_vlan(self, vlan_id): """ @@ -1040,11 +1043,11 @@ class EthernetIf(Interface): client processes. """ vlan_ifname = self._ifname + '.' + str(vlan_id) - tmp = EthernetIf(vlan_ifname) + tmp = VLANIf(vlan_ifname) tmp.remove() -class BondIf(EthernetIf): +class BondIf(VLANIf): """ The Linux bonding driver provides a method for aggregating multiple network diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interface-bonding.py index ac3e1b867..0d5f9f6b7 100755 --- a/src/conf_mode/interface-bonding.py +++ b/src/conf_mode/interface-bonding.py @@ -22,7 +22,7 @@ from copy import deepcopy from sys import exit from netifaces import interfaces -from vyos.ifconfig import BondIf, EthernetIf +from vyos.ifconfig import BondIf, VLANIf from vyos.configdict import list_diff, vlan_to_dict from vyos.config import Config from vyos import ConfigError @@ -82,7 +82,7 @@ def apply_vlan_config(vlan, config): to a VLAN interface """ - if type(vlan) != type(EthernetIf("lo")): + if type(vlan) != type(VLANIf("lo")): raise TypeError() # update interface description used e.g. within SNMP -- cgit v1.2.3 From a610e328750e3cfc23c29a2cafb40d7ef7082b13 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sat, 7 Sep 2019 12:29:12 +0200 Subject: ethernet: T1637: initial rewrite in XML/Python style --- Makefile | 6 +- interface-definitions/interfaces-ethernet.xml | 856 ++++++++++++++++++++++++++ python/vyos/ifconfig.py | 13 +- src/conf_mode/interface-ethernet.py | 298 +++++++++ 4 files changed, 1170 insertions(+), 3 deletions(-) create mode 100644 interface-definitions/interfaces-ethernet.xml create mode 100755 src/conf_mode/interface-ethernet.py diff --git a/Makefile b/Makefile index 61bc06c47..881fc36b1 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,12 @@ interface_definitions: # XXX: delete top level node.def's that now live in other packages rm -f $(TMPL_DIR)/firewall/node.def rm -f $(TMPL_DIR)/interfaces/node.def - rm -f $(TMPL_DIR)/interfaces/bridge/node.tag/ip/node.def rm -f $(TMPL_DIR)/interfaces/bonding/node.tag/ip/node.def + rm -f $(TMPL_DIR)/interfaces/bridge/node.tag/ip/node.def + rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/ip/node.def + rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif/node.tag/ip/node.def + rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif-s/node.tag/ip/node.def + rm -f $(TMPL_DIR)/interfaces/ethernet/node.tag/vif-s/node.tag/vif-c/node.tag/ip/node.def rm -f $(TMPL_DIR)/interfaces/vxlan/node.tag/ip/node.def rm -f $(TMPL_DIR)/protocols/node.def rm -f $(TMPL_DIR)/protocols/static/node.def diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml new file mode 100644 index 000000000..a2de4aeb3 --- /dev/null +++ b/interface-definitions/interfaces-ethernet.xml @@ -0,0 +1,856 @@ + + + + + + + Ethernet interface name + 318 + + ((eth|lan)[0-9]+|(eno|ens|enp|enx).+)$ + + Invalid Ethernet interface name + + ethN + Ethernet interface name + + + en[ospx]N + Ethernet interface name + + + + + + IP address + + dhcp dhcpv6 + + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + dhcp + Dynamic Host Configuration Protocol + + + dhcpv6 + Dynamic Host Configuration Protocol for IPv6 + + + + (dhcp|dhcpv6) + + + + + + + Interface description + + ^.{1,256}$ + + Interface description too long (limit 256 characters) + + + + + DHCP options + + + + + DHCP client identifier + + + + + DHCP client host name (overrides the system host name) + + + + + + + DHCPv6 options + 319 + + + + + Acquire only config parameters, no address + + + + + + IPv6 "temporary" address + + + + + + + + Disable Ethernet flow control (pause frames) + + + + + + Ignore link state changes + + + + + + Disable this bridge interface + + + + + + Duplex mode + + auto half full + + + auto + Auto negotiation (default) + + + half + Half duplex + + + full + Full duplex + + + (auto|half|full) + + duplex must be auto, half or full + + + + + Media Access Control (MAC) address + + h:h:h:h:h:h + Hardware (MAC) address + + + + + + + + + + + ARP cache entry timeout in seconds + + 1-86400 + ARP cache entry timout in seconds (default 30) + + + + + ARP cache entry timeout must be between 1 and 86400 seconds + + + + + Enable proxy-arp on this interface + + + + + + Enable private VLAN proxy ARP on this interface + + + + + + + + Media Access Control (MAC) address + + h:h:h:h:h:h + Hardware (MAC) address + + + + + + + + + Maximum Transmission Unit (MTU) + + 68-9000 + Maximum Transmission Unit + + + + + MTU must be between 68 and 9000 + + + + + Configurable offload options + + + + + Configure GRO (generic receive offload) + + on off + + + on + Enable GRO (generic receive offload) + + + off + Disable GRO (generic receive offload) + + + (on|off) + + Must be either 'on' or 'off' + + + + + Configure GSO (generic segmentation offload) + + on off + + + on + Enable GSO (generic segmentation offload) + + + off + Disable GSO (generic segmentation offload) + + + (on|off) + + Must be either 'on' or 'off' + + + + + Configure scatter-gather option + + on off + + + on + Enable scatter-gather + + + off + Disable scatter-gather + + + (on|off) + + Must be either 'on' or 'off' + + + + + Configure TSO (TCP segmentation offloading) + + on off + + + on + Enable TSO (TCP segmentation offloading) + + + off + Disable TSO (TCP segmentation offloading) + + + (on|off) + + Must be either 'on' or 'off' + + + + + Configure UDP fragmentation offloading + + on off + + + on + Enable UDP fragmentation offloading + + + off + Disable UDP fragmentation offloading + + + (on|off) + + Must be either 'on' or 'off' + + + + + + + CPU interrupt affinity mask + + auto 10 100 1000 2500 5000 10000 + + + auto + Auto negotiation (default) + + + hex + Bitmask representing CPUs that this NIC will interrupt + + + hex,hex + Bitmasks representing CPUs for interrupt and receive processing + + + (auto) + [0-9a-f]+(|,[0-9a-f]+)$ + + IRQ affinity mask must be hex value or auto + + + + + Link speed + + auto 10 100 1000 2500 5000 10000 + + + auto + Auto negotiation (default) + + + 10 + 10 Mbit/sec + + + 100 + 100 Mbit/sec + + + 1000 + 1 Gbit/sec + + + 2500 + 2.5 Gbit/sec + + + 5000 + 5 Gbit/sec + + + 10000 + 10 Gbit/sec + + + (auto|10|100|1000|2500|5000|10000) + + Speed must be auto, 10, 100, 1000, 2500, 5000 or 10000 + + + + + QinQ TAG-S Virtual Local Area Network (VLAN) ID + + + + VLAN ID must be between 0 and 4094 + + + + + IP address + + dhcp dhcpv6 + + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + dhcp + Dynamic Host Configuration Protocol + + + dhcpv6 + Dynamic Host Configuration Protocol for IPv6 + + + + (dhcp|dhcpv6) + + + + + + + Interface description + + ^.{1,256}$ + + Interface description too long (limit 256 characters) + + + + + DHCP options + + + + + DHCP client identifier + + + + + DHCP client host name (overrides the system host name) + + + + + + + DHCPv6 options + 319 + + + + + Acquire only config parameters, no address + + + + + + IPv6 "temporary" address + + + + + + + + Ignore link state changes + + + + + + Disable this bridge interface + + + + + + Set Ethertype + + 0x88A8 0x8100 + + + 0x88A8 + 802.1ad + + + 0x8100 + 802.1q + + + (0x88A8|0x8100) + + Ethertype must be 0x88A8 or 0x8100 + + + + + + + Enable proxy-arp on this interface + + + + + + Enable private VLAN proxy ARP on this interface + + + + + + + + Media Access Control (MAC) address + + h:h:h:h:h:h + Hardware (MAC) address + + + + + + + + + Maximum Transmission Unit (MTU) + + 68-9000 + Maximum Transmission Unit + + + + + MTU must be between 68 and 9000 + + + + + QinQ TAG-C Virtual Local Area Network (VLAN) ID + + + + VLAN ID must be between 0 and 4094 + + + + + IP address + + dhcp dhcpv6 + + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + dhcp + Dynamic Host Configuration Protocol + + + dhcpv6 + Dynamic Host Configuration Protocol for IPv6 + + + + (dhcp|dhcpv6) + + + + + + + Interface description + + ^.{1,256}$ + + Interface description too long (limit 256 characters) + + + + + DHCP options + + + + + DHCP client identifier + + + + + DHCP client host name (overrides the system host name) + + + + + + + DHCPv6 options + 319 + + + + + Acquire only config parameters, no address + + + + + + IPv6 "temporary" address + + + + + + + + Ignore link state changes + + + + + + Disable this bridge interface + + + + + + + + Enable proxy-arp on this interface + + + + + + Enable private VLAN proxy ARP on this interface + + + + + + + + Media Access Control (MAC) address + + h:h:h:h:h:h + Hardware (MAC) address + + + + + + + + + Maximum Transmission Unit (MTU) + + 68-9000 + Maximum Transmission Unit + + + + + MTU must be between 68 and 9000 + + + + + + + + + Virtual Local Area Network (VLAN) ID + + + + VLAN ID must be between 0 and 4094 + + + + + IP address + + dhcp dhcpv6 + + + ipv4net + IPv4 address and prefix length + + + ipv6net + IPv6 address and prefix length + + + dhcp + Dynamic Host Configuration Protocol + + + dhcpv6 + Dynamic Host Configuration Protocol for IPv6 + + + + (dhcp|dhcpv6) + + + + + + + Interface description + + ^.{1,256}$ + + Interface description too long (limit 256 characters) + + + + + DHCP options + + + + + DHCP client identifier + + + + + DHCP client host name (overrides the system host name) + + + + + + + DHCPv6 options + 319 + + + + + Acquire only config parameters, no address + + + + + + IPv6 "temporary" address + + + + + + + + Ignore link state changes + + + + + + Disable this bridge interface + + + + + + VLAN egress QoS + + + + + [:0-7 ]+$ + + QoS mapping should be in the format of \"0:7 2:3\" with numbers 0-9 + + + + + VLAN ingress QoS + + + + + [:0-7 ]+$ + + QoS mapping should be in the format of \"0:7 2:3\" with numbers 0-9 + + + + + + + ARP cache entry timeout in seconds + + 1-86400 + ARP cache entry timout in seconds (default 30) + + + + + ARP cache entry timeout must be between 1 and 86400 seconds + + + + + Enable proxy-arp on this interface + + + + + + Enable private VLAN proxy ARP on this interface + + + + + + + + Media Access Control (MAC) address + + h:h:h:h:h:h + Hardware (MAC) address + + + + + + + + + Maximum Transmission Unit (MTU) + + 68-9000 + Maximum Transmission Unit + + + + + MTU must be between 68 and 9000 + + + + + + + + + diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 524c0f276..7181ff42f 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1047,8 +1047,18 @@ class VLANIf(Interface): tmp.remove() -class BondIf(VLANIf): +class EthernetIf(VLANIf): + """ + Abstraction of a Linux Ethernet Interface + """ + def __init__(self, ifname): + super().__init__(ifname) + def remove(self): + raise OSError('Ethernet interfaces can not be removed') + + +class BondIf(VLANIf): """ The Linux bonding driver provides a method for aggregating multiple network interfaces into a single logical "bonded" interface. The behavior of the @@ -1056,7 +1066,6 @@ class BondIf(VLANIf): either hot standby or load balancing services. Additionally, link integrity monitoring may be performed. """ - def __init__(self, ifname): super().__init__(ifname, type='bond') diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py new file mode 100755 index 000000000..4aed13a62 --- /dev/null +++ b/src/conf_mode/interface-ethernet.py @@ -0,0 +1,298 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 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 . + +import os + +from copy import deepcopy +from sys import exit + +from vyos.ifconfig import EthernetIf, VLANIf +from vyos.configdict import list_diff, vlan_to_dict +from vyos.config import Config +from vyos import ConfigError + +default_config_data = { + 'address': [], + 'address_remove': [], + 'description': '', + 'deleted': False, + 'dhcp_client_id': '', + 'dhcp_hostname': '', + 'dhcpv6_prm_only': False, + 'dhcpv6_temporary': False, + 'disable': False, + 'disable_link_detect': 1, + 'hw_id': '', + 'ip_arp_cache_tmo': 30, + 'ip_proxy_arp': 0, + 'ip_proxy_arp_pvlan': 0, + 'intf': '', + 'mac': '', + 'mtu': 1500, + 'vif_s': [], + 'vif_s_remove': [], + 'vif': [], + 'vif_remove': [] +} + + +def apply_vlan_config(vlan, config): + """ + Generic function to apply a VLAN configuration from a dictionary + to a VLAN interface + """ + + if type(vlan) != type(VLANIf("lo")): + raise TypeError() + + # update interface description used e.g. within SNMP + vlan.ifalias = config['description'] + # ignore link state changes + vlan.link_detect = config['disable_link_detect'] + # Maximum Transmission Unit (MTU) + vlan.mtu = config['mtu'] + # Change VLAN interface MAC address + if config['mac']: + vlan.mac = config['mac'] + + # enable/disable VLAN interface + if config['disable']: + vlan.state = 'down' + else: + vlan.state = 'up' + + # Configure interface address(es) + # - not longer required addresses get removed first + # - newly addresses will be added second + for addr in config['address_remove']: + vlan.del_addr(addr) + for addr in config['address']: + vlan.add_addr(addr) + + +def get_config(): + eth = deepcopy(default_config_data) + conf = Config() + + # determine tagNode instance + try: + eth['intf'] = os.environ['VYOS_TAGNODE_VALUE'] + except KeyError as E: + print("Interface not specified") + + # check if ethernet interface has been removed + cfg_base = 'interfaces ethernet ' + eth['intf'] + if not conf.exists(cfg_base): + 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) + + # retrieve configured interface addresses + if conf.exists('address'): + eth['address'] = conf.return_values('address') + + # get interface addresses (currently effective) - to determine which + # address is no longer valid and needs to be removed + eff_addr = conf.return_effective_values('address') + eth['address_remove'] = list_diff(eff_addr, eth['address']) + + # retrieve interface description + if conf.exists('description'): + eth['description'] = conf.return_value('description') + else: + eth['description'] = eth['intf'] + + # get DHCP client identifier + if conf.exists('dhcp-options client-id'): + eth['dhcp_client_id'] = conf.return_value('dhcp-options client-id') + + # DHCP client host name (overrides the system host name) + if conf.exists('dhcp-options host-name'): + eth['dhcp_hostname'] = conf.return_value('dhcp-options host-name') + + # DHCPv6 only acquire config parameters, no address + if conf.exists('dhcpv6-options parameters-only'): + eth['dhcpv6_prm_only'] = conf.return_value('dhcpv6-options parameters-only') + + # DHCPv6 temporary IPv6 address + if conf.exists('dhcpv6-options temporary'): + eth['dhcpv6_temporary'] = conf.return_value('dhcpv6-options temporary') + + # ignore link state changes + if conf.exists('disable-link-detect'): + eth['disable_link_detect'] = 2 + + # disable interface + if conf.exists('disable'): + eth['disable'] = True + + # 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 proxy-arp on this interface + if conf.exists('ip enable-proxy-arp'): + eth['ip_proxy_arp'] = 1 + + # Enable private VLAN proxy ARP on this interface + if conf.exists('ip proxy-arp-pvlan'): + eth['ip_proxy_arp_pvlan'] = 1 + + # Media Access Control (MAC) address + if conf.exists('mac'): + eth['mac'] = conf.return_value('mac') + + # Maximum Transmission Unit (MTU) + if conf.exists('mtu'): + eth['mtu'] = int(conf.return_value('mtu')) + + # re-set configuration level and retrieve vif-s interfaces + conf.set_level(cfg_base) + # get vif-s interfaces (currently effective) - to determine which vif-s + # interface is no longer present and needs to be removed + eff_intf = conf.list_effective_nodes('vif-s') + act_intf = conf.list_nodes('vif-s') + eth['vif_s_remove'] = list_diff(eff_intf, act_intf) + + if conf.exists('vif-s'): + for vif_s in conf.list_nodes('vif-s'): + # set config level to vif-s interface + conf.set_level(cfg_base + ' vif-s ' + vif_s) + eth['vif_s'].append(vlan_to_dict(conf)) + + # re-set configuration level and retrieve vif-s interfaces + conf.set_level(cfg_base) + # Determine vif interfaces (currently effective) - to determine which + # vif interface is no longer present and needs to be removed + eff_intf = conf.list_effective_nodes('vif') + act_intf = conf.list_nodes('vif') + eth['vif_remove'] = list_diff(eff_intf, act_intf) + + if conf.exists('vif'): + for vif in conf.list_nodes('vif'): + # set config level to vif interface + conf.set_level(cfg_base + ' vif ' + vif) + eth['vif'].append(vlan_to_dict(conf)) + + return eth + + +def verify(eth): + conf = Config() + # some options can not be changed when interface is enslaved to a bond + for bond in conf.list_nodes('interfaces bonding'): + if conf.exists('interfaces bonding ' + bond + ' member interface'): + if eth['name'] in conf.return_values('interfaces bonding ' + bond + ' member interface'): + if eth['disable']: + raise ConfigError('Can not disable interface {} which is a member of {}').format(eth['intf'], bond) + + if eth['address']: + raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond) + + + return None + + +def generate(eth): + import pprint + pprint.pprint(eth) + return None + + +def apply(eth): + e = EthernetIf(eth['intf']) + # update interface description used e.g. within SNMP + e.ifalias = eth['description'] + + # + # missing DHCP/DHCPv6 options go here + # + + # ignore link state changes + e.link_detect = eth['disable_link_detect'] + # configure ARP cache timeout in milliseconds + e.arp_cache_tmp = eth['ip_arp_cache_tmo'] + # Enable proxy-arp on this interface + e.proxy_arp = eth['ip_proxy_arp'] + # Enable private VLAN proxy ARP on this interface + e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan'] + + # Change interface MAC address + if eth['mac']: + e.mac = eth['mac'] + + # Maximum Transmission Unit (MTU) + e.mtu = eth['mtu'] + + # 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) + + # Enable/Disable interface + if eth['disable']: + e.state = 'down' + else: + e.state = 'up' + + # remove no longer required service VLAN interfaces (vif-s) + for vif_s in eth['vif_s_remove']: + e.del_vlan(vif_s) + + # create service VLAN interfaces (vif-s) + for vif_s in eth['vif_s']: + s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) + apply_vlan_config(s_vlan, vif_s) + + # remove no longer required client VLAN interfaces (vif-c) + # on lower service VLAN interface + for vif_c in vif_s['vif_c_remove']: + s_vlan.del_vlan(vif_c) + + # create client VLAN interfaces (vif-c) + # on lower service VLAN interface + for vif_c in vif_s['vif_c']: + c_vlan = s_vlan.add_vlan(vif_c['id']) + apply_vlan_config(c_vlan, vif_c) + + # remove no longer required VLAN interfaces (vif) + for vif in eth['vif_remove']: + e.del_vlan(vif) + + # create VLAN interfaces (vif) + for vif in eth['vif']: + vlan = e.add_vlan(vif['id']) + apply_vlan_config(vlan, vif) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + exit(1) -- cgit v1.2.3 From bebb43450fcca4c086ab1a64be6919441c7c0032 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 18:48:31 +0200 Subject: Python/ifconfig: T1557: support VLAN {ingress,egress}-qos-mapping ingress-qos-map - defines a mapping of VLAN header prio field to the Linux internal packet priority on incoming frames. The format is FROM:TO with multiple mappings separated by spaces. egress-qos-map - defines a mapping of Linux internal packet priority to VLAN header prio field but for outgoing frames. The format is the same as for ingress-qos-map. --- python/vyos/configdict.py | 22 +++++++++++++++++++++- python/vyos/ifconfig.py | 22 +++++++++++++++++++--- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/python/vyos/configdict.py b/python/vyos/configdict.py index 4bc8863bb..1c9cf6897 100644 --- a/python/vyos/configdict.py +++ b/python/vyos/configdict.py @@ -116,6 +116,10 @@ def vlan_to_dict(conf): 'dhcpv6_temporary': False, 'disable': False, 'disable_link_detect': 1, + 'egress_qos': '', + 'egress_qos_changed': False, + 'ingress_qos': '', + 'ingress_qos_changed': False, 'mac': '', 'mtu': 1500 } @@ -153,7 +157,7 @@ def vlan_to_dict(conf): if conf.exists('disable-link-detect'): vlan['disable_link_detect'] = 2 - # disable bond interface + # disable VLAN interface if conf.exists('disable'): vlan['disable'] = True @@ -165,6 +169,22 @@ def vlan_to_dict(conf): if conf.exists('mtu'): vlan['mtu'] = int(conf.return_value('mtu')) + # VLAN egress QoS + if conf.exists('egress-qos'): + vlan['egress_qos'] = conf.return_value('egress-qos') + + # egress changes QoS require VLAN interface recreation + if vlan['egress_qos'] != conf.return_effective_value('egress-qos'): + vlan['egress_qos_changed'] = True + + # VLAN ingress QoS + if conf.exists('ingress-qos'): + vlan['ingress_qos'] = conf.return_value('ingress-qos') + + # ingress changes QoS require VLAN interface recreation + if vlan['ingress_qos'] != conf.return_effective_value('ingress-qos'): + vlan['ingress_qos_changed'] = True + # ethertype is mandatory on vif-s nodes and only exists here! # check if this is a vif-s node at all: if conf.get_level().split()[-2] == 'vif-s': diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 7181ff42f..80b5592c2 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1005,7 +1005,7 @@ class VLANIf(Interface): def __init__(self, ifname, type=None): super().__init__(ifname, type) - def add_vlan(self, vlan_id, ethertype=''): + def add_vlan(self, vlan_id, ethertype='', ingress_qos='', egress_qos=''): """ A virtual LAN (VLAN) is any broadcast domain that is partitioned and isolated in a computer network at the data link layer (OSI layer 2). @@ -1017,6 +1017,13 @@ class VLANIf(Interface): A new object of type VLANIf is returned once the interface has been created. + + @param ethertype: If specified, create 802.1ad or 802.1q Q-in-Q VLAN + interface + @param ingress_qos: Defines a mapping of VLAN header prio field to the + Linux internal packet priority on incoming frames. + @param ingress_qos: Defines a mapping of Linux internal packet priority + to VLAN header prio field but for outgoing frames. """ vlan_ifname = self._ifname + '.' + str(vlan_id) if not os.path.exists('/sys/class/net/{}'.format(vlan_ifname)): @@ -1026,9 +1033,18 @@ class VLANIf(Interface): self._ethertype = ethertype ethertype = 'proto {}'.format(ethertype) + # Optional ingress QOS mapping + opt_i = '' + if ingress_qos: + opt_i = 'ingress-qos-map ' + ingress_qos + # Optional egress QOS mapping + opt_e = '' + if egress_qos: + opt_e = 'egress-qos-map ' + egress_qos + # create interface in the system - cmd = 'ip link add link {intf} name {intf}.{vlan} type vlan {proto} id {vlan}'.format( - intf=self._ifname, vlan=self._vlan_id, proto=ethertype) + cmd = 'ip link add link {intf} name {intf}.{vlan} type vlan {proto} id {vlan} {opt_e} {opt_i}' \ + .format(intf=self._ifname, vlan=self._vlan_id, proto=ethertype, opt_e=opt_e, opt_i=opt_i) self._cmd(cmd) # return new object mapping to the newly created interface -- cgit v1.2.3 From f8d6ba647e0ef4f1c18302bfb4bebb040f2df95c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 18:49:42 +0200 Subject: ethernet: T1637: support VLAN {ingress,egress}-qos-mapping --- src/conf_mode/interface-ethernet.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 4aed13a62..c20e551d6 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -282,7 +282,12 @@ def apply(eth): # create VLAN interfaces (vif) for vif in eth['vif']: - vlan = e.add_vlan(vif['id']) + # QoS priority mapping can only be set during interface creation + # so we delete the interface first if required. + if vif['egress_qos_changed'] or vif['ingress_qos_changed']: + e.del_vlan(vif['id']) + + vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos']) apply_vlan_config(vlan, vif) return None -- cgit v1.2.3 From eb48a7fde5c37f1c905d1c85aca7d0518f65e652 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 19:51:33 +0200 Subject: Python/ifconfig: T1557: import cleanup for subprocess --- python/vyos/ifconfig.py | 62 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 80b5592c2..9b37fdbff 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -15,12 +15,12 @@ import os import re -import subprocess import jinja2 from vyos.validate import * from ipaddress import IPv4Network, IPv6Address from netifaces import ifaddresses, AF_INET, AF_INET6 +from subprocess import Popen, PIPE from time import sleep dhcp_cfg = """ @@ -84,6 +84,36 @@ class Interface: if os.path.isfile('/tmp/vyos.ifconfig.debug'): print('DEBUG/{:<6} {}'.format(self._ifname, msg)) + def _cmd(self, command): + p = Popen(command, stdout=PIPE, shell=True) + tmp = p.communicate()[0].strip() + self._debug_msg("cmd '{}'".format(command)) + if tmp.decode(): + self._debug_msg("returned:\n{}".format(tmp.decode())) + + # do we need some error checking code here? + + def _read_sysfs(self, filename): + """ + Provide a single primitive w/ error checking for reading from sysfs. + """ + value = None + with open(filename, 'r') as f: + value = f.read().rstrip('\n') + + self._debug_msg("read '{}' < '{}'".format(value, filename)) + return value + + def _write_sysfs(self, filename, value): + """ + Provide a single primitive w/ error checking for writing to sysfs. + """ + self._debug_msg("write '{}' > '{}'".format(value, filename)) + with open(filename, 'w') as f: + f.write(str(value)) + + return None + def remove(self): """ Remove interface from operating system. Removing the interface @@ -118,36 +148,6 @@ class Interface: cmd = 'ip link del dev {}'.format(self._ifname) self._cmd(cmd) - def _cmd(self, command): - self._debug_msg("cmd '{}'".format(command)) - - process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) - proc_stdout = process.communicate()[0].strip() - - # add exception handling code - pass - - def _read_sysfs(self, filename): - """ - Provide a single primitive w/ error checking for reading from sysfs. - """ - value = None - with open(filename, 'r') as f: - value = f.read().rstrip('\n') - - self._debug_msg("read '{}' < '{}'".format(value, filename)) - return value - - def _write_sysfs(self, filename, value): - """ - Provide a single primitive w/ error checking for writing to sysfs. - """ - self._debug_msg("write '{}' > '{}'".format(value, filename)) - with open(filename, 'w') as f: - f.write(str(value)) - - return None - @property def mtu(self): """ -- cgit v1.2.3 From 78c0fc6050d05c03bd35c7d4beacef9da432deb3 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 19:52:18 +0200 Subject: Python/ifconfig: T1557: ethernet: support changing flow control Ethernet flow control can be set by set_flow_control() which enables/disables generation of pause frames. --- python/vyos/ifconfig.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 9b37fdbff..9310ee278 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1073,6 +1073,25 @@ class EthernetIf(VLANIf): def remove(self): raise OSError('Ethernet interfaces can not be removed') + def set_flow_control(self, enable): + """ + Changes the pause parameters of the specified Ethernet device. + + @param enable: true -> enable pause frames, false -> disable pause frames + """ + if enable not in ['on', 'off']: + raise ValueError("Value out of range") + + # Assemble command executed on system. Unfortunately there is no way + # to change this setting via sysfs + cmd = 'ethtool --pause {0} autoneg {1} tx {1} rx {1}'.format( + self._ifname, enable) + try: + # An exception will be thrown if the settings are not changed + self._cmd(cmd) + except CalledProcessError: + pass + class BondIf(VLANIf): """ -- cgit v1.2.3 From 735a7d663c279e25feadcfad79e17be7fc0d8c8f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 19:53:49 +0200 Subject: ethernet: T1637: reset MAC address to read hw-id on removal --- src/conf_mode/interface-ethernet.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index c20e551d6..83459cedb 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -140,6 +140,10 @@ def get_config(): if conf.exists('disable-link-detect'): eth['disable_link_detect'] = 2 + # retrieve real hardware address + if conf.exists('hw-id'): + eth['hw_id'] = conf.return_value('hw-id') + # disable interface if conf.exists('disable'): eth['disable'] = True @@ -235,9 +239,12 @@ def apply(eth): # Enable private VLAN proxy ARP on this interface e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan'] - # Change interface MAC address + # Change interface MAC address - re-set to real hardware address (hw-id) + # if custom mac is removed if eth['mac']: e.mac = eth['mac'] + else: + e.mac = eth['hw_id'] # Maximum Transmission Unit (MTU) e.mtu = eth['mtu'] -- cgit v1.2.3 From ca9964099fe67128bd380fb6026f1631ccd89f11 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 19:54:21 +0200 Subject: ethernet: T1637: support changing flow-control --- src/conf_mode/interface-ethernet.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 83459cedb..a12980bfe 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -35,6 +35,7 @@ default_config_data = { 'dhcpv6_temporary': False, 'disable': False, 'disable_link_detect': 1, + 'flow_control': 'on', 'hw_id': '', 'ip_arp_cache_tmo': 30, 'ip_proxy_arp': 0, @@ -140,6 +141,10 @@ def get_config(): if conf.exists('disable-link-detect'): eth['disable_link_detect'] = 2 + # 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') @@ -232,6 +237,8 @@ def apply(eth): # ignore link state changes e.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.arp_cache_tmp = eth['ip_arp_cache_tmo'] # Enable proxy-arp on this interface -- cgit v1.2.3 From 04399a6e724c95c44e136f4675b04262de73d156 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 8 Sep 2019 20:04:45 +0200 Subject: Python/ifconfig: T1557: mac: ignore empty address strings --- python/vyos/ifconfig.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 9310ee278..ab8799e54 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -43,7 +43,6 @@ dhclient_base = r'/var/lib/dhcp/dhclient_' class Interface: - def __init__(self, ifname, type=None): """ This is the base interface class which supports basic IP/MAC address @@ -202,6 +201,10 @@ class Interface: >>> Interface('eth0').mac '00:90:43:fe:fe:1b' """ + # on interface removal (ethernet) an empty string is passed - ignore it + if not mac: + return None + # a mac address consits out of 6 octets octets = len(mac.split(':')) if octets != 6: -- cgit v1.2.3 From 1d2bec57085303420b3e12dc61a44edd62c4c490 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Tue, 10 Sep 2019 21:40:10 +0200 Subject: ethernet: T1637: handle VLAN interface exception on system startup On system bootup the above condition is true but the interface does not exists, which throws an exception, but that's legal. Simply pass the exception! With this change VyOS boots up and configures ethernet VLAN interfaces as expected. --- src/conf_mode/interface-ethernet.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index a12980bfe..3091e0717 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -299,7 +299,12 @@ def apply(eth): # QoS priority mapping can only be set during interface creation # so we delete the interface first if required. if vif['egress_qos_changed'] or vif['ingress_qos_changed']: - e.del_vlan(vif['id']) + try: + # on system bootup the above condition is true but the interface + # does not exists, which throws an exception, but that's legal + e.del_vlan(vif['id']) + except: + pass vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos']) apply_vlan_config(vlan, vif) -- cgit v1.2.3 From f107a252020d225b4e7429cc5c3a61af6cb2e1d9 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 12 Sep 2019 21:23:14 +0200 Subject: ethernet: T1637: only list supported link speeds for completion helper --- interface-definitions/interfaces-ethernet.xml | 29 +++------------------------ 1 file changed, 3 insertions(+), 26 deletions(-) diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml index a2de4aeb3..14a6ff095 100644 --- a/interface-definitions/interfaces-ethernet.xml +++ b/interface-definitions/interfaces-ethernet.xml @@ -337,38 +337,15 @@ - Link speed + Link speed in MBit/s - auto 10 100 1000 2500 5000 10000 + auto + auto Auto negotiation (default) - - 10 - 10 Mbit/sec - - - 100 - 100 Mbit/sec - - - 1000 - 1 Gbit/sec - - - 2500 - 2.5 Gbit/sec - - - 5000 - 5 Gbit/sec - - - 10000 - 10 Gbit/sec - (auto|10|100|1000|2500|5000|10000) -- cgit v1.2.3 From 66884984c7b4b5b445322828541a942fa9e705c1 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 13 Sep 2019 16:36:08 +0200 Subject: Python/ifconfig: T1557: ethernet: add method for changing speed and duplex --- python/vyos/ifconfig.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index ab8799e54..507df0d71 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1095,6 +1095,28 @@ class EthernetIf(VLANIf): except CalledProcessError: pass + def set_speed_duplex(self, speed, duplex): + """ + Set link speed in Mbit/s and duplex. + + @speed can be any link speed in MBit/s, e.g. 10, 100, 1000 auto + @duplex can be half, full, auto + """ + + if speed not in ['auto', '10', '100', '1000', '2500', '5000', '10000', '25000', '40000', '50000', '100000', '400000']: + raise ValueError("Value out of range (speed)") + + if duplex not in ['auto', 'full', 'half']: + raise ValueError("Value out of range (duplex)") + + cmd = 'ethtool -s {}'.format(self._ifname) + if speed == 'auto' or duplex == 'auto': + cmd += ' autoneg on' + else: + cmd += ' speed {} duplex {} autoneg off'.format(speed, duplex) + + return self._cmd(cmd) + class BondIf(VLANIf): """ -- cgit v1.2.3 From fc7685dcbb47a4f80a3e554efa8f60799009151b Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Fri, 13 Sep 2019 16:36:30 +0200 Subject: ethernet: T1637: change speed and duplex settings --- src/conf_mode/interface-ethernet.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 3091e0717..30e7c4b1f 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -35,6 +35,7 @@ default_config_data = { 'dhcpv6_temporary': False, 'disable': False, 'disable_link_detect': 1, + 'duplex': 'auto', 'flow_control': 'on', 'hw_id': '', 'ip_arp_cache_tmo': 30, @@ -43,6 +44,7 @@ default_config_data = { 'intf': '', 'mac': '', 'mtu': 1500, + 'speed': 'auto', 'vif_s': [], 'vif_s_remove': [], 'vif': [], @@ -153,6 +155,10 @@ def get_config(): if conf.exists('disable'): eth['disable'] = True + # 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')) @@ -173,6 +179,10 @@ def get_config(): if conf.exists('mtu'): eth['mtu'] = int(conf.return_value('mtu')) + # interface speed + if conf.exists('speed'): + eth['speed'] = conf.return_value('speed') + # re-set configuration level and retrieve vif-s interfaces conf.set_level(cfg_base) # get vif-s interfaces (currently effective) - to determine which vif-s @@ -205,6 +215,14 @@ def get_config(): def verify(eth): + 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') + conf = Config() # some options can not be changed when interface is enslaved to a bond for bond in conf.list_nodes('interfaces bonding'): @@ -256,6 +274,9 @@ def apply(eth): # Maximum Transmission Unit (MTU) e.mtu = eth['mtu'] + # Set physical interface speed and duplex + e.set_speed_duplex(eth['speed'], eth['duplex']) + # Configure interface address(es) # - not longer required addresses get removed first # - newly addresses will be added second -- cgit v1.2.3 From fcc97a25da94f02e4be1c9b077020490334516c2 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 13:35:57 +0200 Subject: Revert "ethernet: T1637: only list supported link speeds for completion helper" This reverts commit d6a6daaf1d7ed0f1ff2e53490972e0cf11fff000. --- interface-definitions/interfaces-ethernet.xml | 29 ++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml index 14a6ff095..a2de4aeb3 100644 --- a/interface-definitions/interfaces-ethernet.xml +++ b/interface-definitions/interfaces-ethernet.xml @@ -337,15 +337,38 @@ - Link speed in MBit/s + Link speed - auto - + auto 10 100 1000 2500 5000 10000 auto Auto negotiation (default) + + 10 + 10 Mbit/sec + + + 100 + 100 Mbit/sec + + + 1000 + 1 Gbit/sec + + + 2500 + 2.5 Gbit/sec + + + 5000 + 5 Gbit/sec + + + 10000 + 10 Gbit/sec + (auto|10|100|1000|2500|5000|10000) -- cgit v1.2.3 From 7dd89ff63e34ef0e824df5d15966235c09444c27 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 13:38:35 +0200 Subject: ethernet: T1637: add support for 25G, 40G, 50G and 100G link speeds --- interface-definitions/interfaces-ethernet.xml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/interface-definitions/interfaces-ethernet.xml b/interface-definitions/interfaces-ethernet.xml index a2de4aeb3..9244f3b5f 100644 --- a/interface-definitions/interfaces-ethernet.xml +++ b/interface-definitions/interfaces-ethernet.xml @@ -339,7 +339,7 @@ Link speed - auto 10 100 1000 2500 5000 10000 + auto 10 100 1000 2500 5000 10000 25000 40000 50000 100000 auto @@ -369,10 +369,26 @@ 10000 10 Gbit/sec + + 25000 + 25 Gbit/sec + + + 40000 + 40 Gbit/sec + + + 50000 + 50 Gbit/sec + + + 100000 + 100 Gbit/sec + - (auto|10|100|1000|2500|5000|10000) + (auto|10|100|1000|2500|5000|10000|25000|40000|50000|100000) - Speed must be auto, 10, 100, 1000, 2500, 5000 or 10000 + Speed must be auto, 10, 100, 1000, 2500, 5000, 10000, 25000, 40000, 50000 or 100000 -- cgit v1.2.3 From 4c2db299625fb3275df12d3174b64428112f3756 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 13:52:09 +0200 Subject: Python/ifconfig: T1557: redirect _cmd stderr to stdout --- python/vyos/ifconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 507df0d71..398f2ee8f 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -20,7 +20,7 @@ import jinja2 from vyos.validate import * from ipaddress import IPv4Network, IPv6Address from netifaces import ifaddresses, AF_INET, AF_INET6 -from subprocess import Popen, PIPE +from subprocess import Popen, PIPE, STDOUT from time import sleep dhcp_cfg = """ @@ -84,7 +84,7 @@ class Interface: print('DEBUG/{:<6} {}'.format(self._ifname, msg)) def _cmd(self, command): - p = Popen(command, stdout=PIPE, shell=True) + p = Popen(command, stdout=PIPE, stderr=STDOUT, shell=True) tmp = p.communicate()[0].strip() self._debug_msg("cmd '{}'".format(command)) if tmp.decode(): -- cgit v1.2.3 From 1978abbe9d35571bbf57695f04f4a89550a35b1f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 13:57:31 +0200 Subject: Python/ifconfig: T1557: add ethernet interface get_driver_name() --- python/vyos/ifconfig.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 398f2ee8f..de53f8b25 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1076,6 +1076,14 @@ class EthernetIf(VLANIf): def remove(self): raise OSError('Ethernet interfaces can not be removed') + def get_driver_name(self): + """ + Return the driver name used by NIC. Some NICs don't support all + features e.g. changing link-speed, duplex + """ + link = os.readlink('/sys/class/net/{}/device/driver/module'.format(self._ifname)) + return os.path.basename(link) + def set_flow_control(self, enable): """ Changes the pause parameters of the specified Ethernet device. -- cgit v1.2.3 From 822976ac1c6972da38c7cb47dfdfdcee75a68457 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:26:31 +0200 Subject: Python/ifconfig: T1557: return stdout string for _cmd() --- python/vyos/ifconfig.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index de53f8b25..fe3cd20ef 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -91,6 +91,7 @@ class Interface: self._debug_msg("returned:\n{}".format(tmp.decode())) # do we need some error checking code here? + return tmp def _read_sysfs(self, filename): """ -- cgit v1.2.3 From f2ca377c2a92e1036c4ff942bd61d3e4bb4f4a18 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:26:54 +0200 Subject: Python/ifconfig: T1557: call ethtool with full path --- python/vyos/ifconfig.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index fe3cd20ef..9e6c27430 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1096,7 +1096,7 @@ class EthernetIf(VLANIf): # Assemble command executed on system. Unfortunately there is no way # to change this setting via sysfs - cmd = 'ethtool --pause {0} autoneg {1} tx {1} rx {1}'.format( + cmd = '/sbin/ethtool --pause {0} autoneg {1} tx {1} rx {1}'.format( self._ifname, enable) try: # An exception will be thrown if the settings are not changed @@ -1118,7 +1118,7 @@ class EthernetIf(VLANIf): if duplex not in ['auto', 'full', 'half']: raise ValueError("Value out of range (duplex)") - cmd = 'ethtool -s {}'.format(self._ifname) + cmd = '/sbin/ethtool -s {}'.format(self._ifname) if speed == 'auto' or duplex == 'auto': cmd += ' autoneg on' else: -- cgit v1.2.3 From 2e210396036ffc769d941104729f67a5f64a0b24 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:46:03 +0200 Subject: Python/ifconfig: T1557: query driver if it supports auto negotiation --- python/vyos/ifconfig.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 9e6c27430..cbedcc86e 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1085,6 +1085,24 @@ class EthernetIf(VLANIf): link = os.readlink('/sys/class/net/{}/device/driver/module'.format(self._ifname)) return os.path.basename(link) + def has_autoneg(self): + """ + Not all drivers support autonegotiation. + + returns True -> Autonegotiation is supported by driver + False -> Autonegotiation is not supported by driver + """ + regex = 'Supports auto-negotiation:[ ]\w+' + tmp = self._cmd('/sbin/ethtool {}'.format(self._ifname)) + tmp = re.search(regex, tmp.decode()) + + # Output is either 'Supports auto-negotiation: Yes' or + # 'Supports auto-negotiation: No' + if tmp.group().split(':')[1].lstrip() == "Yes": + return True + else: + return False + def set_flow_control(self, enable): """ Changes the pause parameters of the specified Ethernet device. -- cgit v1.2.3 From f5784bd48a6600372696b6731d4300735e710dd3 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:46:30 +0200 Subject: Python/ifconfig: T1557: vmxnet3/virtio_net do not support changing flow control --- python/vyos/ifconfig.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index cbedcc86e..17cc7a2a7 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1112,6 +1112,11 @@ class EthernetIf(VLANIf): if enable not in ['on', 'off']: raise ValueError("Value out of range") + if self.get_driver_name() in ['vmxnet3', 'virtio_net']: + self._debug_msg('{} driver does not support changing flow control settings!' + .format(self.get_driver_name())) + return + # Assemble command executed on system. Unfortunately there is no way # to change this setting via sysfs cmd = '/sbin/ethtool --pause {0} autoneg {1} tx {1} rx {1}'.format( -- cgit v1.2.3 From 9fe2bcb3666bc115e0d5f907b0097a874efa43ff Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:46:44 +0200 Subject: Python/ifconfig: T1557: vmxnet3/virtio_net do not support changing speed/duplex control --- python/vyos/ifconfig.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 17cc7a2a7..e1c1e0246 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1141,6 +1141,12 @@ class EthernetIf(VLANIf): if duplex not in ['auto', 'full', 'half']: raise ValueError("Value out of range (duplex)") + if self.get_driver_name() in ['vmxnet3', 'virtio_net']: + self._debug_msg('{} driver does not support changing speed/duplex settings!' + .format(self.get_driver_name())) + return + + cmd = '/sbin/ethtool -s {}'.format(self._ifname) if speed == 'auto' or duplex == 'auto': cmd += ' autoneg on' -- cgit v1.2.3 From 033b32b20a7a277d2da180388aba78e30c2ed074 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 14:58:05 +0200 Subject: Python/ifconfig: T1557: unify '/sys/class/net/{}' path --- python/vyos/ifconfig.py | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index e1c1e0246..7ebe1248e 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -158,7 +158,7 @@ class Interface: >>> Interface('eth0').mtu '1500' """ - return self._read_sysfs('/sys/class/net/{0}/mtu' + return self._read_sysfs('/sys/class/net/{}/mtu' .format(self._ifname)) @mtu.setter @@ -175,7 +175,7 @@ class Interface: if mtu < 68 or mtu > 9000: raise ValueError('Invalid MTU size: "{}"'.format(mru)) - return self._write_sysfs('/sys/class/net/{0}/mtu' + return self._write_sysfs('/sys/class/net/{}/mtu' .format(self._ifname), mtu) @property @@ -188,7 +188,7 @@ class Interface: >>> Interface('eth0').mac '00:0c:29:11:aa:cc' """ - return self._read_sysfs('/sys/class/net/{0}/address' + return self._read_sysfs('/sys/class/net/{}/address' .format(self._ifname)) @mac.setter @@ -307,7 +307,7 @@ class Interface: >>> Interface('eth0').ifalias '' """ - return self._read_sysfs('/sys/class/net/{0}/ifalias' + return self._read_sysfs('/sys/class/net/{}/ifalias' .format(self._ifname)) @ifalias.setter @@ -331,7 +331,7 @@ class Interface: # clear interface alias ifalias = '\0' - self._write_sysfs('/sys/class/net/{0}/ifalias' + self._write_sysfs('/sys/class/net/{}/ifalias' .format(self._ifname), ifalias) @property @@ -344,7 +344,7 @@ class Interface: >>> Interface('eth0').state 'up' """ - return self._read_sysfs('/sys/class/net/{0}/operstate' + return self._read_sysfs('/sys/class/net/{}/operstate' .format(self._ifname)) @state.setter @@ -763,7 +763,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').aging_time '300' """ - return (self._read_sysfs('/sys/class/net/{0}/bridge/ageing_time' + return (self._read_sysfs('/sys/class/net/{}/bridge/ageing_time' .format(self._ifname)) / 100) @ageing_time.setter @@ -777,7 +777,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').ageing_time = 2 """ time = int(time) * 100 - return self._write_sysfs('/sys/class/net/{0}/bridge/ageing_time' + return self._write_sysfs('/sys/class/net/{}/bridge/ageing_time' .format(self._ifname), time) @property @@ -791,7 +791,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').ageing_time '3' """ - return (self._read_sysfs('/sys/class/net/{0}/bridge/forward_delay' + return (self._read_sysfs('/sys/class/net/{}/bridge/forward_delay' .format(self._ifname)) / 100) @forward_delay.setter @@ -804,7 +804,7 @@ class BridgeIf(Interface): >>> from vyos.ifconfig import Interface >>> BridgeIf('br0').forward_delay = 15 """ - return self._write_sysfs('/sys/class/net/{0}/bridge/forward_delay' + return self._write_sysfs('/sys/class/net/{}/bridge/forward_delay' .format(self._ifname), (int(time) * 100)) @property @@ -818,7 +818,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').hello_time '2' """ - return (self._read_sysfs('/sys/class/net/{0}/bridge/hello_time' + return (self._read_sysfs('/sys/class/net/{}/bridge/hello_time' .format(self._ifname)) / 100) @hello_time.setter @@ -831,7 +831,7 @@ class BridgeIf(Interface): >>> from vyos.ifconfig import Interface >>> BridgeIf('br0').hello_time = 2 """ - return self._write_sysfs('/sys/class/net/{0}/bridge/hello_time' + return self._write_sysfs('/sys/class/net/{}/bridge/hello_time' .format(self._ifname), (int(time) * 100)) @property @@ -846,7 +846,7 @@ class BridgeIf(Interface): '20' """ - return (self._read_sysfs('/sys/class/net/{0}/bridge/max_age' + return (self._read_sysfs('/sys/class/net/{}/bridge/max_age' .format(self._ifname)) / 100) @max_age.setter @@ -859,7 +859,7 @@ class BridgeIf(Interface): >>> from vyos.ifconfig import Interface >>> BridgeIf('br0').max_age = 30 """ - return self._write_sysfs('/sys/class/net/{0}/bridge/max_age' + return self._write_sysfs('/sys/class/net/{}/bridge/max_age' .format(self._ifname), (int(time) * 100)) @property @@ -872,7 +872,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').priority '32768' """ - return self._read_sysfs('/sys/class/net/{0}/bridge/priority' + return self._read_sysfs('/sys/class/net/{}/bridge/priority' .format(self._ifname)) @priority.setter @@ -884,7 +884,7 @@ class BridgeIf(Interface): >>> from vyos.ifconfig import Interface >>> BridgeIf('br0').priority = 8192 """ - return self._write_sysfs('/sys/class/net/{0}/bridge/priority' + return self._write_sysfs('/sys/class/net/{}/bridge/priority' .format(self._ifname), priority) @property @@ -899,7 +899,7 @@ class BridgeIf(Interface): """ state = 0 - with open('/sys/class/net/{0}/bridge/stp_state'.format(self._ifname), 'r') as f: + with open('/sys/class/net/{}/bridge/stp_state'.format(self._ifname), 'r') as f: state = int(f.read().rstrip('\n')) return state @@ -915,7 +915,7 @@ class BridgeIf(Interface): """ if int(state) >= 0 and int(state) <= 1: - return self._write_sysfs('/sys/class/net/{0}/bridge/stp_state' + return self._write_sysfs('/sys/class/net/{}/bridge/stp_state' .format(self._ifname), state) else: raise ValueError("Value out of range") @@ -930,7 +930,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').multicast_querier '0' """ - return self._read_sysfs('/sys/class/net/{0}/bridge/multicast_querier' + return self._read_sysfs('/sys/class/net/{}/bridge/multicast_querier' .format(self._ifname)) @multicast_querier.setter @@ -948,7 +948,7 @@ class BridgeIf(Interface): >>> BridgeIf('br0').multicast_querier = 1 """ if int(enable) >= 0 and int(enable) <= 1: - return self._write_sysfs('/sys/class/net/{0}/bridge/multicast_querier' + return self._write_sysfs('/sys/class/net/{}/bridge/multicast_querier' .format(self._ifname), enable) else: raise ValueError("Value out of range") -- cgit v1.2.3 From fd154227c90c0b0dd10bb14ee5b7585ec2970c22 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 15:25:29 +0200 Subject: bonding: T1614: minor comment cleanup --- src/conf_mode/interface-bonding.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/conf_mode/interface-bonding.py b/src/conf_mode/interface-bonding.py index 0d5f9f6b7..9049913e6 100755 --- a/src/conf_mode/interface-bonding.py +++ b/src/conf_mode/interface-bonding.py @@ -334,8 +334,7 @@ def apply(bond): b = BondIf(bond['intf']) if bond['deleted']: - # - # delete bonding interface + # delete interface b.remove() else: # Some parameters can not be changed when the bond is up. -- cgit v1.2.3 From c5c6d87404b63848068f38ee5c69ccad24feede1 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 15:25:45 +0200 Subject: bridge: T1556: minor comment cleanup --- src/conf_mode/interface-bridge.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/conf_mode/interface-bridge.py b/src/conf_mode/interface-bridge.py index 401182a0d..62589c798 100755 --- a/src/conf_mode/interface-bridge.py +++ b/src/conf_mode/interface-bridge.py @@ -183,8 +183,7 @@ def apply(bridge): br = BridgeIf(bridge['intf']) if bridge['deleted']: - # delete bridge interface - # DHCP is stopped inside remove() + # delete interface br.remove() else: # enable interface -- cgit v1.2.3 From f56b4e190e741bdb2d19d14f2b7004fedc76951c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 15:33:33 +0200 Subject: ethernet: T1637: remove debug pprint --- src/conf_mode/interface-ethernet.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 30e7c4b1f..5bfe35767 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -237,13 +237,9 @@ def verify(eth): return None - def generate(eth): - import pprint - pprint.pprint(eth) return None - def apply(eth): e = EthernetIf(eth['intf']) # update interface description used e.g. within SNMP -- cgit v1.2.3 From 8fe9187419fc77df156bb0cbba3a5ca1d61cc36f Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 15:34:57 +0200 Subject: Python/ifconfig: T1557: use proper inheritance levels on remove() --- python/vyos/ifconfig.py | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 7ebe1248e..980577965 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -125,23 +125,14 @@ class Interface: >>> i = Interface('eth0') >>> i.remove() """ - - # do we have sub interfaces (VLANs)? - # we apply a regex matching subinterfaces (indicated by a .) of a - # parent interface. 'bond0(?:\.\d+){1,2}' will match vif and vif-s/vif-c - # subinterfaces - vlan_ifs = [f for f in os.listdir(r'/sys/class/net') \ - if re.match(self._ifname + r'(?:\.\d+){1,2}', f)] - - for vlan in vlan_ifs: - Interface(vlan).remove() - - # All subinterfaces are now removed, continue on the physical interface - # stop DHCP(v6) if running self._del_dhcp() self._del_dhcpv6() + # Ethernet interfaces can not be removed + if type(self) == type(EthernetIf): + return + # NOTE (Improvement): # after interface removal no other commands should be allowed # to be called and instead should raise an Exception: @@ -1009,6 +1000,31 @@ class VLANIf(Interface): def __init__(self, ifname, type=None): super().__init__(ifname, type) + def remove(self): + """ + Remove interface from operating system. Removing the interface + deconfigures all assigned IP addresses and clear possible DHCP(v6) + client processes. + + Example: + >>> from vyos.ifconfig import Interface + >>> i = Interface('eth0') + >>> i.remove() + """ + # do we have sub interfaces (VLANs)? + # we apply a regex matching subinterfaces (indicated by a .) of a + # parent interface. 'bond0(?:\.\d+){1,2}' will match vif and vif-s/vif-c + # subinterfaces + vlan_ifs = [f for f in os.listdir(r'/sys/class/net') \ + if re.match(self._ifname + r'(?:\.\d+){1,2}', f)] + + for vlan in vlan_ifs: + Interface(vlan).remove() + + # All subinterfaces are now removed, continue on the physical interface + super().remove() + + def add_vlan(self, vlan_id, ethertype='', ingress_qos='', egress_qos=''): """ A virtual LAN (VLAN) is any broadcast domain that is partitioned and @@ -1074,9 +1090,6 @@ class EthernetIf(VLANIf): def __init__(self, ifname): super().__init__(ifname) - def remove(self): - raise OSError('Ethernet interfaces can not be removed') - def get_driver_name(self): """ Return the driver name used by NIC. Some NICs don't support all -- cgit v1.2.3 From 738b62f0fb410daf1dbe97ad8aed9d862b44ec94 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 15:35:27 +0200 Subject: ethernet: T1637: call remove() on interface deletion --- python/vyos/ifconfig.py | 2 +- src/conf_mode/interface-ethernet.py | 171 +++++++++++++++++++----------------- 2 files changed, 90 insertions(+), 83 deletions(-) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 980577965..c0d1660d1 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -130,7 +130,7 @@ class Interface: self._del_dhcpv6() # Ethernet interfaces can not be removed - if type(self) == type(EthernetIf): + if type(self) == type(EthernetIf(self._ifname)): return # NOTE (Improvement): diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 5bfe35767..3faaef96f 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -215,6 +215,9 @@ def get_config(): def verify(eth): + if eth['deleted']: + return None + if eth['speed'] == 'auto': if eth['duplex'] != 'auto': raise ConfigError('If speed is hardcoded, duplex must be hardcoded, too') @@ -242,89 +245,93 @@ def generate(eth): def apply(eth): e = EthernetIf(eth['intf']) - # update interface description used e.g. within SNMP - e.ifalias = eth['description'] - - # - # missing DHCP/DHCPv6 options go here - # - - # ignore link state changes - e.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.arp_cache_tmp = eth['ip_arp_cache_tmo'] - # Enable proxy-arp on this interface - e.proxy_arp = eth['ip_proxy_arp'] - # Enable private VLAN proxy ARP on this interface - e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan'] - - # Change interface MAC address - re-set to real hardware address (hw-id) - # if custom mac is removed - if eth['mac']: - e.mac = eth['mac'] - else: - e.mac = eth['hw_id'] - - # Maximum Transmission Unit (MTU) - e.mtu = eth['mtu'] - - # Set physical interface speed and duplex - e.set_speed_duplex(eth['speed'], eth['duplex']) - - # 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) - - # Enable/Disable interface - if eth['disable']: - e.state = 'down' + if eth['deleted']: + # delete interface + e.remove() else: - e.state = 'up' - - # remove no longer required service VLAN interfaces (vif-s) - for vif_s in eth['vif_s_remove']: - e.del_vlan(vif_s) - - # create service VLAN interfaces (vif-s) - for vif_s in eth['vif_s']: - s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) - apply_vlan_config(s_vlan, vif_s) - - # remove no longer required client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c_remove']: - s_vlan.del_vlan(vif_c) - - # create client VLAN interfaces (vif-c) - # on lower service VLAN interface - for vif_c in vif_s['vif_c']: - c_vlan = s_vlan.add_vlan(vif_c['id']) - apply_vlan_config(c_vlan, vif_c) - - # remove no longer required VLAN interfaces (vif) - for vif in eth['vif_remove']: - e.del_vlan(vif) - - # create VLAN interfaces (vif) - for vif in eth['vif']: - # QoS priority mapping can only be set during interface creation - # so we delete the interface first if required. - if vif['egress_qos_changed'] or vif['ingress_qos_changed']: - try: - # on system bootup the above condition is true but the interface - # does not exists, which throws an exception, but that's legal - e.del_vlan(vif['id']) - except: - pass - - vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos']) - apply_vlan_config(vlan, vif) + # update interface description used e.g. within SNMP + e.ifalias = eth['description'] + + # + # missing DHCP/DHCPv6 options go here + # + + # ignore link state changes + e.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.arp_cache_tmp = eth['ip_arp_cache_tmo'] + # Enable proxy-arp on this interface + e.proxy_arp = eth['ip_proxy_arp'] + # Enable private VLAN proxy ARP on this interface + e.proxy_arp_pvlan = eth['ip_proxy_arp_pvlan'] + + # Change interface MAC address - re-set to real hardware address (hw-id) + # if custom mac is removed + if eth['mac']: + e.mac = eth['mac'] + else: + e.mac = eth['hw_id'] + + # Maximum Transmission Unit (MTU) + e.mtu = eth['mtu'] + + # Set physical interface speed and duplex + e.set_speed_duplex(eth['speed'], eth['duplex']) + + # 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) + + # Enable/Disable interface + if eth['disable']: + e.state = 'down' + else: + e.state = 'up' + + # remove no longer required service VLAN interfaces (vif-s) + for vif_s in eth['vif_s_remove']: + e.del_vlan(vif_s) + + # create service VLAN interfaces (vif-s) + for vif_s in eth['vif_s']: + s_vlan = e.add_vlan(vif_s['id'], ethertype=vif_s['ethertype']) + apply_vlan_config(s_vlan, vif_s) + + # remove no longer required client VLAN interfaces (vif-c) + # on lower service VLAN interface + for vif_c in vif_s['vif_c_remove']: + s_vlan.del_vlan(vif_c) + + # create client VLAN interfaces (vif-c) + # on lower service VLAN interface + for vif_c in vif_s['vif_c']: + c_vlan = s_vlan.add_vlan(vif_c['id']) + apply_vlan_config(c_vlan, vif_c) + + # remove no longer required VLAN interfaces (vif) + for vif in eth['vif_remove']: + e.del_vlan(vif) + + # create VLAN interfaces (vif) + for vif in eth['vif']: + # QoS priority mapping can only be set during interface creation + # so we delete the interface first if required. + if vif['egress_qos_changed'] or vif['ingress_qos_changed']: + try: + # on system bootup the above condition is true but the interface + # does not exists, which throws an exception, but that's legal + e.del_vlan(vif['id']) + except: + pass + + vlan = e.add_vlan(vif['id'], ingress_qos=vif['ingress_qos'], egress_qos=vif['egress_qos']) + apply_vlan_config(vlan, vif) return None -- cgit v1.2.3 From 879036a4db0517dc332c4e2ce3c806495a5fe401 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 16:02:50 +0200 Subject: Python/ifconfig: T1557: delete all assigned IP addresses on remove() --- python/vyos/ifconfig.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index c0d1660d1..4bb320e21 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -129,6 +129,12 @@ class Interface: self._del_dhcp() self._del_dhcpv6() + # remove all assigned IP addresses from interface - this is a bit redundant + # as the kernel will remove all addresses on interface deletion, but we + # can not delete ALL interfaces, see below + for addr in self.get_addr(): + self.del_addr(addr) + # Ethernet interfaces can not be removed if type(self) == type(EthernetIf(self._ifname)): return -- cgit v1.2.3 From 1df0c00879f21dcbb87bdf09291b0c74779e77cb Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 16:23:07 +0200 Subject: Python/ifconfig: T1557: update comments --- python/vyos/ifconfig.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index 4bb320e21..d73e2d43e 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1050,6 +1050,11 @@ class VLANIf(Interface): Linux internal packet priority on incoming frames. @param ingress_qos: Defines a mapping of Linux internal packet priority to VLAN header prio field but for outgoing frames. + + Example: + >>> from vyos.ifconfig import VLANIf + >>> i = VLANIf('eth0') + >>> i.add_vlan(10) """ vlan_ifname = self._ifname + '.' + str(vlan_id) if not os.path.exists('/sys/class/net/{}'.format(vlan_ifname)): @@ -1078,11 +1083,17 @@ class VLANIf(Interface): # or interface description and so on return VLANIf(vlan_ifname) + def del_vlan(self, vlan_id): """ Remove VLAN interface from operating system. Removing the interface deconfigures all assigned IP addresses and clear possible DHCP(v6) client processes. + + Example: + >>> from vyos.ifconfig import VLANIf + >>> i = VLANIf('eth0.10') + >>> i.del_vlan() """ vlan_ifname = self._ifname + '.' + str(vlan_id) tmp = VLANIf(vlan_ifname) @@ -1100,16 +1111,29 @@ class EthernetIf(VLANIf): """ Return the driver name used by NIC. Some NICs don't support all features e.g. changing link-speed, duplex + + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.get_driver_name() + 'vmxnet3' """ link = os.readlink('/sys/class/net/{}/device/driver/module'.format(self._ifname)) return os.path.basename(link) + def has_autoneg(self): """ Not all drivers support autonegotiation. returns True -> Autonegotiation is supported by driver False -> Autonegotiation is not supported by driver + + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.has_autoneg() + 'True' """ regex = 'Supports auto-negotiation:[ ]\w+' tmp = self._cmd('/sbin/ethtool {}'.format(self._ifname)) @@ -1122,11 +1146,17 @@ class EthernetIf(VLANIf): else: return False + def set_flow_control(self, enable): """ Changes the pause parameters of the specified Ethernet device. @param enable: true -> enable pause frames, false -> disable pause frames + + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_flow_control(True) """ if enable not in ['on', 'off']: raise ValueError("Value out of range") @@ -1146,12 +1176,18 @@ class EthernetIf(VLANIf): except CalledProcessError: pass + def set_speed_duplex(self, speed, duplex): """ Set link speed in Mbit/s and duplex. @speed can be any link speed in MBit/s, e.g. 10, 100, 1000 auto @duplex can be half, full, auto + + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_speed_duplex('auto', 'auto') """ if speed not in ['auto', '10', '100', '1000', '2500', '5000', '10000', '25000', '40000', '50000', '100000', '400000']: -- cgit v1.2.3 From b53006d672ba008387bd3e3552070c30a4dca657 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 16:40:44 +0200 Subject: Python/ifconfig: T1557: ethernet: add offloading interfaces --- python/vyos/ifconfig.py | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/python/vyos/ifconfig.py b/python/vyos/ifconfig.py index d73e2d43e..777b185a6 100644 --- a/python/vyos/ifconfig.py +++ b/python/vyos/ifconfig.py @@ -1211,6 +1211,76 @@ class EthernetIf(VLANIf): return self._cmd(cmd) + def set_gro(self, state): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_gro('on') + """ + if state not in ['on', 'off']: + raise ValueError('state must be "on" or "off"') + + cmd = '/sbin/ethtool -K {} gro {}'.format(self._ifname, state) + return self._cmd(cmd) + + + def set_gso(self, state): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_gso('on') + """ + if state not in ['on', 'off']: + raise ValueError('state must be "on" or "off"') + + cmd = '/sbin/ethtool -K {} gso {}'.format(self._ifname, state) + return self._cmd(cmd) + + + def set_sg(self, state): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_sg('on') + """ + if state not in ['on', 'off']: + raise ValueError('state must be "on" or "off"') + + cmd = '/sbin/ethtool -K {} sg {}'.format(self._ifname, state) + return self._cmd(cmd) + + + def set_tso(self, state): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_tso('on') + """ + if state not in ['on', 'off']: + raise ValueError('state must be "on" or "off"') + + cmd = '/sbin/ethtool -K {} tso {}'.format(self._ifname, state) + return self._cmd(cmd) + + + def set_ufo(self, state): + """ + Example: + >>> from vyos.ifconfig import EthernetIf + >>> i = EthernetIf('eth0') + >>> i.set_udp_offload('on') + """ + if state not in ['on', 'off']: + raise ValueError('state must be "on" or "off"') + + cmd = '/sbin/ethtool -K {} ufo {}'.format(self._ifname, state) + return self._cmd(cmd) + + class BondIf(VLANIf): """ The Linux bonding driver provides a method for aggregating multiple network -- cgit v1.2.3 From 63a9d416092e24da02f7d180f4feb6a98bfe85f6 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 16:41:05 +0200 Subject: ethernet: T1637: support offloading functions --- src/conf_mode/interface-ethernet.py | 40 +++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 3faaef96f..72eaee905 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -44,6 +44,11 @@ default_config_data = { 'intf': '', 'mac': '', 'mtu': 1500, + 'offload_gro': 'off', + 'offload_gso': 'off', + 'offload_sg': 'off', + 'offload_tso': 'off', + 'offload_ufo': 'off', 'speed': 'auto', 'vif_s': [], 'vif_s_remove': [], @@ -179,6 +184,26 @@ def get_config(): if conf.exists('mtu'): eth['mtu'] = int(conf.return_value('mtu')) + # 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') @@ -277,6 +302,21 @@ def apply(eth): # Maximum Transmission Unit (MTU) e.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']) -- cgit v1.2.3 From 95b88584fd9239d3143adc6b7935544df208ac88 Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 19:30:55 +0200 Subject: ethernet: T1637: do not overwrite interface description with interface name --- src/conf_mode/interface-ethernet.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 72eaee905..8a72068c5 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -125,8 +125,6 @@ def get_config(): # retrieve interface description if conf.exists('description'): eth['description'] = conf.return_value('description') - else: - eth['description'] = eth['intf'] # get DHCP client identifier if conf.exists('dhcp-options client-id'): -- cgit v1.2.3 From 3bf0a5e586e9139e80cdecd14ab326cee5512fae Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Sun, 15 Sep 2019 20:40:52 +0200 Subject: ethernet: T1637: fix calling arp_cache_tmo property --- src/conf_mode/interface-ethernet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 8a72068c5..4f455e8d3 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -284,7 +284,7 @@ def apply(eth): # disable ethernet flow control (pause frames) e.set_flow_control(eth['flow_control']) # configure ARP cache timeout in milliseconds - e.arp_cache_tmp = eth['ip_arp_cache_tmo'] + e.arp_cache_tmo = eth['ip_arp_cache_tmo'] # Enable proxy-arp on this interface e.proxy_arp = eth['ip_proxy_arp'] # Enable private VLAN proxy ARP on this interface -- cgit v1.2.3 From b27482c0201a433762168abe2d369ea43a599f1c Mon Sep 17 00:00:00 2001 From: Christian Poessinger Date: Thu, 19 Sep 2019 22:29:11 +0200 Subject: ethernet: T1637: interfaces in a bond can be disabled --- src/conf_mode/interface-ethernet.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/conf_mode/interface-ethernet.py b/src/conf_mode/interface-ethernet.py index 4f455e8d3..f82105847 100755 --- a/src/conf_mode/interface-ethernet.py +++ b/src/conf_mode/interface-ethernet.py @@ -253,12 +253,10 @@ def verify(eth): # some options can not be changed when interface is enslaved to a bond for bond in conf.list_nodes('interfaces bonding'): if conf.exists('interfaces bonding ' + bond + ' member interface'): - if eth['name'] in conf.return_values('interfaces bonding ' + bond + ' member interface'): - if eth['disable']: - raise ConfigError('Can not disable interface {} which is a member of {}').format(eth['intf'], bond) - - if eth['address']: - raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond) + bond_member = conf.return_values('interfaces bonding ' + bond + ' member interface') + if eth['name'] in bond_member: + if eth['address']: + raise ConfigError('Can not assign address to interface {} which is a member of {}').format(eth['intf'], bond) return None -- cgit v1.2.3