/* * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.netvirt.openstack.netvirt.impl; import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface; import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService; import org.opendaylight.netvirt.openstack.netvirt.api.Constants; import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider; import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider; import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager; import org.opendaylight.netvirt.openstack.netvirt.api.Southbound; import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork; import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort; import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup; import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule; import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet; import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs; import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD; import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD; import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD; import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager { private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class); private volatile INeutronPortCRUD neutronPortCache; private volatile INeutronSubnetCRUD neutronSubnetCache; private volatile Southbound southbound; private volatile INeutronNetworkCRUD neutronNetworkCache; private volatile ConfigurationService configurationService; private volatile IngressAclProvider ingressAclProvider; private volatile EgressAclProvider egressAclProvider; private volatile NeutronL3Adapter neutronL3Adapter; private boolean isConntrackEnabled = false; public SecurityServicesImpl() { super(); } public SecurityServicesImpl(boolean isConntrack) { super(); this.isConntrackEnabled = isConntrack; } @Override public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.error("neutron port is null"); return false; } LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName()); String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return false; } NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId); if (neutronPort == null) { neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId); if (neutronPort == null) { LOG.error("isPortSecurityReady for {}", terminationPointAugmentation.getName() + "not found"); return false; } } String deviceOwner = neutronPort.getDeviceOwner(); if (!deviceOwner.contains("compute")) { LOG.debug("Port {} is not a compute host, it is a: {}", neutronPortId, deviceOwner); } LOG.debug("isPortSecurityReady() is a {} ", deviceOwner); List securityGroups = neutronPort.getSecurityGroups(); if (securityGroups.isEmpty()) { LOG.debug("Check for device: {} does not contain a Security Group for port: {}", deviceOwner, neutronPortId); return false; } LOG.debug("Security Group Check {} does contain a Neutron Security Group", neutronPortId); return true; } @Override public List getSecurityGroupInPortList(OvsdbTerminationPointAugmentation terminationPointAugmentation) { List neutronSecurityGroups = new ArrayList<>(); if (neutronPortCache == null) { LOG.error("neutron port is null"); return neutronSecurityGroups; } LOG.trace("getSecurityGroupInPortList for {}", terminationPointAugmentation.getName()); String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return neutronSecurityGroups; } NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId); if (neutronPort == null) { neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId); if (neutronPort == null) { LOG.error("getSecurityGroupInPortList for {}", terminationPointAugmentation.getName() + "not found."); return neutronSecurityGroups; } } neutronSecurityGroups = neutronPort.getSecurityGroups(); return neutronSecurityGroups; } @Override public NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.warn("getDHCPServerPort: neutron port cache is null"); } LOG.trace("getDHCPServerPort for {}", terminationPointAugmentation.getName()); NeutronPort neutronPort = null; try { String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return null; } if (null != neutronPortCache) { neutronPort = neutronPortCache.getPort(neutronPortId); } if (neutronPort == null) { neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId); if (neutronPort == null) { LOG.error("getDHCPServerPort: neutron port of {} is not found", neutronPortId); return null; } LOG.info("getDHCPServerPort: neutron port of {} got from cleanupcache", neutronPortId); } /* if the current port is a DHCP port, return the same*/ if (neutronPort.getDeviceOwner().contains("dhcp")) { return neutronPort; } /*Since all the fixed ip assigned to a port should be *from the same network, first port is sufficient.*/ List fixedIps = neutronPort.getFixedIPs(); if (null == fixedIps || 0 == fixedIps.size() ) { LOG.error("getDHCPServerPort: No fixed ip is assigned"); return null; } /* Get all the ports in the subnet and identify the dhcp port*/ String subnetUuid = fixedIps.iterator().next().getSubnetUUID(); NeutronSubnet neutronSubnet = neutronSubnetCache.getSubnet(subnetUuid); if (neutronSubnet == null) { LOG.error("getDHCPServerPort: No subnet is found for " + subnetUuid); return null; } List ports = neutronSubnet.getPortsInSubnet(); for (NeutronPort port : ports) { if (port.getDeviceOwner().contains("dhcp")) { return port; } } } catch (Exception e) { LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e); return null; } return null; } @Override public NeutronPort getNeutronPortFromDhcpIntf( OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.error("getNeutronPortFromDhcpIntf: neutron port is null"); return null; } String neutronPortId = southbound.getInterfaceExternalIdsValue( terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return null; } NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId); if (neutronPort == null) { neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId); if (neutronPort == null) { LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId); return null; } } /* if the current port is a DHCP port, return true*/ if (neutronPort.getDeviceOwner().contains("dhcp")) { LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort ); return neutronPort; } return null; } @Override public NeutronPort getNeutronPortFromCache(OvsdbTerminationPointAugmentation terminationPointAugmentation) { NeutronPort neutronPort = null; LOG.trace("getNeutronPortFromCache for {}", terminationPointAugmentation.getName()); try { String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return null; } if (null != neutronPortCache) { neutronPort = neutronPortCache.getPort(neutronPortId); } if (neutronPort == null) { LOG.trace("getNeutronPortFromCache: neutron port of {} search in cleanupcache", neutronPortId); neutronPort = neutronL3Adapter.getPortFromCleanupCache(neutronPortId); if (neutronPort == null) { LOG.error("getNeutronPortFromCache: neutron port of {} is not found", neutronPortId); return null; } LOG.trace("getNeutronPortFromCache: neutron port of {} got from cleanupcache", neutronPortId); } } catch (Exception e) { LOG.warn("getNeutronPortFromCache:getNeutronPortFromCache failed due to ", e); return null; } return neutronPort; } @Override public boolean isComputePort(OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.warn("isComputePort : neutronPortCache is null"); } NeutronPort neutronPort = null; LOG.trace("isComputePort for {}", terminationPointAugmentation.getName()); String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return false; } if (neutronPortCache != null) { neutronPort = neutronPortCache.getPort(neutronPortId); } if (neutronPort == null) { neutronPort = getNeutronPortFromCache(terminationPointAugmentation); if (neutronPort == null) { return false; } } /*Check the device owner and if it contains compute to identify * whether it is a compute port.*/ String deviceOwner = neutronPort.getDeviceOwner(); if (!deviceOwner.contains("compute")) { LOG.debug("isComputePort : Port {} is not a DHCP server port for device owner {}", neutronPortId,deviceOwner); return false; } return true; } @Override public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.error("isLastPortinSubnet: neutronPortCache is null"); } NeutronPort neutronPort = null; try { LOG.trace("isLastPortinSubnet: for {}", terminationPointAugmentation.getName()); String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return false; } if (neutronPortCache != null) { neutronPort = neutronPortCache.getPort(neutronPortId); } if (neutronPort == null) { neutronPort = getNeutronPortFromCache(terminationPointAugmentation); if (neutronPort == null) { LOG.error("isLastPortinSubnet: neutron port of {} is not found", neutronPortId); return false; } } List neutronPortFixedIp = neutronPort.getFixedIPs(); if (null == neutronPortFixedIp || neutronPortFixedIp.isEmpty()) { return false; } /*Get all the ports in the current node and check whether there * is any port belonging to the same subnet of the input */ List terminationPoints = node.getTerminationPoint(); if (terminationPoints != null && !terminationPoints.isEmpty()) { for (TerminationPoint tp : terminationPoints) { OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = tp.getAugmentation(OvsdbTerminationPointAugmentation.class); if (ovsdbTerminationPointAugmentation != null && !ovsdbTerminationPointAugmentation .getName().equals(Constants.INTEGRATION_BRIDGE)) { String portId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (null != portId) { NeutronPort port = neutronPortCache.getPort(portId); if (null != port && !(port.getID().equals(neutronPort.getID())) && port.getDeviceOwner().contains("compute")) { List portFixedIp = port.getFixedIPs(); if (null == portFixedIp || portFixedIp.isEmpty()) { return false; } if (portFixedIp.iterator().next().getSubnetUUID() .equals(neutronPort.getFixedIPs().iterator().next().getSubnetUUID())) { LOG.trace("isLastPortinSubnet: Port is not the only port."); return false; } } } } } } } catch (Exception e) { LOG.error("isLastPortinSubnet: isLastPortinSubnet failed due to ", e); return false; } return true; } @Override public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) { LOG.trace("isLastPortinBridge: for {}", terminationPointAugmentation.getName()); List terminationPoints = node.getTerminationPoint(); /*Check whether the node has any port other than br-int*/ if (terminationPoints != null && !terminationPoints.isEmpty()) { for (TerminationPoint tp : terminationPoints) { OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation = tp.getAugmentation(OvsdbTerminationPointAugmentation.class); if (null != ovsdbTerminationPointAugmentation && !(ovsdbTerminationPointAugmentation.getName().equals(Constants.INTEGRATION_BRIDGE)) && !(terminationPointAugmentation.getInterfaceUuid() .equals(ovsdbTerminationPointAugmentation.getInterfaceUuid()))) { LOG.debug("isLastPortinBridge: it the last port in bridge {}", terminationPointAugmentation.getName()); return false; } } } return true; } @Override public List getIpAddressList(OvsdbTerminationPointAugmentation terminationPointAugmentation) { if (neutronPortCache == null) { LOG.warn("getIpAddress: neutronPortCache is null"); } NeutronPort neutronPort = null; LOG.trace("getIpAddress: for {}", terminationPointAugmentation.getName()); String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { return null; } if (neutronPortCache != null) { neutronPort = neutronPortCache.getPort(neutronPortId); } if (neutronPort == null) { neutronPort = getNeutronPortFromCache(terminationPointAugmentation); } if (neutronPort == null) { LOG.error("getIpAddress: neutron port of {} is not found", neutronPortId); return null; } return neutronPort.getFixedIPs(); } @Override public List getVmListForSecurityGroup(String portUuid, String securityGroupUuid) { List vmListForSecurityGroup = new ArrayList<>(); /*For every port check whether security grouplist contains the current * security group.*/ try { for (String neutronPortUuid:neutronL3Adapter.getPortCleanupCache().keySet()) { NeutronPort neutronPort = neutronL3Adapter.getPortCleanupCache().get(neutronPortUuid); if (!neutronPort.getDeviceOwner().contains("compute")) { LOG.debug("getVMListForSecurityGroup : the port {} is not " + "compute port belongs to {}", neutronPort.getID(), neutronPort.getDeviceOwner()); continue; } if (portUuid.equals(neutronPort.getID())) { continue; } List securityGroups = neutronPort.getSecurityGroups(); if (null != securityGroups) { for (NeutronSecurityGroup securityGroup:securityGroups) { if (securityGroup.getSecurityGroupUUID().equals(securityGroupUuid)) { LOG.debug("getVMListForSecurityGroup : adding ports with ips {} " + "compute port", neutronPort.getFixedIPs()); if (neutronPort.getFixedIPs() != null) { vmListForSecurityGroup.addAll(neutronPort.getFixedIPs()); } } } } } } catch (Exception e) { LOG.error("getVMListForSecurityGroup: getVMListForSecurityGroup" + " failed due to ", e); return null; } return vmListForSecurityGroup; } @Override public void syncSecurityGroup(NeutronPort port, List securityGroupList, boolean write) { LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + write); if (null != port && null != port.getSecurityGroups()) { Node node = getNode(port); if (node == null) { return; } NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID()); if (null == neutronNetwork) { neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(port.getNetworkUUID()); } if (neutronNetwork == null) { return; } String segmentationId = neutronNetwork.getProviderSegmentationID(); OvsdbTerminationPointAugmentation intf = getInterface(node, port); if (intf == null) { return; } long localPort = southbound.getOFPort(intf); String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC); if (attachedMac == null) { LOG.debug("programVlanRules: No AttachedMac seen in {}", intf); return; } long dpid = getDpidOfIntegrationBridge(node); if (dpid == 0L) { return; } String neutronPortId = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_INTERFACE_ID); if (neutronPortId == null) { LOG.debug("syncSecurityGroup: No neutronPortId seen in {}", intf); return; } for (NeutronSecurityGroup securityGroupInPort:securityGroupList) { ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort, securityGroupInPort, neutronPortId, write); egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort, securityGroupInPort, neutronPortId, write); } } } @Override public void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write) { LOG.trace("syncSecurityGroup:" + securityRule + " Write:" + write); if (null != port && null != port.getSecurityGroups()) { Node node = getNode(port); if (node == null) { return; } NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID()); if (null == neutronNetwork) { neutronNetwork = neutronL3Adapter.getNetworkFromCleanupCache(port.getNetworkUUID()); } if (neutronNetwork == null) { return; } String segmentationId = neutronNetwork.getProviderSegmentationID(); OvsdbTerminationPointAugmentation intf = getInterface(node, port); if (intf == null) { return; } long localPort = southbound.getOFPort(intf); String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC); if (attachedMac == null) { LOG.debug("programVlanRules: No AttachedMac seen in {}", intf); return; } long dpid = getDpidOfIntegrationBridge(node); if (dpid == 0L) { return; } if (NeutronSecurityRule.ETHERTYPE_IPV4.equals(securityRule.getSecurityRuleEthertype())) { if (NeutronSecurityRule.DIRECTION_INGRESS.equals(securityRule.getSecurityRuleDirection())) { ingressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort, securityRule, vmIp, write); } else if (NeutronSecurityRule.DIRECTION_EGRESS.equals(securityRule.getSecurityRuleDirection())) { egressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort, securityRule, vmIp, write); } } } } private long getDpidOfIntegrationBridge(Node node) { LOG.trace("getDpidOfIntegrationBridge:" + node); long dpid = 0L; if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) { dpid = getDpid(node); } if (dpid == 0L) { LOG.warn("getDpidOfIntegerationBridge: dpid not found: {}", node); } return dpid; } private long getDpid(Node node) { LOG.trace("getDpid" + node); long dpid = southbound.getDataPathId(node); if (dpid == 0) { LOG.warn("getDpid: dpid not found: {}", node); } return dpid; } private Node getNode(NeutronPort port) { LOG.trace("getNode:Port" + port); List toplogyNodes = southbound.readOvsdbTopologyNodes(); for (Node topologyNode : toplogyNodes) { try { Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE); List ovsdbPorts = southbound.getTerminationPointsOfBridge(node); for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) { String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort, Constants.EXTERNAL_ID_INTERFACE_ID); if (null != uuid && uuid.equals(port.getID())) { return node; } } } catch (Exception e) { LOG.error("Exception during handlingNeutron network delete", e); } } LOG.info("no node found for port:" + port); return null; } private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) { LOG.trace("getInterface:Node:" + node + " Port:" + port); try { List ovsdbPorts = southbound.getTerminationPointsOfBridge(node); for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) { String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort, Constants.EXTERNAL_ID_INTERFACE_ID); if (null != uuid && uuid.equals(port.getID())) { return ovsdbPort; } } } catch (Exception e) { LOG.error("Exception during handlingNeutron network delete", e); } LOG.info("no interface found for node: " + node + " port:" + port); return null; } @Override public boolean isPortSecurityEnabled(OvsdbTerminationPointAugmentation intf) { NeutronPort neutronPort = getNeutronPortFromCache(intf); if (null == neutronPort) { LOG.error("Neutron Port is null: " + intf); return false; } if (neutronPort.getPortSecurityEnabled()) { LOG.info("Port Security is enabled for Port: " + neutronPort); return true; } LOG.info("Port Security is not enabled for Port: " + neutronPort); return false; } @Override public void setDependencies(ServiceReference serviceReference) { neutronL3Adapter = (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this); southbound = (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this); neutronNetworkCache = (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this); configurationService = (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this); } @Override public void setDependencies(Object impl) { if (impl instanceof INeutronPortCRUD) { neutronPortCache = (INeutronPortCRUD)impl; } else if (impl instanceof INeutronSubnetCRUD) { neutronSubnetCache = (INeutronSubnetCRUD) impl; } else if (impl instanceof IngressAclProvider) { ingressAclProvider = (IngressAclProvider) impl; } else if (impl instanceof EgressAclProvider) { egressAclProvider = (EgressAclProvider) impl; } } @Override public boolean isConntrackEnabled() { return isConntrackEnabled; } }