Skip to content

Commit

Permalink
ovn-tester/ovn_workload: Move Namespace class to CMS plugin.
Browse files Browse the repository at this point in the history
Signed-off-by: Frode Nordahl <[email protected]>
  • Loading branch information
fnordahl committed Sep 21, 2023
1 parent bb2e81d commit ad28530
Show file tree
Hide file tree
Showing 9 changed files with 306 additions and 315 deletions.
305 changes: 299 additions & 6 deletions ovn-tester/cms/ovn_kubernetes/ovn_kubernetes.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,309 @@

from ovn_context import Context
from ovn_utils import DualStackSubnet
from ovn_workload import (
ChassisNode,
Cluster,
DEFAULT_BACKEND_PORT,
DEFAULT_VIP_PORT,
)
from ovn_workload import ChassisNode, Cluster

log = logging.getLogger(__name__)
ClusterBringupCfg = namedtuple('ClusterBringupCfg', ['n_pods_per_node'])
OVN_HEATER_CMS_PLUGIN = 'OVNKubernetes'
ACL_DEFAULT_DENY_PRIO = 1
ACL_DEFAULT_ALLOW_ARP_PRIO = 2
ACL_NETPOL_ALLOW_PRIO = 3
DEFAULT_NS_VIP_SUBNET = netaddr.IPNetwork('30.0.0.0/16')
DEFAULT_NS_VIP_SUBNET6 = netaddr.IPNetwork('30::/32')
DEFAULT_VIP_PORT = 80
DEFAULT_BACKEND_PORT = 8080


class Namespace:
def __init__(self, cluster, name, global_cfg):
self.cluster = cluster
self.nbctl = cluster.nbctl
self.ports = []
self.enforcing = False
self.pg_def_deny_igr = self.nbctl.port_group_create(
f'pg_deny_igr_{name}'
)
self.pg_def_deny_egr = self.nbctl.port_group_create(
f'pg_deny_egr_{name}'
)
self.pg = self.nbctl.port_group_create(f'pg_{name}')
self.addr_set4 = (
self.nbctl.address_set_create(f'as_{name}')
if global_cfg.run_ipv4
else None
)
self.addr_set6 = (
self.nbctl.address_set_create(f'as6_{name}')
if global_cfg.run_ipv6
else None
)
self.sub_as = []
self.sub_pg = []
self.load_balancer = None
self.cluster.n_ns += 1
self.name = name

@ovn_stats.timeit
def add_ports(self, ports):
self.ports.extend(ports)
# Always add port IPs to the address set but not to the PGs.
# Simulate what OpenShift does, which is: create the port groups
# when the first network policy is applied.
if self.addr_set4:
self.nbctl.address_set_add_addrs(
self.addr_set4, [str(p.ip) for p in ports]
)
if self.addr_set6:
self.nbctl.address_set_add_addrs(
self.addr_set6, [str(p.ip6) for p in ports]
)
if self.enforcing:
self.nbctl.port_group_add_ports(self.pg_def_deny_igr, ports)
self.nbctl.port_group_add_ports(self.pg_def_deny_egr, ports)
self.nbctl.port_group_add_ports(self.pg, ports)

def unprovision(self):
# ACLs are garbage collected by OVSDB as soon as all the records
# referencing them are removed.
self.cluster.unprovision_ports(self.ports)
self.nbctl.port_group_del(self.pg_def_deny_igr)
self.nbctl.port_group_del(self.pg_def_deny_egr)
self.nbctl.port_group_del(self.pg)
if self.addr_set4:
self.nbctl.address_set_del(self.addr_set4)
if self.addr_set6:
self.nbctl.address_set_del(self.addr_set6)
for pg in self.sub_pg:
self.nbctl.port_group_del(pg)
for addr_set in self.sub_as:
self.nbctl.address_set_del(addr_set)

def unprovision_ports(self, ports):
"""Unprovision a subset of ports in the namespace without having to
unprovision the entire namespace or any of its network policies."""

for port in ports:
self.ports.remove(port)

self.cluster.unprovision_ports(ports)

def enforce(self):
if self.enforcing:
return
self.enforcing = True
self.nbctl.port_group_add_ports(self.pg_def_deny_igr, self.ports)
self.nbctl.port_group_add_ports(self.pg_def_deny_egr, self.ports)
self.nbctl.port_group_add_ports(self.pg, self.ports)

def create_sub_ns(self, ports, global_cfg):
n_sub_pgs = len(self.sub_pg)
suffix = f'{self.name}_{n_sub_pgs}'
pg = self.nbctl.port_group_create(f'sub_pg_{suffix}')
self.nbctl.port_group_add_ports(pg, ports)
self.sub_pg.append(pg)
if global_cfg.run_ipv4:
addr_set = self.nbctl.address_set_create(f'sub_as_{suffix}')
self.nbctl.address_set_add_addrs(
addr_set, [str(p.ip) for p in ports]
)
self.sub_as.append(addr_set)
if global_cfg.run_ipv6:
addr_set = self.nbctl.address_set_create(f'sub_as_{suffix}6')
self.nbctl.address_set_add_addrs(
addr_set, [str(p.ip6) for p in ports]
)
self.sub_as.append(addr_set)
return n_sub_pgs

@ovn_stats.timeit
def default_deny(self, family):
self.enforce()

