125 lines
4.1 KiB
Python
125 lines
4.1 KiB
Python
# 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_log import log as logging
|
|
|
|
from neutron.agent.linux import ip_lib
|
|
from neutron.i18n import _LE
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
# 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_bridge_names():
|
|
return os.listdir(BRIDGE_FS)
|
|
|
|
|
|
class BridgeDevice(ip_lib.IPDevice):
|
|
def _brctl(self, cmd):
|
|
cmd = ['brctl'] + cmd
|
|
ip_wrapper = ip_lib.IPWrapper(self.namespace)
|
|
return ip_wrapper.netns.execute(cmd, run_as_root=True)
|
|
|
|
def _sysctl(self, cmd):
|
|
"""execute() doesn't return the exit status of the command it runs,
|
|
it returns stdout and stderr. Setting check_exit_code=True will cause
|
|
it to raise a RuntimeError if the exit status of the command is
|
|
non-zero, which in sysctl's case is an error. So we're normalizing
|
|
that into zero (success) and one (failure) here to mimic what
|
|
"echo $?" in a shell would be.
|
|
|
|
This is all because sysctl is too verbose and prints the value you
|
|
just set on success, unlike most other utilities that print nothing.
|
|
|
|
execute() will have dumped a message to the logs with the actual
|
|
output on failure, so it's not lost, and we don't need to print it
|
|
here.
|
|
"""
|
|
cmd = ['sysctl', '-w'] + cmd
|
|
ip_wrapper = ip_lib.IPWrapper(self.namespace)
|
|
try:
|
|
ip_wrapper.netns.execute(cmd, run_as_root=True,
|
|
check_exit_code=True)
|
|
except RuntimeError:
|
|
LOG.exception(_LE("Failed running %s"), cmd)
|
|
return 1
|
|
|
|
return 0
|
|
|
|
@classmethod
|
|
def addbr(cls, name, namespace=None):
|
|
bridge = cls(name, namespace)
|
|
bridge._brctl(['addbr', bridge.name])
|
|
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._brctl(['delbr', self.name])
|
|
|
|
def addif(self, interface):
|
|
return self._brctl(['addif', self.name, interface])
|
|
|
|
def delif(self, interface):
|
|
return self._brctl(['delif', self.name, interface])
|
|
|
|
def setfd(self, fd):
|
|
return self._brctl(['setfd', self.name, str(fd)])
|
|
|
|
def disable_stp(self):
|
|
return self._brctl(['stp', self.name, 'off'])
|
|
|
|
def disable_ipv6(self):
|
|
cmd = 'net.ipv6.conf.%s.disable_ipv6=1' % self.name
|
|
return self._sysctl([cmd])
|
|
|
|
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 []
|