Update specs to v. 2014.1.b3
[openstack-build/neutron-build.git] / debian / patches / disable-udev-tests.patch
1 Description: Disable udev tests
2  udev is not always avaliable in Ubuntu buildds; skip tests that
3  want to use this feature.
4 Author: Chuck Short <zulcss@ubuntu.com>
5 Fowarded: not-needed
6 diff -Naurp neutron-2014.1.b2.orig/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py neutron-2014.1.b2/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py
7 --- neutron-2014.1.b2.orig/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py      2014-01-23 10:13:25.000000000 -0500
8 +++ neutron-2014.1.b2/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py   2014-02-03 08:53:04.409255073 -0500
9 @@ -46,6 +46,7 @@ class FakeIpDevice(object):
10  class TestLinuxBridge(base.BaseTestCase):
11  
12      def setUp(self):
13 +        self.skipTest("udev not consistently available in Ubuntu buildds")
14          super(TestLinuxBridge, self).setUp()
15          self.addCleanup(cfg.CONF.reset)
16          interface_mappings = {'physnet1': 'eth1'}
17 @@ -109,6 +110,7 @@ class TestLinuxBridgeAgent(base.BaseTest
18          self.get_mac.return_value = '00:00:00:00:00:01'
19  
20      def test_update_devices_failed(self):
21 +        self.skipTest("udev not consistently available in Ubuntu buildds")
22          agent = linuxbridge_neutron_agent.LinuxBridgeNeutronAgentRPC({},
23                                                                       0,
24                                                                       None)
25 @@ -130,6 +132,7 @@ class TestLinuxBridgeAgent(base.BaseTest
26                  self.assertEqual(3, log.call_count)
27  
28      def test_process_network_devices_failed(self):
29 +        self.skipTest("udev not consistently available in Ubuntu buildds")
30          device_info = {'current': [1, 2, 3]}
31          agent = linuxbridge_neutron_agent.LinuxBridgeNeutronAgentRPC({},
32                                                                       0,
33 @@ -158,6 +161,7 @@ class TestLinuxBridgeAgent(base.BaseTest
34  
35  class TestLinuxBridgeManager(base.BaseTestCase):
36      def setUp(self):
37 +        self.skipTest("udev not consistently available in Ubuntu buildds")
38          super(TestLinuxBridgeManager, self).setUp()
39          self.interface_mappings = {'physnet1': 'eth1'}
40          self.root_helper = cfg.CONF.AGENT.root_helper
41 @@ -667,6 +671,7 @@ class TestLinuxBridgeManager(base.BaseTe
42  
43  class TestLinuxBridgeRpcCallbacks(base.BaseTestCase):
44      def setUp(self):
45 +        self.skipTest("udev not  consistently available in Ubuntu buildds")
46          cfg.CONF.set_override('local_ip', LOCAL_IP, 'VXLAN')
47          self.addCleanup(cfg.CONF.reset)
48          super(TestLinuxBridgeRpcCallbacks, self).setUp()
49 diff -Naurp neutron-2014.1.b2.orig/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py.orig neutron-2014.1.b2/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py.orig
50 --- neutron-2014.1.b2.orig/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py.orig 1969-12-31 19:00:00.000000000 -0500
51 +++ neutron-2014.1.b2/neutron/tests/unit/linuxbridge/test_lb_neutron_agent.py.orig      2014-01-23 10:13:25.000000000 -0500
52 @@ -0,0 +1,956 @@
53 +# vim: tabstop=4 shiftwidth=4 softtabstop=4
54 +
55 +# Copyright (c) 2012 OpenStack Foundation.
56 +#
57 +#    Licensed under the Apache License, Version 2.0 (the "License"); you may
58 +#    not use this file except in compliance with the License. You may obtain
59 +#    a copy of the License at
60 +#
61 +#         http://www.apache.org/licenses/LICENSE-2.0
62 +#
63 +#    Unless required by applicable law or agreed to in writing, software
64 +#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
65 +#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
66 +#    License for the specific language governing permissions and limitations
67 +#    under the License.
68 +
69 +import contextlib
70 +import os
71 +
72 +import mock
73 +from oslo.config import cfg
74 +import testtools
75 +
76 +from neutron.agent.linux import ip_lib
77 +from neutron.agent.linux import utils
78 +from neutron.common import constants
79 +from neutron.openstack.common.rpc import common as rpc_common
80 +from neutron.plugins.common import constants as p_const
81 +from neutron.plugins.linuxbridge.agent import linuxbridge_neutron_agent
82 +from neutron.plugins.linuxbridge.common import constants as lconst
83 +from neutron.tests import base
84 +
85 +LOCAL_IP = '192.168.0.33'
86 +
87 +
88 +class FakeIpLinkCommand(object):
89 +    def set_up(self):
90 +        pass
91 +
92 +
93 +class FakeIpDevice(object):
94 +    def __init__(self):
95 +        self.link = FakeIpLinkCommand()
96 +
97 +
98 +class TestLinuxBridge(base.BaseTestCase):
99 +
100 +    def setUp(self):
101 +        super(TestLinuxBridge, self).setUp()
102 +        self.addCleanup(cfg.CONF.reset)
103 +        interface_mappings = {'physnet1': 'eth1'}
104 +        root_helper = cfg.CONF.AGENT.root_helper
105 +
106 +        self.linux_bridge = linuxbridge_neutron_agent.LinuxBridgeManager(
107 +            interface_mappings, root_helper)
108 +
109 +    def test_ensure_physical_in_bridge_invalid(self):
110 +        result = self.linux_bridge.ensure_physical_in_bridge('network_id',
111 +                                                             p_const.TYPE_VLAN,
112 +                                                             'physnetx',
113 +                                                             7)
114 +        self.assertFalse(result)
115 +
116 +    def test_ensure_physical_in_bridge_flat(self):
117 +        with mock.patch.object(self.linux_bridge,
118 +                               'ensure_flat_bridge') as flat_bridge_func:
119 +            self.linux_bridge.ensure_physical_in_bridge(
120 +                'network_id', p_const.TYPE_FLAT, 'physnet1', None)
121 +        self.assertTrue(flat_bridge_func.called)
122 +
123 +    def test_ensure_physical_in_bridge_vlan(self):
124 +        with mock.patch.object(self.linux_bridge,
125 +                               'ensure_vlan_bridge') as vlan_bridge_func:
126 +            self.linux_bridge.ensure_physical_in_bridge(
127 +                'network_id', p_const.TYPE_VLAN, 'physnet1', 7)
128 +        self.assertTrue(vlan_bridge_func.called)
129 +
130 +    def test_ensure_physical_in_bridge_vxlan(self):
131 +        self.linux_bridge.vxlan_mode = lconst.VXLAN_UCAST
132 +        with mock.patch.object(self.linux_bridge,
133 +                               'ensure_vxlan_bridge') as vxlan_bridge_func:
134 +            self.linux_bridge.ensure_physical_in_bridge(
135 +                'network_id', 'vxlan', 'physnet1', 7)
136 +        self.assertTrue(vxlan_bridge_func.called)
137 +
138 +
139 +class TestLinuxBridgeAgent(base.BaseTestCase):
140 +
141 +    LINK_SAMPLE = [
142 +        '1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue \\'
143 +        'state UNKNOWN \\'
144 +        'link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00',
145 +        '2: eth77: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 \\'
146 +        'qdisc mq state UP qlen 1000\    link/ether \\'
147 +        'cc:dd:ee:ff:ab:cd brd ff:ff:ff:ff:ff:ff']
148 +
149 +    def setUp(self):
150 +        super(TestLinuxBridgeAgent, self).setUp()
151 +        cfg.CONF.set_override('rpc_backend',
152 +                              'neutron.openstack.common.rpc.impl_fake')
153 +        self.execute_p = mock.patch.object(ip_lib.IPWrapper, '_execute')
154 +        self.execute = self.execute_p.start()
155 +        self.addCleanup(self.execute_p.stop)
156 +        self.execute.return_value = '\n'.join(self.LINK_SAMPLE)
157 +        self.get_mac_p = mock.patch('neutron.agent.linux.utils.'
158 +                                    'get_interface_mac')
159 +        self.get_mac = self.get_mac_p.start()
160 +        self.addCleanup(self.get_mac_p.stop)
161 +        self.get_mac.return_value = '00:00:00:00:00:01'
162 +
163 +    def test_update_devices_failed(self):
164 +        agent = linuxbridge_neutron_agent.LinuxBridgeNeutronAgentRPC({},
165 +                                                                     0,
166 +                                                                     None)
167 +        raise_exception = [0]
168 +
169 +        def info_mock(msg):
170 +            if raise_exception[0] < 2:
171 +                raise_exception[0] += 1
172 +            else:
173 +                raise RuntimeError()
174 +        with mock.patch.object(agent.br_mgr,
175 +                               "update_devices") as update_devices:
176 +            update_devices.side_effect = RuntimeError
177 +            with mock.patch.object(linuxbridge_neutron_agent.LOG,
178 +                                   'info') as log:
179 +                log.side_effect = info_mock
180 +                with testtools.ExpectedException(RuntimeError):
181 +                    agent.daemon_loop()
182 +                self.assertEqual(3, log.call_count)
183 +
184 +    def test_process_network_devices_failed(self):
185 +        device_info = {'current': [1, 2, 3]}
186 +        agent = linuxbridge_neutron_agent.LinuxBridgeNeutronAgentRPC({},
187 +                                                                     0,
188 +                                                                     None)
189 +        raise_exception = [0]
190 +
191 +        def info_mock(msg):
192 +            if raise_exception[0] < 2:
193 +                raise_exception[0] += 1
194 +            else:
195 +                raise RuntimeError()
196 +
197 +        with mock.patch.object(agent.br_mgr,
198 +                               "update_devices") as update_devices:
199 +            update_devices.side_effect = device_info
200 +            with contextlib.nested(
201 +                mock.patch.object(linuxbridge_neutron_agent.LOG, 'info'),
202 +                mock.patch.object(agent, 'process_network_devices')
203 +            ) as (log, process_network_devices):
204 +                log.side_effect = info_mock
205 +                process_network_devices.side_effect = RuntimeError
206 +                with testtools.ExpectedException(RuntimeError):
207 +                    agent.daemon_loop()
208 +                self.assertEqual(3, log.call_count)
209 +
210 +
211 +class TestLinuxBridgeManager(base.BaseTestCase):
212 +    def setUp(self):
213 +        super(TestLinuxBridgeManager, self).setUp()
214 +        self.interface_mappings = {'physnet1': 'eth1'}
215 +        self.root_helper = cfg.CONF.AGENT.root_helper
216 +
217 +        self.lbm = linuxbridge_neutron_agent.LinuxBridgeManager(
218 +            self.interface_mappings, self.root_helper)
219 +
220 +    def test_device_exists(self):
221 +        with mock.patch.object(utils, 'execute') as execute_fn:
222 +            self.assertTrue(self.lbm.device_exists("eth0"))
223 +            execute_fn.side_effect = RuntimeError()
224 +            self.assertFalse(self.lbm.device_exists("eth0"))
225 +
226 +    def test_interface_exists_on_bridge(self):
227 +        with mock.patch.object(os, 'listdir') as listdir_fn:
228 +            listdir_fn.return_value = ["abc"]
229 +            self.assertTrue(
230 +                self.lbm.interface_exists_on_bridge("br-int", "abc")
231 +            )
232 +            self.assertFalse(
233 +                self.lbm.interface_exists_on_bridge("br-int", "abd")
234 +            )
235 +
236 +    def test_get_bridge_name(self):
237 +        nw_id = "123456789101112"
238 +        self.assertEqual(self.lbm.get_bridge_name(nw_id),
239 +                         "brq" + nw_id[0:11])
240 +        nw_id = ""
241 +        self.assertEqual(self.lbm.get_bridge_name(nw_id),
242 +                         "brq")
243 +
244 +    def test_get_subinterface_name(self):
245 +        self.assertEqual(self.lbm.get_subinterface_name("eth0", "0"),
246 +                         "eth0.0")
247 +        self.assertEqual(self.lbm.get_subinterface_name("eth0", ""),
248 +                         "eth0.")
249 +
250 +    def test_get_tap_device_name(self):
251 +        if_id = "123456789101112"
252 +        self.assertEqual(self.lbm.get_tap_device_name(if_id),
253 +                         "tap" + if_id[0:11])
254 +        if_id = ""
255 +        self.assertEqual(self.lbm.get_tap_device_name(if_id),
256 +                         "tap")
257 +
258 +    def test_get_vxlan_device_name(self):
259 +        vn_id = constants.MAX_VXLAN_VNI
260 +        self.assertEqual(self.lbm.get_vxlan_device_name(vn_id),
261 +                         "vxlan-" + str(vn_id))
262 +        self.assertIsNone(self.lbm.get_vxlan_device_name(vn_id + 1))
263 +
264 +    def test_get_all_neutron_bridges(self):
265 +        br_list = ["br-int", "brq1", "brq2", "br-ex"]
266 +        with mock.patch.object(os, 'listdir') as listdir_fn:
267 +            listdir_fn.return_value = br_list
268 +            self.assertEqual(self.lbm.get_all_neutron_bridges(),
269 +                             br_list[1:3])
270 +            self.assertTrue(listdir_fn.called)
271 +
272 +    def test_get_interfaces_on_bridge(self):
273 +        with contextlib.nested(
274 +            mock.patch.object(utils, 'execute'),
275 +            mock.patch.object(os, 'listdir')
276 +        ) as (exec_fn, listdir_fn):
277 +            listdir_fn.return_value = ["qbr1"]
278 +            self.assertEqual(self.lbm.get_interfaces_on_bridge("br0"),
279 +                             ["qbr1"])
280 +
281 +    def test_get_tap_devices_count(self):
282 +        with mock.patch.object(os, 'listdir') as listdir_fn:
283 +            listdir_fn.return_value = ['tap2101', 'eth0.100', 'vxlan-1000']
284 +            self.assertEqual(self.lbm.get_tap_devices_count('br0'), 1)
285 +            listdir_fn.side_effect = OSError()
286 +            self.assertEqual(self.lbm.get_tap_devices_count('br0'), 0)
287 +
288 +    def test_get_interface_by_ip(self):
289 +        with contextlib.nested(
290 +            mock.patch.object(ip_lib.IPWrapper, 'get_devices'),
291 +            mock.patch.object(ip_lib.IpAddrCommand, 'list')
292 +        ) as (get_dev_fn, ip_list_fn):
293 +            device = mock.Mock()
294 +            device.name = 'dev_name'
295 +            get_dev_fn.return_value = [device]
296 +            ip_list_fn.returnvalue = mock.Mock()
297 +            self.assertEqual(self.lbm.get_interface_by_ip(LOCAL_IP),
298 +                             'dev_name')
299 +
300 +    def test_get_bridge_for_tap_device(self):
301 +        with contextlib.nested(
302 +            mock.patch.object(self.lbm, "get_all_neutron_bridges"),
303 +            mock.patch.object(self.lbm, "get_interfaces_on_bridge")
304 +        ) as (get_all_qbr_fn, get_if_fn):
305 +            get_all_qbr_fn.return_value = ["br-int", "br-ex"]
306 +            get_if_fn.return_value = ["tap1", "tap2", "tap3"]
307 +            self.assertEqual(self.lbm.get_bridge_for_tap_device("tap1"),
308 +                             "br-int")
309 +            self.assertIsNone(self.lbm.get_bridge_for_tap_device("tap4"))
310 +
311 +    def test_is_device_on_bridge(self):
312 +        self.assertTrue(not self.lbm.is_device_on_bridge(""))
313 +        with mock.patch.object(os.path, 'exists') as exists_fn:
314 +            exists_fn.return_value = True
315 +            self.assertTrue(self.lbm.is_device_on_bridge("tap1"))
316 +            exists_fn.assert_called_with(
317 +                "/sys/devices/virtual/net/tap1/brport"
318 +            )
319 +
320 +    def test_get_interface_details(self):
321 +        with contextlib.nested(
322 +            mock.patch.object(ip_lib.IpAddrCommand, 'list'),
323 +            mock.patch.object(ip_lib.IpRouteCommand, 'get_gateway')
324 +        ) as (list_fn, getgw_fn):
325 +            gwdict = dict(gateway='1.1.1.1')
326 +            getgw_fn.return_value = gwdict
327 +            ipdict = dict(cidr='1.1.1.1/24',
328 +                          broadcast='1.1.1.255',
329 +                          scope='global',
330 +                          ip_version=4,
331 +                          dynamic=False)
332 +            list_fn.return_value = ipdict
333 +            ret = self.lbm.get_interface_details("eth0")
334 +
335 +            self.assertTrue(list_fn.called)
336 +            self.assertTrue(getgw_fn.called)
337 +            self.assertEqual(ret, (ipdict, gwdict))
338 +
339 +    def test_ensure_flat_bridge(self):
340 +        with contextlib.nested(
341 +            mock.patch.object(ip_lib.IpAddrCommand, 'list'),
342 +            mock.patch.object(ip_lib.IpRouteCommand, 'get_gateway')
343 +        ) as (list_fn, getgw_fn):
344 +            gwdict = dict(gateway='1.1.1.1')
345 +            getgw_fn.return_value = gwdict
346 +            ipdict = dict(cidr='1.1.1.1/24',
347 +                          broadcast='1.1.1.255',
348 +                          scope='global',
349 +                          ip_version=4,
350 +                          dynamic=False)
351 +            list_fn.return_value = ipdict
352 +            with mock.patch.object(self.lbm, 'ensure_bridge') as ens:
353 +                self.assertEqual(
354 +                    self.lbm.ensure_flat_bridge("123", "eth0"),
355 +                    "eth0"
356 +                )
357 +                self.assertTrue(list_fn.called)
358 +                self.assertTrue(getgw_fn.called)
359 +                ens.assert_called_once_with("brq123", "eth0",
360 +                                            ipdict, gwdict)
361 +
362 +    def test_ensure_vlan_bridge(self):
363 +        with contextlib.nested(
364 +            mock.patch.object(self.lbm, 'ensure_vlan'),
365 +            mock.patch.object(self.lbm, 'ensure_bridge'),
366 +            mock.patch.object(self.lbm, 'get_interface_details'),
367 +        ) as (ens_vl_fn, ens, get_int_det_fn):
368 +            ens_vl_fn.return_value = "eth0.1"
369 +            get_int_det_fn.return_value = (None, None)
370 +            self.assertEqual(self.lbm.ensure_vlan_bridge("123", "eth0", "1"),
371 +                             "eth0.1")
372 +            ens.assert_called_with("brq123", "eth0.1", None, None)
373 +
374 +            get_int_det_fn.return_value = ("ips", "gateway")
375 +            self.assertEqual(self.lbm.ensure_vlan_bridge("123", "eth0", "1"),
376 +                             "eth0.1")
377 +            ens.assert_called_with("brq123", "eth0.1", "ips", "gateway")
378 +
379 +    def test_ensure_local_bridge(self):
380 +        with mock.patch.object(self.lbm, 'ensure_bridge') as ens_fn:
381 +            self.lbm.ensure_local_bridge("54321")
382 +            ens_fn.assert_called_once_with("brq54321")
383 +
384 +    def test_ensure_vlan(self):
385 +        with mock.patch.object(self.lbm, 'device_exists') as de_fn:
386 +            de_fn.return_value = True
387 +            self.assertEqual(self.lbm.ensure_vlan("eth0", "1"), "eth0.1")
388 +            de_fn.return_value = False
389 +            with mock.patch.object(utils, 'execute') as exec_fn:
390 +                exec_fn.return_value = False
391 +                self.assertEqual(self.lbm.ensure_vlan("eth0", "1"), "eth0.1")
392 +                exec_fn.assert_called_twice()
393 +                exec_fn.return_value = True
394 +                self.assertIsNone(self.lbm.ensure_vlan("eth0", "1"))
395 +                exec_fn.assert_called_once()
396 +
397 +    def test_ensure_vxlan(self):
398 +        seg_id = "12345678"
399 +        self.lbm.local_int = 'eth0'
400 +        self.lbm.vxlan_mode = lconst.VXLAN_MCAST
401 +        with mock.patch.object(self.lbm, 'device_exists') as de_fn:
402 +            de_fn.return_value = True
403 +            self.assertEqual(self.lbm.ensure_vxlan(seg_id), "vxlan-" + seg_id)
404 +            de_fn.return_value = False
405 +            with mock.patch.object(self.lbm.ip,
406 +                                   'add_vxlan') as add_vxlan_fn:
407 +                add_vxlan_fn.return_value = FakeIpDevice()
408 +                self.assertEqual(self.lbm.ensure_vxlan(seg_id),
409 +                                 "vxlan-" + seg_id)
410 +                add_vxlan_fn.assert_called_with("vxlan-" + seg_id, seg_id,
411 +                                                group="224.0.0.1",
412 +                                                dev=self.lbm.local_int)
413 +                cfg.CONF.set_override('l2_population', 'True', 'VXLAN')
414 +                self.assertEqual(self.lbm.ensure_vxlan(seg_id),
415 +                                 "vxlan-" + seg_id)
416 +                add_vxlan_fn.assert_called_with("vxlan-" + seg_id, seg_id,
417 +                                                group="224.0.0.1",
418 +                                                dev=self.lbm.local_int,
419 +                                                proxy=True)
420 +
421 +    def test_update_interface_ip_details(self):
422 +        gwdict = dict(gateway='1.1.1.1',
423 +                      metric=50)
424 +        ipdict = dict(cidr='1.1.1.1/24',
425 +                      broadcast='1.1.1.255',
426 +                      scope='global',
427 +                      ip_version=4,
428 +                      dynamic=False)
429 +        with contextlib.nested(
430 +            mock.patch.object(ip_lib.IpAddrCommand, 'add'),
431 +            mock.patch.object(ip_lib.IpAddrCommand, 'delete')
432 +        ) as (add_fn, del_fn):
433 +            self.lbm.update_interface_ip_details("br0", "eth0",
434 +                                                 [ipdict], None)
435 +            self.assertTrue(add_fn.called)
436 +            self.assertTrue(del_fn.called)
437 +
438 +        with contextlib.nested(
439 +            mock.patch.object(ip_lib.IpRouteCommand, 'add_gateway'),
440 +            mock.patch.object(ip_lib.IpRouteCommand, 'delete_gateway')
441 +        ) as (addgw_fn, delgw_fn):
442 +            self.lbm.update_interface_ip_details("br0", "eth0",
443 +                                                 None, gwdict)
444 +            self.assertTrue(addgw_fn.called)
445 +            self.assertTrue(delgw_fn.called)
446 +
447 +    def test_ensure_bridge(self):
448 +        with contextlib.nested(
449 +            mock.patch.object(self.lbm, 'device_exists'),
450 +            mock.patch.object(utils, 'execute'),
451 +            mock.patch.object(self.lbm, 'update_interface_ip_details'),
452 +            mock.patch.object(self.lbm, 'interface_exists_on_bridge'),
453 +            mock.patch.object(self.lbm, 'is_device_on_bridge'),
454 +            mock.patch.object(self.lbm, 'get_bridge_for_tap_device'),
455 +        ) as (de_fn, exec_fn, upd_fn, ie_fn, if_br_fn, get_if_br_fn):
456 +            de_fn.return_value = False
457 +            exec_fn.return_value = False
458 +            self.assertEqual(self.lbm.ensure_bridge("br0", None), "br0")
459 +            ie_fn.return_Value = False
460 +            self.lbm.ensure_bridge("br0", "eth0")
461 +            upd_fn.assert_called_with("br0", "eth0", None, None)
462 +            ie_fn.assert_called_with("br0", "eth0")
463 +
464 +            self.lbm.ensure_bridge("br0", "eth0", "ips", "gateway")
465 +            upd_fn.assert_called_with("br0", "eth0", "ips", "gateway")
466 +            ie_fn.assert_called_with("br0", "eth0")
467 +
468 +            exec_fn.side_effect = Exception()
469 +            de_fn.return_value = True
470 +            self.lbm.ensure_bridge("br0", "eth0")
471 +            ie_fn.assert_called_with("br0", "eth0")
472 +
473 +            exec_fn.reset_mock()
474 +            exec_fn.side_effect = None
475 +            de_fn.return_value = True
476 +            ie_fn.return_value = False
477 +            get_if_br_fn.return_value = "br1"
478 +            self.lbm.ensure_bridge("br0", "eth0")
479 +            expected = [
480 +                mock.call(['brctl', 'delif', 'br1', 'eth0'],
481 +                          root_helper=self.root_helper),
482 +                mock.call(['brctl', 'addif', 'br0', 'eth0'],
483 +                          root_helper=self.root_helper),
484 +            ]
485 +            exec_fn.assert_has_calls(expected)
486 +
487 +    def test_ensure_physical_in_bridge(self):
488 +        self.assertFalse(
489 +            self.lbm.ensure_physical_in_bridge("123", p_const.TYPE_VLAN,
490 +                                               "phys", "1")
491 +        )
492 +        with mock.patch.object(self.lbm, "ensure_flat_bridge") as flbr_fn:
493 +            self.assertTrue(
494 +                self.lbm.ensure_physical_in_bridge("123", p_const.TYPE_FLAT,
495 +                                                   "physnet1", None)
496 +            )
497 +            self.assertTrue(flbr_fn.called)
498 +        with mock.patch.object(self.lbm, "ensure_vlan_bridge") as vlbr_fn:
499 +            self.assertTrue(
500 +                self.lbm.ensure_physical_in_bridge("123", p_const.TYPE_VLAN,
501 +                                                   "physnet1", "1")
502 +            )
503 +            self.assertTrue(vlbr_fn.called)
504 +
505 +        with mock.patch.object(self.lbm, "ensure_vxlan_bridge") as vlbr_fn:
506 +            self.lbm.vxlan_mode = lconst.VXLAN_MCAST
507 +            self.assertTrue(
508 +                self.lbm.ensure_physical_in_bridge("123", p_const.TYPE_VXLAN,
509 +                                                   "physnet1", "1")
510 +            )
511 +            self.assertTrue(vlbr_fn.called)
512 +
513 +    def test_add_tap_interface(self):
514 +        with mock.patch.object(self.lbm, "device_exists") as de_fn:
515 +            de_fn.return_value = False
516 +            self.assertFalse(
517 +                self.lbm.add_tap_interface("123", p_const.TYPE_VLAN,
518 +                                           "physnet1", "1", "tap1")
519 +            )
520 +
521 +            de_fn.return_value = True
522 +            with contextlib.nested(
523 +                mock.patch.object(self.lbm, "ensure_local_bridge"),
524 +                mock.patch.object(utils, "execute"),
525 +                mock.patch.object(self.lbm, "get_bridge_for_tap_device")
526 +            ) as (en_fn, exec_fn, get_br):
527 +                exec_fn.return_value = False
528 +                get_br.return_value = True
529 +                self.assertTrue(self.lbm.add_tap_interface("123",
530 +                                                           p_const.TYPE_LOCAL,
531 +                                                           "physnet1", None,
532 +                                                           "tap1"))
533 +                en_fn.assert_called_with("123")
534 +
535 +                get_br.return_value = False
536 +                exec_fn.return_value = True
537 +                self.assertFalse(self.lbm.add_tap_interface("123",
538 +                                                            p_const.TYPE_LOCAL,
539 +                                                            "physnet1", None,
540 +                                                            "tap1"))
541 +
542 +            with mock.patch.object(self.lbm,
543 +                                   "ensure_physical_in_bridge") as ens_fn:
544 +                ens_fn.return_value = False
545 +                self.assertFalse(self.lbm.add_tap_interface("123",
546 +                                                            p_const.TYPE_VLAN,
547 +                                                            "physnet1", "1",
548 +                                                            "tap1"))
549 +
550 +    def test_add_interface(self):
551 +        with mock.patch.object(self.lbm, "add_tap_interface") as add_tap:
552 +            self.lbm.add_interface("123", p_const.TYPE_VLAN, "physnet-1",
553 +                                   "1", "234")
554 +            add_tap.assert_called_with("123", p_const.TYPE_VLAN, "physnet-1",
555 +                                       "1", "tap234")
556 +
557 +    def test_delete_vlan_bridge(self):
558 +        with contextlib.nested(
559 +            mock.patch.object(self.lbm, "device_exists"),
560 +            mock.patch.object(self.lbm, "get_interfaces_on_bridge"),
561 +            mock.patch.object(self.lbm, "remove_interface"),
562 +            mock.patch.object(self.lbm, "get_interface_details"),
563 +            mock.patch.object(self.lbm, "update_interface_ip_details"),
564 +            mock.patch.object(self.lbm, "delete_vlan"),
565 +            mock.patch.object(self.lbm, "delete_vxlan"),
566 +            mock.patch.object(utils, "execute")
567 +        ) as (de_fn, getif_fn, remif_fn, if_det_fn,
568 +              updif_fn, del_vlan, del_vxlan, exec_fn):
569 +            de_fn.return_value = False
570 +            self.lbm.delete_vlan_bridge("br0")
571 +            self.assertFalse(getif_fn.called)
572 +
573 +            de_fn.return_value = True
574 +            getif_fn.return_value = ["eth0", "eth1.1", "eth1", "vxlan-1002"]
575 +            if_det_fn.return_value = ("ips", "gateway")
576 +            exec_fn.return_value = False
577 +            self.lbm.delete_vlan_bridge("br0")
578 +            updif_fn.assert_called_with("eth1", "br0", "ips", "gateway")
579 +            del_vlan.assert_called_with("eth1.1")
580 +            del_vxlan.assert_called_with("vxlan-1002")
581 +
582 +    def test_delete_vxlan_bridge_no_int_mappings(self):
583 +        interface_mappings = {}
584 +        lbm = linuxbridge_neutron_agent.LinuxBridgeManager(
585 +            interface_mappings, self.root_helper)
586 +
587 +        with contextlib.nested(
588 +            mock.patch.object(lbm, "device_exists"),
589 +            mock.patch.object(lbm, "get_interfaces_on_bridge"),
590 +            mock.patch.object(lbm, "remove_interface"),
591 +            mock.patch.object(lbm, "delete_vxlan"),
592 +            mock.patch.object(utils, "execute")
593 +        ) as (de_fn, getif_fn, remif_fn, del_vxlan, exec_fn):
594 +            de_fn.return_value = False
595 +            lbm.delete_vlan_bridge("br0")
596 +            self.assertFalse(getif_fn.called)
597 +
598 +            de_fn.return_value = True
599 +            getif_fn.return_value = ["vxlan-1002"]
600 +            exec_fn.return_value = False
601 +            lbm.delete_vlan_bridge("br0")
602 +            del_vxlan.assert_called_with("vxlan-1002")
603 +
604 +    def test_remove_empty_bridges(self):
605 +        self.lbm.network_map = {'net1': mock.Mock(), 'net2': mock.Mock()}
606 +
607 +        def tap_count_side_effect(*args):
608 +            return 0 if args[0] == 'brqnet1' else 1
609 +
610 +        with contextlib.nested(
611 +            mock.patch.object(self.lbm, "delete_vlan_bridge"),
612 +            mock.patch.object(self.lbm, "get_tap_devices_count",
613 +                              side_effect=tap_count_side_effect),
614 +        ) as (del_br_fn, count_tap_fn):
615 +            self.lbm.remove_empty_bridges()
616 +            del_br_fn.assert_called_once_with('brqnet1')
617 +
618 +    def test_remove_interface(self):
619 +        with contextlib.nested(
620 +            mock.patch.object(self.lbm, "device_exists"),
621 +            mock.patch.object(self.lbm, "is_device_on_bridge"),
622 +            mock.patch.object(utils, "execute")
623 +        ) as (de_fn, isdev_fn, exec_fn):
624 +            de_fn.return_value = False
625 +            self.assertFalse(self.lbm.remove_interface("br0", "eth0"))
626 +            self.assertFalse(isdev_fn.called)
627 +
628 +            de_fn.return_value = True
629 +            isdev_fn.return_value = False
630 +            self.assertTrue(self.lbm.remove_interface("br0", "eth0"))
631 +
632 +            isdev_fn.return_value = True
633 +            exec_fn.return_value = True
634 +            self.assertFalse(self.lbm.remove_interface("br0", "eth0"))
635 +
636 +            exec_fn.return_value = False
637 +            self.assertTrue(self.lbm.remove_interface("br0", "eth0"))
638 +
639 +    def test_delete_vlan(self):
640 +        with contextlib.nested(
641 +            mock.patch.object(self.lbm, "device_exists"),
642 +            mock.patch.object(utils, "execute")
643 +        ) as (de_fn, exec_fn):
644 +            de_fn.return_value = False
645 +            self.lbm.delete_vlan("eth1.1")
646 +            self.assertFalse(exec_fn.called)
647 +
648 +            de_fn.return_value = True
649 +            exec_fn.return_value = False
650 +            self.lbm.delete_vlan("eth1.1")
651 +            self.assertTrue(exec_fn.called)
652 +
653 +    def test_update_devices(self):
654 +        with mock.patch.object(self.lbm, "udev_get_tap_devices") as gt_fn:
655 +            gt_fn.return_value = set(["dev1"])
656 +            self.assertIsNone(self.lbm.update_devices(set(["dev1"])))
657 +
658 +            gt_fn.return_value = set(["dev1", "dev2"])
659 +            self.assertEqual(self.lbm.update_devices(set(["dev2", "dev3"])),
660 +                             {"current": set(["dev1", "dev2"]),
661 +                              "added": set(["dev1"]),
662 +                              "removed": set(["dev3"])
663 +                              })
664 +
665 +    def _check_vxlan_support(self, kernel_version, vxlan_proxy_supported,
666 +                             fdb_append_supported, l2_population,
667 +                             expected_mode):
668 +        def iproute_supported_side_effect(*args):
669 +            if args[1] == 'proxy':
670 +                return vxlan_proxy_supported
671 +            elif args[1] == 'append':
672 +                return fdb_append_supported
673 +
674 +        with contextlib.nested(
675 +            mock.patch("platform.release", return_value=kernel_version),
676 +            mock.patch.object(ip_lib, 'iproute_arg_supported',
677 +                              side_effect=iproute_supported_side_effect),
678 +        ) as (kver_fn, ip_arg_fn):
679 +            self.lbm.check_vxlan_support()
680 +            self.assertEqual(self.lbm.vxlan_mode, expected_mode)
681 +
682 +    def test_vxlan_mode_ucast(self):
683 +        self._check_vxlan_support(kernel_version='3.12',
684 +                                  vxlan_proxy_supported=True,
685 +                                  fdb_append_supported=True,
686 +                                  l2_population=True,
687 +                                  expected_mode=lconst.VXLAN_MCAST)
688 +
689 +    def test_vxlan_mode_mcast(self):
690 +        self._check_vxlan_support(kernel_version='3.12',
691 +                                  vxlan_proxy_supported=True,
692 +                                  fdb_append_supported=False,
693 +                                  l2_population=True,
694 +                                  expected_mode=lconst.VXLAN_MCAST)
695 +        self._check_vxlan_support(kernel_version='3.10',
696 +                                  vxlan_proxy_supported=True,
697 +                                  fdb_append_supported=True,
698 +                                  l2_population=True,
699 +                                  expected_mode=lconst.VXLAN_MCAST)
700 +
701 +    def test_vxlan_mode_unsupported(self):
702 +        self._check_vxlan_support(kernel_version='3.7',
703 +                                  vxlan_proxy_supported=True,
704 +                                  fdb_append_supported=True,
705 +                                  l2_population=False,
706 +                                  expected_mode=lconst.VXLAN_NONE)
707 +        self._check_vxlan_support(kernel_version='3.10',
708 +                                  vxlan_proxy_supported=False,
709 +                                  fdb_append_supported=False,
710 +                                  l2_population=False,
711 +                                  expected_mode=lconst.VXLAN_NONE)
712 +        cfg.CONF.set_override('vxlan_group', '', 'VXLAN')
713 +        self._check_vxlan_support(kernel_version='3.12',
714 +                                  vxlan_proxy_supported=True,
715 +                                  fdb_append_supported=True,
716 +                                  l2_population=True,
717 +                                  expected_mode=lconst.VXLAN_NONE)
718 +
719 +
720 +class TestLinuxBridgeRpcCallbacks(base.BaseTestCase):
721 +    def setUp(self):
722 +        cfg.CONF.set_override('local_ip', LOCAL_IP, 'VXLAN')
723 +        self.addCleanup(cfg.CONF.reset)
724 +        super(TestLinuxBridgeRpcCallbacks, self).setUp()
725 +
726 +        self.u_execute_p = mock.patch('neutron.agent.linux.utils.execute')
727 +        self.u_execute = self.u_execute_p.start()
728 +        self.addCleanup(self.u_execute_p.stop)
729 +
730 +        class FakeLBAgent(object):
731 +            def __init__(self):
732 +                self.agent_id = 1
733 +                self.br_mgr = (linuxbridge_neutron_agent.
734 +                               LinuxBridgeManager({'physnet1': 'eth1'},
735 +                                                  cfg.CONF.AGENT.root_helper))
736 +
737 +                self.br_mgr.vxlan_mode = lconst.VXLAN_UCAST
738 +                segment = mock.Mock()
739 +                segment.network_type = 'vxlan'
740 +                segment.segmentation_id = 1
741 +                self.br_mgr.network_map['net_id'] = segment
742 +
743 +        self.lb_rpc = linuxbridge_neutron_agent.LinuxBridgeRpcCallbacks(
744 +            object(),
745 +            FakeLBAgent()
746 +        )
747 +
748 +        self.root_helper = cfg.CONF.AGENT.root_helper
749 +
750 +    def test_network_delete(self):
751 +        with contextlib.nested(
752 +            mock.patch.object(self.lb_rpc.agent.br_mgr, "get_bridge_name"),
753 +            mock.patch.object(self.lb_rpc.agent.br_mgr, "delete_vlan_bridge")
754 +        ) as (get_br_fn, del_fn):
755 +            get_br_fn.return_value = "br0"
756 +            self.lb_rpc.network_delete("anycontext", network_id="123")
757 +            get_br_fn.assert_called_with("123")
758 +            del_fn.assert_called_with("br0")
759 +
760 +    def test_port_update(self):
761 +        with contextlib.nested(
762 +            mock.patch.object(self.lb_rpc.agent.br_mgr,
763 +                              "get_tap_device_name"),
764 +            mock.patch.object(self.lb_rpc.agent.br_mgr,
765 +                              "udev_get_tap_devices"),
766 +            mock.patch.object(self.lb_rpc.agent.br_mgr,
767 +                              "get_bridge_name"),
768 +            mock.patch.object(self.lb_rpc.agent.br_mgr,
769 +                              "remove_interface"),
770 +            mock.patch.object(self.lb_rpc.agent.br_mgr, "add_interface"),
771 +            mock.patch.object(self.lb_rpc.agent,
772 +                              "plugin_rpc", create=True),
773 +            mock.patch.object(self.lb_rpc.sg_agent,
774 +                              "refresh_firewall", create=True)
775 +        ) as (get_tap_fn, udev_fn, getbr_fn, remif_fn,
776 +              addif_fn, rpc_obj, reffw_fn):
777 +            get_tap_fn.return_value = "tap123"
778 +            udev_fn.return_value = ["tap123", "tap124"]
779 +            port = {"admin_state_up": True,
780 +                    "id": "1234-5678",
781 +                    "network_id": "123-123"}
782 +            self.lb_rpc.port_update("unused_context", port=port,
783 +                                    vlan_id="1", physical_network="physnet1")
784 +            self.assertFalse(reffw_fn.called)
785 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_VLAN,
786 +                                        "physnet1", "1", port["id"])
787 +
788 +            self.lb_rpc.port_update("unused_context", port=port,
789 +                                    network_type=p_const.TYPE_VLAN,
790 +                                    segmentation_id="2",
791 +                                    physical_network="physnet1")
792 +            self.assertFalse(reffw_fn.called)
793 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_VLAN,
794 +                                        "physnet1", "2", port["id"])
795 +
796 +            self.lb_rpc.port_update("unused_context", port=port,
797 +                                    vlan_id=lconst.FLAT_VLAN_ID,
798 +                                    physical_network="physnet1")
799 +            self.assertFalse(reffw_fn.called)
800 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_FLAT,
801 +                                        "physnet1", None, port["id"])
802 +
803 +            self.lb_rpc.port_update("unused_context", port=port,
804 +                                    network_type=p_const.TYPE_FLAT,
805 +                                    segmentation_id=None,
806 +                                    physical_network="physnet1")
807 +            self.assertFalse(reffw_fn.called)
808 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_FLAT,
809 +                                        "physnet1", None, port["id"])
810 +
811 +            self.lb_rpc.port_update("unused_context", port=port,
812 +                                    vlan_id=lconst.LOCAL_VLAN_ID,
813 +                                    physical_network=None)
814 +            self.assertFalse(reffw_fn.called)
815 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_LOCAL,
816 +                                        None, None, port["id"])
817 +
818 +            self.lb_rpc.port_update("unused_context", port=port,
819 +                                    network_type=p_const.TYPE_LOCAL,
820 +                                    segmentation_id=None,
821 +                                    physical_network=None)
822 +            self.assertFalse(reffw_fn.called)
823 +            addif_fn.assert_called_with(port["network_id"], p_const.TYPE_LOCAL,
824 +                                        None, None, port["id"])
825 +
826 +            addif_fn.return_value = True
827 +            self.lb_rpc.port_update("unused_context", port=port,
828 +                                    network_type=p_const.TYPE_LOCAL,
829 +                                    segmentation_id=None,
830 +                                    physical_network=None)
831 +            rpc_obj.update_device_up.assert_called_with(
832 +                self.lb_rpc.context,
833 +                "tap123",
834 +                self.lb_rpc.agent.agent_id,
835 +                cfg.CONF.host
836 +            )
837 +
838 +            addif_fn.return_value = False
839 +            self.lb_rpc.port_update("unused_context", port=port,
840 +                                    network_type=p_const.TYPE_LOCAL,
841 +                                    segmentation_id=None,
842 +                                    physical_network=None)
843 +            rpc_obj.update_device_down.assert_called_with(
844 +                self.lb_rpc.context,
845 +                "tap123",
846 +                self.lb_rpc.agent.agent_id,
847 +                cfg.CONF.host
848 +            )
849 +
850 +            port["admin_state_up"] = False
851 +            port["security_groups"] = True
852 +            getbr_fn.return_value = "br0"
853 +            self.lb_rpc.port_update("unused_context", port=port,
854 +                                    vlan_id="1", physical_network="physnet1")
855 +            self.assertTrue(reffw_fn.called)
856 +            remif_fn.assert_called_with("br0", "tap123")
857 +            rpc_obj.update_device_down.assert_called_with(
858 +                self.lb_rpc.context,
859 +                "tap123",
860 +                self.lb_rpc.agent.agent_id,
861 +                cfg.CONF.host
862 +            )
863 +
864 +    def test_port_update_plugin_rpc_failed(self):
865 +        with contextlib.nested(
866 +                mock.patch.object(self.lb_rpc.agent.br_mgr,
867 +                                  "get_tap_device_name"),
868 +                mock.patch.object(self.lb_rpc.agent.br_mgr,
869 +                                  "udev_get_tap_devices"),
870 +                mock.patch.object(self.lb_rpc.agent.br_mgr,
871 +                                  "get_bridge_name"),
872 +                mock.patch.object(self.lb_rpc.agent.br_mgr,
873 +                                  "remove_interface"),
874 +                mock.patch.object(self.lb_rpc.agent.br_mgr, "add_interface"),
875 +                mock.patch.object(self.lb_rpc.sg_agent,
876 +                                  "refresh_firewall", create=True),
877 +                mock.patch.object(self.lb_rpc.agent,
878 +                                  "plugin_rpc", create=True),
879 +                mock.patch.object(linuxbridge_neutron_agent.LOG, 'error'),
880 +        ) as (get_tap_fn, udev_fn, _, _, _, _, plugin_rpc, log):
881 +            get_tap_fn.return_value = "tap123"
882 +            udev_fn.return_value = ["tap123", "tap124"]
883 +            port = {"admin_state_up": True,
884 +                    "id": "1234-5678",
885 +                    "network_id": "123-123"}
886 +            plugin_rpc.update_device_up.side_effect = rpc_common.Timeout
887 +            self.lb_rpc.port_update(mock.Mock(), port=port)
888 +            self.assertTrue(plugin_rpc.update_device_up.called)
889 +            self.assertEqual(log.call_count, 1)
890 +
891 +            log.reset_mock()
892 +            port["admin_state_up"] = False
893 +            plugin_rpc.update_device_down.side_effect = rpc_common.Timeout
894 +            self.lb_rpc.port_update(mock.Mock(), port=port)
895 +            self.assertTrue(plugin_rpc.update_device_down.called)
896 +            self.assertEqual(log.call_count, 1)
897 +
898 +    def test_fdb_add(self):
899 +        fdb_entries = {'net_id':
900 +                       {'ports':
901 +                        {'agent_ip': [constants.FLOODING_ENTRY,
902 +                                      ['port_mac', 'port_ip']]},
903 +                        'network_type': 'vxlan',
904 +                        'segment_id': 1}}
905 +
906 +        with mock.patch.object(utils, 'execute',
907 +                               return_value='') as execute_fn:
908 +            self.lb_rpc.fdb_add(None, fdb_entries)
909 +
910 +            expected = [
911 +                mock.call(['bridge', 'fdb', 'show', 'dev', 'vxlan-1'],
912 +                          root_helper=self.root_helper),
913 +                mock.call(['bridge', 'fdb', 'add',
914 +                           constants.FLOODING_ENTRY[0],
915 +                           'dev', 'vxlan-1', 'dst', 'agent_ip'],
916 +                          root_helper=self.root_helper,
917 +                          check_exit_code=False),
918 +                mock.call(['ip', 'neigh', 'add', 'port_ip', 'lladdr',
919 +                           'port_mac', 'dev', 'vxlan-1', 'nud', 'permanent'],
920 +                          root_helper=self.root_helper,
921 +                          check_exit_code=False),
922 +                mock.call(['bridge', 'fdb', 'add', 'port_mac', 'dev',
923 +                           'vxlan-1', 'dst', 'agent_ip'],
924 +                          root_helper=self.root_helper,
925 +                          check_exit_code=False),
926 +            ]
927 +            execute_fn.assert_has_calls(expected)
928 +
929 +    def test_fdb_ignore(self):
930 +        fdb_entries = {'net_id':
931 +                       {'ports':
932 +                        {LOCAL_IP: [constants.FLOODING_ENTRY,
933 +                                    ['port_mac', 'port_ip']]},
934 +                        'network_type': 'vxlan',
935 +                        'segment_id': 1}}
936 +
937 +        with mock.patch.object(utils, 'execute',
938 +                               return_value='') as execute_fn:
939 +            self.lb_rpc.fdb_add(None, fdb_entries)
940 +            self.lb_rpc.fdb_remove(None, fdb_entries)
941 +
942 +            self.assertFalse(execute_fn.called)
943 +
944 +        fdb_entries = {'other_net_id':
945 +                       {'ports':
946 +                        {'192.168.0.67': [constants.FLOODING_ENTRY,
947 +                                          ['port_mac', 'port_ip']]},
948 +                        'network_type': 'vxlan',
949 +                        'segment_id': 1}}
950 +
951 +        with mock.patch.object(utils, 'execute',
952 +                               return_value='') as execute_fn:
953 +            self.lb_rpc.fdb_add(None, fdb_entries)
954 +            self.lb_rpc.fdb_remove(None, fdb_entries)
955 +
956 +            self.assertFalse(execute_fn.called)
957 +
958 +    def test_fdb_remove(self):
959 +        fdb_entries = {'net_id':
960 +                       {'ports':
961 +                        {'agent_ip': [constants.FLOODING_ENTRY,
962 +                                      ['port_mac', 'port_ip']]},
963 +                        'network_type': 'vxlan',
964 +                        'segment_id': 1}}
965 +
966 +        with mock.patch.object(utils, 'execute',
967 +                               return_value='') as execute_fn:
968 +            self.lb_rpc.fdb_remove(None, fdb_entries)
969 +
970 +            expected = [
971 +                mock.call(['bridge', 'fdb', 'del',
972 +                           constants.FLOODING_ENTRY[0],
973 +                           'dev', 'vxlan-1', 'dst', 'agent_ip'],
974 +                          root_helper=self.root_helper,
975 +                          check_exit_code=False),
976 +                mock.call(['ip', 'neigh', 'del', 'port_ip', 'lladdr',
977 +                           'port_mac', 'dev', 'vxlan-1'],
978 +                          root_helper=self.root_helper,
979 +                          check_exit_code=False),
980 +                mock.call(['bridge', 'fdb', 'del', 'port_mac',
981 +                           'dev', 'vxlan-1', 'dst', 'agent_ip'],
982 +                          root_helper=self.root_helper,
983 +                          check_exit_code=False),
984 +            ]
985 +            execute_fn.assert_has_calls(expected)
986 +
987 +    def test_fdb_update_chg_ip(self):
988 +        fdb_entries = {'chg_ip':
989 +                       {'net_id':
990 +                        {'agent_ip':
991 +                         {'before': [['port_mac', 'port_ip_1']],
992 +                          'after': [['port_mac', 'port_ip_2']]}}}}
993 +
994 +        with mock.patch.object(utils, 'execute',
995 +                               return_value='') as execute_fn:
996 +            self.lb_rpc.fdb_update(None, fdb_entries)
997 +
998 +            expected = [
999 +                mock.call(['ip', 'neigh', 'add', 'port_ip_2', 'lladdr',
1000 +                           'port_mac', 'dev', 'vxlan-1', 'nud', 'permanent'],
1001 +                          root_helper=self.root_helper,
1002 +                          check_exit_code=False),
1003 +                mock.call(['ip', 'neigh', 'del', 'port_ip_1', 'lladdr',
1004 +                           'port_mac', 'dev', 'vxlan-1'],
1005 +                          root_helper=self.root_helper,
1006 +                          check_exit_code=False)
1007 +            ]
1008 +            execute_fn.assert_has_calls(expected)