addr_set = f'self.addr_set{family}.name'
self.nbctl.acl_add(
self.pg_def_deny_igr.name,
'to-lport',
ACL_DEFAULT_DENY_PRIO,
'port-group',
f'ip4.src == \\${addr_set} && '
f'outport == @{self.pg_def_deny_igr.name}',
'drop',
)
self.nbctl.acl_add(
self.pg_def_deny_egr.name,
'to-lport',
ACL_DEFAULT_DENY_PRIO,
'port-group',
f'ip4.dst == \\${addr_set} && '
f'inport == @{self.pg_def_deny_egr.name}',
'drop',
)
self.nbctl.acl_add(
self.pg_def_deny_igr.name,
'to-lport',
ACL_DEFAULT_ALLOW_ARP_PRIO,
'port-group',
f'outport == @{self.pg_def_deny_igr.name} && arp',
'allow',
)
self.nbctl.acl_add(
self.pg_def_deny_egr.name,
'to-lport',
ACL_DEFAULT_ALLOW_ARP_PRIO,
'port-group',
f'inport == @{self.pg_def_deny_egr.name} && arp',
'allow',
)

@ovn_stats.timeit
def allow_within_namespace(self, family):
self.enforce()

addr_set = f'self.addr_set{family}.name'
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip4.src == \\${addr_set} && outport == @{self.pg.name}',
'allow-related',
)
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip4.dst == \\${addr_set} && inport == @{self.pg.name}',
'allow-related',
)

@ovn_stats.timeit
def allow_cross_namespace(self, ns, family):
self.enforce()

addr_set = f'self.addr_set{family}.name'
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip4.src == \\${addr_set} && outport == @{ns.pg.name}',
'allow-related',
)
ns_addr_set = f'ns.addr_set{family}.name'
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip4.dst == \\${ns_addr_set} && inport == @{self.pg.name}',
'allow-related',
)

@ovn_stats.timeit
def allow_sub_namespace(self, src, dst, family):
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip{family}.src == \\${self.sub_as[src].name} && '
f'outport == @{self.sub_pg[dst].name}',
'allow-related',
)
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip{family}.dst == \\${self.sub_as[dst].name} && '
f'inport == @{self.sub_pg[src].name}',
'allow-related',
)

@ovn_stats.timeit
def allow_from_external(
self, external_ips, include_ext_gw=False, family=4
):
self.enforce()
# If requested, include the ext-gw of the first port in the namespace
# so we can check that this rule is enforced.
if include_ext_gw:
assert len(self.ports) > 0
if family == 4 and self.ports[0].ext_gw:
external_ips.append(self.ports[0].ext_gw)
elif family == 6 and self.ports[0].ext_gw6:
external_ips.append(self.ports[0].ext_gw6)
ips = [str(ip) for ip in external_ips]
self.nbctl.acl_add(
self.pg.name,
'to-lport',
ACL_NETPOL_ALLOW_PRIO,
'port-group',
f'ip.{family} == {{{",".join(ips)}}} && '
f'outport == @{self.pg.name}',
'allow-related',
)

@ovn_stats.timeit
def check_enforcing_internal(self):
# "Random" check that first pod can reach last pod in the namespace.
if len(self.ports) > 1:
src = self.ports[0]
dst = self.ports[-1]
worker = src.metadata
if src.ip:
worker.ping_port(self.cluster, src, dst.ip)
if src.ip6:
worker.ping_port(self.cluster, src, dst.ip6)

@ovn_stats.timeit
def check_enforcing_external(self):
if len(self.ports) > 0:
dst = self.ports[0]
worker = dst.metadata
worker.ping_external(self.cluster, dst)

@ovn_stats.timeit
def check_enforcing_cross_ns(self, ns):
if len(self.ports) > 0 and len(ns.ports) > 0:
dst = ns.ports[0]
src = self.ports[0]
worker = src.metadata
if src.ip and dst.ip:
worker.ping_port(self.cluster, src, dst.ip)
if src.ip6 and dst.ip6:
worker.ping_port(self.cluster, src, dst.ip6)

def create_load_balancer(self):
self.load_balancer = lb.OvnLoadBalancer(f'lb_{self.name}', self.nbctl)

@ovn_stats.timeit
def provision_vips_to_load_balancers(self, backend_lists, version):
vip_ns_subnet = DEFAULT_NS_VIP_SUBNET
if version == 6:
vip_ns_subnet = DEFAULT_NS_VIP_SUBNET6
vip_net = vip_ns_subnet.next(self.cluster.n_ns)
n_vips = len(self.load_balancer.vips.keys())
vip_ip = vip_net.ip.__add__(n_vips + 1)

if version == 6:
vips = {
f'[{vip_ip + i}]:{DEFAULT_VIP_PORT}': [
f'[{p.ip6}]:{DEFAULT_BACKEND_PORT}' for p in ports
]
for i, ports in enumerate(backend_lists)
}
self.load_balancer.add_vips(vips)
else:
vips = {
f'{vip_ip + i}:{DEFAULT_VIP_PORT}': [
f'{p.ip}:{DEFAULT_BACKEND_PORT}' for p in ports
]
for i, ports in enumerate(backend_lists)
}
self.load_balancer.add_vips(vips)


class OVNKubernetesCluster(Cluster):
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/cluster_density.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
import ovn_exceptions

Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/density_heavy.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
import ovn_load_balancer as lb
import ovn_exceptions
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/density_light.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd


Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd
import ovn_exceptions

Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol_cross_ns.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd

NpCrossNsCfg = namedtuple('NpCrossNsCfg', ['n_ns', 'pods_ns_ratio'])
Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/netpol_multitenant.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from collections import namedtuple
import netaddr
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd


Expand Down
2 changes: 1 addition & 1 deletion ovn-tester/cms/ovn_kubernetes/tests/service_route.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from collections import namedtuple
from ovn_context import Context
from ovn_workload import Namespace
from cms.ovn_kubernetes import Namespace
from ovn_ext_cmd import ExtCmd

import netaddr
Expand Down
Loading

0 comments on commit ad28530

Please sign in to comment.