diff options
| author | Daniil Baturin <daniil@vyos.io> | 2026-03-24 15:26:26 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-03-24 15:26:26 +0000 |
| commit | a9a75eb7dce077bceee1ae13dc943b05d8759925 (patch) | |
| tree | dafec312330120450ba0de57b3f4ca51343178d1 | |
| parent | cb1b97548ce0cb51ee4445c2b1cdc375cd9b6121 (diff) | |
| parent | 1b7b7a468cab0fd23fdeef0d0b76d9812d80980a (diff) | |
| download | vyos-1x-a9a75eb7dce077bceee1ae13dc943b05d8759925.tar.gz vyos-1x-a9a75eb7dce077bceee1ae13dc943b05d8759925.zip | |
Merge pull request #5039 from natali-rs1985/T8355
vpp: T8355: Set MTU for vpp interfaces
| -rw-r--r-- | interface-definitions/vpp_interface_bonding.xml.in | 3 | ||||
| -rw-r--r-- | interface-definitions/vpp_interface_gre.xml.in | 3 | ||||
| -rw-r--r-- | interface-definitions/vpp_interface_ipip.xml.in | 3 | ||||
| -rw-r--r-- | interface-definitions/vpp_interface_vxlan.xml.in | 3 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/bond.py | 6 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/gre.py | 6 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/interface.py | 22 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/ipip.py | 6 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/loopback.py | 5 | ||||
| -rw-r--r-- | python/vyos/ifconfig/vpp/vxlan.py | 5 | ||||
| -rw-r--r-- | python/vyos/utils/network.py | 25 | ||||
| -rw-r--r-- | python/vyos/vpp/control_vpp.py | 7 | ||||
| -rwxr-xr-x | src/conf_mode/interfaces_vxlan.py | 6 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_bonding.py | 17 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_gre.py | 3 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_ipip.py | 3 | ||||
| -rw-r--r-- | src/conf_mode/vpp_interfaces_vxlan.py | 28 |
17 files changed, 127 insertions, 24 deletions
diff --git a/interface-definitions/vpp_interface_bonding.xml.in b/interface-definitions/vpp_interface_bonding.xml.in index 9f114d157..78166e306 100644 --- a/interface-definitions/vpp_interface_bonding.xml.in +++ b/interface-definitions/vpp_interface_bonding.xml.in @@ -108,6 +108,9 @@ </node> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/interface/mtu-68-16000.xml.i> + <leafNode name="mtu"> + <defaultValue>1500</defaultValue> + </leafNode> #include <include/vpp/vif.xml.i> </children> </tagNode> diff --git a/interface-definitions/vpp_interface_gre.xml.in b/interface-definitions/vpp_interface_gre.xml.in index 0ac3fdf1f..a0228420a 100644 --- a/interface-definitions/vpp_interface_gre.xml.in +++ b/interface-definitions/vpp_interface_gre.xml.in @@ -76,6 +76,9 @@ #include <include/interface/tunnel-remote.xml.i> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/interface/mtu-68-16000.xml.i> + <leafNode name="mtu"> + <defaultValue>1476</defaultValue> + </leafNode> </children> </tagNode> </children> diff --git a/interface-definitions/vpp_interface_ipip.xml.in b/interface-definitions/vpp_interface_ipip.xml.in index c965c531c..a214f728e 100644 --- a/interface-definitions/vpp_interface_ipip.xml.in +++ b/interface-definitions/vpp_interface_ipip.xml.in @@ -24,6 +24,9 @@ #include <include/interface/tunnel-remote.xml.i> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/interface/mtu-68-16000.xml.i> + <leafNode name="mtu"> + <defaultValue>1476</defaultValue> + </leafNode> </children> </tagNode> </children> diff --git a/interface-definitions/vpp_interface_vxlan.xml.in b/interface-definitions/vpp_interface_vxlan.xml.in index 9ba90e2a0..1de141b1e 100644 --- a/interface-definitions/vpp_interface_vxlan.xml.in +++ b/interface-definitions/vpp_interface_vxlan.xml.in @@ -25,6 +25,9 @@ #include <include/vni.xml.i> #include <include/interface/address-ipv4-ipv6.xml.i> #include <include/interface/mtu-68-16000.xml.i> + <leafNode name="mtu"> + <defaultValue>1450</defaultValue> + </leafNode> </children> </tagNode> </children> diff --git a/python/vyos/ifconfig/vpp/bond.py b/python/vyos/ifconfig/vpp/bond.py index 75849a620..b3bcce449 100644 --- a/python/vyos/ifconfig/vpp/bond.py +++ b/python/vyos/ifconfig/vpp/bond.py @@ -143,10 +143,8 @@ class VPPBondInterface(Interface, VPPInterface): for member in config.get('member', {}).get('interface', []): self.add_member(interface=member) - # Set rx-mode - rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') - if rx_mode: - self.set_rx_mode(rx_mode) + # Apply VPP-specific interface settings + VPPInterface.update(self, config) # Apply all settings to the lcp pair (kernel) interface super().update(config) diff --git a/python/vyos/ifconfig/vpp/gre.py b/python/vyos/ifconfig/vpp/gre.py index 0cec5e3c9..4cdb27213 100644 --- a/python/vyos/ifconfig/vpp/gre.py +++ b/python/vyos/ifconfig/vpp/gre.py @@ -136,9 +136,7 @@ class VPPGREInterface(Interface, VPPInterface): # Add gre interface self.add_gre() - # Set rx-mode - rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') - if rx_mode: - self.set_rx_mode(rx_mode) + # Apply VPP-specific interface settings + VPPInterface.update(self, config) super().update(config) diff --git a/python/vyos/ifconfig/vpp/interface.py b/python/vyos/ifconfig/vpp/interface.py index 1b87af4d2..17be83814 100644 --- a/python/vyos/ifconfig/vpp/interface.py +++ b/python/vyos/ifconfig/vpp/interface.py @@ -54,3 +54,25 @@ class VPPInterface: lcp_name = lcp_pair.get('vpp_name_kernel') if lcp_name: self.vpp.iface_rxmode(lcp_name, rx_mode) + + def set_mtu_vpp(self, mtu): + # Set MTU for the VPP interface + self.vpp.set_iface_mtu(self.vpp_ifname, mtu) + + # Set MTU for the LCP pair interface + lcp_pair = self.vpp.lcp_pair_find(vpp_name_hw=self.vpp_ifname) + if lcp_pair: + lcp_name = lcp_pair.get('vpp_name_kernel') + if lcp_name: + self.vpp.set_iface_mtu(lcp_name, mtu) + + def update(self, config): + # Set MTU + if 'mtu' in config: + mtu = int(config['mtu']) + self.set_mtu_vpp(mtu) + + # Set rx-mode + rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') + if rx_mode: + self.set_rx_mode(rx_mode) diff --git a/python/vyos/ifconfig/vpp/ipip.py b/python/vyos/ifconfig/vpp/ipip.py index fff79fd43..4605cfa8f 100644 --- a/python/vyos/ifconfig/vpp/ipip.py +++ b/python/vyos/ifconfig/vpp/ipip.py @@ -100,10 +100,8 @@ class VPPIPIPInterface(Interface, VPPInterface): # Add ipip interface self.add_ipip() - # Set rx-mode - rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') - if rx_mode: - self.set_rx_mode(rx_mode) + # Apply VPP-specific interface settings + VPPInterface.update(self, config) # Apply all settings to the lcp pair (kernel) interface super().update(config) diff --git a/python/vyos/ifconfig/vpp/loopback.py b/python/vyos/ifconfig/vpp/loopback.py index 36a30cb58..4d3325820 100644 --- a/python/vyos/ifconfig/vpp/loopback.py +++ b/python/vyos/ifconfig/vpp/loopback.py @@ -96,10 +96,7 @@ class VPPLoopbackInterface(Interface, VPPInterface): # Add loopback interface self.add() - # Set rx-mode - rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') - if rx_mode: - self.set_rx_mode(rx_mode) + VPPInterface.update(self, config) # Apply all settings to the lcp pair (kernel) interface super().update(config) diff --git a/python/vyos/ifconfig/vpp/vxlan.py b/python/vyos/ifconfig/vpp/vxlan.py index 8ca9bee70..f09ed9be3 100644 --- a/python/vyos/ifconfig/vpp/vxlan.py +++ b/python/vyos/ifconfig/vpp/vxlan.py @@ -117,9 +117,6 @@ class VPPVXLANInterface(Interface, VPPInterface): # Add vxlan interface self.add_vxlan() - # Set rx-mode - rx_mode = config.get('vpp_settings', {}).get('interface_rx_mode') - if rx_mode: - self.set_rx_mode(rx_mode) + VPPInterface.update(self, config) super().update(config) diff --git a/python/vyos/utils/network.py b/python/vyos/utils/network.py index 217428a21..de283e546 100644 --- a/python/vyos/utils/network.py +++ b/python/vyos/utils/network.py @@ -696,3 +696,28 @@ def is_valid_ipv6_address_or_range(addr: str) -> bool: return ip_network(addr).version == 6 except: return False + + +def get_interfaces_by_ip(ip_address: str) -> list: + """ + Return a list of all interface names assigned the given IP address. + Args: + ip_address (str): The IP address to search for. + Returns: + list: List of interface names (str) that have the given IP address assigned. + Returns an empty list if no interface has the IP assigned. + """ + import netifaces + from vyos.template import is_ipv6 + + addr_type = AF_INET + if is_ipv6(ip_address): + addr_type = AF_INET6 + + ifaces = [] + for interface in netifaces.interfaces(): + addresses = netifaces.ifaddresses(interface) + for addr_info in addresses.get(addr_type, []): + if addr_info.get('addr') == ip_address: + ifaces.append(interface) + return ifaces diff --git a/python/vyos/vpp/control_vpp.py b/python/vyos/vpp/control_vpp.py index 2daaed423..5f3a18848 100644 --- a/python/vyos/vpp/control_vpp.py +++ b/python/vyos/vpp/control_vpp.py @@ -422,8 +422,11 @@ class VPPControl: mtu (int): MTU """ iface_index = self.get_sw_if_index(iface_name_vpp) - api_call_args: dict[str, str | int] = {'sw_if_index': iface_index, 'mtu': mtu} - return self.__vpp_api_client.api.hw_interface_set_mtu(**api_call_args) + api_call_args: dict[str, int | list[int]] = { + 'sw_if_index': iface_index, + 'mtu': [mtu, 0, 0, 0], + } + return self.__vpp_api_client.api.sw_interface_set_mtu(**api_call_args) @_Decorators.api_call def get_sw_if_dev_type(self, ifname: str) -> int | None: diff --git a/src/conf_mode/interfaces_vxlan.py b/src/conf_mode/interfaces_vxlan.py index 5e23654e1..968214354 100755 --- a/src/conf_mode/interfaces_vxlan.py +++ b/src/conf_mode/interfaces_vxlan.py @@ -159,8 +159,10 @@ def verify(vxlan): lower_mtu = Interface(vxlan['source_interface']).get_mtu() if lower_mtu < (int(vxlan['mtu']) + vxlan_overhead): - raise ConfigError(f'Underlaying device MTU is to small ({lower_mtu} '\ - f'bytes) for VXLAN overhead ({vxlan_overhead} bytes!)') + Warning( + f'Underlying device MTU is too small ({lower_mtu} ' + f'bytes) for VXLAN overhead ({vxlan_overhead} bytes!)' + ) # Check for mixed IPv4 and IPv6 addresses protocol = None diff --git a/src/conf_mode/vpp_interfaces_bonding.py b/src/conf_mode/vpp_interfaces_bonding.py index fa49f2da5..46252c635 100644 --- a/src/conf_mode/vpp_interfaces_bonding.py +++ b/src/conf_mode/vpp_interfaces_bonding.py @@ -19,10 +19,12 @@ from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.configdep import set_dependents, call_dependents +from vyos.configverify import verify_mtu_ipv6 from vyos import ConfigError from vyos.utils.assertion import assert_mac from vyos.utils.process import is_systemd_service_active +from vyos.ifconfig import Interface from vyos.ifconfig.vpp import VPPBondInterface from vyos.vpp.config_deps import deps_bond_dict from vyos.vpp.config_deps import deps_bridge_dict @@ -174,6 +176,19 @@ def verify(config): f'it already belongs to bridge interface: {", ".join(bridge_members)}.' ) + if mtu := config.get('mtu'): + mtu = int(mtu) + max_mtu = Interface(iface).get_max_mtu() + min_mtu = Interface(iface).get_min_mtu() + if mtu > max_mtu: + raise ConfigError( + f'Configured MTU is greater than member interface "{iface}" maximum of {max_mtu}!' + ) + if mtu < min_mtu: + raise ConfigError( + f'Configured MTU is less than member interface "{iface}" minimum of {min_mtu}!' + ) + if 'mac' in config: mac = config['mac'] try: @@ -190,6 +205,8 @@ def verify(config): f'Cannot remove interface {vif_iface}: it is still in use by the PPPoE server' ) + verify_mtu_ipv6(config) + def generate(config): pass diff --git a/src/conf_mode/vpp_interfaces_gre.py b/src/conf_mode/vpp_interfaces_gre.py index 1258f906c..3756449a2 100644 --- a/src/conf_mode/vpp_interfaces_gre.py +++ b/src/conf_mode/vpp_interfaces_gre.py @@ -21,6 +21,7 @@ from vyos import ConfigError from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.configdep import set_dependents, call_dependents +from vyos.configverify import verify_mtu_ipv6 from vyos.utils.process import is_systemd_service_active from vyos.ifconfig.vpp import VPPGREInterface @@ -128,6 +129,8 @@ def verify(config): if config.get('source_address') == config.get('remote'): raise ConfigError('Remote address must not be the same as source address') + verify_mtu_ipv6(config) + # Disable checks as point-to-multipoint mode does not work without 'teib' feature that is not implemented yet # # check multipoint mode # if config.get('mode') == 'point-to-multipoint': diff --git a/src/conf_mode/vpp_interfaces_ipip.py b/src/conf_mode/vpp_interfaces_ipip.py index d029f3619..dd4a19e36 100644 --- a/src/conf_mode/vpp_interfaces_ipip.py +++ b/src/conf_mode/vpp_interfaces_ipip.py @@ -21,6 +21,7 @@ from vyos import ConfigError from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.configdep import set_dependents, call_dependents +from vyos.configverify import verify_mtu_ipv6 from vyos.utils.process import is_systemd_service_active from vyos.ifconfig.vpp import VPPIPIPInterface @@ -102,6 +103,8 @@ def verify(config): if config.get('source_address') == config.get('remote'): raise ConfigError('Remote address must not be the same as source address') + verify_mtu_ipv6(config) + def generate(config): pass diff --git a/src/conf_mode/vpp_interfaces_vxlan.py b/src/conf_mode/vpp_interfaces_vxlan.py index 38349cb4c..ac9a9517b 100644 --- a/src/conf_mode/vpp_interfaces_vxlan.py +++ b/src/conf_mode/vpp_interfaces_vxlan.py @@ -18,9 +18,14 @@ from vyos import ConfigError +from vyos.base import Warning from vyos.config import Config from vyos.configdict import get_interface_dict from vyos.configdep import set_dependents, call_dependents +from vyos.configverify import verify_mtu_ipv6 +from vyos.ifconfig import Interface +from vyos.template import is_ipv6 +from vyos.utils.network import get_interfaces_by_ip from vyos.utils.process import is_systemd_service_active from vyos.ifconfig.vpp import VPPVXLANInterface @@ -117,6 +122,29 @@ def verify(config): if config.get('source_address') == config.get('remote'): raise ConfigError('Remote address must not be the same as source address') + # VXLAN adds at least an overhead of 50 bytes - we need to check the + # underlying device if our VXLAN package is not going to be fragmented! + source_address = config['source_address'] + vxlan_overhead = 50 + if is_ipv6(source_address): + # IPv6 adds an extra 20 bytes overhead because the IPv6 header is 20 + # bytes larger than the IPv4 header - assuming no extra options are + # in use. + vxlan_overhead += 20 + + ifaces_with_ip = get_interfaces_by_ip(source_address) + vpp_ifaces = config['vpp_ether_vif_ifaces'] + matching_iface = next((iface for iface in ifaces_with_ip if iface in vpp_ifaces)) + + lower_mtu = Interface(matching_iface).get_mtu() + if lower_mtu < (int(config['mtu']) + vxlan_overhead): + Warning( + f'Underlying device MTU is too small ({lower_mtu} bytes) ' + f'for VXLAN overhead ({vxlan_overhead} bytes!)' + ) + + verify_mtu_ipv6(config) + def generate(config): pass |
