1 # Copyright (C) 2014,2015 VA Linux Systems Japan K.K.
2 # Copyright (C) 2014,2015 YAMAMOTO Takashi <yamamoto at valinux co jp>
5 # Licensed under the Apache License, Version 2.0 (the "License"); you may
6 # not use this file except in compliance with the License. You may obtain
7 # a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 # License for the specific language governing permissions and limitations
20 import neutron.plugins.ml2.drivers.openvswitch.agent.common.constants \
22 from neutron.tests.unit.plugins.ml2.drivers.openvswitch.agent.\
23 openflow.ovs_ofctl import ovs_bridge_test_base
26 call = mock.call # short hand
29 class OVSTunnelBridgeTest(ovs_bridge_test_base.OVSBridgeTestBase,
30 ovs_bridge_test_base.OVSDVRProcessTestMixin):
31 dvr_process_table_id = ovs_const.DVR_PROCESS
32 dvr_process_next_table_id = ovs_const.PATCH_LV_TO_TUN
35 super(OVSTunnelBridgeTest, self).setUp()
36 self.setup_bridge_mock('br-tun', self.br_tun_cls)
38 def test_setup_default_table(self):
39 patch_int_ofport = 5555
40 mock_do_action_flows = mock.patch.object(self.br,
41 'do_action_flows').start()
42 self.mock.attach_mock(mock_do_action_flows, 'do_action_flows')
43 self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
44 arp_responder_enabled=False)
45 flow_args = [{'priority': 1, 'in_port': patch_int_ofport,
46 'actions': 'resubmit(,2)'},
47 {'priority': 0, 'actions': 'drop'},
48 {'priority': 0, 'table': 2,
49 'dl_dst': '00:00:00:00:00:00/01:00:00:00:00:00',
50 'actions': 'resubmit(,20)'},
51 {'priority': 0, 'table': 2,
52 'dl_dst': '01:00:00:00:00:00/01:00:00:00:00:00',
53 'actions': 'resubmit(,22)'},
54 {'priority': 0, 'table': 3, 'actions': 'drop'},
55 {'priority': 0, 'table': 4, 'actions': 'drop'},
56 {'priority': 0, 'table': 6, 'actions': 'drop'},
57 {'priority': 1, 'table': 10,
58 'actions': 'learn(cookie=0,table=20,priority=1,'
59 'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
60 'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
61 'load:0->NXM_OF_VLAN_TCI[],'
62 'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
63 'output:NXM_OF_IN_PORT[]),'
64 'output:%s' % patch_int_ofport},
65 {'priority': 0, 'table': 20, 'actions': 'resubmit(,22)'}
67 expected = [call.do_action_flows('add', flow_args),
68 call.add_flow(priority=0, table=22, actions='drop')]
69 self.assertEqual(expected, self.mock.mock_calls)
71 def test_setup_default_table_arp_responder_enabled(self):
72 patch_int_ofport = 5555
73 mock_do_action_flows = mock.patch.object(self.br,
74 'do_action_flows').start()
75 self.mock.attach_mock(mock_do_action_flows, 'do_action_flows')
76 self.br.setup_default_table(patch_int_ofport=patch_int_ofport,
77 arp_responder_enabled=True)
78 flow_args = [{'priority': 1, 'in_port': patch_int_ofport,
79 'actions': 'resubmit(,2)'},
80 {'priority': 0, 'actions': 'drop'},
81 {'priority': 1, 'table': 2, 'dl_dst': 'ff:ff:ff:ff:ff:ff',
82 'actions': 'resubmit(,21)', 'proto': 'arp'},
83 {'priority': 0, 'table': 2,
84 'dl_dst': '00:00:00:00:00:00/01:00:00:00:00:00',
85 'actions': 'resubmit(,20)'},
86 {'priority': 0, 'table': 2,
87 'dl_dst': '01:00:00:00:00:00/01:00:00:00:00:00',
88 'actions': 'resubmit(,22)'},
89 {'priority': 0, 'table': 3, 'actions': 'drop'},
90 {'priority': 0, 'table': 4, 'actions': 'drop'},
91 {'priority': 0, 'table': 6, 'actions': 'drop'},
92 {'priority': 1, 'table': 10,
93 'actions': 'learn(cookie=0,table=20,priority=1,'
94 'hard_timeout=300,NXM_OF_VLAN_TCI[0..11],'
95 'NXM_OF_ETH_DST[]=NXM_OF_ETH_SRC[],'
96 'load:0->NXM_OF_VLAN_TCI[],'
97 'load:NXM_NX_TUN_ID[]->NXM_NX_TUN_ID[],'
98 'output:NXM_OF_IN_PORT[]),'
99 'output:%s' % patch_int_ofport},
100 {'priority': 0, 'table': 20, 'actions': 'resubmit(,22)'},
101 {'priority': 0, 'table': 21, 'actions': 'resubmit(,22)'}
103 expected = [call.do_action_flows('add', flow_args),
104 call.add_flow(priority=0, table=22, actions='drop')]
105 self.assertEqual(expected, self.mock.mock_calls)
107 def test_provision_local_vlan(self):
108 network_type = 'vxlan'
110 segmentation_id = 777
112 self.br.provision_local_vlan(network_type=network_type, lvid=lvid,
113 segmentation_id=segmentation_id,
114 distributed=distributed)
116 call.add_flow(priority=1, tun_id=segmentation_id,
117 actions='mod_vlan_vid:%s,resubmit(,10)' % lvid,
120 self.assertEqual(expected, self.mock.mock_calls)
122 def test_reclaim_local_vlan(self):
123 network_type = 'vxlan'
124 segmentation_id = 777
125 self.br.reclaim_local_vlan(network_type=network_type,
126 segmentation_id=segmentation_id)
128 call.delete_flows(tun_id=segmentation_id, table=4),
130 self.assertEqual(expected, self.mock.mock_calls)
132 def test_install_flood_to_tun(self):
135 ports = [11, 44, 22, 33]
136 self.br.install_flood_to_tun(vlan=vlan,
140 call.mod_flow(table=22, dl_vlan=vlan,
141 actions='strip_vlan,set_tunnel:%(tun)s,'
142 'output:%(ports)s' % {
144 'ports': ','.join(map(str, ports)),
147 self.assertEqual(expected, self.mock.mock_calls)
149 def test_delete_flood_to_tun(self):
151 self.br.delete_flood_to_tun(vlan=vlan)
153 call.delete_flows(table=22, dl_vlan=vlan),
155 self.assertEqual(expected, self.mock.mock_calls)
157 def test_install_unicast_to_tun(self):
160 mac = '08:60:6e:7f:74:e7'
162 self.br.install_unicast_to_tun(vlan=vlan,
167 call.add_flow(priority=2, table=20, dl_dst=mac, dl_vlan=vlan,
168 actions='strip_vlan,set_tunnel:%(tun)s,'
169 'output:%(port)s' % {
174 self.assertEqual(expected, self.mock.mock_calls)
176 def test_delete_unicast_to_tun(self):
178 mac = '08:60:6e:7f:74:e7'
179 self.br.delete_unicast_to_tun(vlan=vlan, mac=mac)
181 call.delete_flows(table=20, dl_dst=mac, dl_vlan=vlan),
183 self.assertEqual(expected, self.mock.mock_calls)
185 def test_delete_unicast_to_tun_without_mac(self):
188 self.br.delete_unicast_to_tun(vlan=vlan, mac=mac)
190 call.delete_flows(table=20, dl_vlan=vlan),
192 self.assertEqual(expected, self.mock.mock_calls)
194 def test_install_arp_responder(self):
197 mac = '08:60:6e:7f:74:e7'
198 self.br.install_arp_responder(vlan=vlan, ip=ip, mac=mac)
200 call.add_flow(proto='arp', nw_dst=ip,
201 actions='move:NXM_OF_ETH_SRC[]->NXM_OF_ETH_DST[],'
202 'mod_dl_src:%(mac)s,load:0x2->NXM_OF_ARP_OP[],'
203 'move:NXM_NX_ARP_SHA[]->NXM_NX_ARP_THA[],'
204 'move:NXM_OF_ARP_SPA[]->NXM_OF_ARP_TPA[],'
205 'load:%(mac)#x->NXM_NX_ARP_SHA[],'
206 'load:%(ip)#x->NXM_OF_ARP_SPA[],in_port' % {
207 'mac': netaddr.EUI(mac,
208 dialect=netaddr.mac_unix),
209 'ip': netaddr.IPAddress(ip),
211 priority=1, table=21, dl_vlan=vlan),
213 self.assertEqual(expected, self.mock.mock_calls)
215 def test_delete_arp_responder(self):
218 self.br.delete_arp_responder(vlan=vlan, ip=ip)
220 call.delete_flows(table=21, dl_vlan=vlan, proto='arp', nw_dst=ip),
222 self.assertEqual(expected, self.mock.mock_calls)
224 def test_delete_arp_responder_without_ip(self):
227 self.br.delete_arp_responder(vlan=vlan, ip=ip)
229 call.delete_flows(table=21, dl_vlan=vlan, proto='arp'),
231 self.assertEqual(expected, self.mock.mock_calls)
233 def test_setup_tunnel_port(self):
234 network_type = 'vxlan'
236 self.br.setup_tunnel_port(network_type=network_type, port=port)
238 call.add_flow(priority=1, in_port=port, actions='resubmit(,4)'),
240 self.assertEqual(expected, self.mock.mock_calls)
242 def test_cleanup_tunnel_port(self):
244 self.br.cleanup_tunnel_port(port=port)
246 call.delete_flows(in_port=port),
248 self.assertEqual(expected, self.mock.mock_calls)
250 def test_add_dvr_mac_tun(self):
251 mac = '00:02:b3:13:fe:3d'
253 self.br.add_dvr_mac_tun(mac=mac, port=port)
255 call.add_flow(priority=1, table=9, dl_src=mac,
256 actions='output:%s' % port),
258 self.assertEqual(expected, self.mock.mock_calls)
260 def test_remove_dvr_mac_tun(self):
261 mac = '00:02:b3:13:fe:3d'
262 self.br.remove_dvr_mac_tun(mac=mac)
264 call.delete_flows(eth_src=mac, table_id=9),
266 self.assertEqual(expected, self.mock.mock_calls)
268 def _mock_add_tunnel_port(self, deferred_br=False):
269 port_name = 'fake_port'
270 remote_ip = '192.168.1.3'
271 local_ip = '192.168.1.2'
272 tunnel_type = 'vxlan'
273 vxlan_udp_port = '4789'
276 with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.add_port',
277 return_value=9999) as add_port, \
278 self.br.deferred() as deferred_br:
279 ofport = deferred_br.add_tunnel_port(port_name, remote_ip,
280 local_ip, tunnel_type,
284 with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.add_port',
285 return_value=9999) as add_port:
286 ofport = self.br.add_tunnel_port(port_name, remote_ip,
287 local_ip, tunnel_type,
290 self.assertEqual(9999, ofport)
291 self.assertEqual(1, add_port.call_count)
292 self.assertEqual(port_name, add_port.call_args[0][0])
294 def _mock_delete_port(self, deferred_br=False):
295 port_name = 'fake_port'
297 with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
298 'delete_port') as delete_port, \
299 self.br.deferred() as deferred_br:
300 deferred_br.delete_port(port_name)
302 with mock.patch('neutron.agent.common.ovs_lib.OVSBridge.'
303 'delete_port') as delete_port:
304 self.br.delete_port(port_name)
305 self.assertEqual([call(port_name)], delete_port.mock_calls)
307 def test_add_tunnel_port(self):
308 self._mock_add_tunnel_port()
310 def test_delete_port(self):
311 self._mock_delete_port()
313 def test_deferred_br_add_tunnel_port(self):
314 self._mock_add_tunnel_port(True)
316 def test_deferred_br_delete_port(self):
317 self._mock_delete_port(True)