Mapping between Neutron and OVN data models¶
The primary job of the Neutron OVN ML2 driver is to translate requests for resources into OVN’s data model. Resources are created in OVN by updating the appropriate tables in the OVN northbound database (an ovsdb database). This document looks at the mappings between the data that exists in Neutron and what the resulting entries in the OVN northbound DB would look like.
Network¶
Neutron Network:
id
name
subnets
admin_state_up
status
tenant_id
Once a network is created, we should create an entry in the Logical Switch table.
OVN northbound DB Logical Switch:
external_ids: {
'neutron:network_name': network.name
}
Subnet¶
Neutron Subnet:
id
name
ip_version
network_id
cidr
gateway_ip
allocation_pools
dns_nameservers
host_routers
tenant_id
enable_dhcp
ipv6_ra_mode
ipv6_address_mode
Once a subnet is created, we should create an entry in the DHCP Options table with the DHCPv4 or DHCPv6 options.
OVN northbound DB DHCP_Options:
cidr
options
external_ids: {
'subnet_id': subnet.id
}
Port¶
Neutron Port:
id
name
network_id
admin_state_up
mac_address
fixed_ips
device_id
device_owner
tenant_id
status
When a port is created, we should create an entry in the Logical Switch Ports table in the OVN northbound DB.
OVN Northbound DB Logical Switch Port:
switch: reference to OVN Logical Switch
router_port: (empty)
name: port.id
up: (read-only)
macs: [port.mac_address]
port_security:
external_ids: {'neutron:port_name': port.name}
If the port has extra DHCP options defined, we should create an entry in the DHCP Options table in the OVN northbound DB.
OVN northbound DB DHCP_Options:
cidr
options
external_ids: {
'subnet_id': subnet.id,
'port_id': port.id
}
Router¶
Neutron Router:
id
name
admin_state_up
status
tenant_id
external_gw_info:
network_id
external_fixed_ips: list of dicts
ip_address
subnet_id
...
OVN Northbound DB Logical Router:
ip:
default_gw:
external_ids:
Router Port¶
...
OVN Northbound DB Logical Router Port:
router: (reference to Logical Router)
network: (reference to network this port is connected to)
mac:
external_ids:
Security Groups¶
Neutron Port:
id
security_group: id
network_id
Neutron Security Group
id
name
tenant_id
security_group_rules
Neutron Security Group Rule
id
tenant_id
security_group_id
direction
remote_group_id
ethertype
protocol
port_range_min
port_range_max
remote_ip_prefix
...
OVN Northbound DB ACL Rule:
lswitch: (reference to Logical Switch - port.network_id)
priority: (0..65535)
match: boolean expressions according to security rule
Translation map (sg_rule ==> match expression)
-----------------------------------------------
sg_rule.direction="Ingress" => "inport=port.id"
sg_rule.direction="Egress" => "outport=port.id"
sg_rule.ethertype => "eth.type"
sg_rule.protocol => "ip.proto"
sg_rule.port_range_min/port_range_max =>
"port_range_min <= tcp.src <= port_range_max"
"port_range_min <= udp.src <= port_range_max"
sg_rule.remote_ip_prefix => "ip4.src/mask, ip4.dst/mask, ipv6.src/mask, ipv6.dst/mask"
(all match options for ACL can be found here:
https://github.com/openvswitch/ovs/blob/ovn/ovn/ovn-sb.xml)
action: "allow-related"
log: true/false
external_ids: {'neutron:port_id': port.id}
{'neutron:security_rule_id': security_rule.id}
Security groups maps between three neutron objects to one OVN-NB object, this enable us to do the mapping in various ways, depending on OVN capabilities
The current implementation will use the first option in this list for simplicity, but all options are kept here for future reference
For every <neutron port, security rule> pair, define an ACL entry:
Leads to many ACL entries. acl.match = sg_rule converted example: ((inport==port.id) && (ip.proto == "tcp") && (1024 <= tcp.src <= 4095) && (ip.src==192.168.0.1/16)) external_ids: {'neutron:port_id': port.id} {'neutron:security_rule_id': security_rule.id}
For every <neutron port, security group> pair, define an ACL entry:
Reduce the number of ACL entries. Means we have to manage the match field in case specific rule changes example: (((inport==port.id) && (ip.proto == "tcp") && (1024 <= tcp.src <= 4095) && (ip.src==192.168.0.1/16)) || ((outport==port.id) && (ip.proto == "udp") && (1024 <= tcp.src <= 4095)) || ((inport==port.id) && (ip.proto == 6) ) || ((inport==port.id) && (eth.type == 0x86dd))) (This example is a security group with four security rules) external_ids: {'neutron:port_id': port.id} {'neutron:security_group_id': security_group.id}
For every <lswitch, security group> pair, define an ACL entry:
Reduce even more the number of ACL entries. Manage complexity increase example: (((inport==port.id) && (ip.proto == "tcp") && (1024 <= tcp.src <= 4095) && (ip.src==192.168.0.1/16)) || ((outport==port.id) && (ip.proto == "udp") && (1024 <= tcp.src <= 4095)) || ((inport==port.id) && (ip.proto == 6) ) || ((inport==port.id) && (eth.type == 0x86dd))) || (((inport==port2.id) && (ip.proto == "tcp") && (1024 <= tcp.src <= 4095) && (ip.src==192.168.0.1/16)) || ((outport==port2.id) && (ip.proto == "udp") && (1024 <= tcp.src <= 4095)) || ((inport==port2.id) && (ip.proto == 6) ) || ((inport==port2.id) && (eth.type == 0x86dd))) external_ids: {'neutron:security_group': security_group.id}
Which option to pick depends on OVN match field length capabilities, and the trade off between better performance due to less ACL entries compared to the complexity to manage them.
If the default behaviour is not “drop” for unmatched entries, a rule with lowest priority must be added to drop all traffic (“match==1”)
Spoofing protection rules are being added by OVN internally and we need to ignore the automatically added rules in Neutron