dragonflow/dragonflow/db/models/l2.py

197 lines
5.9 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
from jsonmodels import fields
from jsonmodels import models
from neutron_lib.api.definitions import portbindings
from oslo_config import cfg
from oslo_log import log
from dragonflow.controller import port_locator
import dragonflow.db.field_types as df_fields
import dragonflow.db.model_framework as mf
from dragonflow.db.models import core
from dragonflow.db.models import host_route
from dragonflow.db.models import mixins
from dragonflow.db.models import qos
from dragonflow.db.models import secgroups
LOG = log.getLogger(__name__)
@mf.register_model
@mf.construct_nb_db_model(
indexes={
'network_type': 'network_type',
'physical_network': 'physical_network',
},
)
class LogicalSwitch(mf.ModelBase, mixins.Name, mixins.Version, mixins.Topic,
mixins.UniqueKey, mixins.BasicEvents):
table_name = "lswitch"
is_external = fields.BoolField()
mtu = fields.IntField()
segmentation_id = fields.IntField()
# TODO(oanson) Validate network_type
network_type = fields.StringField()
# TODO(oanson) Validate physical_network
physical_network = fields.StringField()
qos_policy = df_fields.ReferenceField(qos.QosPolicy)
@mf.register_model
@mf.construct_nb_db_model(
indexes={
'lswitch': 'lswitch.id',
},
)
class Subnet(mf.ModelBase, mixins.Name, mixins.Topic, mixins.Version,
mixins.BasicEvents):
table_name = "lsubnet"
enable_dhcp = fields.BoolField()
dhcp_ip = df_fields.IpAddressField()
cidr = df_fields.IpNetworkField()
gateway_ip = df_fields.IpAddressField()
dns_nameservers = df_fields.ListOfField(df_fields.IpAddressField())
host_routes = fields.ListField(host_route.HostRoute)
lswitch = df_fields.ReferenceField(LogicalSwitch, required=True)
class AddressPair(models.Base):
ip_address = df_fields.IpAddressField(required=True)
mac_address = df_fields.MacAddressField(required=True)
class DhcpParams(models.Base):
opts = df_fields.DhcpOptsDictField()
siaddr = df_fields.IpAddressField()
BINDING_CHASSIS = 'chassis'
BINDING_VTEP = 'vtep'
class PortBinding(models.Base):
type = df_fields.EnumField((BINDING_CHASSIS, BINDING_VTEP), required=True)
chassis = df_fields.ReferenceField(core.Chassis)
vtep_address = df_fields.IpAddressField()
@property
def ip(self):
if self.type == BINDING_CHASSIS:
return self.chassis.ip
elif self.type == BINDING_VTEP:
return self.vtep_address
return None
@property
def is_local(self):
if self.type == BINDING_CHASSIS:
return self.chassis.id == cfg.CONF.host
return False
def __deepcopy__(self, memo):
return PortBinding(
type=self.type,
chassis=copy.deepcopy(self.chassis, memo),
vtep_address=self.vtep_address,
)
# Port events
EVENT_LOCAL_UPDATED = 'local_updated'
EVENT_REMOTE_UPDATED = 'remote_updated'
EVENT_BIND_LOCAL = 'bind_local'
EVENT_UNBIND_LOCAL = 'unbind_local'
EVENT_BIND_REMOTE = 'bind_remote'
EVENT_UNBIND_REMOTE = 'unbind_remote'
@mf.register_model
@mf.construct_nb_db_model(events={
EVENT_BIND_LOCAL,
EVENT_UNBIND_LOCAL,
EVENT_BIND_REMOTE,
EVENT_UNBIND_REMOTE,
EVENT_LOCAL_UPDATED,
EVENT_REMOTE_UPDATED,
}, indexes={
'chassis_id': 'binding.chassis.id',
'lswitch_id': 'lswitch.id',
'ip,lswitch': ('ips', 'lswitch.id'),
'switch,owner': ('lswitch.unique_key', 'device_owner')
})
class LogicalPort(mf.ModelBase, mixins.Name, mixins.Version, mixins.Topic,
mixins.UniqueKey, mixins.BasicEvents):
table_name = "lport"
ips = df_fields.ListOfField(df_fields.IpAddressField())
subnets = df_fields.ReferenceListField(Subnet)
macs = df_fields.ListOfField(df_fields.MacAddressField())
enabled = fields.BoolField()
binding = fields.EmbeddedField(PortBinding)
lswitch = df_fields.ReferenceField(LogicalSwitch)
security_groups = df_fields.ReferenceListField(secgroups.SecurityGroup)
allowed_address_pairs = fields.ListField(AddressPair)
port_security_enabled = fields.BoolField()
device_owner = fields.StringField()
device_id = fields.StringField()
qos_policy = df_fields.ReferenceField(qos.QosPolicy)
dhcp_params = fields.EmbeddedField(DhcpParams)
binding_vnic_type = df_fields.EnumField(portbindings.VNIC_TYPES)
@property
def ip(self):
try:
return self.ips[0]
except IndexError:
return None
@property
def mac(self):
try:
return self.macs[0]
except IndexError:
return None
@property
def is_local(self):
return port_locator.is_port_local(self)
@property
def is_remote(self):
return port_locator.is_port_remote(self)
@property
def all_ips(self):
ips = set(self.ips)
ips.update(pair.ip_address for pair in self.allowed_address_pairs)
return ips
def __str__(self):
data = {}
for name in dir(self):
if name.startswith('_'):
continue
cls_definition = getattr(self.__class__, name, None)
if isinstance(cls_definition, fields.BaseField):
if name in self._set_fields:
data[name] = getattr(self, name)
elif not cls_definition: # Display only instnaces, not classes
data[name] = getattr(self, name)
return str(data)