dragonflow/dragonflow/ovsdb/impl_idl.py

217 lines
6.2 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.
from oslo_config import cfg
from ovs.db import idl
from ovsdbapp.backend.ovs_idl import connection
from ovsdbapp.backend.ovs_idl import idlutils
from ovsdbapp.schema.open_vswitch import impl_idl
from dragonflow.common import constants
from dragonflow.db.models import switch
from dragonflow.ovsdb import commands
ovsdb_monitor_table_filter_default = {
'Interface': [
'ofport',
'name',
'admin_state',
'type',
'external_ids',
'options',
'mac_in_use',
'ingress_policing_burst',
'ingress_policing_rate',
],
'Bridge': [
'ports',
'name',
'controller',
'fail_mode',
'datapath_type',
],
'Port': [
'name',
'external_ids',
'interfaces',
'qos',
],
'QoS': [
'queues',
'external_ids',
'type',
],
'Queue': [
'dscp',
'external_ids',
'other_config',
],
'Controller': [
'target',
],
'Open_vSwitch': [
'bridges',
'cur_cfg',
'next_cfg'
]
}
_HANDLED_INTERFACE_TYPES = (
constants.SWITCH_COMPUTE_INTERFACE,
constants.SWITCH_TUNNEL_INTERFACE,
constants.SWITCH_BRIDGE_INTERFACE,
)
def _is_ovsport_update_valid(action, switch_port):
if switch_port.name == cfg.CONF.df_metadata.metadata_interface:
return True
if switch_port.type not in _HANDLED_INTERFACE_TYPES:
return False
if switch_port.name.startswith('qg'):
return False
if (switch_port.type == constants.SWITCH_COMPUTE_INTERFACE and
switch_port.lport is None):
return False
if action == 'set':
# No need for 'updated' event if the port_num is being deleted
port_num = switch_port.port_num
if (port_num is None) or (port_num < 0):
return False
return True
def _get_interface_type(row):
interface_type = row.type
interface_name = row.name
if interface_type == "internal" and "br" in interface_name:
return constants.SWITCH_BRIDGE_INTERFACE
if interface_type == "patch":
return constants.SWITCH_PATCH_INTERFACE
if 'iface-id' in row.external_ids:
return constants.SWITCH_COMPUTE_INTERFACE
options = row.options
if 'remote_ip' in options:
return constants.SWITCH_TUNNEL_INTERFACE
return constants.SWITCH_UNKNOWN_INTERFACE
def _port_from_idl_row(row):
res = switch.SwitchPort(
id=str(row.uuid),
name=row.name,
type=_get_interface_type(row),
)
if row.ofport:
res.port_num = int(row.ofport[0])
if row.mac_in_use:
res.mac_in_use = row.mac_in_use[0]
if row.admin_state:
res.admin_state = row.admin_state[0]
if res.type == constants.SWITCH_PATCH_INTERFACE:
res.peer = row.options['peer']
if res.type == constants.SWITCH_TUNNEL_INTERFACE:
res.tunnel_type = row.type
external_ids = row.external_ids
lport_id = external_ids.get('iface-id')
if lport_id is not None:
res.lport = lport_id
attached_mac = external_ids.get('attached-mac')
if attached_mac is not None:
res.attached_mac = attached_mac
return res
class DFIdl(idl.Idl):
def __init__(self, remote, schema, db_change_callback):
super(DFIdl, self).__init__(remote, schema)
self.db_change_callback = db_change_callback
def notify(self, event, row, updates=None):
if not row or not hasattr(row, '_table'):
return
if row._table.name != 'Interface':
return
local_interface = _port_from_idl_row(row)
action = event if event != 'update' else 'set'
if _is_ovsport_update_valid(action, local_interface):
self.db_change_callback(
local_interface.table_name,
local_interface.id,
action,
local_interface.to_json(),
)
def df_idl_from_server(connection_string, schema_name,
db_change_callback):
"""Create the Idl instance by pulling the schema from OVSDB server"""
helper = idlutils.get_schema_helper(connection_string, schema_name)
tables = ovsdb_monitor_table_filter_default
for table_name, columns in tables.items():
if columns == 'all':
helper.register_table(table_name)
else:
helper.register_columns(table_name, columns)
return DFIdl(connection_string, helper, db_change_callback)
class DFOvsdbApi(impl_idl.OvsdbIdl):
"""The command generator of OVS DB operation
This is a sub-class of OvsdbIdl, which is defined in neutron. The super
class OvsdbIdl has defined lots of command. Dragonflow can use
them. And Dragonflow can extend its own commands in this class.
"""
def __init__(self, db_connection, timeout, db_change_callback):
idl = df_idl_from_server(db_connection, 'Open_vSwitch',
db_change_callback)
type(self).ovsdb_connection = None
ovsdb_connection = connection.Connection(idl, timeout)
super(DFOvsdbApi, self).__init__(ovsdb_connection)
def get_bridge_ports(self, bridge):
return commands.GetBridgePorts(self, bridge)
def add_patch_port(self, bridge, port, peer_port):
return commands.AddPatchPort(self, bridge, port, peer_port)
def add_virtual_tunnel_port(self, tunnel_type, local_ip=None):
return commands.AddVirtualTunnelPort(self, tunnel_type, local_ip)
def create_qos(self, port_id, qos):
return commands.CreateQos(self, port_id, qos)
def update_qos(self, port_id, qos):
return commands.UpdateQos(self, port_id, qos)
def delete_qos(self, port_id):
return commands.DeleteQos(self, port_id)