def _add_arp_protection(self, machine, addresses, extra_port_dict=None): port_dict = {'fixed_ips': [{'ip_address': a} for a in addresses]} if extra_port_dict: port_dict.update(extra_port_dict) name = net_helpers.VethFixture.get_peer_name(machine.port.name) arp_protect.setup_arp_spoofing_protection(name, port_dict) self.addCleanup(arp_protect.delete_arp_spoofing_protection, [name])
def treat_devices_added_updated(self, devices): try: devices_details_list = self.plugin_rpc.get_devices_details_list( self.context, devices, self.agent_id) except Exception as e: LOG.debug("Unable to get port details for " "%(devices)s: %(e)s", {'devices': devices, 'e': e}) # resync is needed return True for device_details in devices_details_list: device = device_details['device'] LOG.debug("Port %s added", device) if 'port_id' in device_details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), {'device': device, 'details': device_details}) if self.prevent_arp_spoofing: port = self.br_mgr.get_tap_device_name( device_details['port_id']) arp_protect.setup_arp_spoofing_protection(port, device_details) if device_details['admin_state_up']: # create the networking for the port network_type = device_details.get('network_type') if network_type: segmentation_id = device_details.get('segmentation_id') else: # compatibility with pre-Havana RPC vlan_id encoding vlan_id = device_details.get('vlan_id') (network_type, segmentation_id) = lconst.interpret_vlan_id(vlan_id) if self.br_mgr.add_interface( device_details['network_id'], network_type, device_details['physical_network'], segmentation_id, device_details['port_id']): # update plugin about port status self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) else: self.remove_port_binding(device_details['network_id'], device_details['port_id']) else: LOG.info(_LI("Device %s not defined on plugin"), device) return False
def treat_devices_added_updated(self, devices): try: devices_details_list = self.plugin_rpc.get_devices_details_list( self.context, devices, self.agent_id) except Exception as e: LOG.debug("Unable to get port details for " "%(devices)s: %(e)s", {'devices': devices, 'e': e}) # resync is needed return True for device_details in devices_details_list: device = device_details['device'] LOG.debug("Port %s added", device) if 'port_id' in device_details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), {'device': device, 'details': device_details}) if self.prevent_arp_spoofing: port = self.br_mgr.get_tap_device_name( device_details['port_id']) arp_protect.setup_arp_spoofing_protection(port, device_details) if device_details['admin_state_up']: # create the networking for the port network_type = device_details.get('network_type') if network_type: segmentation_id = device_details.get('segmentation_id') else: # compatibility with pre-Havana RPC vlan_id encoding vlan_id = device_details.get('vlan_id') (network_type, segmentation_id) = lconst.interpret_vlan_id(vlan_id) if self.br_mgr.add_interface( device_details['network_id'], network_type, device_details['physical_network'], segmentation_id, device_details['port_id']): # update plugin about port status self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) else: self.remove_port_binding(device_details['network_id'], device_details['port_id']) else: LOG.info(_LI("Device %s not defined on plugin"), device) return False
def _add_arp_protection(self, machine, addresses, extra_port_dict=None): port_dict = { "fixed_ips": [{"ip_address": a} for a in addresses], "device_owner": "nobody", "mac_address": machine.port.link.address, } if extra_port_dict: port_dict.update(extra_port_dict) name = net_helpers.VethFixture.get_peer_name(machine.port.name) arp_protect.setup_arp_spoofing_protection(name, port_dict) self.addCleanup(arp_protect.delete_arp_spoofing_protection, [name])
def treat_devices_added_updated(self, devices): try: devices_details_list = self.plugin_rpc.get_devices_details_list(self.context, devices, self.agent_id) except Exception: LOG.exception(_LE("Unable to get port details for %s"), devices) # resync is needed return True for device_details in devices_details_list: device = device_details["device"] LOG.debug("Port %s added", device) if "port_id" in device_details: LOG.info( _LI("Port %(device)s updated. Details: %(details)s"), {"device": device, "details": device_details} ) if self.prevent_arp_spoofing: port = self.br_mgr.get_tap_device_name(device_details["port_id"]) arp_protect.setup_arp_spoofing_protection(port, device_details) if device_details["admin_state_up"]: # create the networking for the port network_type = device_details.get("network_type") segmentation_id = device_details.get("segmentation_id") if self.br_mgr.add_interface( device_details["network_id"], network_type, device_details["physical_network"], segmentation_id, device_details["port_id"], ): # update plugin about port status self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) else: physical_network = device_details["physical_network"] self.remove_port_binding(device_details["network_id"], physical_network, device_details["port_id"]) else: LOG.info(_LI("Device %s not defined on plugin"), device) return False
def setup_arp_spoofing_protection(self, device, device_details): arp_protect.setup_arp_spoofing_protection(device, device_details)
def setup_arp_spoofing_protection(self, device, device_details): arp_protect.setup_arp_spoofing_protection(device, device_details)
def treat_devices_added_updated(self, devices): try: devices_details_list = self.plugin_rpc.get_devices_details_list( self.context, devices, self.agent_id) except Exception: LOG.exception(_LE("Unable to get port details for %s"), devices) # resync is needed return True for device_details in devices_details_list: device = device_details['device'] LOG.debug("Port %s added", device) if 'port_id' in device_details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), { 'device': device, 'details': device_details }) if self.prevent_arp_spoofing: port = self.br_mgr.get_tap_device_name( device_details['port_id']) arp_protect.setup_arp_spoofing_protection( port, device_details) # create the networking for the port network_type = device_details.get('network_type') segmentation_id = device_details.get('segmentation_id') tap_in_bridge = self.br_mgr.add_interface( device_details['network_id'], network_type, device_details['physical_network'], segmentation_id, device_details['port_id'], device_details['device_owner']) # REVISIT(scheuran): Changed the way how ports admin_state_up # is implemented. # # Old lb implementation: # - admin_state_up: ensure that tap is plugged into bridge # - admin_state_down: remove tap from bridge # New lb implementation: # - admin_state_up: set tap device state to up # - admin_state_down: set tap device stae to down # # However both approaches could result in races with # nova/libvirt and therefore to an invalid system state in the # scenario, where an instance is booted with a port configured # with admin_state_up = False: # # Libvirt does the following actions in exactly # this order (see libvirt virnetdevtap.c) # 1) Create the tap device, set its MAC and MTU # 2) Plug the tap into the bridge # 3) Set the tap online # # Old lb implementation: # A race could occur, if the lb agent removes the tap device # right after step 1). Then libvirt will add it to the bridge # again in step 2). # New lb implementation: # The race could occur if the lb-agent sets the taps device # state to down right after step 2). In step 3) libvirt # might set it to up again. # # This is not an issue if an instance is booted with a port # configured with admin_state_up = True. Libvirt would just # set the tap device up again. # # This refactoring is recommended for the following reasons: # 1) An existing race with libvirt caused by the behavior of # the old implementation. See Bug #1312016 # 2) The new code is much more readable self._ensure_port_admin_state(device_details['port_id'], device_details['admin_state_up']) # update plugin about port status if admin_state is up if device_details['admin_state_up']: if tap_in_bridge: self.plugin_rpc.update_device_up( self.context, device, self.agent_id, cfg.CONF.host) else: self.plugin_rpc.update_device_down( self.context, device, self.agent_id, cfg.CONF.host) else: LOG.info(_LI("Device %s not defined on plugin"), device) return False
def _test_port_add_arp_spoofing(self, vif, port): mac_addresses = {port['mac_address']} ip_addresses = {p['ip_address'] for p in port['fixed_ips']} if port.get('allowed_address_pairs'): mac_addresses |= {p['mac_address'] for p in port['allowed_address_pairs']} ip_addresses |= {p['ip_address'] for p in port['allowed_address_pairs']} spoof_chain = arp_protect.SPOOF_CHAIN_PREFIX + vif mac_chain = arp_protect.MAC_CHAIN_PREFIX + vif expected = [ mock.call(['ebtables', '-t', 'nat', '--concurrent', '-L'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.ANY, mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N', 'neutronMAC-%s' % vif, '-P', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', 'neutronMAC-%s' % vif, '-j', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I', 'PREROUTING', '-i', vif, '-j', mac_chain], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I', mac_chain, '-i', vif, '--among-src', '%s' % ','.join(sorted(mac_addresses)), '-j', 'RETURN'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N', spoof_chain, '-P', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', spoof_chain, '-j', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True) ] for addr in sorted(ip_addresses): expected.extend([ mock.call(['ebtables', '-t', 'nat', '--concurrent', '-I', spoof_chain, '-p', 'ARP', '--arp-ip-src', addr, '-j', 'ACCEPT'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), ]) expected.extend([ mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', 'PREROUTING', '-i', vif, '-j', spoof_chain, '-p', 'ARP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True, privsep_exec=True), ]) arp_protect.setup_arp_spoofing_protection(vif, port) self.execute.assert_has_calls(expected)
def test_port_trusted(self, dasp): arp_protect.setup_arp_spoofing_protection(VIF, PORT_TRUSTED) dasp.assert_called_with([VIF])
def test_port_no_security(self, dasp): arp_protect.setup_arp_spoofing_protection(VIF, PORT_NO_SEC) dasp.assert_called_with([VIF])
def treat_devices_added_updated(self, devices): try: devices_details_list = self.plugin_rpc.get_devices_details_list( self.context, devices, self.agent_id) except Exception: LOG.exception(_LE("Unable to get port details for %s"), devices) # resync is needed return True for device_details in devices_details_list: device = device_details['device'] LOG.debug("Port %s added", device) if 'port_id' in device_details: LOG.info(_LI("Port %(device)s updated. Details: %(details)s"), {'device': device, 'details': device_details}) if self.prevent_arp_spoofing: port = self.br_mgr.get_tap_device_name( device_details['port_id']) arp_protect.setup_arp_spoofing_protection(port, device_details) # create the networking for the port network_type = device_details.get('network_type') segmentation_id = device_details.get('segmentation_id') tap_in_bridge = self.br_mgr.add_interface( device_details['network_id'], network_type, device_details['physical_network'], segmentation_id, device_details['port_id'], device_details['device_owner']) # REVISIT(scheuran): Changed the way how ports admin_state_up # is implemented. # # Old lb implementation: # - admin_state_up: ensure that tap is plugged into bridge # - admin_state_down: remove tap from bridge # New lb implementation: # - admin_state_up: set tap device state to up # - admin_state_down: set tap device stae to down # # However both approaches could result in races with # nova/libvirt and therefore to an invalid system state in the # scenario, where an instance is booted with a port configured # with admin_state_up = False: # # Libvirt does the following actions in exactly # this order (see libvirt virnetdevtap.c) # 1) Create the tap device, set its MAC and MTU # 2) Plug the tap into the bridge # 3) Set the tap online # # Old lb implementation: # A race could occur, if the lb agent removes the tap device # right after step 1). Then libvirt will add it to the bridge # again in step 2). # New lb implementation: # The race could occur if the lb-agent sets the taps device # state to down right after step 2). In step 3) libvirt # might set it to up again. # # This is not an issue if an instance is booted with a port # configured with admin_state_up = True. Libvirt would just # set the tap device up again. # # This refactoring is recommended for the following reasons: # 1) An existing race with libvirt caused by the behavior of # the old implementation. See Bug #1312016 # 2) The new code is much more readable self._ensure_port_admin_state(device_details['port_id'], device_details['admin_state_up']) # update plugin about port status if admin_state is up if device_details['admin_state_up']: if tap_in_bridge: self.plugin_rpc.update_device_up(self.context, device, self.agent_id, cfg.CONF.host) else: self.plugin_rpc.update_device_down(self.context, device, self.agent_id, cfg.CONF.host) else: LOG.info(_LI("Device %s not defined on plugin"), device) return False
def _test_port_add_arp_spoofing(self, vif, port): mac_addresses = {port['mac_address']} ip_addresses = {p['ip_address'] for p in port['fixed_ips']} if port.get('allowed_address_pairs'): mac_addresses |= {p['mac_address'] for p in port['allowed_address_pairs']} ip_addresses |= {p['ip_address'] for p in port['allowed_address_pairs']} spoof_chain = arp_protect.SPOOF_CHAIN_PREFIX + vif mac_chain = arp_protect.MAC_CHAIN_PREFIX + vif expected = [ mock.call(['ebtables', '-t', 'nat', '--concurrent', '-L'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), mock.ANY, mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N', 'neutronMAC-%s' % vif, '-P', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', 'PREROUTING', '-i', vif, '-j', mac_chain], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', mac_chain, '-i', vif, '--among-src', '%s' % ','.join(sorted(mac_addresses)), '-j', 'RETURN'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), mock.ANY, mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-N', spoof_chain, '-P', 'DROP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), mock.call(['ebtables', '-t', 'nat', '--concurrent', '-F', spoof_chain], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), ] for addr in sorted(ip_addresses): expected.extend([ mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', spoof_chain, '-p', 'ARP', '--arp-ip-src', addr, '-j', 'ACCEPT'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), ]) expected.extend([ mock.ANY, mock.call(['ebtables', '-t', 'nat', '--concurrent', '-A', 'PREROUTING', '-i', vif, '-j', spoof_chain, '-p', 'ARP'], check_exit_code=True, extra_ok_codes=None, log_fail_as_error=True, run_as_root=True), ]) arp_protect.setup_arp_spoofing_protection(vif, port) self.execute.assert_has_calls(expected)
def test_port_trusted(self, dasp): arp_protect.setup_arp_spoofing_protection(VIF, PORT_TRUSTED) dasp.assert_called_with([VIF])
def test_port_no_security(self, dasp): arp_protect.setup_arp_spoofing_protection(VIF, PORT_NO_SEC) dasp.assert_called_with([VIF])