990dc709e30a8e82519ad76189794d978ead0e6f
[netvirt.git] / openstack / net-virt / src / main / java / org / opendaylight / netvirt / openstack / netvirt / impl / NeutronL3Adapter.java
1 /*
2  * Copyright (c) 2014 - 2016 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.netvirt.openstack.netvirt.impl;
10
11 import static org.opendaylight.netvirt.openstack.netvirt.api.Action.ADD;
12 import static org.opendaylight.netvirt.openstack.netvirt.api.Action.DELETE;
13 import static org.opendaylight.netvirt.openstack.netvirt.api.Action.UPDATE;
14
15 import com.google.common.base.Preconditions;
16 import org.apache.commons.lang3.tuple.ImmutablePair;
17 import org.apache.commons.lang3.tuple.Pair;
18 import org.opendaylight.netvirt.openstack.netvirt.AbstractEvent;
19 import org.opendaylight.netvirt.openstack.netvirt.AbstractHandler;
20 import org.opendaylight.netvirt.openstack.netvirt.ConfigInterface;
21 import org.opendaylight.netvirt.openstack.netvirt.NeutronL3AdapterEvent;
22 import org.opendaylight.netvirt.openstack.netvirt.api.Action;
23 import org.opendaylight.netvirt.openstack.netvirt.api.ArpProvider;
24 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
25 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
26 import org.opendaylight.netvirt.openstack.netvirt.api.EventDispatcher;
27 import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolver;
28 import org.opendaylight.netvirt.openstack.netvirt.api.GatewayMacResolverListener;
29 import org.opendaylight.netvirt.openstack.netvirt.api.IcmpEchoProvider;
30 import org.opendaylight.netvirt.openstack.netvirt.api.InboundNatProvider;
31 import org.opendaylight.netvirt.openstack.netvirt.api.L3ForwardingProvider;
32 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
33 import org.opendaylight.netvirt.openstack.netvirt.api.OutboundNatProvider;
34 import org.opendaylight.netvirt.openstack.netvirt.api.RoutingProvider;
35 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
36 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
37 import org.opendaylight.netvirt.openstack.netvirt.api.Status;
38 import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
39 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
40 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronFloatingIP;
41 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
42 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter;
43 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronRouter_Interface;
44 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
45 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
46 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronFloatingIPCRUD;
47 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronNetworkCRUD;
48 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronPortCRUD;
49 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
50 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSubnet;
51 import org.opendaylight.netvirt.openstack.netvirt.translator.crud.INeutronSubnetCRUD;
52 import org.opendaylight.netvirt.openstack.netvirt.translator.iaware.impl.NeutronIAwareUtil;
53 import org.opendaylight.netvirt.utils.neutron.utils.NeutronModelsDataStoreHelper;
54 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
55 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Ipv4Address;
57 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev100924.MacAddress;
58 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.Routers;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.l3.rev150712.routers.attributes.routers.Router;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.Ports;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
64 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
65 import org.osgi.framework.ServiceReference;
66 import org.slf4j.Logger;
67 import org.slf4j.LoggerFactory;
68
69 import java.net.Inet4Address;
70 import java.net.InetAddress;
71 import java.net.UnknownHostException;
72 import java.util.ArrayList;
73 import java.util.Collection;
74 import java.util.HashMap;
75 import java.util.Iterator;
76 import java.util.List;
77 import java.util.Map;
78
79 /**
80  * Neutron L3 Adapter implements a hub-like adapter for the various Neutron events. Based on
81  * these events, the abstract router callbacks can be generated to the multi-tenant aware router,
82  * as well as the multi-tenant router forwarding provider.
83  */
84 public class NeutronL3Adapter extends AbstractHandler implements GatewayMacResolverListener, ConfigInterface {
85     private static final Logger LOG = LoggerFactory.getLogger(NeutronL3Adapter.class);
86
87     // The implementation for each of these services is resolved by the OSGi Service Manager
88     private volatile ConfigurationService configurationService;
89     private volatile TenantNetworkManager tenantNetworkManager;
90     private volatile NodeCacheManager nodeCacheManager;
91     private volatile INeutronNetworkCRUD neutronNetworkCache;
92     private volatile INeutronSubnetCRUD neutronSubnetCache;
93     private volatile INeutronPortCRUD neutronPortCache;
94     private volatile INeutronFloatingIPCRUD neutronFloatingIpCache;
95     private volatile L3ForwardingProvider l3ForwardingProvider;
96     private volatile InboundNatProvider inboundNatProvider;
97     private volatile OutboundNatProvider outboundNatProvider;
98     private volatile ArpProvider arpProvider;
99     private volatile RoutingProvider routingProvider;
100     private volatile GatewayMacResolver gatewayMacResolver;
101     private volatile SecurityServicesManager securityServicesManager;
102     private volatile IcmpEchoProvider icmpEchoProvider;
103
104     private class FloatIpData {
105         // br-int of node where floating ip is associated with tenant port
106         private final Long dpid;
107         // patch port in br-int used to reach br-ex
108         private final Long ofPort;
109         // segmentation id of the net where fixed ip is instantiated
110         private final String segId;
111         // mac address assigned to neutron port of floating ip
112         private final String macAddress;
113         private final String floatingIpAddress;
114         // ip address given to tenant vm
115         private final String fixedIpAddress;
116         private final String neutronRouterMac;
117
118         FloatIpData(final Long dpid, final Long ofPort, final String segId, final String macAddress,
119                     final String floatingIpAddress, final String fixedIpAddress, final String neutronRouterMac) {
120             this.dpid = dpid;
121             this.ofPort = ofPort;
122             this.segId = segId;
123             this.macAddress = macAddress;
124             this.floatingIpAddress = floatingIpAddress;
125             this.fixedIpAddress = fixedIpAddress;
126             this.neutronRouterMac = neutronRouterMac;
127         }
128     }
129
130     private Map<String, String> networkIdToRouterMacCache;
131     private Map<String, List<Neutron_IPs>> networkIdToRouterIpListCache;
132     private Map<String, NeutronRouter_Interface> subnetIdToRouterInterfaceCache;
133
134     private Map<String, Pair<Long, Uuid>> neutronPortToDpIdCache;
135     private Map<String, FloatIpData> floatIpDataMapCache;
136
137     private String externalRouterMac;
138     private Boolean enabled = false;
139     private Boolean isCachePopulationDone = false;
140     private Map<String, NeutronPort> portCleanupCache;
141     private Map<String, NeutronNetwork> networkCleanupCache;
142
143     private Southbound southbound;
144     private DistributedArpService distributedArpService;
145     private NeutronModelsDataStoreHelper neutronModelsDataStoreHelper;
146
147     private static final String OWNER_ROUTER_INTERFACE = "network:router_interface";
148     private static final String OWNER_ROUTER_INTERFACE_DISTRIBUTED = "network:router_interface_distributed";
149     private static final String OWNER_ROUTER_GATEWAY = "network:router_gateway";
150     private static final String OWNER_FLOATING_IP = "network:floatingip";
151     private static final String DEFAULT_EXT_RTR_MAC = "00:00:5E:00:01:01";
152
153     public NeutronL3Adapter(NeutronModelsDataStoreHelper neutronHelper) {
154         LOG.info(">>>>>> NeutronL3Adapter constructor {}", this.getClass());
155         this.neutronModelsDataStoreHelper = neutronHelper;
156     }
157
158     private void initL3AdapterMembers() {
159         Preconditions.checkNotNull(configurationService);
160
161         if (configurationService.isL3ForwardingEnabled()) {
162             this.networkIdToRouterMacCache = new HashMap<>();
163             this.networkIdToRouterIpListCache = new HashMap<>();
164             this.subnetIdToRouterInterfaceCache = new HashMap<>();
165             this.neutronPortToDpIdCache = new HashMap<>();
166             this.floatIpDataMapCache = new HashMap<>();
167
168             this.externalRouterMac = configurationService.getDefaultGatewayMacAddress(null);
169             if (this.externalRouterMac == null) {
170                 this.externalRouterMac = DEFAULT_EXT_RTR_MAC;
171             }
172             this.enabled = true;
173             LOG.info("OVSDB L3 forwarding is enabled");
174         } else {
175             LOG.debug("OVSDB L3 forwarding is disabled");
176         }
177         this.portCleanupCache = new HashMap<>();
178         this.networkCleanupCache = new HashMap<>();
179     }
180
181     //
182     // Callbacks from AbstractHandler
183     //
184     @Override
185     public void processEvent(AbstractEvent abstractEvent) {
186         if (!(abstractEvent instanceof NeutronL3AdapterEvent)) {
187             LOG.error("Unable to process abstract event " + abstractEvent);
188             return;
189         }
190         if (!this.enabled) {
191             return;
192         }
193
194         NeutronL3AdapterEvent ev = (NeutronL3AdapterEvent) abstractEvent;
195         switch (ev.getAction()) {
196             case UPDATE:
197                 if (ev.getSubType() == NeutronL3AdapterEvent.SubType.SUBTYPE_EXTERNAL_MAC_UPDATE) {
198                     updateExternalRouterMac( ev.getMacAddress().getValue() );
199                 } else {
200                     LOG.warn("Received update for an unexpected event " + ev);
201                 }
202                 break;
203             case ADD:
204                 // fall through...
205                 // break;
206             case DELETE:
207                 // fall through...
208                 // break;
209             default:
210                 LOG.warn("Unable to process event " + ev);
211                 break;
212         }
213     }
214
215     //
216     // Callbacks from GatewayMacResolverListener
217     //
218
219     @Override
220     public void gatewayMacResolved(Long externalNetworkBridgeDpid, IpAddress gatewayIpAddress, MacAddress macAddress) {
221         LOG.info("got gatewayMacResolved callback for ip {} on dpid {} to mac {}",
222                 gatewayIpAddress, externalNetworkBridgeDpid, macAddress);
223         if (!this.enabled) {
224             return;
225         }
226
227         if (macAddress == null || macAddress.getValue() == null) {
228             // TODO: handle cases when mac is null
229             return;
230         }
231
232         //
233         // Enqueue event so update is handled by adapter's thread
234         //
235         enqueueEvent( new NeutronL3AdapterEvent(externalNetworkBridgeDpid, gatewayIpAddress, macAddress) );
236     }
237
238     private void populateL3ForwardingCaches() {
239         if (!this.enabled) {
240             return;
241         }
242         if(this.isCachePopulationDone || this.neutronFloatingIpCache == null
243                 || this.neutronPortCache == null ||this.neutronNetworkCache == null) {
244             return;
245         }
246         this.isCachePopulationDone = true;
247         LOG.debug("Populating NetVirt L3 caches from data store configuration");
248         Routers routers = this.neutronModelsDataStoreHelper.readAllNeutronRouters();
249         Ports ports = this.neutronModelsDataStoreHelper.readAllNeutronPorts();
250         if(routers != null && routers.getRouter() != null && ports != null) {
251             LOG.debug("L3 Cache Population : {} Neutron router present in data store",routers.getRouter().size());
252             for( Router router : routers.getRouter()) {
253                 LOG.debug("L3 Cache Population : Populate caches for router {}",router);
254                 if(!ports.getPort().isEmpty()) {
255                     for( Port port : ports.getPort()) {
256                         if (port.getDeviceId().equals(router.getUuid().getValue()) &&
257                                 port.getDeviceOwner().equals(OWNER_ROUTER_INTERFACE)) {
258                             LOG.debug("L3 Cache Population : Router interface {} found.",port);
259                             networkIdToRouterMacCache.put(port.getNetworkId().getValue()
260                                     , port.getMacAddress().getValue());
261
262                             networkIdToRouterIpListCache.put(port.getNetworkId().getValue(),
263                                     NeutronIAwareUtil.convertMDSalIpToNeutronIp(port.getFixedIps()));
264                             subnetIdToRouterInterfaceCache.put(port.getFixedIps().get(0).getSubnetId().getValue(),
265                                     NeutronIAwareUtil.convertMDSalInterfaceToNeutronRouterInterface(port));
266                         }
267                     }
268                 }else {
269                     LOG.warn("L3 Cache Population :Did not find any port information " +
270                             "in config Data Store for router {}",router);
271                 }
272             }
273         }
274         LOG.debug("NetVirt L3 caches population is done");
275     }
276
277     private Pair<Long, Uuid> getDpIdOfNeutronPort(String neutronTenantPortUuid) {
278         if(neutronPortToDpIdCache.get(neutronTenantPortUuid) == null) {
279             List<Node> bridges = this.southbound.readOvsdbTopologyBridgeNodes();
280             LOG.debug("getDpIdOfNeutronPort : {} bridges present in ovsdb topology",bridges.size());
281             for(Node bridge : bridges) {
282                 List<OvsdbTerminationPointAugmentation> interfaces
283                         = southbound.extractTerminationPointAugmentations(bridge);
284                 if(interfaces != null && !interfaces.isEmpty()) {
285                     LOG.debug("getDpIdOfNeutronPort : {} termination point present on bridge {}",
286                             interfaces.size(), bridge.getNodeId());
287                     for (OvsdbTerminationPointAugmentation intf : interfaces) {
288                         NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
289                         if(neutronPort != null && neutronPort.getID().equals(neutronTenantPortUuid)) {
290                             Long dpId = getDpidForIntegrationBridge(bridge);
291                             Uuid interfaceUuid = intf.getInterfaceUuid();
292                             LOG.debug("getDpIdOfNeutronPort : Found bridge {} and interface {} for the tenant neutron" +
293                                     " port {}",dpId,interfaceUuid,neutronTenantPortUuid);
294                             handleInterfaceEventAdd(neutronPort.getPortUUID(), dpId, interfaceUuid);
295                             break;
296                         }
297                     }
298                 }
299             }
300         }
301         return neutronPortToDpIdCache.get(neutronTenantPortUuid);
302     }
303
304     private Collection<FloatIpData> getAllFloatingIPsWithMetadata() {
305         LOG.debug("getAllFloatingIPsWithMetadata : Fechting all floating Ips and it's metadata");
306         List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
307         if(neutronFloatingIps != null && !neutronFloatingIps.isEmpty()) {
308             for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
309                 if(!floatIpDataMapCache.containsKey(neutronFloatingIP.getID())){
310                     LOG.debug("Metadata for floating ip {} is not present in the cache. " +
311                             "Fetching from data store.",neutronFloatingIP.getID());
312                     this.getFloatingIPWithMetadata(neutronFloatingIP.getID());
313                 }
314             }
315         }
316         LOG.debug("getAllFloatingIPsWithMetadata : {} floating points found in data store",floatIpDataMapCache.size());
317         return floatIpDataMapCache.values();
318     }
319     private FloatIpData getFloatingIPWithMetadata(String neutronFloatingId) {
320         LOG.debug("getFloatingIPWithMetadata : Get Floating ip and it's meta data for neutron " +
321                 "floating id {} ",neutronFloatingId);
322         if(floatIpDataMapCache.get(neutronFloatingId) == null) {
323             NeutronFloatingIP neutronFloatingIP = neutronFloatingIpCache.getFloatingIP(neutronFloatingId);
324             if (neutronFloatingIP == null) {
325                 LOG.error("getFloatingIPWithMetadata : Floating ip {} is missing from data store, that should not happen",neutronFloatingId);
326                 return null;
327             }
328             List<NeutronPort> neutronPorts = neutronPortCache.getAllPorts();
329             NeutronPort neutronPortForFloatIp = null;
330             for (NeutronPort neutronPort : neutronPorts) {
331                 if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
332                         neutronPort.getDeviceID().equals(neutronFloatingIP.getID())) {
333                     neutronPortForFloatIp = neutronPort;
334                     break;
335                 }
336             }
337
338             String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
339             if(neutronTenantPortUuid == null) {
340                 return null;
341             }
342             Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
343             String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
344             String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
345             String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
346
347             NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
348             NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
349                     neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
350             String providerSegmentationId = tenantNeutronNetwork != null ?
351                     tenantNeutronNetwork.getProviderSegmentationID() : null;
352             String neutronRouterMac = tenantNeutronNetwork != null ?
353                     networkIdToRouterMacCache.get(tenantNeutronNetwork.getID()) : null;
354
355             if (nodeIfPair == null || neutronTenantPortUuid == null ||
356                     providerSegmentationId == null || providerSegmentationId.isEmpty() ||
357                     floatingIpMac == null || floatingIpMac.isEmpty() ||
358                     neutronRouterMac == null || neutronRouterMac.isEmpty()) {
359                 LOG.debug("getFloatingIPWithMetadata :Floating IP {}<->{}, incomplete floatPort {} tenantPortUuid {} " +
360                                 "seg {} mac {} rtrMac {}",
361                         fixedIpAddress,
362                         floatingIpAddress,
363                         neutronPortForFloatIp,
364                         neutronTenantPortUuid,
365                         providerSegmentationId,
366                         floatingIpMac,
367                         neutronRouterMac);
368
369                 return null;
370             }
371
372             // get ofport for patch port in br-int
373             final Long dpId = nodeIfPair.getLeft();
374             final Long ofPort = findOFPortForExtPatch(dpId);
375             if (ofPort == null) {
376                 LOG.warn("getFloatingIPWithMetadata : Unable to locate OF port of patch port " +
377                                 "to connect floating ip to external bridge. dpid {}",
378                         dpId);
379                 return null;
380             }
381
382             final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
383                     floatingIpAddress, fixedIpAddress, neutronRouterMac);
384             floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
385
386         }
387         return floatIpDataMapCache.get(neutronFloatingId);
388     }
389     /**
390      * Invoked to configure the mac address for the external gateway in br-ex. ovsdb netvirt needs help in getting
391      * mac for given ip in br-ex (bug 3378). For example, since ovsdb has no real arp, it needs a service in can
392      * subscribe so that the mac address associated to the gateway ip address is available.
393      *
394      * @param externalRouterMacUpdate  The mac address to be associated to the gateway.
395      */
396     public void updateExternalRouterMac(final String externalRouterMacUpdate) {
397         Preconditions.checkNotNull(externalRouterMacUpdate);
398
399         flushExistingIpRewrite();
400         this.externalRouterMac = externalRouterMacUpdate;
401         rebuildExistingIpRewrite();
402     }
403
404     /**
405      * Process the event.
406      *
407      * @param action the {@link Action} action to be handled.
408      * @param subnet An instance of NeutronSubnet object.
409      */
410     public void handleNeutronSubnetEvent(final NeutronSubnet subnet, Action action) {
411         LOG.debug("Neutron subnet {} event : {}", action, subnet.toString());
412         if (action == ADD) {
413             this.storeNetworkInCleanupCache(neutronNetworkCache.getNetwork(subnet.getNetworkUUID()));
414         }
415     }
416
417     /**
418      * Process the port event as a router interface event.
419      * For a not delete action, since a port is only create when the tennat uses the subnet, it is required to
420      * verify if all routers across all nodes have the interface for the port's subnet(s) configured.
421      *
422      * @param action the {@link Action} action to be handled.
423      * @param neutronPort An instance of NeutronPort object.
424      */
425     public void handleNeutronPortEvent(final NeutronPort neutronPort, Action action) {
426         LOG.debug("Neutron port {} event : {}", action, neutronPort.toString());
427
428         if (action == UPDATE) {
429             // FIXME: Bug 4971 Move cleanup cache to SG Impl
430             this.updatePortInCleanupCache(neutronPort, neutronPort.getOriginalPort());
431             if (neutronPort.getPortSecurityEnabled()) {
432                 this.processSecurityGroupUpdate(neutronPort);
433             }
434             if (isPortSecurityEnableUpdated(neutronPort)) {
435                 this.processPortSecurityEnableUpdated(neutronPort);
436             }
437         }
438
439         if (!this.enabled) {
440             return;
441         }
442
443         final boolean isDelete = action == DELETE;
444
445         if (action == DELETE) {
446             // Bug 5164: Cleanup Floating IP OpenFlow Rules when port is deleted.
447             this.cleanupFloatingIPRules(neutronPort);
448         }
449         else if (action == UPDATE){
450             // Bug 5353: VM restart cause floatingIp flows to be removed
451             this.updateFloatingIPRules(neutronPort);
452         }
453
454         if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_GATEWAY)){
455             if (!isDelete) {
456                 LOG.info("Port {} is network router gateway interface, "
457                         + "triggering gateway resolution for the attached external network", neutronPort);
458                 this.triggerGatewayMacResolver(neutronPort);
459             }else{
460                 NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(neutronPort.getNetworkUUID());
461                 if (null == externalNetwork) {
462                     externalNetwork = this.getNetworkFromCleanupCache(neutronPort.getNetworkUUID());
463                 }
464
465                 if (externalNetwork != null && externalNetwork.isRouterExternal()) {
466                     final NeutronSubnet externalSubnet = getExternalNetworkSubnet(neutronPort);
467                     // TODO support IPv6
468                     if (externalSubnet != null &&
469                             externalSubnet.getIpVersion() == 4) {
470                         gatewayMacResolver.stopPeriodicRefresh(new Ipv4Address(externalSubnet.getGatewayIP()));
471                     }
472                 }
473             }
474         }
475
476         // Treat the port event as a router interface event if the port belongs to router. This is a
477         // helper for handling cases when handleNeutronRouterInterfaceEvent is not available
478         //
479         if (neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE) ||
480             neutronPort.getDeviceOwner().equalsIgnoreCase(OWNER_ROUTER_INTERFACE_DISTRIBUTED)) {
481
482             if (neutronPort.getFixedIPs() != null) {
483                 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
484                     NeutronRouter_Interface neutronRouterInterface =
485                         new NeutronRouter_Interface(neutronIP.getSubnetUUID(), neutronPort.getPortUUID());
486                     // id of router interface to be same as subnet
487                     neutronRouterInterface.setID(neutronIP.getSubnetUUID());
488                     neutronRouterInterface.setTenantID(neutronPort.getTenantID());
489
490                     this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
491                 }
492             }
493         } else {
494             // We made it here, port is not used as a router interface. If this is not a delete action, make sure that
495             // all nodes that are supposed to have a router interface for the port's subnet(s), have it configured. We
496             // need to do this check here because a router interface is not added to a node until tenant becomes needed
497             // there.
498             //
499             if (!isDelete && neutronPort.getFixedIPs() != null) {
500                 for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
501                     NeutronRouter_Interface neutronRouterInterface =
502                             subnetIdToRouterInterfaceCache.get(neutronIP.getSubnetUUID());
503                     if (neutronRouterInterface != null) {
504                         this.handleNeutronRouterInterfaceEvent(null /*neutronRouter*/, neutronRouterInterface, action);
505                     }
506                 }
507             }
508             this.updateL3ForNeutronPort(neutronPort, isDelete);
509         }
510     }
511
512     /**
513      * Process the event.
514      *
515      * @param action the {@link Action} action to be handled.
516      * @param neutronRouter An instance of NeutronRouter object.
517      */
518     public void handleNeutronRouterEvent(final NeutronRouter neutronRouter, Action action) {
519         LOG.debug("Neutron router {} event : {}", action, neutronRouter.toString());
520     }
521
522     /**
523      * Process the event enforcing actions and verifying dependencies between all router's interface. For example,
524      * delete the ports on the same subnet.
525      *
526      * @param action the {@link Action} action to be handled.
527      * @param neutronRouter An instance of NeutronRouter object.
528      * @param neutronRouterInterface An instance of NeutronRouter_Interface object.
529      */
530     public void handleNeutronRouterInterfaceEvent(final NeutronRouter neutronRouter,
531                                                   final NeutronRouter_Interface neutronRouterInterface,
532                                                   Action action) {
533         LOG.debug("Router interface {} got event {}. Subnet {}",
534                      neutronRouterInterface.getPortUUID(),
535                      action,
536                      neutronRouterInterface.getSubnetUUID());
537         if (!this.enabled) {
538             return;
539         }
540
541         final boolean isDelete = action == DELETE;
542
543         this.programFlowsForNeutronRouterInterface(neutronRouterInterface, isDelete);
544
545         // As neutron router interface is added/removed, we need to iterate through all the neutron ports and
546         // see if they are affected by l3
547         //
548         for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
549             boolean currPortShouldBeDeleted = false;
550             // Note: delete in this case only applies to 1)router interface delete and 2)ports on the same subnet
551             if (isDelete) {
552                 if (neutronPort.getFixedIPs() != null) {
553                     for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
554                         if (neutronRouterInterface.getSubnetUUID().equalsIgnoreCase(neutronIP.getSubnetUUID())) {
555                             currPortShouldBeDeleted = true;
556                             break;
557                         }
558                     }
559                 }
560             }
561             this.updateL3ForNeutronPort(neutronPort, currPortShouldBeDeleted);
562         }
563
564     }
565
566     /**
567      * Invoked when a neutron message regarding the floating ip association is sent to odl via ml2. If the action is
568      * a creation, it will first add ARP rules for the given floating ip and then configure the DNAT (rewrite the
569      * packets from the floating IP address to the internal fixed ip) rules on OpenFlow Table 30 and SNAT rules (other
570      * way around) on OpenFlow Table 100.
571      *
572      * @param actionIn the {@link Action} action to be handled.
573      * @param neutronFloatingIP An {@link NeutronFloatingIP} instance of NeutronFloatingIP object.
574      */
575     public void handleNeutronFloatingIPEvent(final NeutronFloatingIP neutronFloatingIP,
576                                              Action actionIn) {
577         Preconditions.checkNotNull(neutronFloatingIP);
578
579         LOG.debug(" Floating IP {} {}<->{}, network uuid {}", actionIn,
580                 neutronFloatingIP.getFixedIPAddress(),
581                 neutronFloatingIP.getFloatingIPAddress(),
582                 neutronFloatingIP.getFloatingNetworkUUID());
583         if (!this.enabled) {
584             return;
585         }
586
587         Action action;
588
589         // Consider action to be delete if getFixedIPAddress is null
590         //
591         if (neutronFloatingIP.getFixedIPAddress() == null) {
592             action = DELETE;
593         } else {
594             action = actionIn;
595         }
596
597         // this.programFlowsForFloatingIP(neutronFloatingIP, action == Action.DELETE);
598
599         if (action != DELETE) {
600             // must be first, as it updates floatIpDataMapCache
601             programFlowsForFloatingIPArpAdd(neutronFloatingIP);
602
603             programFlowsForFloatingIPInbound(neutronFloatingIP, ADD);
604             programFlowsForFloatingIPOutbound(neutronFloatingIP, ADD);
605         } else {
606             programFlowsForFloatingIPOutbound(neutronFloatingIP, DELETE);
607             programFlowsForFloatingIPInbound(neutronFloatingIP, DELETE);
608
609             // must be last, as it updates floatIpDataMapCache
610             programFlowsForFloatingIPArpDelete(neutronFloatingIP.getID());
611         }
612     }
613
614     /**
615      * This method performs creation or deletion of in-bound rules into Table 30 for a existing available floating
616      * ip, otherwise for newer one.
617      */
618     private void programFlowsForFloatingIPInbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
619         Preconditions.checkNotNull(neutronFloatingIP);
620
621         final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
622         if (fid == null) {
623             LOG.trace("programFlowsForFloatingIPInboundAdd {} for {} uuid {} not in local cache",
624                     action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
625             return;
626         }
627         programInboundIpRewriteStage1(fid.dpid, fid.ofPort, fid.segId, fid.floatingIpAddress, fid.fixedIpAddress,
628                                       action);
629     }
630
631     /**
632      * This method performs creation or deletion of out-bound rules into Table 100 for a existing available floating
633      * ip, otherwise for newer one.
634      */
635     private void programFlowsForFloatingIPOutbound(final NeutronFloatingIP neutronFloatingIP, final Action action) {
636         Preconditions.checkNotNull(neutronFloatingIP);
637
638         final FloatIpData fid = getFloatingIPWithMetadata(neutronFloatingIP.getID());
639         if (fid == null) {
640             LOG.trace("programFlowsForFloatingIPOutbound {} for {} uuid {} not in local cache",
641                     action, neutronFloatingIP.getFloatingIPAddress(), neutronFloatingIP.getID());
642             return;
643         }
644         programOutboundIpRewriteStage1(fid, action);
645     }
646
647     private void flushExistingIpRewrite() {
648         for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
649             programOutboundIpRewriteStage1(fid, DELETE);
650         }
651     }
652
653     private void rebuildExistingIpRewrite() {
654         for (FloatIpData fid : getAllFloatingIPsWithMetadata()) {
655             programOutboundIpRewriteStage1(fid, ADD);
656         }
657     }
658
659     /**
660      * This method creates ARP response rules into OpenFlow Table 30 for a given floating ip. In order to connect
661      * to br-ex from br-int, a patch-port is used. Thus, the patch-port will be responsible to respond the ARP
662      * requests.
663      */
664     private void programFlowsForFloatingIPArpAdd(final NeutronFloatingIP neutronFloatingIP) {
665         Preconditions.checkNotNull(neutronFloatingIP);
666         Preconditions.checkNotNull(neutronFloatingIP.getFixedIPAddress());
667         Preconditions.checkNotNull(neutronFloatingIP.getFloatingIPAddress());
668
669         // find bridge Node where floating ip is configured by looking up cache for its port
670         final NeutronPort neutronPortForFloatIp = findNeutronPortForFloatingIp(neutronFloatingIP.getID());
671         final String neutronTenantPortUuid = neutronFloatingIP.getPortUUID();
672         final Pair<Long, Uuid> nodeIfPair = this.getDpIdOfNeutronPort(neutronTenantPortUuid);
673         final String floatingIpMac = neutronPortForFloatIp == null ? null : neutronPortForFloatIp.getMacAddress();
674         final String fixedIpAddress = neutronFloatingIP.getFixedIPAddress();
675         final String floatingIpAddress = neutronFloatingIP.getFloatingIPAddress();
676
677         final NeutronPort tenantNeutronPort = neutronPortCache.getPort(neutronTenantPortUuid);
678         final NeutronNetwork tenantNeutronNetwork = tenantNeutronPort != null ?
679                 neutronNetworkCache.getNetwork(tenantNeutronPort.getNetworkUUID()) : null;
680         final String providerSegmentationId = tenantNeutronNetwork != null ?
681                 tenantNeutronNetwork.getProviderSegmentationID() : null;
682         final String neutronRouterMac = tenantNeutronNetwork != null ?
683                 networkIdToRouterMacCache.get(tenantNeutronNetwork.getID()) : null;
684
685         if (nodeIfPair == null || neutronTenantPortUuid == null ||
686                 providerSegmentationId == null || providerSegmentationId.isEmpty() ||
687                 floatingIpMac == null || floatingIpMac.isEmpty() ||
688                 neutronRouterMac == null || neutronRouterMac.isEmpty()) {
689             LOG.trace("Floating IP {}<->{}, incomplete floatPort {} tenantPortUuid {} seg {} mac {} rtrMac {}",
690                     fixedIpAddress,
691                     floatingIpAddress,
692                     neutronPortForFloatIp,
693                     neutronTenantPortUuid,
694                     providerSegmentationId,
695                     floatingIpMac,
696                     neutronRouterMac);
697             return;
698         }
699
700         // get ofport for patch port in br-int
701         final Long dpId = nodeIfPair.getLeft();
702         final Long ofPort = findOFPortForExtPatch(dpId);
703         if (ofPort == null) {
704             LOG.warn("Unable to locate OF port of patch port to connect floating ip to external bridge. dpid {}",
705                     dpId);
706             return;
707         }
708
709         // Respond to ARPs for the floating ip address by default, via the patch port that connects br-int to br-ex
710         //
711         if (distributedArpService.programStaticRuleStage1(dpId, encodeExcplicitOFPort(ofPort), floatingIpMac, floatingIpAddress,
712                 ADD)) {
713             final FloatIpData floatIpData = new FloatIpData(dpId, ofPort, providerSegmentationId, floatingIpMac,
714                     floatingIpAddress, fixedIpAddress, neutronRouterMac);
715             floatIpDataMapCache.put(neutronFloatingIP.getID(), floatIpData);
716             LOG.info("Floating IP {}<->{} programmed ARP mac {} on OFport {} seg {} dpid {}",
717                     neutronFloatingIP.getFixedIPAddress(), neutronFloatingIP.getFloatingIPAddress(),
718                     floatingIpMac, ofPort, providerSegmentationId, dpId);
719         }
720     }
721
722     private void programFlowsForFloatingIPArpDelete(final String neutronFloatingIPUuid) {
723         final FloatIpData floatIpData = getFloatingIPWithMetadata(neutronFloatingIPUuid);
724         if (floatIpData == null) {
725             LOG.trace("programFlowsForFloatingIPArpDelete for uuid {} is not needed", neutronFloatingIPUuid);
726             return;
727         }
728
729         if (distributedArpService.programStaticRuleStage1(floatIpData.dpid, encodeExcplicitOFPort(floatIpData.ofPort), floatIpData.macAddress,
730                 floatIpData.floatingIpAddress, DELETE)) {
731             floatIpDataMapCache.remove(neutronFloatingIPUuid);
732             LOG.info("Floating IP {} un-programmed ARP mac {} on {} dpid {}",
733                     floatIpData.floatingIpAddress, floatIpData.macAddress, floatIpData.ofPort, floatIpData.dpid);
734         }
735     }
736
737     private NeutronPort findNeutronPortForFloatingIp(final String floatingIpUuid) {
738         for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
739             if (neutronPort.getDeviceOwner().equals(OWNER_FLOATING_IP) &&
740                     neutronPort.getDeviceID().equals(floatingIpUuid)) {
741                 return neutronPort;
742             }
743         }
744         return null;
745     }
746
747     private Long findOFPortForExtPatch(Long dpId) {
748         final String brInt = configurationService.getIntegrationBridgeName();
749         final String brExt = configurationService.getExternalBridgeName();
750         final String portNameInt = configurationService.getPatchPortName(new ImmutablePair<>(brInt, brExt));
751
752         Preconditions.checkNotNull(dpId);
753         Preconditions.checkNotNull(portNameInt);
754
755         final long dpidPrimitive = dpId;
756         for (Node node : nodeCacheManager.getBridgeNodes()) {
757             if (dpidPrimitive == southbound.getDataPathId(node)) {
758                 final OvsdbTerminationPointAugmentation terminationPointOfBridge =
759                         southbound.getTerminationPointOfBridge(node, portNameInt);
760                 return terminationPointOfBridge == null ? null : terminationPointOfBridge.getOfport();
761             }
762         }
763         return null;
764     }
765
766     /**
767      * Process the event.
768      *
769      * @param action the {@link Action} action to be handled.
770      * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronFloatingIP object.
771      */
772     public void handleNeutronNetworkEvent(final NeutronNetwork neutronNetwork, Action action) {
773         LOG.debug("neutronNetwork {}: network: {}", action, neutronNetwork);
774         if (action == UPDATE) {
775             this.updateNetworkInCleanupCache(neutronNetwork);
776         }
777     }
778
779     //
780     // Callbacks from OVSDB's southbound handler
781     //
782     /**
783      * Process the event.
784      *
785      * @param bridgeNode An instance of Node object.
786      * @param intf An {@link org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105
787      * .OvsdbTerminationPointAugmentation} instance of OvsdbTerminationPointAugmentation object.
788      * @param neutronNetwork An {@link NeutronNetwork} instance of NeutronNetwork
789      * object.
790      * @param action the {@link Action} action to be handled.
791      */
792     public void handleInterfaceEvent(final Node bridgeNode, final OvsdbTerminationPointAugmentation intf,
793                                      final NeutronNetwork neutronNetwork, Action action) {
794         LOG.debug("southbound interface {} node:{} interface:{}, neutronNetwork:{}",
795                      action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork);
796
797         final NeutronPort neutronPort = tenantNetworkManager.getTenantPort(intf);
798         if (action != DELETE && neutronPort != null) {
799             // FIXME: Bug 4971 Move cleanup cache to SG Impl
800             storePortInCleanupCache(neutronPort);
801         }
802
803         if (!this.enabled) {
804             return;
805         }
806
807         final Long dpId = getDpidForIntegrationBridge(bridgeNode);
808         final Uuid interfaceUuid = intf.getInterfaceUuid();
809
810         LOG.trace("southbound interface {} node:{} interface:{}, neutronNetwork:{} port:{} dpid:{} intfUuid:{}",
811                 action, bridgeNode.getNodeId().getValue(), intf.getName(), neutronNetwork, neutronPort, dpId, interfaceUuid);
812
813         if (neutronPort != null) {
814             final String neutronPortUuid = neutronPort.getPortUUID();
815
816             if (action != DELETE && dpId != null && interfaceUuid != null) {
817                 handleInterfaceEventAdd(neutronPortUuid, dpId, interfaceUuid);
818             }
819
820             handleNeutronPortEvent(neutronPort, action);
821         }
822
823         if (action == DELETE && interfaceUuid != null) {
824             handleInterfaceEventDelete(intf, dpId);
825         }
826     }
827
828     private void handleInterfaceEventAdd(final String neutronPortUuid, Long dpId, final Uuid interfaceUuid) {
829         neutronPortToDpIdCache.put(neutronPortUuid, new ImmutablePair<>(dpId, interfaceUuid));
830         LOG.debug("handleInterfaceEvent add cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
831                 neutronPortUuid, dpId, interfaceUuid.getValue());
832     }
833
834     private void handleInterfaceEventDelete(final OvsdbTerminationPointAugmentation intf, final Long dpId) {
835         // Remove entry from neutronPortToDpIdCache based on interface uuid
836         for (Map.Entry<String, Pair<Long, Uuid>> entry : neutronPortToDpIdCache.entrySet()) {
837             final String currPortUuid = entry.getKey();
838             if (intf.getInterfaceUuid().equals(entry.getValue().getRight())) {
839                 LOG.debug("handleInterfaceEventDelete remove cache entry NeutronPortUuid {} : dpid {}, ifUuid {}",
840                         currPortUuid, dpId, intf.getInterfaceUuid().getValue());
841                 neutronPortToDpIdCache.remove(currPortUuid);
842                 break;
843             }
844         }
845     }
846
847     //
848     // Internal helpers
849     //
850     private void updateL3ForNeutronPort(final NeutronPort neutronPort, final boolean isDelete) {
851
852         final String networkUUID = neutronPort.getNetworkUUID();
853         final String routerMacAddress = networkIdToRouterMacCache.get(networkUUID);
854
855         if(!isDelete) {
856             // If there is no router interface handling the networkUUID, we are done
857             if (routerMacAddress == null || routerMacAddress.isEmpty()) {
858                 return;
859             }
860
861             // If this is the neutron port for the router interface itself, ignore it as well. Ports that represent the
862             // router interface are handled via handleNeutronRouterInterfaceEvent.
863             if (routerMacAddress.equalsIgnoreCase(neutronPort.getMacAddress())) {
864                 return;
865             }
866         }
867
868         final NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(networkUUID);
869         final String providerSegmentationId = neutronNetwork != null ?
870                                               neutronNetwork.getProviderSegmentationID() : null;
871         final String tenantMac = neutronPort.getMacAddress();
872
873         if (providerSegmentationId == null || providerSegmentationId.isEmpty() ||
874             tenantMac == null || tenantMac.isEmpty()) {
875             // done: go no further w/out all the info needed...
876             return;
877         }
878
879         final Action action = isDelete ? DELETE : ADD;
880         List<Node> nodes = nodeCacheManager.getBridgeNodes();
881         if (nodes.isEmpty()) {
882             LOG.trace("updateL3ForNeutronPort has no nodes to work with");
883         }
884         for (Node node : nodes) {
885             final Long dpid = getDpidForIntegrationBridge(node);
886             if (dpid == null) {
887                 continue;
888             }
889             if (neutronPort.getFixedIPs() == null) {
890                 continue;
891             }
892             for (Neutron_IPs neutronIP : neutronPort.getFixedIPs()) {
893                 final String tenantIpStr = neutronIP.getIpAddress();
894                 if (tenantIpStr.isEmpty()) {
895                     continue;
896                 }
897
898                 // Configure L3 fwd. We do that regardless of tenant network present, because these rules are
899                 // still needed when routing to subnets non-local to node (bug 2076).
900                 programL3ForwardingStage1(node, dpid, providerSegmentationId, tenantMac, tenantIpStr, action);
901             }
902         }
903     }
904
905     private void processSecurityGroupUpdate(NeutronPort neutronPort) {
906         LOG.trace("processSecurityGroupUpdate:" + neutronPort);
907         /**
908          * Get updated data and original data for the the changed. Identify the security groups that got
909          * added and removed and call the appropriate providers for updating the flows.
910          */
911         try {
912             List<NeutronSecurityGroup> addedGroup = getsecurityGroupChanged(neutronPort,
913                                                                             neutronPort.getOriginalPort());
914             List<NeutronSecurityGroup> deletedGroup = getsecurityGroupChanged(neutronPort.getOriginalPort(),
915                                                                               neutronPort);
916
917             if (null != addedGroup && !addedGroup.isEmpty()) {
918                 securityServicesManager.syncSecurityGroup(neutronPort,addedGroup,true);
919             }
920             if (null != deletedGroup && !deletedGroup.isEmpty()) {
921                 securityServicesManager.syncSecurityGroup(neutronPort,deletedGroup,false);
922             }
923
924         } catch (Exception e) {
925             LOG.error("Exception in processSecurityGroupUpdate", e);
926         }
927     }
928
929     private void processPortSecurityEnableUpdated(NeutronPort neutronPort) {
930         LOG.trace("processPortSecurityEnableUpdated:" + neutronPort);
931         securityServicesManager.syncFixedSecurityGroup(neutronPort,
932             neutronPort.getPortSecurityEnabled());
933     }
934
935     private boolean isPortSecurityEnableUpdated(NeutronPort neutronPort) {
936         LOG.trace("isPortSecuirtyEnableUpdated:" + neutronPort);
937         if (neutronPort != null
938                 && neutronPort.getOriginalPort() != null
939                 && neutronPort.getOriginalPort().getPortSecurityEnabled() != null
940                 && neutronPort.getPortSecurityEnabled() != null
941                 && neutronPort.getOriginalPort().getPortSecurityEnabled() != neutronPort
942                         .getPortSecurityEnabled()) {
943             return true;
944         }
945         return false;
946     }
947
948
949     private List<NeutronSecurityGroup> getsecurityGroupChanged(NeutronPort port1, NeutronPort port2) {
950         LOG.trace("getsecurityGroupChanged:" + "Port1:" + port1 + "Port2" + port2);
951         if (port1 == null) {
952             return null;
953         }
954         List<NeutronSecurityGroup> list1 = new ArrayList<>(port1.getSecurityGroups());
955         if (port2 == null) {
956             return list1;
957         }
958         List<NeutronSecurityGroup> list2 = new ArrayList<>(port2.getSecurityGroups());
959         for (Iterator<NeutronSecurityGroup> iterator = list1.iterator(); iterator.hasNext();) {
960             NeutronSecurityGroup securityGroup1 = iterator.next();
961             for (NeutronSecurityGroup securityGroup2 :list2) {
962                 if (securityGroup1.getID().equals(securityGroup2.getID())) {
963                     iterator.remove();
964                 }
965             }
966         }
967         return list1;
968     }
969
970     private void programL3ForwardingStage1(Node node, Long dpid, String providerSegmentationId,
971                                            String macAddress, String ipStr,
972                                            Action actionForNode) {
973         if (actionForNode == DELETE) {
974             LOG.trace("Deleting Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
975                          node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
976         }
977         if (actionForNode == ADD) {
978             LOG.trace("Adding Flow : programL3ForwardingStage1 for node {} providerId {} mac {} ip {} action {}",
979                     node.getNodeId().getValue(), providerSegmentationId, macAddress, ipStr, actionForNode);
980         }
981
982         this.programL3ForwardingStage2(node, dpid, providerSegmentationId,
983                                                        macAddress, ipStr, actionForNode);
984     }
985
986     private Status programL3ForwardingStage2(Node node, Long dpid, String providerSegmentationId,
987                                              String macAddress,
988                                              String address,
989                                              Action actionForNode) {
990         Status status;
991         try {
992             InetAddress inetAddress = InetAddress.getByName(address);
993             status = l3ForwardingProvider == null ?
994                      new Status(StatusCode.SUCCESS) :
995                      l3ForwardingProvider.programForwardingTableEntry(dpid, providerSegmentationId,
996                                                                       inetAddress, macAddress, actionForNode);
997         } catch (UnknownHostException e) {
998             status = new Status(StatusCode.BADREQUEST);
999         }
1000
1001         if (status.isSuccess()) {
1002             LOG.debug("ProgramL3Forwarding {} for mac:{} addr:{} node:{} action:{}",
1003                          l3ForwardingProvider == null ? "skipped" : "programmed",
1004                          macAddress, address, node.getNodeId().getValue(), actionForNode);
1005         } else {
1006             LOG.error("ProgramL3Forwarding failed for mac:{} addr:{} node:{} action:{} status:{}",
1007                          macAddress, address, node.getNodeId().getValue(), actionForNode, status);
1008         }
1009         return status;
1010     }
1011
1012     // --
1013
1014     private void programFlowsForNeutronRouterInterface(final NeutronRouter_Interface destNeutronRouterInterface,
1015                                                        Boolean isDelete) {
1016         Preconditions.checkNotNull(destNeutronRouterInterface);
1017
1018         final NeutronPort neutronPort = neutronPortCache.getPort(destNeutronRouterInterface.getPortUUID());
1019         String macAddress = neutronPort != null ? neutronPort.getMacAddress() : null;
1020         List<Neutron_IPs> ipList = neutronPort != null ? neutronPort.getFixedIPs() : null;
1021         final NeutronSubnet subnet = neutronSubnetCache.getSubnet(destNeutronRouterInterface.getSubnetUUID());
1022         final NeutronNetwork neutronNetwork = subnet != null ?
1023                                               neutronNetworkCache.getNetwork(subnet.getNetworkUUID()) : null;
1024         final String destinationSegmentationId = neutronNetwork != null ?
1025                                                  neutronNetwork.getProviderSegmentationID() : null;
1026         final Boolean isExternal = neutronNetwork != null ? neutronNetwork.getRouterExternal() : Boolean.TRUE;
1027         final String cidr = subnet != null ? subnet.getCidr() : null;
1028         final int mask = getMaskLenFromCidr(cidr);
1029
1030         LOG.trace("programFlowsForNeutronRouterInterface called for interface {} isDelete {}",
1031                      destNeutronRouterInterface, isDelete);
1032
1033         // in delete path, mac address as well as ip address are not provided. Being so, let's find them from
1034         // the local cache
1035         if (neutronNetwork != null) {
1036             if (macAddress == null || macAddress.isEmpty()) {
1037                 macAddress = networkIdToRouterMacCache.get(neutronNetwork.getNetworkUUID());
1038             }
1039             if (ipList == null || ipList.isEmpty()) {
1040                 ipList = networkIdToRouterIpListCache.get(neutronNetwork.getNetworkUUID());
1041             }
1042         }
1043
1044         if (destinationSegmentationId == null || destinationSegmentationId.isEmpty() ||
1045             cidr == null || cidr.isEmpty() ||
1046             macAddress == null || macAddress.isEmpty() ||
1047             ipList == null || ipList.isEmpty()) {
1048             LOG.debug("programFlowsForNeutronRouterInterface is bailing seg:{} cidr:{} mac:{}  ip:{}",
1049                          destinationSegmentationId, cidr, macAddress, ipList);
1050             // done: go no further w/out all the info needed...
1051             return;
1052         }
1053
1054         final Action actionForNode = isDelete ? DELETE : ADD;
1055
1056         // Keep cache for finding router's mac from network uuid -- add
1057         //
1058         if (! isDelete) {
1059             networkIdToRouterMacCache.put(neutronNetwork.getNetworkUUID(), macAddress);
1060             networkIdToRouterIpListCache.put(neutronNetwork.getNetworkUUID(), new ArrayList<>(ipList));
1061             subnetIdToRouterInterfaceCache.put(subnet.getSubnetUUID(), destNeutronRouterInterface);
1062         }
1063
1064         List<Node> nodes = nodeCacheManager.getBridgeNodes();
1065         if (nodes.isEmpty()) {
1066             LOG.trace("programFlowsForNeutronRouterInterface has no nodes to work with");
1067         }
1068         for (Node node : nodes) {
1069             final Long dpid = getDpidForIntegrationBridge(node);
1070             if (dpid == null) {
1071                 continue;
1072             }
1073
1074             for (Neutron_IPs neutronIP : ipList) {
1075                 final String ipStr = neutronIP.getIpAddress();
1076                 if (ipStr.isEmpty()) {
1077                     LOG.debug("programFlowsForNeutronRouterInterface is skipping node {} ip {}",
1078                             node.getNodeId().getValue(), ipStr);
1079                     continue;
1080                 }
1081
1082                 // Iterate through all other interfaces and add/remove reflexive flows to this interface
1083                 //
1084                 for (NeutronRouter_Interface srcNeutronRouterInterface : subnetIdToRouterInterfaceCache.values()) {
1085                     programFlowsForNeutronRouterInterfacePair(node, dpid,
1086                                                               srcNeutronRouterInterface, destNeutronRouterInterface,
1087                                                               neutronNetwork, destinationSegmentationId,
1088                                                               macAddress, ipStr, mask, actionForNode,
1089                                                               true /*isReflexsive*/);
1090                 }
1091
1092                 if (! isExternal) {
1093                     programFlowForNetworkFromExternal(node, dpid, destinationSegmentationId, macAddress, ipStr, mask,
1094                             actionForNode);
1095                 }
1096                 // Enable ARP responder by default, because router interface needs to be responded always.
1097                 distributedArpService.programStaticRuleStage1(dpid, destinationSegmentationId, macAddress, ipStr, actionForNode);
1098                 programIcmpEcho(dpid, destinationSegmentationId, macAddress, ipStr, actionForNode);
1099             }
1100
1101             // Compute action to be programmed. In the case of rewrite exclusions, we must never program rules
1102             // for the external neutron networks.
1103             //
1104             {
1105                 final Action actionForRewriteExclusion = isExternal ? DELETE : actionForNode;
1106                 programIpRewriteExclusionStage1(node, dpid, destinationSegmentationId, cidr, actionForRewriteExclusion);
1107             }
1108         }
1109
1110         if (isDelete) {
1111             networkIdToRouterMacCache.remove(neutronNetwork.getNetworkUUID());
1112             networkIdToRouterIpListCache.remove(neutronNetwork.getNetworkUUID());
1113             subnetIdToRouterInterfaceCache.remove(subnet.getSubnetUUID());
1114         }
1115     }
1116
1117     private void programFlowForNetworkFromExternal(final Node node,
1118                                                    final Long dpid,
1119                                                    final String destinationSegmentationId,
1120                                                    final String dstMacAddress,
1121                                                    final String destIpStr,
1122                                                    final int destMask,
1123                                                    final Action actionForNode) {
1124         programRouterInterfaceStage1(node, dpid, Constants.EXTERNAL_NETWORK, destinationSegmentationId,
1125                 dstMacAddress, destIpStr, destMask, actionForNode);
1126     }
1127
1128     private void programFlowsForNeutronRouterInterfacePair(final Node node,
1129                                                            final Long dpid,
1130                                                            final NeutronRouter_Interface srcNeutronRouterInterface,
1131                                                            final NeutronRouter_Interface dstNeutronRouterInterface,
1132                                                            final NeutronNetwork dstNeutronNetwork,
1133                                                            final String destinationSegmentationId,
1134                                                            final String dstMacAddress,
1135                                                            final String destIpStr,
1136                                                            final int destMask,
1137                                                            final Action actionForNode,
1138                                                            Boolean isReflexsive) {
1139         Preconditions.checkNotNull(srcNeutronRouterInterface);
1140         Preconditions.checkNotNull(dstNeutronRouterInterface);
1141
1142         final String sourceSubnetId = srcNeutronRouterInterface.getSubnetUUID();
1143         if (sourceSubnetId == null) {
1144             LOG.error("Could not get provider Subnet ID from router interface {}",
1145                          srcNeutronRouterInterface.getID());
1146             return;
1147         }
1148
1149         final NeutronSubnet sourceSubnet = neutronSubnetCache.getSubnet(sourceSubnetId);
1150         final String sourceNetworkId = sourceSubnet == null ? null : sourceSubnet.getNetworkUUID();
1151         if (sourceNetworkId == null) {
1152             LOG.error("Could not get provider Network ID from subnet {}", sourceSubnetId);
1153             return;
1154         }
1155
1156         final NeutronNetwork sourceNetwork = neutronNetworkCache.getNetwork(sourceNetworkId);
1157         if (sourceNetwork == null) {
1158             LOG.error("Could not get provider Network for Network ID {}", sourceNetworkId);
1159             return;
1160         }
1161
1162         if (! sourceNetwork.getTenantID().equals(dstNeutronNetwork.getTenantID())) {
1163             // Isolate subnets from different tenants within the same router
1164             return;
1165         }
1166         final String sourceSegmentationId = sourceNetwork.getProviderSegmentationID();
1167         if (sourceSegmentationId == null) {
1168             LOG.error("Could not get provider Segmentation ID for Subnet {}", sourceSubnetId);
1169             return;
1170         }
1171         if (sourceSegmentationId.equals(destinationSegmentationId)) {
1172             // Skip 'self'
1173             return;
1174         }
1175
1176         programRouterInterfaceStage1(node, dpid, sourceSegmentationId, destinationSegmentationId,
1177                                      dstMacAddress, destIpStr, destMask, actionForNode);
1178
1179         // Flip roles src->dst; dst->src
1180         if (isReflexsive) {
1181             final NeutronPort sourceNeutronPort = neutronPortCache.getPort(srcNeutronRouterInterface.getPortUUID());
1182             final String macAddress2 = sourceNeutronPort != null ? sourceNeutronPort.getMacAddress() : null;
1183             final List<Neutron_IPs> ipList2 = sourceNeutronPort != null ? sourceNeutronPort.getFixedIPs() : null;
1184             final String cidr2 = sourceSubnet.getCidr();
1185             final int mask2 = getMaskLenFromCidr(cidr2);
1186
1187             if (cidr2 == null || cidr2.isEmpty() ||
1188                 macAddress2 == null || macAddress2.isEmpty() ||
1189                 ipList2 == null || ipList2.isEmpty()) {
1190                 LOG.trace("programFlowsForNeutronRouterInterfacePair reflexive is bailing seg:{} cidr:{} mac:{} ip:{}",
1191                              sourceSegmentationId, cidr2, macAddress2, ipList2);
1192                 // done: go no further w/out all the info needed...
1193                 return;
1194             }
1195
1196             for (Neutron_IPs neutronIP2 : ipList2) {
1197                 final String ipStr2 = neutronIP2.getIpAddress();
1198                 if (ipStr2.isEmpty()) {
1199                     continue;
1200                 }
1201                 programFlowsForNeutronRouterInterfacePair(node, dpid, dstNeutronRouterInterface,
1202                                                           srcNeutronRouterInterface,
1203                                                           sourceNetwork, sourceSegmentationId,
1204                                                           macAddress2, ipStr2, mask2, actionForNode,
1205                                                           false /*isReflexsive*/);
1206             }
1207         }
1208     }
1209
1210     private void programRouterInterfaceStage1(Node node, Long dpid, String sourceSegmentationId,
1211                                               String destinationSegmentationId,
1212                                               String macAddress, String ipStr, int mask,
1213                                               Action actionForNode) {
1214         if (actionForNode == DELETE) {
1215             LOG.trace("Deleting Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
1216                          " action {}",
1217                          node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
1218                          macAddress, ipStr, mask, actionForNode);
1219         }
1220         if (actionForNode == ADD) {
1221             LOG.trace("Adding Flow : programRouterInterfaceStage1 for node {} sourceSegId {} destSegId {} mac {} ip {} mask {}" +
1222                          " action {}",
1223                          node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
1224                          macAddress, ipStr, mask, actionForNode);
1225         }
1226
1227         this.programRouterInterfaceStage2(node, dpid, sourceSegmentationId, destinationSegmentationId,
1228                                                           macAddress, ipStr, mask, actionForNode);
1229     }
1230
1231     private Status programRouterInterfaceStage2(Node node, Long dpid, String sourceSegmentationId,
1232                                                 String destinationSegmentationId,
1233                                                 String macAddress,
1234                                                 String address, int mask,
1235                                                 Action actionForNode) {
1236         Status status;
1237         try {
1238             InetAddress inetAddress = InetAddress.getByName(address);
1239             status = routingProvider == null ?
1240                      new Status(StatusCode.SUCCESS) :
1241                      routingProvider.programRouterInterface(dpid, sourceSegmentationId, destinationSegmentationId,
1242                                                             macAddress, inetAddress, mask, actionForNode);
1243         } catch (UnknownHostException e) {
1244             status = new Status(StatusCode.BADREQUEST);
1245         }
1246
1247         if (status.isSuccess()) {
1248             LOG.debug("programRouterInterfaceStage2 {} for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{}",
1249                          routingProvider == null ? "skipped" : "programmed",
1250                          macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
1251                          actionForNode);
1252         } else {
1253             LOG.error("programRouterInterfaceStage2 failed for mac:{} addr:{}/{} node:{} srcTunId:{} destTunId:{} action:{} status:{}",
1254                          macAddress, address, mask, node.getNodeId().getValue(), sourceSegmentationId, destinationSegmentationId,
1255                          actionForNode, status);
1256         }
1257         return status;
1258     }
1259
1260     private boolean programIcmpEcho(Long dpid, String segOrOfPort,
1261                                            String macAddress, String ipStr,
1262                                            Action action) {
1263         if (action == DELETE ) {
1264             LOG.trace("Deleting Flow : programIcmpEcho dpid {} segOrOfPort {} mac {} ip {} action {}",
1265                     dpid, segOrOfPort, macAddress, ipStr, action);
1266         }
1267         if (action == ADD) {
1268             LOG.trace("Adding Flow : programIcmpEcho dpid {} segOrOfPort {} mac {} ip {} action {}",
1269                     dpid, segOrOfPort, macAddress, ipStr, action);
1270         }
1271
1272         Status status = new Status(StatusCode.UNSUPPORTED);
1273         if (icmpEchoProvider != null){
1274             try {
1275                 InetAddress inetAddress = InetAddress.getByName(ipStr);
1276                 status = icmpEchoProvider.programIcmpEchoEntry(dpid, segOrOfPort,
1277                                                 macAddress, inetAddress, action);
1278             } catch (UnknownHostException e) {
1279                 status = new Status(StatusCode.BADREQUEST);
1280             }
1281         }
1282
1283         if (status.isSuccess()) {
1284             LOG.debug("programIcmpEcho {} for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{}",
1285                     icmpEchoProvider == null ? "skipped" : "programmed",
1286                     macAddress, ipStr, dpid, segOrOfPort, action);
1287         } else {
1288             LOG.error("programIcmpEcho failed for mac:{} addr:{} dpid:{} segOrOfPort:{} action:{} status:{}",
1289                     macAddress, ipStr, dpid, segOrOfPort, action, status);
1290         }
1291
1292         return status.isSuccess();
1293     }
1294
1295     private boolean programInboundIpRewriteStage1(Long dpid, Long inboundOFPort, String providerSegmentationId,
1296                                                   String matchAddress, String rewriteAddress,
1297                                                   Action action) {
1298         if (action == DELETE ) {
1299             LOG.trace("Deleting Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
1300                     " action {}",
1301                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
1302         }
1303         if (action == ADD ) {
1304             LOG.trace("Adding Flow : programInboundIpRewriteStage1 dpid {} OFPort {} seg {} matchAddress {} rewriteAddress {}" +
1305                     " action {}",
1306                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
1307         }
1308
1309         Status status = programInboundIpRewriteStage2(dpid, inboundOFPort, providerSegmentationId, matchAddress,
1310                 rewriteAddress, action);
1311         return status.isSuccess();
1312     }
1313
1314     private Status programInboundIpRewriteStage2(Long dpid, Long inboundOFPort, String providerSegmentationId,
1315                                                  String matchAddress, String rewriteAddress,
1316                                                  Action action) {
1317         Status status;
1318         try {
1319             InetAddress inetMatchAddress = InetAddress.getByName(matchAddress);
1320             InetAddress inetRewriteAddress = InetAddress.getByName(rewriteAddress);
1321             status = inboundNatProvider == null ?
1322                     new Status(StatusCode.SUCCESS) :
1323                     inboundNatProvider.programIpRewriteRule(dpid, inboundOFPort, providerSegmentationId,
1324                             inetMatchAddress, inetRewriteAddress,
1325                             action);
1326         } catch (UnknownHostException e) {
1327             status = new Status(StatusCode.BADREQUEST);
1328         }
1329
1330         if (status.isSuccess()) {
1331             final boolean isSkipped = inboundNatProvider == null;
1332             LOG.debug("programInboundIpRewriteStage2 {} for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}",
1333                     isSkipped ? "skipped" : "programmed",
1334                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action);
1335         } else {
1336             LOG.error("programInboundIpRewriteStage2 failed for dpid:{} ofPort:{} seg:{} match:{} rewrite:{} action:{}" +
1337                          " status:{}",
1338                     dpid, inboundOFPort, providerSegmentationId, matchAddress, rewriteAddress, action,
1339                     status);
1340         }
1341         return status;
1342     }
1343
1344     private void programIpRewriteExclusionStage1(Node node, Long dpid, String providerSegmentationId, String cidr,
1345                                                  Action actionForRewriteExclusion) {
1346         if (actionForRewriteExclusion == DELETE ) {
1347             LOG.trace("Deleting Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
1348                          node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
1349         }
1350         if (actionForRewriteExclusion == ADD) {
1351             LOG.trace("Adding Flow : programIpRewriteExclusionStage1 node {} providerId {} cidr {} action {}",
1352                          node.getNodeId().getValue(), providerSegmentationId, cidr, actionForRewriteExclusion);
1353         }
1354
1355         this.programIpRewriteExclusionStage2(node, dpid, providerSegmentationId, cidr,actionForRewriteExclusion);
1356     }
1357
1358     private Status programIpRewriteExclusionStage2(Node node, Long dpid, String providerSegmentationId, String cidr,
1359                                                    Action actionForNode) {
1360         final Status status = outboundNatProvider == null ? new Status(StatusCode.SUCCESS) :
1361                 outboundNatProvider.programIpRewriteExclusion(dpid, providerSegmentationId, cidr, actionForNode);
1362
1363         if (status.isSuccess()) {
1364             final boolean isSkipped = outboundNatProvider == null;
1365             LOG.debug("IpRewriteExclusion {} for cidr:{} node:{} action:{}",
1366                          isSkipped ? "skipped" : "programmed",
1367                          cidr, node.getNodeId().getValue(), actionForNode);
1368         } else {
1369             LOG.error("IpRewriteExclusion failed for cidr:{} node:{} action:{} status:{}",
1370                          cidr, node.getNodeId().getValue(), actionForNode, status);
1371         }
1372         return status;
1373     }
1374
1375     private void programOutboundIpRewriteStage1(FloatIpData fid, Action action) {
1376
1377         if (action == DELETE) {
1378             LOG.trace("Deleting Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} ",
1379                     fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
1380         }
1381         if (action == ADD) {
1382             LOG.trace("Adding Flow : programOutboundIpRewriteStage1 dpid {} seg {} fixedIpAddress {} floatIp {} action {} " ,
1383                     fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
1384         }
1385
1386         this.programOutboundIpRewriteStage2(fid, action);
1387     }
1388
1389     private Status programOutboundIpRewriteStage2(FloatIpData fid, Action action) {
1390         Status status;
1391         try {
1392             InetAddress matchSrcAddress = InetAddress.getByName(fid.fixedIpAddress);
1393             InetAddress rewriteSrcAddress = InetAddress.getByName(fid.floatingIpAddress);
1394             status = outboundNatProvider == null ?
1395                     new Status(StatusCode.SUCCESS) :
1396                     outboundNatProvider.programIpRewriteRule(
1397                             fid.dpid, fid.segId, fid.neutronRouterMac, matchSrcAddress, fid.macAddress,
1398                             this.externalRouterMac, rewriteSrcAddress, fid.ofPort, action);
1399         } catch (UnknownHostException e) {
1400             status = new Status(StatusCode.BADREQUEST);
1401         }
1402
1403         if (status.isSuccess()) {
1404             final boolean isSkipped = outboundNatProvider == null;
1405             LOG.debug("programOutboundIpRewriteStage2 {} for dpid {} seg {} fixedIpAddress {} floatIp {}" +
1406                             " action {}",
1407                          isSkipped ? "skipped" : "programmed",
1408                          fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action);
1409         } else {
1410             LOG.error("programOutboundIpRewriteStage2 failed for dpid {} seg {} fixedIpAddress {} floatIp {}" +
1411                          " action {} status:{}",
1412                          fid.dpid, fid.segId, fid.fixedIpAddress, fid.floatingIpAddress, action, status);
1413         }
1414         return status;
1415     }
1416
1417     private int getMaskLenFromCidr(String cidr) {
1418         if (cidr == null) {
1419             return 0;
1420         }
1421         String[] splits = cidr.split("/");
1422         if (splits.length != 2) {
1423             return 0;
1424         }
1425
1426         int result;
1427         try {
1428             result = Integer.parseInt(splits[1].trim());
1429         } catch (NumberFormatException nfe) {
1430             result = 0;
1431         }
1432         return result;
1433     }
1434
1435     private Long getDpidForIntegrationBridge(Node node) {
1436         // Check if node is integration bridge; and only then return its dpid
1437         if (southbound.getBridge(node, configurationService.getIntegrationBridgeName()) != null) {
1438             return southbound.getDataPathId(node);
1439         }
1440         return null;
1441     }
1442
1443     private Long getDpidForExternalBridge(Node node) {
1444         // Check if node is external bridge; and only then return its dpid
1445         if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
1446             return southbound.getDataPathId(node);
1447         }
1448         return null;
1449     }
1450
1451     private Node getExternalBridgeNode(){
1452         //Pickup the first node that has external bridge (br-ex).
1453         //NOTE: We are assuming that all the br-ex are serving one external network and gateway ip of
1454         //the external network is reachable from every br-ex
1455         // TODO: Consider other deployment scenario, and thing of better solution.
1456         List<Node> allBridges = nodeCacheManager.getBridgeNodes();
1457         for(Node node : allBridges){
1458             if (southbound.getBridge(node, configurationService.getExternalBridgeName()) != null) {
1459                 return node;
1460             }
1461         }
1462         return null;
1463     }
1464
1465     private NeutronSubnet getExternalNetworkSubnet(NeutronPort gatewayPort){
1466         if (gatewayPort.getFixedIPs() == null) {
1467             return null;
1468         }
1469         for (Neutron_IPs neutronIPs : gatewayPort.getFixedIPs()) {
1470             String subnetUUID = neutronIPs.getSubnetUUID();
1471             NeutronSubnet extSubnet = neutronSubnetCache.getSubnet(subnetUUID);
1472             if (extSubnet != null && extSubnet.getGatewayIP() != null) {
1473                 return extSubnet;
1474             }
1475             if (extSubnet == null) {
1476                 // TODO: when subnet is created, try again.
1477                 LOG.debug("subnet {} in not found", subnetUUID);
1478              }
1479         }
1480         return null;
1481     }
1482
1483     private void cleanupFloatingIPRules(final NeutronPort neutronPort) {
1484         List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
1485         if (neutronFloatingIps != null && !neutronFloatingIps.isEmpty()) {
1486             for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
1487                 // Neutron floating Ip's port uuid cannot be null (Bug#5894)
1488                 if (neutronFloatingIP.getPortUUID() != null &&
1489                         (neutronFloatingIP.getPortUUID().equals(neutronPort.getPortUUID()))) {
1490                     handleNeutronFloatingIPEvent(neutronFloatingIP, DELETE);
1491                 }
1492             }
1493         }
1494     }
1495
1496     private void updateFloatingIPRules(final NeutronPort neutronPort) {
1497         List<NeutronFloatingIP> neutronFloatingIps = neutronFloatingIpCache.getAllFloatingIPs();
1498         if (neutronFloatingIps != null) {
1499             for (NeutronFloatingIP neutronFloatingIP : neutronFloatingIps) {
1500                 if (neutronFloatingIP.getPortUUID() != null
1501                         && neutronFloatingIP.getPortUUID().equals(
1502                                 neutronPort.getPortUUID())) {
1503                     handleNeutronFloatingIPEvent(neutronFloatingIP, UPDATE);
1504                 }
1505             }
1506         }
1507     }
1508
1509
1510     private void triggerGatewayMacResolver(final NeutronPort gatewayPort){
1511
1512         Preconditions.checkNotNull(gatewayPort);
1513         NeutronNetwork externalNetwork = neutronNetworkCache.getNetwork(gatewayPort.getNetworkUUID());
1514
1515         if(externalNetwork != null){
1516             if(externalNetwork.isRouterExternal()){
1517                 final NeutronSubnet externalSubnet = getExternalNetworkSubnet(gatewayPort);
1518
1519                 // TODO: address IPv6 case.
1520                 if (externalSubnet != null &&
1521                         externalSubnet.getIpVersion() == 4 &&
1522                         gatewayPort.getFixedIPs() != null) {
1523                     LOG.info("Trigger MAC resolution for gateway ip {}", externalSubnet.getGatewayIP());
1524                     Neutron_IPs neutronIP = null;
1525                     for (Neutron_IPs nIP : gatewayPort.getFixedIPs()) {
1526                         InetAddress ipAddress;
1527                         try {
1528                             ipAddress = InetAddress.getByName(nIP.getIpAddress());
1529                         } catch (UnknownHostException e) {
1530                             LOG.warn("unknown host exception {}", e);
1531                             continue;
1532                         }
1533                         if (ipAddress instanceof Inet4Address) {
1534                             neutronIP = nIP;
1535                             break;
1536                         }
1537                     }
1538                     if (neutronIP == null) {
1539                         // TODO IPv6 neighbor discovery
1540                         LOG.debug("Ignoring gateway ports with IPv6 only fixed ip {}",
1541                                   gatewayPort.getFixedIPs());
1542                     } else {
1543                         gatewayMacResolver.resolveMacAddress(
1544                             this, /* gatewayMacResolverListener */
1545                             null, /* externalNetworkBridgeDpid */
1546                             true, /* refreshExternalNetworkBridgeDpidIfNeeded */
1547                             new Ipv4Address(externalSubnet.getGatewayIP()),
1548                             new Ipv4Address(neutronIP.getIpAddress()),
1549                             new MacAddress(gatewayPort.getMacAddress()),
1550                             true /* periodicRefresh */);
1551                     }
1552                 } else {
1553                     LOG.warn("No gateway IP address found for external network {}", externalNetwork);
1554                 }
1555             }
1556         }else{
1557             LOG.warn("Neutron network not found for router interface {}", gatewayPort);
1558         }
1559     }
1560
1561
1562     private void storePortInCleanupCache(NeutronPort port) {
1563         this.portCleanupCache.put(port.getPortUUID(),port);
1564     }
1565
1566
1567     private void updatePortInCleanupCache(NeutronPort updatedPort,NeutronPort originalPort) {
1568         removePortFromCleanupCache(originalPort);
1569         storePortInCleanupCache(updatedPort);
1570     }
1571
1572     public void removePortFromCleanupCache(NeutronPort port) {
1573         if(port != null) {
1574             this.portCleanupCache.remove(port.getPortUUID());
1575         }
1576     }
1577
1578     public Map<String, NeutronPort> getPortCleanupCache() {
1579         return this.portCleanupCache;
1580     }
1581
1582     public NeutronPort getPortFromCleanupCache(String portid) {
1583         for (String neutronPortUuid : this.portCleanupCache.keySet()) {
1584             if (neutronPortUuid.equals(portid)) {
1585                 LOG.info("getPortFromCleanupCache: Matching NeutronPort found {}", portid);
1586                 return this.portCleanupCache.get(neutronPortUuid);
1587             }
1588         }
1589         return null;
1590     }
1591
1592     private void storeNetworkInCleanupCache(NeutronNetwork network) {
1593         this.networkCleanupCache.put(network.getNetworkUUID(), network);
1594     }
1595
1596
1597     private void updateNetworkInCleanupCache(NeutronNetwork network) {
1598         for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
1599             if (neutronNetworkUuid.equals(network.getNetworkUUID())) {
1600                 this.networkCleanupCache.remove(neutronNetworkUuid);
1601             }
1602         }
1603         this.networkCleanupCache.put(network.getNetworkUUID(), network);
1604     }
1605
1606     public void removeNetworkFromCleanupCache(String networkid) {
1607         NeutronNetwork network = null;
1608         for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
1609             if (neutronNetworkUuid.equals(networkid)) {
1610                 network = networkCleanupCache.get(neutronNetworkUuid);
1611                 break;
1612             }
1613         }
1614         if (network != null) {
1615             for (String neutronPortUuid:this.portCleanupCache.keySet()) {
1616                 if (this.portCleanupCache.get(neutronPortUuid).getNetworkUUID().equals(network.getNetworkUUID())) {
1617                     LOG.info("This network is used by another port", network);
1618                     return;
1619                 }
1620             }
1621             this.networkCleanupCache.remove(network.getNetworkUUID());
1622         }
1623     }
1624
1625     public Map<String, NeutronNetwork> getNetworkCleanupCache() {
1626         return this.networkCleanupCache;
1627     }
1628
1629     public NeutronNetwork getNetworkFromCleanupCache(String networkid) {
1630         for (String neutronNetworkUuid:this.networkCleanupCache.keySet()) {
1631             if (neutronNetworkUuid.equals(networkid)) {
1632                 LOG.info("getPortFromCleanupCache: Matching NeutronPort found {}", networkid);
1633                 return networkCleanupCache.get(neutronNetworkUuid);
1634             }
1635         }
1636         return null;
1637     }
1638     /**
1639      * Return String that represents OF port with marker explicitly provided (reverse of MatchUtils:parseExplicitOFPort)
1640      *
1641      * @param ofPort the OF port number
1642      * @return the string with encoded OF port (example format "OFPort|999")
1643      */
1644     public static String encodeExcplicitOFPort(Long ofPort) {
1645         return "OFPort|" + ofPort.toString();
1646     }
1647     private void initNetworkCleanUpCache() {
1648         if (this.neutronNetworkCache != null) {
1649             for (NeutronNetwork neutronNetwork : neutronNetworkCache.getAllNetworks()) {
1650                 networkCleanupCache.put(neutronNetwork.getNetworkUUID(), neutronNetwork);
1651             }
1652         }
1653     }
1654     private void initPortCleanUpCache() {
1655         if (this.neutronPortCache != null) {
1656             for (NeutronPort neutronPort : neutronPortCache.getAllPorts()) {
1657                 portCleanupCache.put(neutronPort.getPortUUID(), neutronPort);
1658             }
1659         }
1660     }
1661     @Override
1662     public void setDependencies(ServiceReference serviceReference) {
1663         eventDispatcher =
1664                 (EventDispatcher) ServiceHelper.getGlobalInstance(EventDispatcher.class, this);
1665         eventDispatcher.eventHandlerAdded(serviceReference, this);
1666         tenantNetworkManager =
1667                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1668         configurationService =
1669                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1670         arpProvider =
1671                 (ArpProvider) ServiceHelper.getGlobalInstance(ArpProvider.class, this);
1672         inboundNatProvider =
1673                 (InboundNatProvider) ServiceHelper.getGlobalInstance(InboundNatProvider.class, this);
1674         outboundNatProvider =
1675                 (OutboundNatProvider) ServiceHelper.getGlobalInstance(OutboundNatProvider.class, this);
1676         routingProvider =
1677                 (RoutingProvider) ServiceHelper.getGlobalInstance(RoutingProvider.class, this);
1678         l3ForwardingProvider =
1679                 (L3ForwardingProvider) ServiceHelper.getGlobalInstance(L3ForwardingProvider.class, this);
1680         distributedArpService =
1681                  (DistributedArpService) ServiceHelper.getGlobalInstance(DistributedArpService.class, this);
1682         nodeCacheManager =
1683                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1684         southbound =
1685                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1686         gatewayMacResolver =
1687                 (GatewayMacResolver) ServiceHelper.getGlobalInstance(GatewayMacResolver.class, this);
1688         securityServicesManager =
1689                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1690
1691         initL3AdapterMembers();
1692     }
1693
1694     @Override
1695     public void setDependencies(Object impl) {
1696         if (impl instanceof INeutronNetworkCRUD) {
1697             neutronNetworkCache = (INeutronNetworkCRUD)impl;
1698             initNetworkCleanUpCache();
1699         } else if (impl instanceof INeutronPortCRUD) {
1700             neutronPortCache = (INeutronPortCRUD)impl;
1701             initPortCleanUpCache();
1702         } else if (impl instanceof INeutronSubnetCRUD) {
1703             neutronSubnetCache = (INeutronSubnetCRUD)impl;
1704         } else if (impl instanceof INeutronFloatingIPCRUD) {
1705             neutronFloatingIpCache = (INeutronFloatingIPCRUD)impl;
1706         } else if (impl instanceof ArpProvider) {
1707             arpProvider = (ArpProvider)impl;
1708         } else if (impl instanceof InboundNatProvider) {
1709             inboundNatProvider = (InboundNatProvider)impl;
1710         } else if (impl instanceof OutboundNatProvider) {
1711             outboundNatProvider = (OutboundNatProvider)impl;
1712         } else if (impl instanceof RoutingProvider) {
1713             routingProvider = (RoutingProvider)impl;
1714         } else if (impl instanceof L3ForwardingProvider) {
1715             l3ForwardingProvider = (L3ForwardingProvider)impl;
1716         }else if (impl instanceof GatewayMacResolver) {
1717             gatewayMacResolver = (GatewayMacResolver)impl;
1718         }else if (impl instanceof IcmpEchoProvider) {
1719             icmpEchoProvider = (IcmpEchoProvider)impl;
1720         }
1721
1722         populateL3ForwardingCaches();
1723     }
1724 }