Added support for remote security group update.
[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.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     private static final Logger LOG = LoggerFactory.getLogger(TenantNetworkManagerImpl.class);
40     private volatile INeutronPortCRUD neutronPortCache;
41     private volatile INeutronSubnetCRUD neutronSubnetCache;
42     private volatile Southbound southbound;
43     private volatile INeutronNetworkCRUD neutronNetworkCache;
44     private volatile ConfigurationService configurationService;
45     private volatile IngressAclProvider ingressAclProvider;
46     private volatile EgressAclProvider egressAclProvider;
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(String portUuid, 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                 if (portUuid.equals(neutronPort.getID())) {
316                     continue;
317                 }
318                 List<NeutronSecurityGroup> securityGroups = neutronPort.getSecurityGroups();
319                 if (null != securityGroups) {
320                     for (NeutronSecurityGroup securityGroup:securityGroups) {
321                         if (securityGroup.getSecurityGroupUUID().equals(securityGroupUuid)) {
322                             LOG.debug("getVMListForSecurityGroup : adding ports with ips {} "
323                                     + "compute port", neutronPort.getFixedIPs());
324                             vmListForSecurityGroup.addAll(neutronPort.getFixedIPs());
325                         }
326                     }
327                 }
328
329             }
330         } catch (Exception e) {
331             LOG.error("getVMListForSecurityGroup: getVMListForSecurityGroup"
332                     + " failed due to ", e);
333             return null;
334         }
335         return vmListForSecurityGroup;
336
337     }
338
339     @Override
340     public void syncSecurityGroup(NeutronPort port, List<NeutronSecurityGroup> securityGroupList, boolean write) {
341         LOG.trace("syncSecurityGroup:" + securityGroupList + " Write:" + Boolean.valueOf(write));
342         if (null != port && null != port.getSecurityGroups()) {
343             Node node = getNode(port);
344             NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
345             String segmentationId = neutronNetwork.getProviderSegmentationID();
346             OvsdbTerminationPointAugmentation intf = getInterface(node, port);
347             long localPort = southbound.getOFPort(intf);
348             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
349             if (attachedMac == null) {
350                 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
351                 return;
352             }
353             long dpid = getDpidOfIntegrationBridge(node);
354             String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
355                                                                            Constants.EXTERNAL_ID_INTERFACE_ID);
356             for (NeutronSecurityGroup securityGroupInPort:securityGroupList) {
357                 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
358                                                           securityGroupInPort, neutronPortId, write);
359                 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
360                                                          securityGroupInPort, neutronPortId, write);
361             }
362         }
363     }
364
365     @Override
366     public void syncSecurityRule(NeutronPort port, NeutronSecurityRule securityRule,Neutron_IPs vmIp, boolean write) {
367         LOG.trace("syncSecurityGroup:" + securityRule + " Write:" + Boolean.valueOf(write));
368         if (null != port && null != port.getSecurityGroups()) {
369             Node node = getNode(port);
370             NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
371             String segmentationId = neutronNetwork.getProviderSegmentationID();
372             OvsdbTerminationPointAugmentation intf = getInterface(node, port);
373             long localPort = southbound.getOFPort(intf);
374             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
375             if (attachedMac == null) {
376                 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
377                 return;
378             }
379             long dpid = getDpidOfIntegrationBridge(node);
380             if ("IPv4".equals(securityRule.getSecurityRuleEthertype())
381                     && "ingress".equals(securityRule.getSecurityRuleDirection())) {
382
383                 ingressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
384                                                            securityRule, vmIp, write);
385             } else if (securityRule.getSecurityRuleEthertype().equals("IPv4")
386                     && securityRule.getSecurityRuleDirection().equals("egress")) {
387                 egressAclProvider.programPortSecurityRule(dpid, segmentationId, attachedMac, localPort,
388                                                           securityRule, vmIp, write);
389             }
390         }
391     }
392
393     private long getDpidOfIntegrationBridge(Node node) {
394         LOG.trace("getDpidOfIntegrationBridge:" + node);
395         long dpid = 0L;
396         if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
397             dpid = getDpid(node);
398         }
399         return dpid;
400     }
401
402     private long getDpid(Node node) {
403         LOG.trace("getDpid" + node);
404         long dpid = southbound.getDataPathId(node);
405         if (dpid == 0) {
406             LOG.warn("getDpid: dpid not found: {}", node);
407         }
408         return dpid;
409     }
410
411     private Node getNode(NeutronPort port) {
412         LOG.trace("getNode:Port" + port);
413         List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
414
415         for (Node topologyNode : toplogyNodes) {
416             try {
417                 Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
418                 List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
419                 for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
420                     String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
421                                                             Constants.EXTERNAL_ID_INTERFACE_ID);
422                     if (null != uuid && uuid.equals(port.getID())) {
423                         return node;
424                     }
425                 }
426             } catch (Exception e) {
427                 LOG.error("Exception during handlingNeutron network delete", e);
428             }
429         }
430         return null;
431     }
432
433     private OvsdbTerminationPointAugmentation getInterface(Node node, NeutronPort port) {
434         LOG.trace("getInterface:Node:" + node + " Port:" + port);
435         try {
436             List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
437             for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
438                 String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
439                                                                       Constants.EXTERNAL_ID_INTERFACE_ID);
440                 if (null != uuid && uuid.equals(port.getID())) {
441                     return ovsdbPort;
442                 }
443             }
444         } catch (Exception e) {
445             LOG.error("Exception during handlingNeutron network delete", e);
446         }
447         return null;
448     }
449
450     @Override
451     public void setDependencies(ServiceReference serviceReference) {
452         southbound =
453                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
454         neutronNetworkCache =
455                 (INeutronNetworkCRUD) ServiceHelper.getGlobalInstance(INeutronNetworkCRUD.class, this);
456         configurationService =
457                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
458     }
459
460     @Override
461     public void setDependencies(Object impl) {
462         if (impl instanceof INeutronPortCRUD) {
463             neutronPortCache = (INeutronPortCRUD)impl;
464         } else if (impl instanceof INeutronSubnetCRUD) {
465             neutronSubnetCache = (INeutronSubnetCRUD) impl;
466         } else if (impl instanceof IngressAclProvider) {
467             ingressAclProvider = (IngressAclProvider) impl;
468         } else if (impl instanceof EgressAclProvider) {
469             egressAclProvider = (EgressAclProvider) impl;
470         }
471     }
472 }