Merge "Unit test for ovsdb.southbound.ovsdb.transact"
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / impl / SecurityServicesImpl.java
1 /*
2  * Copyright (c) 2014, 2015 Red Hat, Inc. and others. All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.ovsdb.openstack.netvirt.impl;
10
11 import org.opendaylight.ovsdb.openstack.netvirt.ConfigInterface;
12 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
13 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
14 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
15 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
16 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
17 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
18 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
19 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
20 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
21 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
22 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
23 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
24 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
25 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
26 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
28 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
30 import org.osgi.framework.ServiceReference;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34 import java.util.ArrayList;
35 import java.util.List;
36
37 public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
38     private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
39     private volatile INeutronPortCRUD neutronPortCache;
40     private volatile INeutronSubnetCRUD neutronSubnetCache;
41     private volatile Southbound southbound;
42     private volatile INeutronNetworkCRUD neutronNetworkCache;
43     private volatile ConfigurationService configurationService;
44     private volatile IngressAclProvider ingressAclProvider;
45     private volatile EgressAclProvider egressAclProvider;
46     private volatile SecurityServicesManager securityServicesManager;
47
48     @Override
49     public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
50         if (neutronPortCache == null) {
51             LOG.error("neutron port is null");
52             return false;
53         }
54         LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName());
55         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
56                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
57         if (neutronPortId == null) {
58             return false;
59         }
60         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
61         if (neutronPort == null) {
62             return false;
63         }
64         String deviceOwner = neutronPort.getDeviceOwner();
65         if (!deviceOwner.contains("compute")) {
66             LOG.debug("Port {} is not a compute host, it is a: {}", neutronPortId, deviceOwner);
67         }
68         LOG.debug("isPortSecurityReady() is a {} ", deviceOwner);
69         List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
70         if (securityGroups.isEmpty()) {
71             LOG.debug("Check for device: {} does not contain a Security Group for port: {}", deviceOwner,
72                       neutronPortId);
73             return false;
74         }
75         LOG.debug("Security Group Check {} does contain a Neutron Security Group", neutronPortId);
76         return true;
77     }
78
79     @Override
80     public List<NeutronSecurityGroup> getSecurityGroupInPortList(OvsdbTerminationPointAugmentation
81                                                              terminationPointAugmentation) {
82         List<NeutronSecurityGroup> neutronSecurityGroups = new ArrayList<NeutronSecurityGroup>();
83         if (neutronPortCache == null) {
84             LOG.error("neutron port is null");
85             return neutronSecurityGroups;
86         }
87         LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName());
88         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
89                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
90         if (neutronPortId == null) {
91             return neutronSecurityGroups;
92         }
93         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
94         if (neutronPort == null) {
95             return neutronSecurityGroups;
96         }
97         neutronSecurityGroups = neutronPort.getSecurityGroups();
98         return neutronSecurityGroups;
99
100     }
101
102     @Override
103     public NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
104         if (neutronPortCache == null) {
105             LOG.error("getDHCPServerPort: neutron port is null");
106             return null;
107         }
108         LOG.trace("getDHCPServerPort for {}",
109                   terminationPointAugmentation.getName());
110         try {
111             String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
112                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
113             if (neutronPortId == null) {
114                 return null;
115             }
116             NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
117             if (neutronPort == null) {
118                 LOG.error("getDHCPServerPort: neutron port of {} is not found", neutronPortId);
119                 return null;
120             }
121             /* if the current port is a DHCP port, return the same*/
122             if (neutronPort.getDeviceOwner().contains("dhcp")) {
123                 return neutronPort;
124             }
125             /*Since all the fixed ip assigned to a port should be
126              *from the same network, first port is sufficient.*/
127             List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
128             if (null == fixedIps || 0 == fixedIps.size() ) {
129                 LOG.error("getDHCPServerPort: No fixed ip is assigned");
130                 return null;
131             }
132             /* Get all the ports in the subnet and identify the dhcp port*/
133             String subnetUuid = fixedIps.iterator().next().getSubnetUUID();
134             NeutronSubnet neutronSubnet = neutronSubnetCache.getSubnet(subnetUuid);
135             List<NeutronPort> ports = neutronSubnet.getPortsInSubnet();
136             for (NeutronPort port : ports) {
137                 if (port.getDeviceOwner().contains("dhcp")) {
138                     return port;
139                 }
140             }
141         } catch (Exception e) {
142             LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e);
143             return null;
144         }
145         return null;
146     }
147
148     @Override
149     public NeutronPort getNeutronPortFromDhcpIntf(
150             OvsdbTerminationPointAugmentation terminationPointAugmentation) {
151         if (neutronPortCache == null) {
152             LOG.error("getNeutronPortFromDhcpIntf: neutron port is null");
153             return null;
154         }
155         String neutronPortId = southbound.getInterfaceExternalIdsValue(
156                 terminationPointAugmentation,
157                 Constants.EXTERNAL_ID_INTERFACE_ID);
158         if (neutronPortId == null) {
159             return null;
160         }
161         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
162         if (neutronPort == null) {
163             LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId);
164             return null;
165         }
166         /* if the current port is a DHCP port, return true*/
167         if (neutronPort.getDeviceOwner().contains("dhcp")) {
168             LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort );
169             return neutronPort;
170         }
171         return null;
172     }
173
174     @Override
175     public boolean isComputePort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
176         if (neutronPortCache == null) {
177             LOG.error("neutron port is null");
178             return false;
179         }
180         LOG.trace("isComputePort for {}", terminationPointAugmentation.getName());
181         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
182                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
183         if (neutronPortId == null) {
184             return false;
185         }
186         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
187         if (neutronPort == null) {
188             return false;
189         }
190         /*Check the device owner and if it contains compute to identify
191          * whether it is a compute port.*/
192         String deviceOwner = neutronPort.getDeviceOwner();
193         if (!deviceOwner.contains("compute")) {
194             LOG.debug("isComputePort : Port {} is not a DHCP server port for device owner {}",
195                       neutronPortId,deviceOwner);
196             return false;
197         }
198         return true;
199     }
200
201     @Override
202     public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
203         if (neutronPortCache == null) {
204             LOG.error("isLastPortinSubnet: neutron port is null");
205             return false;
206         }
207         try {
208             LOG.trace("isLastPortinSubnet: for {}", terminationPointAugmentation.getName());
209             String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
210                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
211             if (neutronPortId == null) {
212                 return false;
213             }
214             NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
215             if (neutronPort == null) {
216                 LOG.error("isLastPortinSubnet: neutron port of {} is not found", neutronPortId);
217                 return false;
218             }
219             List<Neutron_IPs> neutronPortFixedIp = neutronPort.getFixedIPs();
220             if (null == neutronPortFixedIp || neutronPortFixedIp.isEmpty()) {
221                 return false;
222             }
223             /*Get all the ports in the current node and check whether there
224              * is any port belonging to the same subnet of the input
225              */
226             List<TerminationPoint> terminationPoints = node.getTerminationPoint();
227             if (terminationPoints != null && !terminationPoints.isEmpty()) {
228                 for (TerminationPoint tp : terminationPoints) {
229                     OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
230                             tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
231                     if (ovsdbTerminationPointAugmentation != null && !ovsdbTerminationPointAugmentation
232                             .getName().equals(Constants.INTEGRATION_BRIDGE)) {
233                         String portId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
234                                                                                 Constants.EXTERNAL_ID_INTERFACE_ID);
235                         if (null != portId) {
236                             NeutronPort port = neutronPortCache.getPort(portId);
237                             if (null != port && !(port.getID().equals(neutronPort.getID()))
238                                     && port.getDeviceOwner().contains("compute")) {
239                                 List<Neutron_IPs> portFixedIp = port.getFixedIPs();
240                                 if (null == portFixedIp || portFixedIp.isEmpty()) {
241                                     return false;
242                                 }
243                                 if (portFixedIp.iterator().next().getSubnetUUID()
244                                         .equals(neutronPort.getFixedIPs().iterator().next().getSubnetUUID())) {
245                                     LOG.trace("isLastPortinSubnet: Port is not the only port.");
246                                     return false;
247                                 }
248                             }
249                         }
250                     }
251                 }
252             }
253         } catch (Exception e) {
254             LOG.error("isLastPortinSubnet: isLastPortinSubnet failed due to ", e);
255             return false;
256         }
257         return true;
258     }
259
260     @Override
261     public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
262         LOG.trace("isLastPortinBridge: for {}", terminationPointAugmentation.getName());
263         List<TerminationPoint> terminationPoints = node.getTerminationPoint();
264         /*Check whether the node has any port other than br-int*/
265         if (terminationPoints != null && !terminationPoints.isEmpty()) {
266             for (TerminationPoint tp : terminationPoints) {
267                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
268                         tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
269                 if (null != ovsdbTerminationPointAugmentation
270                         && !(ovsdbTerminationPointAugmentation.getName().equals(Constants.INTEGRATION_BRIDGE))
271                         && !(terminationPointAugmentation.getInterfaceUuid()
272                         .equals(ovsdbTerminationPointAugmentation.getInterfaceUuid()))) {
273                     LOG.debug("isLastPortinBridge: it the last port in bridge {}",
274                             terminationPointAugmentation.getName());
275                     return false;
276                 }
277             }
278         }
279         return true;
280     }
281
282     @Override
283     public List<Neutron_IPs> getIpAddressList(Node node,
284                                           OvsdbTerminationPointAugmentation terminationPointAugmentation) {
285         if (neutronPortCache == null) {
286             LOG.error("getIpAddress: neutron port is null");
287             return null;
288         }
289         LOG.trace("getIpAddress: for {}", terminationPointAugmentation.getName());
290         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
291                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
292         if (neutronPortId == null) {
293             return null;
294         }
295         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
296         if (neutronPort == null) {
297             LOG.error("getIpAddress: neutron port of {} is not found", neutronPortId);
298             return null;
299         }
300         return neutronPort.getFixedIPs();
301     }
302
303     @Override
304     public List<Neutron_IPs> getVmListForSecurityGroup(List<Neutron_IPs> srcAddressList, String securityGroupUuid) {
305         List<Neutron_IPs> vmListForSecurityGroup = new ArrayList<Neutron_IPs>();
306         /*For every port check whether security grouplist contains the current
307          * security group.*/
308         try {
309             for (NeutronPort neutronPort:neutronPortCache.getAllPorts()) {
310                 if (!neutronPort.getDeviceOwner().contains("compute")) {
311                     LOG.debug("getVMListForSecurityGroup : the port {} is not "
312                             + "compute port belongs to {}", neutronPort.getID(), neutronPort.getDeviceOwner());
313                     continue;
314                 }
315                 List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
316                 if (null != securityGroups) {
317                     for (NeutronSecurityGroup securityGroup:securityGroups) {
318                         if (securityGroup.getSecurityGroupUUID().equals(securityGroupUuid)
319                                 && !neutronPort.getFixedIPs().containsAll(srcAddressList)) {
320                             LOG.debug("getVMListForSecurityGroup : adding ports with ips {} "
321                                     + "compute port", neutronPort.getFixedIPs());
322                             vmListForSecurityGroup.addAll(neutronPort.getFixedIPs());
323                         }
324                     }
325                 }
326
327             }
328         } catch (Exception e) {
329             LOG.error("getVMListForSecurityGroup: getVMListForSecurityGroup"
330                     + " failed due to ", e);
331             return null;
332         }
333         return vmListForSecurityGroup;
334
335     }
336
337     @Override
338     public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
339         LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + Boolean.valueOf(write));
340         if (null != port && null != port.getSecurityGroups()) {
341             Node node = getNode(port);
342             NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
343             String segmentationId = neutronNetwork.getProviderSegmentationID();
344             OvsdbTerminationPointAugmentation intf = getInterface(node, port);
345             long localPort = southbound.getOFPort(intf);
346             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
347             if (attachedMac == null) {
348                 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
349                 return;
350             }
351             long dpid = getDpidOfIntegrationBridge(node);
352             List<Neutron_IPs> srcAddressList = securityServicesManager.getIpAddressList(node, intf);
353             for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
354                 ingressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
355                                                           securityGroupInPort, srcAddressList, write);
356                 egressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
357                                                          securityGroupInPort, srcAddressList, write);
358             }
359         }
360     }
361
362     private long getDpidOfIntegrationBridge(Node node) {
363         LOG.trace("getDpidOfIntegrationBridge:" + node);
364         long dpid = 0L;
365         if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
366             dpid = getDpid(node);
367         }
368         return dpid;
369     }
370
371     private long getDpid(Node node) {
372         LOG.trace("getDpid" + node);
373         long dpid = southbound.getDataPathId(node);
374         if (dpid == 0) {
375             LOG.warn("getDpid: dpid not found: {}", node);
376         }
377         return dpid;
378     }
379
380     private Node getNode(NeutronPort port) {
381         LOG.trace("getNode:Port" + port);
382         List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
383
384         for (Node topologyNode : toplogyNodes) {
385             try {
386                 Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
387                 List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
388                 for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
389                     String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
390                                                             Constants.EXTERNAL_ID_INTERFACE_ID);
391                     if (null != uuid && uuid.equals(port.getID())) {
392                         return node;
393                     }
394                 }
395             } catch (Exception e) {
396                 LOG.error("Exception during handlingNeutron network delete", e);
397             }
398         }
399         return null;
400     }
401
402     private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
403         LOG.trace("getInterface:Node:" + node + " Port:" + port);
404         try {
405             List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
406             for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
407                 String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
408                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
409                 if (null != uuid && uuid.equals(port.getID())) {
410                     return ovsdbPort;
411                 }
412             }
413         } catch (Exception e) {
414             LOG.error("Exception during handlingNeutron network delete", e);
415         }
416         return null;
417     }
418
419     @Override
420     public void setDependencies(ServiceReference serviceReference) {
421         southbound =
422                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
423         neutronNetworkCache =
424                 (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
425         configurationService =
426                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
427         securityServicesManager =
428                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
429     }
430
431     @Override
432     public void setDependencies(Object impl) {
433         if (impl instanceof INeutronPortCRUD) {
434             neutronPortCache = (INeutronPortCRUD)impl;
435         } else if (impl instanceof INeutronSubnetCRUD) {
436             neutronSubnetCache = (INeutronSubnetCRUD) impl;
437         } else if (impl instanceof IngressAclProvider) {
438             ingressAclProvider = (IngressAclProvider) impl;
439         } else if (impl instanceof EgressAclProvider) {
440             egressAclProvider = (EgressAclProvider) impl;
441         }
442     }
443 }