def handle_port(self, context, port): """Handle port update event""" # Check if port is trusted and called at once. if nl_net.is_port_trusted(port) and not self.fwg_map.get_port(port): self._add_rule_for_trusted_port(port) self.fwg_map.set_port(port) return if not self._is_port_layer2(port): return # check if port is already assigned to a fwg if self.fwg_map.get_port_fwg(port): return fwg = self.plugin_rpc.get_firewall_group_for_port( context, port.get('port_id')) if not fwg: LOG.info( "Firewall group applied to port %s is " "not available on server.", port['port_id']) return ret = self._apply_fwg_rules(fwg, [port]) status = self._compute_status(fwg, ret, event=consts.HANDLE_PORT) self.fwg_map.set_port_fwg(port, fwg) self._send_fwg_status(context, fwg_id=fwg['id'], status=status, host=self.conf.host)
def _get_security_groups_on_port(self, context, port): """Check that all security groups on port belong to tenant. :returns: all security groups on port belonging to tenant) """ port = port['port'] if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): return if port.get('device_owner') and net.is_port_trusted(port): return port_sg = port.get(ext_sg.SECURITYGROUPS, []) tenant_id = port.get('tenant_id') sg_objs = sg_obj.SecurityGroup.get_objects(context, id=port_sg) valid_groups = set( g.id for g in sg_objs if (context.is_admin or not tenant_id or g.tenant_id == tenant_id or sg_obj.SecurityGroup.is_shared_with_tenant( context, g.id, tenant_id))) requested_groups = set(port_sg) port_sg_missing = requested_groups - valid_groups if port_sg_missing: raise ext_sg.SecurityGroupNotFound(id=', '.join(port_sg_missing)) return sg_objs
def _determine_port_security_and_has_ip(self, context, port): """Returns a tuple of booleans (port_security_enabled, has_ip). Port_security is the value associated with the port if one is present otherwise the value associated with the network is returned. has_ip is if the port is associated with an ip or not. """ has_ip = self._ip_on_port(port) # we don't apply security groups for dhcp, router if port.get('device_owner') and net.is_port_trusted(port): return (False, has_ip) if validators.is_attr_set(port.get(psec.PORTSECURITY)): port_security_enabled = port[psec.PORTSECURITY] # If port has an ip and security_groups are passed in # conveniently set port_security_enabled to true this way # user doesn't also have to pass in port_security_enabled=True # when creating ports. elif has_ip and validators.is_attr_set(port.get('security_groups')): port_security_enabled = True else: port_security_enabled = self._get_network_security_binding( context, port['network_id']) return (port_security_enabled, has_ip)
def _get_devices_info(self, context, devices): # NOTE(kevinbenton): this format is required by the sg code, it is # defined in get_port_from_device and mimics # make_port_dict_with_security_groups in ML2 db result = {} for device in devices: ovo = self.rcache.get_resource_by_id('Port', device) if not ovo: continue port = ovo.to_dict() # the caller expects trusted ports to be excluded from the result if net.is_port_trusted(port): continue port['security_groups'] = list(ovo.security_group_ids) port['security_group_rules'] = [] port['security_group_source_groups'] = [] port['fixed_ips'] = [str(f['ip_address']) for f in port['fixed_ips']] # NOTE(kevinbenton): this id==device is only safe for OVS. a lookup # will be required for linux bridge and others that don't have the # full port UUID port['device'] = port['id'] port['port_security_enabled'] = getattr( ovo.security, 'port_security_enabled', True) result[device] = port return result
def _determine_port_security_and_has_ip(self, context, port): """Returns a tuple of booleans (port_security_enabled, has_ip). Port_security is the value associated with the port if one is present otherwise the value associated with the network is returned. has_ip is if the port is associated with an ip or not. """ has_ip = self._ip_on_port(port) # we don't apply security groups for dhcp, router if port.get('device_owner') and net.is_port_trusted(port): return (False, has_ip) if validators.is_attr_set(port.get(psec.PORTSECURITY)): port_security_enabled = port[psec.PORTSECURITY] # If port has an ip and security_groups are passed in # conveniently set port_security_enabled to true this way # user doesn't also have to pass in port_security_enabled=True # when creating ports. elif has_ip and validators.is_attr_set(port.get('security_groups')): port_security_enabled = True else: port_security_enabled = self._get_network_security_binding( context, port['network_id']) return (port_security_enabled, has_ip)
def _get_security_groups_on_port(self, context, port): """Check that all security groups on port belong to tenant. :returns: all security groups IDs on port belonging to tenant. """ port = port['port'] if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): return if port.get('device_owner') and net.is_port_trusted(port): return port_sg = port.get(ext_sg.SECURITYGROUPS, []) filters = {'id': port_sg} tenant_id = port.get('tenant_id') if tenant_id: filters['tenant_id'] = [tenant_id] valid_groups = set(g['id'] for g in self.get_security_groups( context, fields=['id'], filters=filters)) requested_groups = set(port_sg) port_sg_missing = requested_groups - valid_groups if port_sg_missing: raise ext_sg.SecurityGroupNotFound(id=', '.join(port_sg_missing)) return list(requested_groups)
def _get_security_groups_on_port(self, context, port): """Check that all security groups on port belong to tenant. :returns: all security groups IDs on port belonging to tenant. """ port = port['port'] if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): return if port.get('device_owner') and net.is_port_trusted(port): return port_sg = port.get(ext_sg.SECURITYGROUPS, []) tenant_id = port.get('tenant_id') sg_objs = sg_obj.SecurityGroup.get_objects(context, id=port_sg) valid_groups = set( g.id for g in sg_objs if (not tenant_id or g.tenant_id == tenant_id or sg_obj.SecurityGroup.is_shared_with_tenant( context, g.id, tenant_id)) ) requested_groups = set(port_sg) port_sg_missing = requested_groups - valid_groups if port_sg_missing: raise ext_sg.SecurityGroupNotFound(id=', '.join(port_sg_missing)) return list(requested_groups)
def _get_security_groups_on_port(self, context, port): """Check that all security groups on port belong to tenant. :returns: all security groups IDs on port belonging to tenant. """ port = port['port'] if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): return if port.get('device_owner') and net.is_port_trusted(port): return port_sg = port.get(ext_sg.SECURITYGROUPS, []) filters = {'id': port_sg} tenant_id = port.get('tenant_id') if tenant_id: filters['tenant_id'] = [tenant_id] valid_groups = set(g['id'] for g in self.get_security_groups(context, fields=['id'], filters=filters)) requested_groups = set(port_sg) port_sg_missing = requested_groups - valid_groups if port_sg_missing: raise ext_sg.SecurityGroupNotFound(id=', '.join(port_sg_missing)) return list(requested_groups)
def _validate_max_ips_per_port(self, fixed_ip_list, device_owner): if net.is_port_trusted({'device_owner': device_owner}): return if len(fixed_ip_list) > cfg.CONF.max_fixed_ips_per_port: msg = _('Exceeded maximum amount of fixed ips per port') raise exc.InvalidInput(error_message=msg)
def setup_arp_spoofing_protection(vif, port_details): current_rules = ebtables(['-L']).splitlines() if not port_details.get('port_security_enabled', True): # clear any previous entries related to this port delete_arp_spoofing_protection([vif], current_rules) LOG.info( _LI("Skipping ARP spoofing rules for port '%s' because " "it has port security disabled"), vif) return if net.is_port_trusted(port_details): # clear any previous entries related to this port delete_arp_spoofing_protection([vif], current_rules) LOG.debug( "Skipping ARP spoofing rules for network owned port " "'%s'.", vif) return _install_mac_spoofing_protection(vif, port_details, current_rules) # collect all of the addresses and cidrs that belong to the port addresses = {f['ip_address'] for f in port_details['fixed_ips']} if port_details.get('allowed_address_pairs'): addresses |= { p['ip_address'] for p in port_details['allowed_address_pairs'] } addresses = {ip for ip in addresses if netaddr.IPNetwork(ip).version == 4} if any(netaddr.IPNetwork(ip).prefixlen == 0 for ip in addresses): # don't try to install protection because a /0 prefix allows any # address anyway and the ARP_SPA can only match on /1 or more. return install_arp_spoofing_protection(vif, addresses, current_rules)
def _get_devices_info(self, context, devices): # NOTE(kevinbenton): this format is required by the sg code, it is # defined in get_port_from_device and mimics # make_port_dict_with_security_groups in ML2 db result = {} for device in devices: ovo = self.rcache.get_resource_by_id('Port', device) if not ovo: continue port = ovo.to_dict() # the caller expects trusted ports to be excluded from the result if net.is_port_trusted(port): continue port['security_groups'] = list(ovo.security_group_ids) port['security_group_rules'] = [] port['security_group_source_groups'] = [] port['security_group_remote_address_groups'] = [] port['fixed_ips'] = [ str(f['ip_address']) for f in port['fixed_ips'] ] # NOTE(kevinbenton): this id==device is only safe for OVS. a lookup # will be required for linux bridge and others that don't have the # full port UUID port['device'] = port['id'] port['port_security_enabled'] = getattr(ovo.security, 'port_security_enabled', True) result[device] = port return result
def _ensure_default_security_group_on_port(self, context, port): # we don't apply security groups for dhcp, router port = port['port'] if port.get('device_owner') and net.is_port_trusted(port): return if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): default_sg = self._ensure_default_security_group(context, port['tenant_id']) port[ext_sg.SECURITYGROUPS] = [default_sg]
def _ensure_default_security_group_on_port(self, context, port): # we don't apply security groups for dhcp, router port = port['port'] if port.get('device_owner') and net.is_port_trusted(port): return if not validators.is_attr_set(port.get(ext_sg.SECURITYGROUPS)): default_sg = self._ensure_default_security_group( context, port['tenant_id']) port[ext_sg.SECURITYGROUPS] = [default_sg]
def _validate_max_ips_per_port(self, fixed_ip_list, device_owner): """Validate the number of fixed ips on a port Do not allow multiple ip addresses on a port since the nsx backend cannot add multiple static dhcp bindings with the same port """ if (device_owner and net.is_port_trusted({'device_owner': device_owner})): return if validators.is_attr_set(fixed_ip_list) and len(fixed_ip_list) > 1: msg = _('Exceeded maximum amount of fixed ips per port') raise n_exc.InvalidInput(error_message=msg)
def _validate_max_ips_per_port(self, fixed_ip_list, device_owner): """Validate the number of fixed ips on a port Do not allow multiple ip addresses on a port since the nsx backend cannot add multiple static dhcp bindings with the same port """ if (device_owner and nl_net_utils.is_port_trusted({'device_owner': device_owner})): return if validators.is_attr_set(fixed_ip_list) and len(fixed_ip_list) > 1: msg = _('Exceeded maximum amount of fixed ips per port') raise n_exc.InvalidInput(error_message=msg)
def _ensure_default_security_group_on_port(self, context, port): # we don't apply security groups for dhcp, router port = port['port'] if port.get('device_owner') and net.is_port_trusted(port): return port_sg = port.get(ext_sg.SECURITYGROUPS) if port_sg is None or not validators.is_attr_set(port_sg): # TODO(ralonsoh): "tenant_id" reference should be removed. port_project = port.get('project_id') or port.get('tenant_id') default_sg = self._ensure_default_security_group(context, port_project) if default_sg: port[ext_sg.SECURITYGROUPS] = [default_sg]
def setup_arp_spoofing_protection(vif, port_details): if not port_details.get('port_security_enabled', True): # clear any previous entries related to this port delete_arp_spoofing_protection([vif]) LOG.info("Skipping ARP spoofing rules for port '%s' because " "it has port security disabled", vif) return if net.is_port_trusted(port_details): # clear any previous entries related to this port delete_arp_spoofing_protection([vif]) LOG.debug("Skipping ARP spoofing rules for network owned port " "'%s'.", vif) return _setup_arp_spoofing_protection(vif, port_details)
def setup_arp_spoofing_protection(vif, port_details): if not port_details.get('port_security_enabled', True): # clear any previous entries related to this port delete_arp_spoofing_protection([vif]) LOG.info("Skipping ARP spoofing rules for port '%s' because " "it has port security disabled", vif) return if net.is_port_trusted(port_details): # clear any previous entries related to this port delete_arp_spoofing_protection([vif]) LOG.debug("Skipping ARP spoofing rules for network owned port " "'%s'.", vif) return _setup_arp_spoofing_protection(vif, port_details)
def setup_arp_spoofing_protection(vif, port_details, socket_dir): kvs_device_name, port_index = get_kvs_device_name_port_index( vif, socket_dir) LOG.info( "setup_arp_spoofing_protection called: vif %s, kvs_device_name %s", vif, kvs_device_name) if port_index is None: LOG.error( "setup_arp_spoofing_protection failed: port_index could " "not be found for vhost/vdev %s", kvs_device_name) return if not port_details.get('port_security_enabled', True): # clear any previous entries related to this port _delete_arp_spoofing_protection(port_index) LOG.info( "Skipping ARP spoofing rules for port '%s' because " "it has port security disabled", vif) return if net.is_port_trusted(port_details): # clear any previous entries related to this port _delete_arp_spoofing_protection(port_index) LOG.info("Skipping ARP spoofing rules for network owned port " "'%s'.", vif) return ##apply diff rules, delete extra rules new_pairs = _new_anti_spoofing_rules(vif, port_details, port_index) #Single port represents parent-port and subports in case of trunk. #parent-port rules are associated with vlan=0, and subport rules are associated with other vlans. #Here, we should not touch/delete trunk's subports rules. existing_pairs = kvs_net.list_anti_spoofing_rules(port_index, vlan=0) if existing_pairs is None: existing_pairs = [] new_set = set() for new_pair in new_pairs: new_set.add((new_pair["ip"], new_pair["mac"])) existing_set = set() for existing_pair in existing_pairs: existing_set.add((existing_pair["ip"], existing_pair["mac"])) setup = new_set - existing_set delete = existing_set - new_set for (ip, mac) in setup: kvs_net.add_anti_spoofing_rule(port_index, mac, ip) #vlan = 0 for (ip, mac) in delete: kvs_net.delete_anti_spoofing_rule(port_index, mac, ip) #vlan = 0
def _handle_security_group(self, t_ctx, q_ctx, port): if 'security_groups' not in port: return if port.get('device_owner') and net.is_port_trusted(port): return if not port['security_groups']: raw_client = self.neutron_handle._get_client(t_ctx) params = {'name': 'default'} t_sgs = raw_client.list_security_groups( **params)['security_groups'] if t_sgs: port['security_groups'] = [t_sgs[0]['id']] if port['security_groups'] is q_constants.ATTR_NOT_SPECIFIED: return for sg_id in port['security_groups']: self.get_security_group(q_ctx, sg_id)
def _handle_security_group(self, t_ctx, q_ctx, port): if 'security_groups' not in port: return if port.get('device_owner') and net.is_port_trusted(port): return if not port['security_groups']: raw_client = self.neutron_handle._get_client(t_ctx) params = {'name': 'default'} t_sgs = raw_client.list_security_groups( **params)['security_groups'] if t_sgs: port['security_groups'] = [t_sgs[0]['id']] if port['security_groups'] is q_constants.ATTR_NOT_SPECIFIED: return for sg_id in port['security_groups']: self.get_security_group(q_ctx, sg_id)
def _determine_port_security(self, context, port): """Returns a boolean (port_security_enabled). Port_security is the value associated with the port if one is present otherwise the value associated with the network is returned. """ # we don't apply security groups for dhcp, router if port.get('device_owner') and net.is_port_trusted(port): return False if validators.is_attr_set(port.get(psec.PORTSECURITY)): port_security_enabled = port[psec.PORTSECURITY] else: port_security_enabled = self._get_network_security_binding( context, port['network_id']) return port_security_enabled
def _determine_port_security(self, context, port): """Returns a boolean (port_security_enabled). Port_security is the value associated with the port if one is present otherwise the value associated with the network is returned. """ # we don't apply security groups for dhcp, router if port.get('device_owner') and net.is_port_trusted(port): return False if validators.is_attr_set(port.get(psec.PORTSECURITY)): port_security_enabled = port[psec.PORTSECURITY] else: port_security_enabled = self._get_network_security_binding( context, port['network_id']) return port_security_enabled
def _get_provider_security_groups_on_port(self, context, port): p = port['port'] tenant_id = p['tenant_id'] provider_sgs = p.get(provider_sg.PROVIDER_SECURITYGROUPS, n_constants.ATTR_NOT_SPECIFIED) if p.get('device_owner') and n_utils.is_port_trusted(p): return if not validators.is_attr_set(provider_sgs): if provider_sgs is n_constants.ATTR_NOT_SPECIFIED: provider_sgs = self._get_tenant_provider_security_groups( context, tenant_id) else: # Accept None as indication that this port should not be # associated with any provider security-group. provider_sgs = [] return provider_sgs
def _get_provider_security_groups_on_port(self, context, port): p = port['port'] tenant_id = p['tenant_id'] provider_sgs = p.get(provider_sg.PROVIDER_SECURITYGROUPS, n_constants.ATTR_NOT_SPECIFIED) if p.get('device_owner') and n_utils.is_port_trusted(p): return if not validators.is_attr_set(provider_sgs): if provider_sgs is n_constants.ATTR_NOT_SPECIFIED: provider_sgs = self._get_tenant_provider_security_groups( context, tenant_id) else: # Accept None as indication that this port should not be # associated with any provider security-group. provider_sgs = [] return provider_sgs
def delete_port(self, context, port): """This is being called when a port is deleted by the agent. """ # delete_port should be handled only unbound timing for a port. # If 'vif_port' is included in the port dict, this is called after # deleted the port and should be ignored. if 'vif_port' in port: return port = self.fwg_map.get_port(port) if port and nl_net.is_port_trusted(port): self._delete_rule_for_trusted_port(port) self.fwg_map.remove_port(port) return if not self._is_port_layer2(port): return fwg = self.fwg_map.get_port_fwg(port) if not fwg: LOG.info( "Firewall group associated to port %(port_id)s is " "not available on server.", {'port_id': port['port_id']}) return ret = self._apply_fwg_rules(fwg, [port], event=consts.DELETE_FWG) port_id = self.fwg_map.port_id(port) if port_id in fwg['ports']: fwg['ports'].remove(port_id) # update the fwg dict to known_fwgs self.fwg_map.set_fwg(fwg) self.fwg_map.remove_port(port) status = self._compute_status(fwg, ret, event=consts.DELETE_PORT) self._send_fwg_status(context, fwg['id'], status, self.conf.host)
def _get_devices_info(self, context, devices): return dict( (port['id'], port) for port in self.plugin.get_ports_from_devices(context, devices) if port and not net.is_port_trusted(port) )
def _get_devices_info(self, context, devices): return dict( (port['id'], port) for port in self.plugin.get_ports_from_devices(context, devices) if port and not net.is_port_trusted(port))
def is_lsp_trusted(port): return n_utils.is_port_trusted(port) if port.get('device_owner') else False
def test_is_port_trusted(self): self.assertTrue( net.is_port_trusted({ 'device_owner': constants.DEVICE_OWNER_NETWORK_PREFIX + 'dev' }))
def test_is_port_not_trusted(self): self.assertFalse( net.is_port_trusted({ 'device_owner': constants.DEVICE_OWNER_COMPUTE_PREFIX + 'dev' }))