Bug 7606: Fix for missed tunnel flows, after VM live migration
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / netvirt / openstack / netvirt / impl / SecurityGroupCacheManagerImpl.java
1 /*
2  * Copyright © 2014, 2017 HP, 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.netvirt.openstack.netvirt.impl;
10
11 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
12 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityGroupCRUD;
13 import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
14 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
15 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityGroupCacheManger;
16 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
17 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
18 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
19 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
20 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityRule;
21 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
22 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSecurityRuleCRUD;
23 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
25 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
26 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
27 import org.osgi.framework.ServiceReference;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 import java.util.ArrayList;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.HashMap;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.ConcurrentHashMap;
38
39
40 /**
41  * @author Aswin Suryanarayanan.
42  */
43
44 public class SecurityGroupCacheManagerImpl implements ConfigInterface, SecurityGroupCacheManger {
45
46     private final Map<String, Map<String, NodeId>> securityGroupCache = new ConcurrentHashMap<>();
47     private static final Logger LOG = LoggerFactory.getLogger(SecurityGroupCacheManagerImpl.class);
48     private volatile SecurityServicesManager securityServicesManager;
49     private volatile Southbound southbound;
50     private volatile INeutronPortCRUD neutronPortCache;
51     private volatile NeutronL3Adapter neutronL3Adapter;
52     private volatile INeutronSecurityRuleCRUD neutronSecurityRule;
53
54     @Override
55     public void portAdded(String securityGroupUuid, String portUuid) {
56         LOG.debug("In portAdded securityGroupUuid: {} portUuid: {} " , securityGroupUuid, portUuid);
57         NeutronPort port = neutronL3Adapter.getPortPreferablyFromCleanupCache(portUuid);
58         if(port == null) {
59             return;
60         }
61         processPortAdded(securityGroupUuid, port);
62     }
63
64     @Override
65     public void portRemoved(String securityGroupUuid, String portUuid) {
66         LOG.debug("In portRemoved securityGroupUuid: {} portUuid: {} " , securityGroupUuid, portUuid);
67         NeutronPort port = neutronL3Adapter.getPortPreferablyFromCleanupCache(portUuid);
68         if(port == null) {
69             return;
70         }
71         processPortRemoved(securityGroupUuid, port);
72     }
73
74     @Override
75     public void addToCache(String remoteSgUuid, String portUuid, NodeId nodeId) {
76         LOG.debug("In addToCache remoteSgUuid:" + remoteSgUuid + " portUuid:" + portUuid);
77         Map<String, NodeId> remoteSgPorts = securityGroupCache.computeIfAbsent(remoteSgUuid, k -> new HashMap<>());
78         remoteSgPorts.put(portUuid, nodeId);
79     }
80
81     @Override
82     public void removeFromCache(String remoteSgUuid, String portUuid, NodeId nodeId) {
83         LOG.debug("In removeFromCache remoteSgUuid:" + remoteSgUuid + " portUuid:" + portUuid);
84         Map<String, NodeId> remoteSgPorts = securityGroupCache.get(remoteSgUuid);
85         if (null == remoteSgPorts) {
86             LOG.debug("The port list is empty for security group:" + remoteSgUuid);
87             return;
88         }
89         Set<String> portSet = remoteSgPorts.keySet();
90         for (Iterator<String> iterator = portSet.iterator(); iterator.hasNext();) {
91             String cachedPort = iterator.next();
92             if (cachedPort.equals(portUuid)) {
93                 NodeId cachedNodeId = remoteSgPorts.get(cachedPort);
94                 if(cachedNodeId.equals(nodeId)) {
95                     iterator.remove();
96                     break;
97                 }
98             }
99         }
100         if (portSet.isEmpty()) {
101             securityGroupCache.remove(remoteSgUuid);
102         }
103     }
104
105     private void processPortAdded(String securityGroupUuid, NeutronPort port) {
106         processSyncRule(securityGroupUuid, port, true);
107     }
108
109     private void processSyncRule(String securityGroupUuid, NeutronPort port, boolean write) {
110         /*
111          * Itreate through the cache maintained for the security group added. For each port in the cache
112          * add the rule to allow traffic to/from the new port added.
113          */
114         LOG.debug("In processPortAdded securityGroupUuid: {}, NeutronPort: {}", securityGroupUuid, port);
115         Map<String, NodeId> portMap = securityGroupCache.get(securityGroupUuid);
116         if (null == portMap) {
117             LOG.debug("The port list is empty for security group: {}", securityGroupUuid);
118             return;
119         }
120         Set portSet = portMap.entrySet();
121         Iterator itr = portSet.iterator();
122         Map<String, List<NeutronSecurityRule>> secGrpRulesMap = new HashMap<String, List<NeutronSecurityRule>>();
123         while(itr.hasNext()) {
124             Map.Entry<String, NodeId> portEntry = (Map.Entry)itr.next();
125             String cachedportUuid = portEntry.getKey();
126             NodeId nodeId = portEntry.getValue();
127             if (cachedportUuid.equals(port.getID())) {
128                 continue;
129             }
130             NeutronPort cachedport = neutronL3Adapter.getPortPreferablyFromCleanupCache(cachedportUuid);
131             if(cachedport == null) {
132                 continue;
133             }
134             retrieveAndSyncSecurityRules(securityGroupUuid, cachedport, nodeId, secGrpRulesMap, port, write);
135         }
136     }
137
138     private void processPortRemoved(String securityGroupUuid, NeutronPort port) {
139         processSyncRule(securityGroupUuid, port, false);
140     }
141
142     private void retrieveAndSyncSecurityRules(String securityGroupUuid, NeutronPort cachedport, NodeId nodeId,
143             Map<String, List<NeutronSecurityRule> > secGrpRulesMap, NeutronPort currentPort, boolean write) {
144         /*
145          * Get the list of security rules in the port with portUuid that has securityGroupUuid as a remote
146          * security group.
147          */
148         List<NeutronSecurityRule> securityRules =  new ArrayList<NeutronSecurityRule>();
149         List<NeutronSecurityGroup> securityGroups = cachedport.getSecurityGroups();
150         for (NeutronSecurityGroup securityGroup : securityGroups) {
151             securityRules = secGrpRulesMap.get(securityGroup.getSecurityGroupUUID());
152             if (securityRules == null) {
153                 securityRules = getSecurityRulesforGroup(securityGroup);
154                 secGrpRulesMap.put(securityGroup.getSecurityGroupUUID(), securityRules);
155             }
156             for (NeutronSecurityRule securityRule : securityRules) {
157                 if (securityGroupUuid.equals(securityRule.getSecurityRemoteGroupID())) {
158                     if (currentPort.getFixedIPs() == null) {
159                         continue;
160                     }
161                     for (Neutron_IPs vmIp : currentPort.getFixedIPs()) {
162                         if (write) {
163                             securityServicesManager.syncSecurityRule(cachedport, securityRule, vmIp, nodeId, securityGroup, true);
164                         } else {
165                             securityServicesManager.syncSecurityRule(cachedport, securityRule, vmIp, nodeId, securityGroup, false);
166                         }
167                     }
168                 }
169             }
170         }
171     }
172
173     private void init() {
174         /*
175          * Rebuild the cache in case of a restart.
176          */
177         Map<String, NodeId> portNodeCache = getPortNodeCache();
178         List<NeutronPort> portList = neutronPortCache.getAllPorts();
179         for (NeutronPort port:portList) {
180             List<NeutronSecurityGroup> securityGroupList = port.getSecurityGroups();
181             if ( null != securityGroupList) {
182                 for (NeutronSecurityGroup securityGroup : securityGroupList) {
183                     List<NeutronSecurityRule> securityRuleList = getSecurityRulesforGroup(securityGroup);
184                     if ( null != securityRuleList) {
185                         for (NeutronSecurityRule securityRule : securityRuleList) {
186                             if (null != securityRule.getSecurityRemoteGroupID()) {
187                                 this.addToCache(securityRule.getSecurityRemoteGroupID(), port.getID(), portNodeCache.get(port.getID()));
188                             }
189                         }
190                     }
191                 }
192             }
193         }
194     }
195
196     private Map<String, NodeId> getPortNodeCache() {
197         Map<String, NodeId> portNodeCache = new HashMap();
198         List<Node> toplogyNodes = southbound.readOvsdbTopologyNodes();
199
200         for (Node topologyNode : toplogyNodes) {
201             try {
202                 Node node = southbound.getBridgeNode(topologyNode,Constants.INTEGRATION_BRIDGE);
203                 if (node == null) {
204                     LOG.error("getNode: br-int interface is not found for node:{}", topologyNode.getNodeId().getValue());
205                 }
206                 List<OvsdbTerminationPointAugmentation> ovsdbPorts = southbound.getTerminationPointsOfBridge(node);
207                 for (OvsdbTerminationPointAugmentation ovsdbPort : ovsdbPorts) {
208                     String uuid = southbound.getInterfaceExternalIdsValue(ovsdbPort,
209                                                             Constants.EXTERNAL_ID_INTERFACE_ID);
210                     NodeId nodeId = node.getNodeId();
211                     if (null != uuid && null != nodeId) {
212                         portNodeCache.put(uuid, nodeId);
213                     }
214                 }
215             } catch (Exception e) {
216                 LOG.error("Exception during handlingNeutron network delete", e);
217             }
218         }
219         return portNodeCache;
220     }
221
222     private List<NeutronSecurityRule> getSecurityRulesforGroup(NeutronSecurityGroup securityGroup) {
223         List<NeutronSecurityRule> securityRules = new ArrayList<>();
224         List<NeutronSecurityRule> rules = neutronSecurityRule.getAllNeutronSecurityRules();
225         for (NeutronSecurityRule securityRule : rules) {
226             if (securityGroup.getID().equals(securityRule.getSecurityRuleGroupID())) {
227                 securityRules.add(securityRule);
228             }
229         }
230         return securityRules;
231     }
232
233     @Override
234     public void setDependencies(ServiceReference serviceReference) {
235         neutronL3Adapter =
236                 (NeutronL3Adapter) ServiceHelper.getGlobalInstance(NeutronL3Adapter.class, this);
237         securityServicesManager =
238                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
239         southbound =
240                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
241         neutronPortCache = (INeutronPortCRUD) ServiceHelper.getGlobalInstance(INeutronPortCRUD.class, this);
242         neutronSecurityRule = (INeutronSecurityRuleCRUD) ServiceHelper.getGlobalInstance(INeutronSecurityRuleCRUD.class, this);
243         init();
244     }
245
246     @Override
247     public void setDependencies(Object impl) {
248     }
249 }