625ae9404f838d1484ecac0496091f85b3ff28f2
[openstack-build/neutron-build.git] / neutron / agent / linux / bridge_lib.py
1 # Copyright 2015 Intel Corporation.
2 # Copyright 2015 Isaku Yamahata <isaku.yamahata at intel com>
3 #                               <isaku.yamahata at gmail com>
4 # All Rights Reserved.
5 #
6 #
7 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
8 #    not use this file except in compliance with the License. You may obtain
9 #    a copy of the License at
10 #
11 #         http://www.apache.org/licenses/LICENSE-2.0
12 #
13 #    Unless required by applicable law or agreed to in writing, software
14 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 #    License for the specific language governing permissions and limitations
17 #    under the License.
18
19 import os
20 from oslo_log import log as logging
21
22 from neutron.agent.linux import ip_lib
23 from neutron.i18n import _LE
24
25 LOG = logging.getLogger(__name__)
26
27 # NOTE(toabctl): Don't use /sys/devices/virtual/net here because not all tap
28 # devices are listed here (i.e. when using Xen)
29 BRIDGE_FS = "/sys/class/net/"
30 BRIDGE_INTERFACE_FS = BRIDGE_FS + "%(bridge)s/brif/%(interface)s"
31 BRIDGE_INTERFACES_FS = BRIDGE_FS + "%s/brif/"
32 BRIDGE_PORT_FS_FOR_DEVICE = BRIDGE_FS + "%s/brport"
33 BRIDGE_PATH_FOR_DEVICE = BRIDGE_PORT_FS_FOR_DEVICE + '/bridge'
34
35
36 def is_bridged_interface(interface):
37     if not interface:
38         return False
39     else:
40         return os.path.exists(BRIDGE_PORT_FS_FOR_DEVICE % interface)
41
42
43 def get_bridge_names():
44     return os.listdir(BRIDGE_FS)
45
46
47 class BridgeDevice(ip_lib.IPDevice):
48     def _brctl(self, cmd):
49         cmd = ['brctl'] + cmd
50         ip_wrapper = ip_lib.IPWrapper(self.namespace)
51         return ip_wrapper.netns.execute(cmd, run_as_root=True)
52
53     def _sysctl(self, cmd):
54         """execute() doesn't return the exit status of the command it runs,
55         it returns stdout and stderr. Setting check_exit_code=True will cause
56         it to raise a RuntimeError if the exit status of the command is
57         non-zero, which in sysctl's case is an error. So we're normalizing
58         that into zero (success) and one (failure) here to mimic what
59         "echo $?" in a shell would be.
60
61         This is all because sysctl is too verbose and prints the value you
62         just set on success, unlike most other utilities that print nothing.
63
64         execute() will have dumped a message to the logs with the actual
65         output on failure, so it's not lost, and we don't need to print it
66         here.
67         """
68         cmd = ['sysctl', '-w'] + cmd
69         ip_wrapper = ip_lib.IPWrapper(self.namespace)
70         try:
71             ip_wrapper.netns.execute(cmd, run_as_root=True,
72                                      check_exit_code=True)
73         except RuntimeError:
74             LOG.exception(_LE("Failed running %s"), cmd)
75             return 1
76
77         return 0
78
79     @classmethod
80     def addbr(cls, name, namespace=None):
81         bridge = cls(name, namespace)
82         bridge._brctl(['addbr', bridge.name])
83         return bridge
84
85     @classmethod
86     def get_interface_bridge(cls, interface):
87         try:
88             path = os.readlink(BRIDGE_PATH_FOR_DEVICE % interface)
89         except OSError:
90             return None
91         else:
92             name = path.rpartition('/')[-1]
93             return cls(name)
94
95     def delbr(self):
96         return self._brctl(['delbr', self.name])
97
98     def addif(self, interface):
99         return self._brctl(['addif', self.name, interface])
100
101     def delif(self, interface):
102         return self._brctl(['delif', self.name, interface])
103
104     def setfd(self, fd):
105         return self._brctl(['setfd', self.name, str(fd)])
106
107     def disable_stp(self):
108         return self._brctl(['stp', self.name, 'off'])
109
110     def disable_ipv6(self):
111         cmd = 'net.ipv6.conf.%s.disable_ipv6=1' % self.name
112         return self._sysctl([cmd])
113
114     def owns_interface(self, interface):
115         return os.path.exists(
116             BRIDGE_INTERFACE_FS % {'bridge': self.name,
117                                    'interface': interface})
118
119     def get_interfaces(self):
120         try:
121             return os.listdir(BRIDGE_INTERFACES_FS % self.name)
122         except OSError:
123             return []