You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
neutron/neutron/agent/linux/bridge_lib.py

145 lines
4.7 KiB

# Copyright 2015 Intel Corporation.
# Copyright 2015 Isaku Yamahata <isaku.yamahata at intel com>
# <isaku.yamahata at gmail com>
# All Rights Reserved.
#
#
# 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 os
from oslo_utils import excutils
from neutron.agent.linux import ip_lib
# NOTE(toabctl): Don't use /sys/devices/virtual/net here because not all tap
# devices are listed here (i.e. when using Xen)
BRIDGE_FS = "/sys/class/net/"
BRIDGE_INTERFACE_FS = BRIDGE_FS + "%(bridge)s/brif/%(interface)s"
BRIDGE_INTERFACES_FS = BRIDGE_FS + "%s/brif/"
BRIDGE_PORT_FS_FOR_DEVICE = BRIDGE_FS + "%s/brport"
BRIDGE_PATH_FOR_DEVICE = BRIDGE_PORT_FS_FOR_DEVICE + '/bridge'
def is_bridged_interface(interface):
if not interface:
return False
else:
return os.path.exists(BRIDGE_PORT_FS_FOR_DEVICE % interface)
def get_interface_ifindex(interface):
try:
with open(os.path.join(BRIDGE_FS, interface, 'ifindex'), 'r') as fh:
return int(fh.read().strip())
except (IOError, ValueError):
pass
def get_bridge_names():
return os.listdir(BRIDGE_FS)
class BridgeDevice(ip_lib.IPDevice):
def _ip_link(self, cmd):
cmd = ['ip', 'link'] + cmd
ip_wrapper = ip_lib.IPWrapper(self.namespace)
return ip_wrapper.netns.execute(cmd, run_as_root=True)
@classmethod
def addbr(cls, name, namespace=None):
bridge = cls(name, namespace, 'bridge')
try:
bridge.link.create()
except RuntimeError:
with excutils.save_and_reraise_exception() as ectx:
ectx.reraise = not bridge.exists()
return bridge
@classmethod
def get_interface_bridge(cls, interface):
try:
path = os.readlink(BRIDGE_PATH_FOR_DEVICE % interface)
except OSError:
return None
else:
name = path.rpartition('/')[-1]
return cls(name)
def delbr(self):
return self.link.delete()
def addif(self, interface):
return self._ip_link(['set', 'dev', interface, 'master', self.name])
def delif(self, interface):
return self._ip_link(['set', 'dev', interface, 'nomaster'])
def setfd(self, fd):
return self._ip_link(['set', 'dev', self.name, 'type', 'bridge',
'forward_delay', str(fd)])
def disable_stp(self):
return self._ip_link(['set', 'dev', self.name, 'type', 'bridge',
'stp_state', 0])
def owns_interface(self, interface):
return os.path.exists(
BRIDGE_INTERFACE_FS % {'bridge': self.name,
'interface': interface})
def get_interfaces(self):
try:
return os.listdir(BRIDGE_INTERFACES_FS % self.name)
except OSError:
return []
class FdbInterface(object):
"""provide basic functionality to edit the FDB table"""
@staticmethod
def _execute_bridge(cmd, namespace, **kwargs):
ip_wrapper = ip_lib.IPWrapper(namespace)
return ip_wrapper.netns.execute(cmd, run_as_root=True, **kwargs)
@classmethod
def _cmd(cls, op, mac, dev, ip_dst, namespace, **kwargs):
cmd = ['bridge', 'fdb', op, mac, 'dev', dev]
if ip_dst is not None:
cmd += ['dst', ip_dst]
cls._execute_bridge(cmd, namespace, **kwargs)
@classmethod
def add(cls, mac, dev, ip_dst=None, namespace=None, **kwargs):
return cls._cmd('add', mac, dev, ip_dst, namespace, **kwargs)
@classmethod
def append(cls, mac, dev, ip_dst=None, namespace=None, **kwargs):
return cls._cmd('append', mac, dev, ip_dst, namespace, **kwargs)
@classmethod
def replace(cls, mac, dev, ip_dst=None, namespace=None, **kwargs):
return cls._cmd('replace', mac, dev, ip_dst, namespace, **kwargs)
@classmethod
def delete(cls, mac, dev, ip_dst=None, namespace=None, **kwargs):
return cls._cmd('delete', mac, dev, ip_dst, namespace, **kwargs)
@classmethod
def show(cls, dev=None, namespace=None, **kwargs):
cmd = ['bridge', 'fdb', 'show']
if dev:
cmd += ['dev', dev]
return cls._execute_bridge(cmd, namespace, **kwargs)