From 2265bb4dc27965da3dce7e3f476366b7d1e911f3 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sat, 1 Apr 2023 13:14:30 +0200 Subject: xml: include building block file name should end with .i and not .in --- interface-definitions/container.xml.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'interface-definitions/container.xml.in') diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index 6947ed500..0849af656 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -117,7 +117,7 @@ Container host name - #include + #include Host-name must be alphanumeric and can contain hyphens -- cgit v1.2.3 From 0ea3e1420c373027bdf57ea9e794b81dd6b6ad4f Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sat, 1 Apr 2023 15:31:46 +0200 Subject: container: T5082: switch to netavark network stack We now support assigning discrete IPv6 addresses to a container. --- data/templates/container/containers.conf.j2 | 2 +- debian/control | 1 + interface-definitions/container.xml.in | 7 ++- src/conf_mode/container.py | 95 +++++++++++++++-------------- 4 files changed, 56 insertions(+), 49 deletions(-) (limited to 'interface-definitions/container.xml.in') diff --git a/data/templates/container/containers.conf.j2 b/data/templates/container/containers.conf.j2 index 9f66aed27..c635ca213 100644 --- a/data/templates/container/containers.conf.j2 +++ b/data/templates/container/containers.conf.j2 @@ -282,7 +282,7 @@ default_sysctls = [ # Before changing this value all containers must be stopped otherwise it is likely that # iptables rules and network interfaces might leak on the host. A reboot will fix this. # -network_backend = "cni" +network_backend = "netavark" # Path to directory where CNI plugin binaries are located. # diff --git a/debian/control b/debian/control index 028b7cd43..8cd49f62a 100644 --- a/debian/control +++ b/debian/control @@ -99,6 +99,7 @@ Depends: mtr-tiny, ndisc6, ndppd, + netavark, netplug, nfct, nftables (>= 0.9.3), diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index 0849af656..b09536a16 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -191,15 +191,20 @@ - Assign static IP address to container ipv4 IPv4 address + + ipv6 + IPv6 address + + + diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 4e4db7180..5cfbfc30c 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -16,6 +16,7 @@ import os +from hashlib import sha256 from ipaddress import ip_address from ipaddress import ip_network from json import dumps as json_write @@ -27,7 +28,6 @@ from vyos.configdict import node_changed from vyos.configdict import is_node_changed from vyos.util import call from vyos.util import cmd -from vyos.util import dict_search from vyos.util import run from vyos.util import rc_cmd from vyos.util import write_file @@ -166,21 +166,29 @@ def verify(container): raise ConfigError(f'Container network "{network_name}" does not exist!') if 'address' in container_config['network'][network_name]: - address = container_config['network'][network_name]['address'] - network = None - if is_ipv4(address): - network = [x for x in container['network'][network_name]['prefix'] if is_ipv4(x)][0] - elif is_ipv6(address): - network = [x for x in container['network'][network_name]['prefix'] if is_ipv6(x)][0] - - # Specified container IP address must belong to network prefix - if ip_address(address) not in ip_network(network): - raise ConfigError(f'Used container address "{address}" not in network "{network}"!') - - # We can not use the first IP address of a network prefix as this is used by podman - if ip_address(address) == ip_network(network)[1]: - raise ConfigError(f'IP address "{address}" can not be used for a container, '\ - 'reserved for the container engine!') + cnt_ipv4 = 0 + cnt_ipv6 = 0 + for address in container_config['network'][network_name]['address']: + network = None + if is_ipv4(address): + network = [x for x in container['network'][network_name]['prefix'] if is_ipv4(x)][0] + cnt_ipv4 += 1 + elif is_ipv6(address): + network = [x for x in container['network'][network_name]['prefix'] if is_ipv6(x)][0] + cnt_ipv6 += 1 + + # Specified container IP address must belong to network prefix + if ip_address(address) not in ip_network(network): + raise ConfigError(f'Used container address "{address}" not in network "{network}"!') + + # We can not use the first IP address of a network prefix as this is used by podman + if ip_address(address) == ip_network(network)[1]: + raise ConfigError(f'IP address "{address}" can not be used for a container, '\ + 'reserved for the container engine!') + + if cnt_ipv4 > 1 or cnt_ipv6 > 1: + raise ConfigError(f'Only one IP address per address family can be used for '\ + f'container "{name}". {cnt_ipv4} IPv4 and {cnt_ipv6} IPv6 address(es)!') if 'device' in container_config: for dev, dev_config in container_config['device'].items(): @@ -338,9 +346,13 @@ def generate_run_arguments(name, container_config): ip_param = '' networks = ",".join(container_config['network']) for network in container_config['network']: - if 'address' in container_config['network'][network]: - address = container_config['network'][network]['address'] - ip_param = f'--ip {address}' + if 'address' not in container_config['network'][network]: + continue + for address in container_config['network'][network]['address']: + if is_ipv6(address): + ip_param += f' --ip6 {address}' + else: + ip_param += f' --ip {address}' return f'{container_base_cmd} --net {networks} {ip_param} {entrypoint} {image} {command} {command_arguments}'.strip() @@ -355,33 +367,26 @@ def generate(container): if 'network' in container: for network, network_config in container['network'].items(): tmp = { - 'cniVersion' : '0.4.0', - 'name' : network, - 'plugins' : [{ - 'type': 'bridge', - 'bridge': f'cni-{network}', - 'isGateway': True, - 'ipMasq': False, - 'hairpinMode': False, - 'ipam' : { - 'type': 'host-local', - 'routes': [], - 'ranges' : [], - }, - }] + 'name': network, + 'id' : sha256(f'{network}'.encode()).hexdigest(), + 'driver': 'bridge', + 'network_interface': f'podman-{network}', + 'subnets': [], + 'ipv6_enabled': False, + 'internal': False, + 'dns_enabled': False, + 'ipam_options': { + 'driver': 'host-local' + } } - for prefix in network_config['prefix']: - net = [{'gateway' : inc_ip(prefix, 1), 'subnet' : prefix}] - tmp['plugins'][0]['ipam']['ranges'].append(net) + net = {'subnet' : prefix, 'gateway' : inc_ip(prefix, 1)} + tmp['subnets'].append(net) - # install per address-family default orutes - default_route = '0.0.0.0/0' if is_ipv6(prefix): - default_route = '::/0' - tmp['plugins'][0]['ipam']['routes'].append({'dst': default_route}) + tmp['ipv6_enabled'] = True - write_file(f'/etc/cni/net.d/{network}.conflist', json_write(tmp, indent=2)) + write_file(f'/etc/containers/networks/{network}.json', json_write(tmp, indent=2)) if 'registry' in container: cmd = f'podman logout --all' @@ -432,10 +437,7 @@ def apply(container): # Delete old networks if needed if 'network_remove' in container: for network in container['network_remove']: - call(f'podman network rm {network}') - tmp = f'/etc/cni/net.d/{network}.conflist' - if os.path.exists(tmp): - os.unlink(tmp) + call(f'podman network rm {network} >/dev/null 2>&1') # Add container disabled_new = False @@ -459,8 +461,7 @@ def apply(container): os.unlink(file_path) continue - tmp = dict_search('container_restart', container) - if tmp and name in tmp: + if 'container_restart' in container and name in container['container_restart']: cmd(f'systemctl restart vyos-container-{name}.service') if disabled_new: -- cgit v1.2.3 From 809f28f2b95a788d23db006a041955e7167a285d Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 2 Apr 2023 09:25:35 +0200 Subject: xml: re-use generic-description.xml.i building block whenever possible Remove redundant XML CLI node definitions for the common description node by referencing the common building block. --- interface-definitions/bcast-relay.xml.in | 6 +----- interface-definitions/container.xml.in | 6 +----- interface-definitions/load-balancing-wan.xml.in | 10 +--------- interface-definitions/nat66.xml.in | 12 ++---------- interface-definitions/pki.xml.in | 12 ++---------- interface-definitions/service-webproxy.xml.in | 12 ++---------- interface-definitions/snmp.xml.in | 10 +--------- interface-definitions/vpn-l2tp.xml.in | 6 +----- 8 files changed, 11 insertions(+), 63 deletions(-) (limited to 'interface-definitions/container.xml.in') diff --git a/interface-definitions/bcast-relay.xml.in b/interface-definitions/bcast-relay.xml.in index aeaa5ab37..e2993f3f3 100644 --- a/interface-definitions/bcast-relay.xml.in +++ b/interface-definitions/bcast-relay.xml.in @@ -34,11 +34,7 @@ - - - Description - - + #include #include #include diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index b09536a16..b52054dd0 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -348,11 +348,7 @@ Network name cannot be longer than 11 characters - - - Network description - - + #include Prefix which allocated to that network diff --git a/interface-definitions/load-balancing-wan.xml.in b/interface-definitions/load-balancing-wan.xml.in index 2b812eb4d..c1d7e2c67 100644 --- a/interface-definitions/load-balancing-wan.xml.in +++ b/interface-definitions/load-balancing-wan.xml.in @@ -191,15 +191,7 @@ - - - Description for this rule - - txt - Description for this rule - - - + #include Destination diff --git a/interface-definitions/nat66.xml.in b/interface-definitions/nat66.xml.in index 6ea611789..7a8970bdf 100644 --- a/interface-definitions/nat66.xml.in +++ b/interface-definitions/nat66.xml.in @@ -24,11 +24,7 @@ NAT66 rule number must be between 1 and 999999 - - - Rule description - - + #include Disable NAT66 rule @@ -156,11 +152,7 @@ NAT66 rule number must be between 1 and 999999 - - - Rule description - - + #include Disable NAT66 rule diff --git a/interface-definitions/pki.xml.in b/interface-definitions/pki.xml.in index c4fde2c78..a13a357fd 100644 --- a/interface-definitions/pki.xml.in +++ b/interface-definitions/pki.xml.in @@ -16,11 +16,7 @@ CA certificate in PEM format - - - Description - - + #include CA private key in PEM format @@ -63,11 +59,7 @@ Certificate in PEM format - - - Description - - + #include Certificate private key diff --git a/interface-definitions/service-webproxy.xml.in b/interface-definitions/service-webproxy.xml.in index a315aa2ef..b24997816 100644 --- a/interface-definitions/service-webproxy.xml.in +++ b/interface-definitions/service-webproxy.xml.in @@ -538,11 +538,7 @@ - - - Description for source-group - - + #include Domain for source-group @@ -644,11 +640,7 @@ - - - Time-period description - - + #include diff --git a/interface-definitions/snmp.xml.in b/interface-definitions/snmp.xml.in index 592db7f4e..559e09388 100644 --- a/interface-definitions/snmp.xml.in +++ b/interface-definitions/snmp.xml.in @@ -78,15 +78,7 @@ Contact information is limited to 255 characters or less - - - Description information - - .{1,255} - - Description is limited to 255 characters or less - - + #include IP address to listen for incoming SNMP requests diff --git a/interface-definitions/vpn-l2tp.xml.in b/interface-definitions/vpn-l2tp.xml.in index 0a92017bd..6b64c5f5d 100644 --- a/interface-definitions/vpn-l2tp.xml.in +++ b/interface-definitions/vpn-l2tp.xml.in @@ -124,11 +124,7 @@ #include - - - Description for L2TP remote-access settings - - + #include #include -- cgit v1.2.3 From b65296a0ff39e66d87e916971477cce351f6d5a5 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 2 Apr 2023 09:27:03 +0200 Subject: container: T5134: support binding container network to specific VRF Container networks now can be bound to a specific VRF instance. set vrf name table set container network vrf --- interface-definitions/container.xml.in | 1 + src/conf_mode/container.py | 13 +++++++++++++ 2 files changed, 14 insertions(+) (limited to 'interface-definitions/container.xml.in') diff --git a/interface-definitions/container.xml.in b/interface-definitions/container.xml.in index b52054dd0..9b6d2369d 100644 --- a/interface-definitions/container.xml.in +++ b/interface-definitions/container.xml.in @@ -367,6 +367,7 @@ + #include diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py index 3827f4c70..05595f86f 100755 --- a/src/conf_mode/container.py +++ b/src/conf_mode/container.py @@ -26,6 +26,8 @@ from vyos.config import Config from vyos.configdict import dict_merge from vyos.configdict import node_changed from vyos.configdict import is_node_changed +from vyos.configverify import verify_vrf +from vyos.ifconfig import Interface from vyos.util import call from vyos.util import cmd from vyos.util import run @@ -250,6 +252,8 @@ def verify(container): if v6_prefix > 1: raise ConfigError(f'Only one IPv6 prefix can be defined for network "{network}"!') + # Verify VRF exists + verify_vrf(network_config) # A network attached to a container can not be deleted if {'network_remove', 'name'} <= set(container): @@ -469,6 +473,15 @@ def apply(container): if disabled_new: call('systemctl daemon-reload') + # Start network and assign it to given VRF if requested. this can only be done + # after the containers got started as the podman network interface will + # only be enabled by the first container and yet I do not know how to enable + # the network interface in advance + if 'network' in container: + for network, network_config in container['network'].items(): + tmp = Interface(f'podman-{network}') + tmp.set_vrf(network_config.get('vrf', '')) + return None if __name__ == '__main__': -- cgit v1.2.3