ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
if csnat_ofport != constants.OFPORT_INVALID:
ofports = str(csnat_ofport) + ',' + ofports
+ ip_version = subnet_info['ip_version']
if ofports:
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- "output:%s" %
- (subnet_info['gateway_mac'], ofports))
-
- self.tun_br.add_flow(table=constants.DVR_PROCESS,
- priority=3,
- dl_vlan=local_vlan,
- proto='arp',
- nw_dst=subnet_info['gateway_ip'],
- actions="drop")
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
+
+ args = {'table': constants.DVR_PROCESS,
+ 'priority': 3,
+ 'dl_vlan': local_vlan,
+ 'actions': "drop"}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+ self.tun_br.add_flow(**args)
self.tun_br.add_flow(table=constants.DVR_PROCESS,
priority=2,
dl_vlan=local_vlan,
if csnat_ofport != constants.OFPORT_INVALID:
ofports = str(csnat_ofport) + ',' + ofports
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'], ofports))
+ ip_version = subnet_info['ip_version']
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
def _bind_centralized_snat_port_on_dvr_subnet(self, port, fixed_ips,
device_owner, local_vlan):
ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
ofports = str(ldm.get_csnat_ofport()) + ',' + ofports
ip_subnet = subnet_info['cidr']
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'], ofports))
+
+ # TODO(xuhanp) remove the IPv6 related add_flow once SNAT is not
+ # used for IPv6 DVR.
+ ip_version = subnet_info['ip_version']
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC, local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
def bind_port_to_dvr(self, port, network_type, fixed_ips,
device_owner, local_vlan_id):
dl_vlan=local_vlan,
dl_dst=ovsport.get_mac())
ldm.remove_all_compute_ofports()
-
+ ip_version = subnet_info['ip_version']
if ldm.get_csnat_ofport() != -1:
# If there is a csnat port on this agent, preserve
# the local_dvr_map state
ofports = str(ldm.get_csnat_ofport())
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'], ofports))
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
+
else:
# removed port is a distributed router interface
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- proto='ip', dl_vlan=local_vlan,
- nw_dst=ip_subnet)
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet, None, None)
+ self.int_br.delete_flows(**args)
# remove subnet from local_dvr_map as no dvr (or) csnat
# ports available on this agent anymore
self.local_dvr_map.pop(sub_uuid, None)
- self.tun_br.delete_flows(table=constants.DVR_PROCESS,
- dl_vlan=local_vlan,
- proto='arp',
- nw_dst=subnet_info['gateway_ip'])
+ args = {'table': constants.DVR_PROCESS,
+ 'dl_vlan': local_vlan}
+ if ip_version == 4:
+ args['proto'] = 'arp'
+ args['nw_dst'] = subnet_info['gateway_ip']
+ else:
+ args['proto'] = 'icmp6'
+ args['icmp_type'] = n_const.ICMPV6_TYPE_RA
+ args['dl_src'] = subnet_info['gateway_mac']
+
+ self.tun_br.delete_flows(**args)
ovsport.remove_subnet(sub_uuid)
self.tun_br.delete_flows(table=constants.DVR_PROCESS,
ldm.remove_compute_ofport(port.vif_id)
ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
ip_subnet = subnet_info['cidr']
-
+ ip_version = subnet_info['ip_version']
# first remove this vm port rule
self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
dl_vlan=local_vlan,
# If there is a csnat port on this agent, preserve
# the local_dvr_map state
ofports = str(ldm.get_csnat_ofport()) + ',' + ofports
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'], ofports))
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
else:
if ofports:
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'],
- ofports))
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
else:
# remove the flow altogether, as no ports (both csnat/
# compute) are available on this subnet in this
# agent
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet)
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet, None, None)
+ self.int_br.delete_flows(**args)
+
# release port state
self.local_ports.pop(port.vif_id, None)
self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
dl_vlan=local_vlan,
dl_dst=ovsport.get_mac())
-
ofports = ','.join(map(str, ldm.get_compute_ofports().values()))
+ ip_version = subnet_info['ip_version']
if ofports:
- self.int_br.add_flow(table=constants.DVR_TO_SRC_MAC,
- priority=2,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet,
- actions="strip_vlan,mod_dl_src:%s,"
- " output:%s" %
- (subnet_info['gateway_mac'], ofports))
+ # TODO(xuhanp) remove the IPv6 related add_flow once SNAT is not
+ # used for IPv6 DVR.
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet,
+ 2, ("strip_vlan,mod_dl_src:%s,output:%s" %
+ (subnet_info['gateway_mac'], ofports)))
+ self.int_br.add_flow(**args)
else:
- self.int_br.delete_flows(table=constants.DVR_TO_SRC_MAC,
- proto='ip',
- dl_vlan=local_vlan,
- nw_dst=ip_subnet)
+ args = self._get_flow_args_by_version(
+ ip_version, constants.DVR_TO_SRC_MAC,
+ local_vlan, ip_subnet, None, None)
+ self.int_br.delete_flows(**args)
+
if not ldm.is_dvr_owned():
# if not owned by DVR (only used for csnat), remove this
# subnet state altogether
# release port state
self.local_ports.pop(port.vif_id, None)
+ def _get_flow_args_by_version(self, ip_version, table,
+ vlan, subnet, priority, actions):
+ """
+ Get flow args for DVR by IP version.
+ priority and actions are optional to support both add_flows
+ and delete_flows
+ """
+ args = {'table': table,
+ 'dl_vlan': vlan}
+ if ip_version == 4:
+ args['proto'] = 'ip'
+ args['nw_dst'] = subnet
+ else:
+ args['proto'] = 'ipv6'
+ args['ipv6_dst'] = subnet
+ if priority:
+ args['priority'] = priority
+ if actions:
+ args['actions'] = actions
+ return args
+
def unbind_port_from_dvr(self, vif_port, local_vlan_id):
if not self.in_distributed_mode():
return
self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
return_value={'gateway_ip': '1.1.1.1',
'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',
self.assertTrue(add_flow_tun_fn.called)
self.assertTrue(delete_flows_int_fn.called)
- def _test_port_bound_for_dvr(self, device_owner):
+ def _test_port_bound_for_dvr(self, device_owner, ip_version=4):
self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
'set_db_attribute',
return_value=True):
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_subnet_for_dvr',
return_value={
- 'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
+ 'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',
None, None, self._fixed_ips,
n_const.DEVICE_OWNER_DVR_INTERFACE,
False)
+ expected = [
+ mock.call(
+ table=constants.TUN_TABLE['vxlan'],
+ priority=1, tun_id=None,
+ actions="mod_vlan_vid:%s,"
+ "resubmit(,%s)" %
+ (self.agent.local_vlan_map[self._net_uuid].vlan,
+ constants.DVR_NOT_LEARN)),
+ mock.call(
+ table=constants.DVR_PROCESS, priority=2,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ dl_dst=self._port.vif_mac,
+ actions='drop'),
+ mock.call(
+ table=constants.DVR_PROCESS, priority=1,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ dl_src=self._port.vif_mac,
+ actions="mod_dl_src:%s,resubmit(,%s)" % (
+ self.agent.dvr_agent.dvr_mac_address,
+ constants.PATCH_LV_TO_TUN))]
+ if ip_version == 4:
+ expected.insert(1, mock.call(
+ proto='arp',
+ nw_dst=gateway_ip, actions='drop',
+ priority=3, table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan)))
+ else:
+ expected.insert(1, mock.call(
+ icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
+ dl_src='aa:bb:cc:11:22:33', actions='drop',
+ priority=3, table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan)))
+
+ self.assertEqual(expected, add_flow_tun_fn.call_args_list)
self.agent.port_bound(self._compute_port, self._net_uuid,
'vxlan', None, None,
self._compute_fixed_ips,
device_owner, False)
- self.assertTrue(add_flow_tun_fn.called)
- self.assertTrue(add_flow_int_fn.called)
+ expected = [
+ mock.call(table=constants.DVR_TO_SRC_MAC, priority=4,
+ dl_dst=self._compute_port.vif_mac,
+ dl_vlan=self.agent.local_vlan_map[self._net_uuid].vlan,
+ actions="strip_vlan,mod_dl_src:%s,"
+ "output:%s" %
+ ('aa:bb:cc:11:22:33', self._compute_port.ofport))
+ ]
+ if ip_version == 4:
+ expected.append(mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ priority=2, proto='ip',
+ nw_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ actions="strip_vlan,mod_dl_src:%s,"
+ "output:%s" %
+ ('aa:bb:cc:11:22:33', self._compute_port.ofport)))
+ else:
+ expected.append(mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ priority=2, proto='ipv6',
+ ipv6_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ actions="strip_vlan,mod_dl_src:%s,"
+ "output:%s" %
+ ('aa:bb:cc:11:22:33', self._compute_port.ofport)))
+ self.assertEqual(expected, add_flow_int_fn.call_args_list)
self.assertTrue(delete_flows_int_fn.called)
def test_port_bound_for_dvr_with_compute_ports(self):
- self._test_port_bound_for_dvr(device_owner="compute:None")
+ self._test_port_bound_for_dvr(
+ device_owner="compute:None")
+ self._test_port_bound_for_dvr(
+ device_owner="compute:None", ip_version=6)
def test_port_bound_for_dvr_with_lbaas_vip_ports(self):
self._test_port_bound_for_dvr(
device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
+ self._test_port_bound_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
def test_port_bound_for_dvr_with_dhcp_ports(self):
self._test_port_bound_for_dvr(
device_owner=n_const.DEVICE_OWNER_DHCP)
+ self._test_port_bound_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
def test_port_bound_for_dvr_with_csnat_ports(self, ofport=10):
self._setup_for_dvr_test()
self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
return_value={'gateway_ip': '1.1.1.1',
'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',
self.assertTrue(delete_flows_int_fn.called)
def test_treat_devices_removed_for_dvr_interface(self, ofport=10):
+ self._test_treat_devices_removed_for_dvr_interface(ofport)
+ self._test_treat_devices_removed_for_dvr_interface(
+ ofport, ip_version=6)
+
+ def _test_treat_devices_removed_for_dvr_interface(self, ofport=10,
+ ip_version=4):
self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
'set_db_attribute',
return_value=True):
return_value=str(self._old_local_vlan)),
mock.patch.object(
self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',
delete_flows_int_fn,
delete_flows_tun_fn):
self.agent.treat_devices_removed([self._port.vif_id])
- self.assertTrue(delete_flows_int_fn.called)
- self.assertTrue(delete_flows_tun_fn.called)
-
- def _test_treat_devices_removed_for_dvr(self, device_owner):
+ if ip_version == 4:
+ expected = [mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ nw_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ proto='ip')]
+ else:
+ expected = [mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ ipv6_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ proto='ipv6')]
+ self.assertEqual(expected,
+ delete_flows_int_fn.call_args_list)
+ if ip_version == 4:
+ expected = [mock.call(
+ proto='arp',
+ nw_dst=gateway_ip,
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ else:
+ expected = [mock.call(
+ icmp_type=n_const.ICMPV6_TYPE_RA, proto='icmp6',
+ dl_src='aa:bb:cc:11:22:33',
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ expected.extend([
+ mock.call(
+ table=constants.DVR_PROCESS,
+ dl_dst=self._port.vif_mac,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan)),
+ mock.call(
+ table=constants.DVR_PROCESS,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan),
+ dl_src=self._port.vif_mac)
+ ])
+ self.assertEqual(expected, delete_flows_tun_fn.call_args_list)
+
+ def _test_treat_devices_removed_for_dvr(self, device_owner, ip_version=4):
self._setup_for_dvr_test()
+ if ip_version == 4:
+ gateway_ip = '1.1.1.1'
+ cidr = '1.1.1.0/24'
+ else:
+ gateway_ip = '2001:100::1'
+ cidr = '2001:100::0/64'
with mock.patch('neutron.agent.linux.ovs_lib.OVSBridge.'
'set_db_attribute',
return_value=True):
return_value=str(self._old_local_vlan)),
mock.patch.object(
self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
- return_value={'gateway_ip': '1.1.1.1',
- 'cidr': '1.1.1.0/24',
+ return_value={'gateway_ip': gateway_ip,
+ 'cidr': cidr,
+ 'ip_version': ip_version,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',
update_dev_down_fn,
delete_flows_int_fn):
self.agent.treat_devices_removed([self._compute_port.vif_id])
- self.assertTrue(delete_flows_int_fn.called)
+ expected = [
+ mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ dl_dst=self._compute_port.vif_mac,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))]
+ if ip_version == 4:
+ expected.append(mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ proto='ip', nw_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))
+ )
+ else:
+ expected.append(mock.call(
+ table=constants.DVR_TO_SRC_MAC,
+ proto='ipv6', ipv6_dst=cidr,
+ dl_vlan=(
+ self.agent.local_vlan_map[self._net_uuid].vlan))
+ )
+ self.assertEqual(expected, delete_flows_int_fn.call_args_list)
def test_treat_devices_removed_for_dvr_with_compute_ports(self):
- self._test_treat_devices_removed_for_dvr(device_owner="compute:None")
+ self._test_treat_devices_removed_for_dvr(
+ device_owner="compute:None")
+ self._test_treat_devices_removed_for_dvr(
+ device_owner="compute:None", ip_version=6)
def test_treat_devices_removed_for_dvr_with_lbaas_vip_ports(self):
self._test_treat_devices_removed_for_dvr(
device_owner=n_const.DEVICE_OWNER_LOADBALANCER)
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_LOADBALANCER, ip_version=6)
def test_treat_devices_removed_for_dvr_with_dhcp_ports(self):
self._test_treat_devices_removed_for_dvr(
device_owner=n_const.DEVICE_OWNER_DHCP)
+ self._test_treat_devices_removed_for_dvr(
+ device_owner=n_const.DEVICE_OWNER_DHCP, ip_version=6)
def test_treat_devices_removed_for_dvr_csnat_port(self, ofport=10):
self._setup_for_dvr_test()
self.agent.dvr_agent.plugin_rpc, 'get_subnet_for_dvr',
return_value={'gateway_ip': '1.1.1.1',
'cidr': '1.1.1.0/24',
+ 'ip_version': 4,
'gateway_mac': 'aa:bb:cc:11:22:33'}),
mock.patch.object(self.agent.dvr_agent.plugin_rpc,
'get_ports_on_host_by_subnet',