Deepak Tiwari 2c83eb26a5 Add SRIOV mirroring support to Tap as a Service.
The following patch allows VF to VF mirroring in Tap-as-a-Service
Code-changes are applicable for new tap agent driver for sriov on
Intel i40e nic.

Vlan Mirror input parameter is part of tap-flow-create API

The current TaaS SRIOV driver is based on Intel i40e NIC driver with
following requirements:-

hardware: Intel Ethernet Network Adapter XXV710 (25GbE)
Driver: Intel i40e v4.16.0

Ref Spec: openstack/neutron-specs/specs/rocky/port-mirroring-sriov-vfs.rst
Commit: https://review.openstack.org/#/c/574477/

Change-Id: Id3aa83d7e1e22ae1806cef0c93e5dd61169c6735
2019-04-09 18:41:39 -05:00

365 lines
16 KiB
Python

# Copyright (C) 2018 AT&T
#
# 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 neutron.conf.agent import common
from neutron_taas.common import constants as taas_consts
from neutron_taas.common import utils as common_utils
from neutron_taas.services.taas.agents.extensions import taas as taas_base
from neutron_taas.services.taas.drivers.linux import sriov_nic_exceptions \
as taas_exc
from neutron_taas.services.taas.drivers.linux import sriov_nic_utils \
as sriov_utils
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import excutils
import threading
LOG = logging.getLogger(__name__)
TaaS_DRIVER_NAME = 'Taas SRIOV NIC Switch driver'
class SriovNicTaasDriver(taas_base.TaasAgentDriver):
def __init__(self):
super(SriovNicTaasDriver, self).__init__()
LOG.debug("Initializing Taas SRIOV NIC Switch Driver")
self.agent_api = None
self.root_helper = common.get_root_helper(cfg.CONF)
self.lock = threading.Lock()
def initialize(self):
LOG.debug("Initialize routine called for Taas SRIOV NIC Switch Driver")
self.sriov_utils = sriov_utils.SriovNicUtils()
return
def consume_api(self, agent_api):
self.agent_api = agent_api
def create_tap_service(self, tap_service):
ts_port = tap_service['port']
LOG.debug("SRIOV Driver: Inside create_tap_service: "
"Port-id: %(port_id)s",
{'port_id': ts_port['id']})
port_params = self.sriov_utils.get_sriov_port_params(ts_port)
LOG.info("TaaS SRIOV: create_tap_service RPC invoked for "
"port %(id)s, MAC %(ts_port_mac)s, PCI %(ts_pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"src_vlans %(src_vlans)s; ",
{'id': ts_port['id'],
'ts_port_mac': port_params['mac'],
'ts_pci_slot': port_params['pci_slot'],
'vf_index': port_params['vf_index'],
'pf_device': port_params['pf_device'],
'src_vlans': port_params['src_vlans']})
return
def delete_tap_service(self, tap_service):
ts_port = tap_service['port']
LOG.debug("SRIOV Driver: Inside delete_tap_service: "
"Port-id: %(port_id)s",
{'port_id': ts_port['id']})
port_params = self.sriov_utils.get_sriov_port_params(ts_port)
LOG.info("TaaS SRIOV: delete_tap_service RPC invoked for "
"port %(id)s, MAC %(ts_port_mac)s, PCI %(ts_pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"src_vlans %(src_vlans)s; ",
{'id': ts_port['id'],
'ts_port_mac': port_params['mac'],
'ts_pci_slot': port_params['pci_slot'],
'vf_index': port_params['vf_index'],
'pf_device': port_params['pf_device'],
'src_vlans': port_params['src_vlans']})
return
def create_tap_flow(self, tap_flow):
source_port = tap_flow['port']
ts_port = tap_flow['tap_service_port']
direction = tap_flow['tap_flow']['direction']
vlan_filter = tap_flow['tap_flow']['vlan_filter']
vf_to_vf_all_vlans = False
LOG.debug("SRIOV Driver: Inside create_tap_flow: "
"SRC Port-id: %(src_port_id)s, "
"DEST Port-id: %(dest_port_id)s "
"Direction: %(direction)s",
{'src_port_id': source_port['id'],
'dest_port_id': ts_port['id'],
'direction': direction})
src_port_params = self.sriov_utils.get_sriov_port_params(source_port)
ts_port_params = self.sriov_utils.get_sriov_port_params(ts_port)
LOG.info("TaaS src_port_params "
"port %(id)s, MAC %(port_mac)s, PCI %(pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"src_vlans %(src_vlans)s; ",
{'id': source_port['id'],
'port_mac': src_port_params['mac'],
'pci_slot': src_port_params['pci_slot'],
'vf_index': src_port_params['vf_index'],
'pf_device': src_port_params['pf_device'],
'src_vlans': src_port_params['src_vlans']})
LOG.info("TaaS ts_port_params "
"port %(id)s, MAC %(port_mac)s, PCI %(pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"VLAN-Filter %(vlan_filter)s, src_vlans %(src_vlans)s; ",
{'id': ts_port['id'],
'port_mac': ts_port_params['mac'],
'pci_slot': ts_port_params['pci_slot'],
'vf_index': ts_port_params['vf_index'],
'pf_device': ts_port_params['pf_device'],
'vlan_filter': vlan_filter,
'src_vlans': ts_port_params['src_vlans']})
# If no VLAN filter configured on source port, then include all vlans
if not src_port_params['src_vlans'] or \
src_port_params['src_vlans'] == '0':
src_port_params['src_vlans'] = taas_consts.VLAN_RANGE
LOG.debug("TaaS no src_vlans in src_port")
# If no VLAN filter configured on probe port, then include all vlans
if not vlan_filter:
vlan_filter = taas_consts.VLAN_RANGE
vf_to_vf_all_vlans = True
LOG.debug("VF to VF mirroring for all VLANs. "
"Direction %(direction)s",
{'direction': direction})
if not src_port_params['pci_slot']:
LOG.error("No PCI Slot for source_port %(id)s with MAC %(mac)s; ",
{'id': source_port['id'],
'mac': src_port_params['mac'],
'source_vlans': src_port_params['src_vlans']})
raise taas_exc.PciSlotNotFound(port_id=source_port['id'],
mac=src_port_params['mac'])
if not ts_port_params['pci_slot']:
LOG.error("No PCI Slot for ts_port %(id)s with MAC %(mac)s; ",
{'id': ts_port['id'], 'mac': ts_port_params['mac'],
'vlan_filter': vlan_filter})
raise taas_exc.PciSlotNotFound(port_id=ts_port['id'],
mac=ts_port_params['mac'])
if src_port_params['pf_device'] != ts_port_params['pf_device']:
LOG.error("SRIOV NIC Driver only supports mirroring b/w "
"VF_src %(VF_src)s -> VF_probe %(VF_probe)s on same PF. "
"PF_src %(PF_src)s and PF_probe %(PF_probe)s "
"are different; ",
{'VF_src': src_port_params['vf_index'],
'VF_probe': ts_port_params['vf_index'],
'PF_src': src_port_params['pf_device'],
'PF_probe': ts_port_params['pf_device']})
return
# Fetch common VLAN tags
src_vlans_list = sorted(set(common_utils.get_list_from_ranges_str(
src_port_params['src_vlans'])))
vlan_filter_list = sorted(set(
common_utils.get_list_from_ranges_str(vlan_filter)))
common_vlans_list = list(set(src_vlans_list).intersection(
vlan_filter_list))
common_vlans_rng_str = common_utils.get_ranges_str_from_list(
common_vlans_list)
LOG.info("TaaS src_vlans_list %(src_vlans_list)s, "
"vlan_filter_list %(vlan_filter_list)s, "
"common_vlans_list %(common_vlans_list)s, "
"common_vlans_rng_str %(common_vlans_rng_str)s; ",
{'src_vlans_list': src_vlans_list,
'vlan_filter_list': vlan_filter_list,
'common_vlans_list': common_vlans_list,
'common_vlans_rng_str': common_vlans_rng_str})
if ts_port_params['pf_device'] and \
ts_port_params['vf_index'] and \
src_port_params['vf_index']:
with self.lock:
try:
LOG.info("TaaS invoking execute_sysfs_command")
self.sriov_utils.execute_sysfs_command(
'add',
ts_port_params,
src_port_params,
common_vlans_rng_str,
vf_to_vf_all_vlans,
direction)
except Exception:
LOG.error("TaaS error in invoking execute_sysfs_command")
with excutils.save_and_reraise_exception():
raise taas_exc.SriovNicSwitchDriverInvocationError(
ts_pf_dev=ts_port_params['pf_device'],
ts_vf_index=ts_port_params['vf_index'],
source_vf_index=src_port_params['vf_index'],
common_vlans_rng_str=common_vlans_rng_str,
vf_to_vf_all_vlans=vf_to_vf_all_vlans,
direction=direction)
return
def delete_tap_flow(self, tap_flow):
source_port = tap_flow['port']
ts_port = tap_flow['tap_service_port']
vlan_filter = tap_flow['tap_flow']['vlan_filter']
direction = tap_flow['tap_flow']['direction']
LOG.debug("SRIOV Driver: Inside delete_tap_flow: "
"SRC Port-id: %(src_port_id)s, "
"DEST Port-id: %(dest_port_id)s "
"Direction: %(direction)s",
{'src_port_id': source_port['id'],
'dest_port_id': ts_port['id'],
'direction': direction})
src_port_params = self.sriov_utils.get_sriov_port_params(source_port)
ts_port_params = self.sriov_utils.get_sriov_port_params(ts_port)
LOG.info("TaaS src_port_params "
"port %(id)s, MAC %(port_mac)s, PCI %(pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"src_vlans %(src_vlans)s; ",
{'id': source_port['id'],
'port_mac': src_port_params['mac'],
'pci_slot': src_port_params['pci_slot'],
'vf_index': src_port_params['vf_index'],
'pf_device': src_port_params['pf_device'],
'src_vlans': src_port_params['src_vlans']})
LOG.info("TaaS ts_port_params "
"port %(id)s, MAC %(port_mac)s, PCI %(pci_slot)s, "
"VF-Index %(vf_index)s, PF-Device %(pf_device)s, "
"VLAN-Filter %(vlan_filter)s, src_vlans %(src_vlans)s; ",
{'id': ts_port['id'],
'port_mac': ts_port_params['mac'],
'pci_slot': ts_port_params['pci_slot'],
'vf_index': ts_port_params['vf_index'],
'pf_device': ts_port_params['pf_device'],
'vlan_filter': vlan_filter,
'src_vlans': ts_port_params['src_vlans']})
# If no VLAN filter configured on source port, then include all vlans
if not src_port_params['src_vlans']:
src_port_params['src_vlans'] = taas_consts.VLAN_RANGE
LOG.debug("TaaS no src_vlans in src_port")
# If no VLAN filter configured on probe port, then include all vlans
if not vlan_filter:
vf_to_vf_all_vlans = True
LOG.debug("VF to VF mirroring for all VLANs. "
"Direction %(direction)s",
{'direction': direction})
if not src_port_params['pci_slot']:
LOG.error("No PCI Slot for source_port %(id)s with MAC %(mac)s; ",
{'id': source_port['id'],
'mac': src_port_params['mac'],
'source_vlans': src_port_params['src_vlans']})
raise taas_exc.PciSlotNotFound(port_id=source_port['id'],
mac=src_port_params['mac'])
if not ts_port_params['pci_slot']:
LOG.error("No PCI Slot for ts_port %(id)s with MAC %(mac)s; ",
{'id': ts_port['id'], 'mac': ts_port_params['mac']})
raise taas_exc.PciSlotNotFound(port_id=ts_port['id'],
mac=ts_port_params['mac'])
# Fetch common VLAN tags
src_vlans_list = []
for src_vlans_str in tap_flow['source_vlans_list']:
src_vlans_list.extend(common_utils.get_list_from_ranges_str(
src_vlans_str))
src_vlans_list = sorted(set(src_vlans_list))
vlan_filter_list = []
for vlan_filter_str in tap_flow['vlan_filter_list']:
vlan_filter_list.extend(common_utils.get_list_from_ranges_str(
vlan_filter_str))
vlan_filter_list = sorted(set(vlan_filter_list))
common_vlans_list = \
list(set(src_vlans_list).intersection(vlan_filter_list))
common_vlans_rng_str = \
common_utils.get_ranges_str_from_list(common_vlans_list)
LOG.info("TaaS src_vlans_list %(src_vlans_list)s, "
"vlan_filter_list %(vlan_filter_list)s, "
"common_vlans_list %(common_vlans_list)s, "
"common_vlans_rng_str %(common_vlans_rng_str)s; ",
{'src_vlans_list': src_vlans_list,
'vlan_filter_list': vlan_filter_list,
'common_vlans_list': common_vlans_list,
'common_vlans_rng_str': common_vlans_rng_str})
if ts_port_params['pf_device'] and \
ts_port_params['vf_index'] and \
src_port_params['vf_index']:
with self.lock:
try:
LOG.info("TaaS invoking execute_sysfs_command")
self.sriov_utils.execute_sysfs_command('rem',
ts_port_params,
src_port_params,
taas_consts.
VLAN_RANGE,
False,
'BOTH')
except Exception:
LOG.error("TaaS error in invoking execute_sysfs_command")
with excutils.save_and_reraise_exception():
raise taas_exc.SriovNicSwitchDriverInvocationError(
ts_pf_dev=ts_port_params['pf_device'],
ts_vf_index=ts_port_params['vf_index'],
source_vf_index=src_port_params['vf_index'],
common_vlans_rng_str=taas_consts.VLAN_RANGE,
vf_to_vf_all_vlans=vf_to_vf_all_vlans,
direction=direction)
if common_vlans_rng_str:
try:
LOG.info("TaaS invoking execute_sysfs_command")
self.sriov_utils.execute_sysfs_command(
'add',
ts_port_params,
src_port_params,
common_vlans_rng_str,
False,
'BOTH')
except Exception:
LOG.error("TaaS error in invoking "
"execute_sysfs_command")
with excutils.save_and_reraise_exception():
raise taas_exc.SriovNicSwitchDriverInvocationError(
ts_pf_dev=ts_port_params['pf_device'],
ts_vf_index=ts_port_params['vf_index'],
source_vf_index=src_port_params['vf_index'],
common_vlans_rng_str=common_vlans_rng_str,
vf_to_vf_all_vlans=vf_to_vf_all_vlans,
direction=direction)
return