Merge "Revert "Added cluster aware mdsal utils class to net-virt.""
[ovsdb.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.NeutronSecurityRule;
22 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSubnet;
23 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
24 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
25 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronPortCRUD;
26 import org.opendaylight.ovsdb.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
27 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
29 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
30 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
31 import org.osgi.framework.ServiceReference;
32 import org.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34
35 import java.util.ArrayList;
36 import java.util.List;
37
38 public class SecurityServicesImpl implements ConfigInterface, SecurityServicesManager {
39
40     private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
41     private volatile INeutronPortCRUD neutronPortCache;
42     private volatile INeutronSubnetCRUD neutronSubnetCache;
43     private volatile Southbound southbound;
44     private volatile INeutronNetworkCRUD neutronNetworkCache;
45     private volatile ConfigurationService configurationService;
46     private volatile IngressAclProvider ingressAclProvider;
47     private volatile EgressAclProvider egressAclProvider;
48     private boolean isConntrackEnabled = false;
49
50     public SecurityServicesImpl() {
51         super();
52     }
53
54     public SecurityServicesImpl(boolean isConntrack) {
55         super();
56         this.isConntrackEnabled = isConntrack;
57     }
58
59     @Override
60     public boolean isPortSecurityReady(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
61         if (neutronPortCache == null) {
62             LOG.error("neutron port is null");
63             return false;
64         }
65         LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName());
66         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
67                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
68         if (neutronPortId == null) {
69             return false;
70         }
71         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
72         if (neutronPort == null) {
73             return false;
74         }
75         String deviceOwner = neutronPort.getDeviceOwner();
76         if (!deviceOwner.contains("compute")) {
77             LOG.debug("Port {} is not a compute host, it is a: {}", neutronPortId, deviceOwner);
78         }
79         LOG.debug("isPortSecurityReady() is a {} ", deviceOwner);
80         List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
81         if (securityGroups.isEmpty()) {
82             LOG.debug("Check for device: {} does not contain a Security Group for port: {}", deviceOwner,
83                       neutronPortId);
84             return false;
85         }
86         LOG.debug("Security Group Check {} does contain a Neutron Security Group", neutronPortId);
87         return true;
88     }
89
90     @Override
91     public List<NeutronSecurityGroup> getSecurityGroupInPortList(OvsdbTerminationPointAugmentation
92                                                              terminationPointAugmentation) {
93         List<NeutronSecurityGroup> neutronSecurityGroups = new ArrayList<>();
94         if (neutronPortCache == null) {
95             LOG.error("neutron port is null");
96             return neutronSecurityGroups;
97         }
98         LOG.trace("isPortSecurityReady for {}", terminationPointAugmentation.getName());
99         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
100                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
101         if (neutronPortId == null) {
102             return neutronSecurityGroups;
103         }
104         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
105         if (neutronPort == null) {
106             return neutronSecurityGroups;
107         }
108         neutronSecurityGroups = neutronPort.getSecurityGroups();
109         return neutronSecurityGroups;
110
111     }
112
113     @Override
114     public NeutronPort getDhcpServerPort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
115         if (neutronPortCache == null) {
116             LOG.error("getDHCPServerPort: neutron port is null");
117             return null;
118         }
119         LOG.trace("getDHCPServerPort for {}",
120                   terminationPointAugmentation.getName());
121         try {
122             String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
123                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
124             if (neutronPortId == null) {
125                 return null;
126             }
127             NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
128             if (neutronPort == null) {
129                 LOG.error("getDHCPServerPort: neutron port of {} is not found", neutronPortId);
130                 return null;
131             }
132             /* if the current port is a DHCP port, return the same*/
133             if (neutronPort.getDeviceOwner().contains("dhcp")) {
134                 return neutronPort;
135             }
136             /*Since all the fixed ip assigned to a port should be
137              *from the same network, first port is sufficient.*/
138             List<Neutron_IPs> fixedIps = neutronPort.getFixedIPs();
139             if (null == fixedIps || 0 == fixedIps.size() ) {
140                 LOG.error("getDHCPServerPort: No fixed ip is assigned");
141                 return null;
142             }
143             /* Get all the ports in the subnet and identify the dhcp port*/
144             String subnetUuid = fixedIps.iterator().next().getSubnetUUID();
145             NeutronSubnet neutronSubnet = neutronSubnetCache.getSubnet(subnetUuid);
146             if (neutronSubnet == null) {
147                 LOG.error("getDHCPServerPort: No subnet is found for " + subnetUuid);
148                 return null;
149             }
150             List<NeutronPort> ports = neutronSubnet.getPortsInSubnet();
151             for (NeutronPort port : ports) {
152                 if (port.getDeviceOwner().contains("dhcp")) {
153                     return port;
154                 }
155             }
156         } catch (Exception e) {
157             LOG.error("getDHCPServerPort:getDHCPServerPort failed due to ", e);
158             return null;
159         }
160         return null;
161     }
162
163     @Override
164     public NeutronPort getNeutronPortFromDhcpIntf(
165             OvsdbTerminationPointAugmentation terminationPointAugmentation) {
166         if (neutronPortCache == null) {
167             LOG.error("getNeutronPortFromDhcpIntf: neutron port is null");
168             return null;
169         }
170         String neutronPortId = southbound.getInterfaceExternalIdsValue(
171                 terminationPointAugmentation,
172                 Constants.EXTERNAL_ID_INTERFACE_ID);
173         if (neutronPortId == null) {
174             return null;
175         }
176         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
177         if (neutronPort == null) {
178             LOG.error("getNeutronPortFromDhcpIntf: neutron port of {} is not found", neutronPortId);
179             return null;
180         }
181         /* if the current port is a DHCP port, return true*/
182         if (neutronPort.getDeviceOwner().contains("dhcp")) {
183             LOG.trace("getNeutronPortFromDhcpIntf: neutronPort is a dhcp port", neutronPort );
184             return neutronPort;
185         }
186         return null;
187     }
188
189     @Override
190     public boolean isComputePort(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
191         if (neutronPortCache == null) {
192             LOG.error("neutron port is null");
193             return false;
194         }
195         LOG.trace("isComputePort for {}", terminationPointAugmentation.getName());
196         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
197                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
198         if (neutronPortId == null) {
199             return false;
200         }
201         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
202         if (neutronPort == null) {
203             return false;
204         }
205         /*Check the device owner and if it contains compute to identify
206          * whether it is a compute port.*/
207         String deviceOwner = neutronPort.getDeviceOwner();
208         if (!deviceOwner.contains("compute")) {
209             LOG.debug("isComputePort : Port {} is not a DHCP server port for device owner {}",
210                       neutronPortId,deviceOwner);
211             return false;
212         }
213         return true;
214     }
215
216     @Override
217     public boolean isLastPortinSubnet(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
218         if (neutronPortCache == null) {
219             LOG.error("isLastPortinSubnet: neutron port is null");
220             return false;
221         }
222         try {
223             LOG.trace("isLastPortinSubnet: for {}", terminationPointAugmentation.getName());
224             String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
225                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
226             if (neutronPortId == null) {
227                 return false;
228             }
229             NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
230             if (neutronPort == null) {
231                 LOG.error("isLastPortinSubnet: neutron port of {} is not found", neutronPortId);
232                 return false;
233             }
234             List<Neutron_IPs> neutronPortFixedIp = neutronPort.getFixedIPs();
235             if (null == neutronPortFixedIp || neutronPortFixedIp.isEmpty()) {
236                 return false;
237             }
238             /*Get all the ports in the current node and check whether there
239              * is any port belonging to the same subnet of the input
240              */
241             List<TerminationPoint> terminationPoints = node.getTerminationPoint();
242             if (terminationPoints != null && !terminationPoints.isEmpty()) {
243                 for (TerminationPoint tp : terminationPoints) {
244                     OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
245                             tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
246                     if (ovsdbTerminationPointAugmentation != null && !ovsdbTerminationPointAugmentation
247                             .getName().equals(Constants.INTEGRATION_BRIDGE)) {
248                         String portId = southbound.getInterfaceExternalIdsValue(ovsdbTerminationPointAugmentation,
249                                                                                 Constants.EXTERNAL_ID_INTERFACE_ID);
250                         if (null != portId) {
251                             NeutronPort port = neutronPortCache.getPort(portId);
252                             if (null != port && !(port.getID().equals(neutronPort.getID()))
253                                     && port.getDeviceOwner().contains("compute")) {
254                                 List<Neutron_IPs> portFixedIp = port.getFixedIPs();
255                                 if (null == portFixedIp || portFixedIp.isEmpty()) {
256                                     return false;
257                                 }
258                                 if (portFixedIp.iterator().next().getSubnetUUID()
259                                         .equals(neutronPort.getFixedIPs().iterator().next().getSubnetUUID())) {
260                                     LOG.trace("isLastPortinSubnet: Port is not the only port.");
261                                     return false;
262                                 }
263                             }
264                         }
265                     }
266                 }
267             }
268         } catch (Exception e) {
269             LOG.error("isLastPortinSubnet: isLastPortinSubnet failed due to ", e);
270             return false;
271         }
272         return true;
273     }
274
275     @Override
276     public boolean isLastPortinBridge(Node node, OvsdbTerminationPointAugmentation terminationPointAugmentation) {
277         LOG.trace("isLastPortinBridge: for {}", terminationPointAugmentation.getName());
278         List<TerminationPoint> terminationPoints = node.getTerminationPoint();
279         /*Check whether the node has any port other than br-int*/
280         if (terminationPoints != null && !terminationPoints.isEmpty()) {
281             for (TerminationPoint tp : terminationPoints) {
282                 OvsdbTerminationPointAugmentation ovsdbTerminationPointAugmentation =
283                         tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
284                 if (null != ovsdbTerminationPointAugmentation
285                         && !(ovsdbTerminationPointAugmentation.getName().equals(Constants.INTEGRATION_BRIDGE))
286                         && !(terminationPointAugmentation.getInterfaceUuid()
287                         .equals(ovsdbTerminationPointAugmentation.getInterfaceUuid()))) {
288                     LOG.debug("isLastPortinBridge: it the last port in bridge {}",
289                             terminationPointAugmentation.getName());
290                     return false;
291                 }
292             }
293         }
294         return true;
295     }
296
297     @Override
298     public List<Neutron_IPs> getIpAddressList(OvsdbTerminationPointAugmentation terminationPointAugmentation) {
299         if (neutronPortCache == null) {
300             LOG.error("getIpAddress: neutron port is null");
301             return null;
302         }
303         LOG.trace("getIpAddress: for {}", terminationPointAugmentation.getName());
304         String neutronPortId = southbound.getInterfaceExternalIdsValue(terminationPointAugmentation,
305                                                                        Constants.EXTERNAL_ID_INTERFACE_ID);
306         if (neutronPortId == null) {
307             return null;
308         }
309         NeutronPort neutronPort = neutronPortCache.getPort(neutronPortId);
310         if (neutronPort == null) {
311             LOG.error("getIpAddress: neutron port of {} is not found", neutronPortId);
312             return null;
313         }
314         return neutronPort.getFixedIPs();
315     }
316
317     @Override
318     public List<Neutron_IPs> getVmListForSecurityGroup(String portUuid, String securityGroupUuid) {
319         List<Neutron_IPs> vmListForSecurityGroup = new ArrayList<>();
320         /*For every port check whether security grouplist contains the current
321          * security group.*/
322         try {
323             for (NeutronPort neutronPort:neutronPortCache.getAllPorts()) {
324                 if (!neutronPort.getDeviceOwner().contains("compute")) {
325                     LOG.debug("getVMListForSecurityGroup : the port {} is not "
326                             + "compute port belongs to {}", neutronPort.getID(), neutronPort.getDeviceOwner());
327                     continue;
328                 }
329                 if (portUuid.equals(neutronPort.getID())) {
330                     continue;
331                 }
332                 List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
333                 if (null != securityGroups) {
334                     for (NeutronSecurityGroup securityGroup:securityGroups) {
335                         if (securityGroup.getSecurityGroupUUID().equals(securityGroupUuid)) {
336                             LOG.debug("getVMListForSecurityGroup : adding ports with ips {} "
337                                     + "compute port", neutronPort.getFixedIPs());
338                             if (neutronPort.getFixedIPs() != null) {
339                                 vmListForSecurityGroup.addAll(neutronPort.getFixedIPs());
340                             }
341                         }
342                     }
343                 }
344
345             }
346         } catch (Exception e) {
347             LOG.error("getVMListForSecurityGroup: getVMListForSecurityGroup"
348                     + " failed due to ", e);
349             return null;
350         }
351         return vmListForSecurityGroup;
352
353     }
354
355     @Override
356     public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
357         LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + write);
358         if (null != port && null != port.getSecurityGroups()) {
359             Node node = getNode(port);
360             if (node == null) {
361                 return;
362             }
363             NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
364             if (neutronNetwork == null) {
365                 return;
366             }
367             String segmentationId = neutronNetwork.getProviderSegmentationID();
368             OvsdbTerminationPointAugmentation intf = getInterface(node, port);
369             if (intf == null) {
370                 return;
371             }
372             long localPort = southbound.getOFPort(intf);
373             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
374             if (attachedMac == null) {
375                 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
376                 return;
377             }
378             long dpid = getDpidOfIntegrationBridge(node);
379             if (dpid == 0L) {
380                 return;
381             }
382             String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
383                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
384             if (neutronPortId == null) {
385                 LOG.debug("syncSecurityGroup: No neutronPortId seen in {}", intf);
386                 return;
387             }
388             for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
389                 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
390                                                           securityGroupInPort, neutronPortId, write);
391                 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
392                                                          securityGroupInPort, neutronPortId, write);
393             }
394         }
395     }
396
397     @Override
398     public void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write) {
399         LOG.trace("syncSecurityGroup:" + securityRule + " Write:" + write);
400         if (null != port && null != port.getSecurityGroups()) {
401             Node node = getNode(port);
402             if (node == null) {
403                 return;
404             }
405             NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
406             if (neutronNetwork == null) {
407                 return;
408             }
409             String segmentationId = neutronNetwork.getProviderSegmentationID();
410             OvsdbTerminationPointAugmentation intf = getInterface(node, port);
411             if (intf == null) {
412                 return;
413             }
414             long localPort = southbound.getOFPort(intf);
415             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
416             if (attachedMac == null) {
417                 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
418                 return;
419             }
420             long dpid = getDpidOfIntegrationBridge(node);
421             if (dpid == 0L) {
422                 return;
423             }
424             if ("IPv4".equals(securityRule.getSecurityRuleEthertype())
425                     && "ingress".equals(securityRule.getSecurityRuleDirection())) {
426
427                 ingressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
428                                                            securityRule, vmIp, write);
429             } else if (securityRule.getSecurityRuleEthertype().equals("IPv4")
430                     && securityRule.getSecurityRuleDirection().equals("egress")) {
431                 egressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
432                                                           securityRule, vmIp, write);
433             }
434         }
435     }
436
437     private long getDpidOfIntegrationBridge(Node node) {
438         LOG.trace("getDpidOfIntegrationBridge:" + node);
439         long dpid = 0L;
440         if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
441             dpid = getDpid(node);
442         }
443         if (dpid == 0L) {
444             LOG.warn("getDpidOfIntegerationBridge: dpid not found: {}", node);
445         }
446         return dpid;
447     }
448
449     private long getDpid(Node node) {
450         LOG.trace("getDpid" + node);
451         long dpid = southbound.getDataPathId(node);
452         if (dpid == 0) {
453             LOG.warn("getDpid: dpid not found: {}", node);
454         }
455         return dpid;
456     }
457
458     private Node getNode(NeutronPort port) {
459         LOG.trace("getNode:Port" + port);
460         List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
461
462         for (Node topologyNode : toplogyNodes) {
463             try {
464                 Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
465                 List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
466                 for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
467                     String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
468                                                             Constants.EXTERNAL_ID_INTERFACE_ID);
469                     if (null != uuid && uuid.equals(port.getID())) {
470                         return node;
471                     }
472                 }
473             } catch (Exception e) {
474                 LOG.error("Exception during handlingNeutron network delete", e);
475             }
476         }
477         LOG.info("no node found for port:" + port);
478         return null;
479     }
480
481     private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
482         LOG.trace("getInterface:Node:" + node + " Port:" + port);
483         try {
484             List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
485             for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
486                 String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
487                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
488                 if (null != uuid && uuid.equals(port.getID())) {
489                     return ovsdbPort;
490                 }
491             }
492         } catch (Exception e) {
493             LOG.error("Exception during handlingNeutron network delete", e);
494         }
495         LOG.info("no interface found for node: " + node + " port:" + port);
496         return null;
497     }
498
499     @Override
500     public void setDependencies(ServiceReference serviceReference) {
501         southbound =
502                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
503         neutronNetworkCache =
504                 (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
505         configurationService =
506                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
507     }
508
509     @Override
510     public void setDependencies(Object impl) {
511         if (impl instanceof INeutronPortCRUD) {
512             neutronPortCache = (INeutronPortCRUD)impl;
513         } else if (impl instanceof INeutronSubnetCRUD) {
514             neutronSubnetCache = (INeutronSubnetCRUD) impl;
515         } else if (impl instanceof IngressAclProvider) {
516             ingressAclProvider = (IngressAclProvider) impl;
517         } else if (impl instanceof EgressAclProvider) {
518             egressAclProvider = (EgressAclProvider) impl;
519         }
520     }
521
522     @Override
523     public boolean isConntrackEnabled() {
524         return isConntrackEnabled;
525     }
526 }