cae4efc1d9
In some cases, tunneling applications will also want to specify the source IP of the tunnel. This is in case the tunneling network is different than the main network, as specified by local_ip. Change-Id: I39b0cc0bdfee7a1a13f8e0e9625e210ff83f6d9a
217 lines
6.2 KiB
Python
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)
|