Clean up logging
[netvirt.git] / openstack / net-virt-providers / src / main / java / org / opendaylight / ovsdb / openstack / netvirt / providers / openflow13 / OF13Provider.java
1 /**
2  * Copyright (C) 2013 Red Hat, Inc.
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 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
9
10 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
11 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
12 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
13 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
16 import org.opendaylight.neutron.spi.NeutronNetwork;
17 import org.opendaylight.neutron.spi.NeutronPort;
18 import org.opendaylight.neutron.spi.Neutron_IPs;
19 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
20 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
21 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
22 import org.opendaylight.ovsdb.openstack.netvirt.api.ClassifierProvider;
23 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
24 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
25 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
26 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
27 import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
31 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
32 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
33 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
34 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
35 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
36 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
37 import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
38 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
39 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
40 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
80 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
83 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
84 import org.osgi.framework.BundleContext;
85 import org.osgi.framework.ServiceReference;
86 import org.slf4j.Logger;
87 import org.slf4j.LoggerFactory;
88
89 import com.google.common.base.Optional;
90 import com.google.common.base.Preconditions;
91 import com.google.common.collect.Lists;
92 import com.google.common.collect.Maps;
93 import com.google.common.util.concurrent.CheckedFuture;
94
95 import java.net.InetAddress;
96 import java.util.List;
97 import java.util.Map;
98 import java.util.concurrent.ExecutionException;
99
100
101 /**
102  * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
103  *
104  * @author Madhu Venugopal
105  * @author Brent Salisbury
106  * @author Dave Tucker
107  * @author Sam Hague
108  */
109 // Methods' parameters in this class follow the same pattern to avoid confusion between same-typed parameters
110 // The patterns need to be preserved even though not all parameters are used in all methods
111 @SuppressWarnings("UnusedParameters")
112 public class OF13Provider implements ConfigInterface, NetworkingProvider {
113     private static final Logger LOG = LoggerFactory.getLogger(OF13Provider.class);
114     private static final short TABLE_0_DEFAULT_INGRESS = 0;
115     private static final short TABLE_1_ISOLATE_TENANT = 10;
116     private static final short TABLE_2_LOCAL_FORWARD = 20;
117     private static Long groupId = 1L;
118     private DataBroker dataBroker = null;
119
120     private volatile ConfigurationService configurationService;
121     private volatile BridgeConfigurationManager bridgeConfigurationManager;
122     private volatile TenantNetworkManager tenantNetworkManager;
123     private volatile SecurityServicesManager securityServicesManager;
124     private volatile ClassifierProvider classifierProvider;
125     private volatile IngressAclProvider ingressAclProvider;
126     private volatile EgressAclProvider egressAclProvider;
127     private volatile NodeCacheManager nodeCacheManager;
128     private volatile L2ForwardingProvider l2ForwardingProvider;
129
130     public static final String NAME = "OF13Provider";
131     private volatile BundleContext bundleContext;
132     private volatile Southbound southbound;
133
134     public OF13Provider() {
135         this.dataBroker = NetvirtProvidersProvider.getDataBroker();
136     }
137
138     @Override
139     public String getName() {
140         return NAME;
141     }
142
143     @Override
144     public boolean supportsServices() {
145         return true;
146     }
147
148     @Override
149     public boolean hasPerTenantTunneling() {
150         return false;
151     }
152
153     // The method is tested for in OF13ProviderTest
154     @SuppressWarnings("unused")
155     private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
156         InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
157         if (srcTunnelEndPoint == null) {
158             LOG.error("Tunnel Endpoint not configured for Node {}", node);
159             return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
160         }
161
162         if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
163             LOG.error("{} is not Overlay ready", node);
164             return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
165         }
166
167         if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
168             LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
169             return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
170         }
171         return new Status(StatusCode.SUCCESS);
172     }
173
174     private String getTunnelName(String tunnelType, InetAddress dst) {
175         return tunnelType+"-"+dst.getHostAddress();
176     }
177
178     private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
179         String tunnelBridgeName = configurationService.getIntegrationBridgeName();
180         String portName = getTunnelName(tunnelType, dst);
181         LOG.info("addTunnelPort enter: portName: {}", portName);
182         if (southbound.extractTerminationPointAugmentation(node, portName) != null
183                 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
184             LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
185             return true;
186         }
187
188         Map<String, String> options = Maps.newHashMap();
189         options.put("key", "flow");
190         options.put("local_ip", src.getHostAddress());
191         options.put("remote_ip", dst.getHostAddress());
192
193         if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
194             LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
195             return false;
196         }
197
198             LOG.info("addTunnelPort exit: portName: {}", portName);
199         return true;
200     }
201
202     /* delete port from ovsdb port table */
203     private boolean deletePort(Node node, String bridgeName, String portName) {
204         // TODO SB_MIGRATION
205         // might need to convert from ovsdb node to bridge node
206         return southbound.deleteTerminationPoint(node, portName);
207     }
208
209     private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
210         String tunnelBridgeName = configurationService.getIntegrationBridgeName();
211         String portName = getTunnelName(tunnelType, dst);
212         return deletePort(node, tunnelBridgeName, portName);
213     }
214
215     private boolean deletePhysicalPort(Node node, String phyIntfName) {
216         String intBridgeName = configurationService.getIntegrationBridgeName();
217         return deletePort(node, intBridgeName, phyIntfName);
218     }
219
220     private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
221                                          String attachedMac, long localPort) {
222         /*
223          * Table(0) Rule #3
224          * ----------------
225          * Match: VM sMac and Local Ingress Port
226          * Action:Action: Set Tunnel ID and GOTO Local Table (5)
227          */
228
229         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
230                 segmentationId, localPort, attachedMac, true);
231
232         /*
233          * Table(0) Rule #4
234          * ----------------
235          * Match: Drop any remaining Ingress Local VM Packets
236          * Action: Drop w/ a low priority
237          */
238
239         handleDropSrcIface(dpid, localPort, true);
240
241         /*
242          * Table(2) Rule #1
243          * ----------------
244          * Match: Match TunID and Destination DL/dMAC Addr
245          * Action: Output Port
246          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
247          */
248
249         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
250
251         /*
252          * Table(2) Rule #2
253          * ----------------
254          * Match: Tunnel ID and dMAC (::::FF:FF)
255          * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
256          * actions=output:2,3,4,5
257          */
258
259         handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
260         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
261
262         /*
263          * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
264          */
265         /*
266          * Table(1) Rule #3
267          * ----------------
268          * Match:  Any remaining Ingress Local VM Packets
269          * Action: Drop w/ a low priority
270          * -------------------------------------------
271          * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
272          */
273
274         handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
275
276         /*
277          * Table(2) Rule #3
278          * ----------------
279          * Match: Any Remaining Flows w/a TunID
280          * Action: Drop w/ a low priority
281          * table=2,priority=8192,tun_id=0x5 actions=drop
282          */
283
284         handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
285     }
286
287     private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
288         /*
289          * Table(0) Rule #3
290          * ----------------
291          * Match: VM sMac and Local Ingress Port
292          * Action:Action: Set Tunnel ID and GOTO Local Table (5)
293          */
294
295         handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
296
297         /*
298          * Table(0) Rule #4
299          * ----------------
300          * Match: Drop any remaining Ingress Local VM Packets
301          * Action: Drop w/ a low priority
302          */
303
304         handleDropSrcIface(dpid, localPort, false);
305
306         /*
307          * Table(2) Rule #1
308          * ----------------
309          * Match: Match TunID and Destination DL/dMAC Addr
310          * Action: Output Port
311          * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
312          */
313
314         handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
315
316         /*
317          * Table(2) Rule #2
318          * ----------------
319          * Match: Tunnel ID and dMAC (::::FF:FF)
320          * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
321          * actions=output:2,3,4,5
322          */
323
324         handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
325         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
326     }
327
328     private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
329         /*
330          * Table(0) Rule #2
331          * ----------------
332          * Match: Ingress Port, Tunnel ID
333          * Action: GOTO Local Table (20)
334          */
335
336         handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
337
338         /*
339          * Table(1) Rule #2
340          * ----------------
341          * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
342          * Action: Flood to selected destination TEPs
343          * -------------------------------------------
344          * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
345          * actions=output:10,output:11,goto_table:2
346          */
347
348         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
349
350     }
351
352     private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
353         /*
354          * Table(1) Rule #1
355          * ----------------
356          * Match: Drop any remaining Ingress Local VM Packets
357          * Action: Drop w/ a low priority
358          * -------------------------------------------
359          * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
360          * actions=output:11,goto_table:2
361          */
362
363         handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
364     }
365
366     private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
367         /*
368          * Table(1) Rule #1
369          * ----------------
370          * Match: Drop any remaining Ingress Local VM Packets
371          * Action: Drop w/ a low priority
372          * -------------------------------------------
373          * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
374          * actions=output:11,goto_table:2
375          */
376
377         handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
378     }
379
380     /* Remove tunnel rules if last node in this tenant network */
381     private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
382         /*
383          * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
384          */
385         /*
386          * Table(1) Rule #3
387          * ----------------
388          * Match:  Any remaining Ingress Local VM Packets
389          * Action: Drop w/ a low priority
390          * -------------------------------------------
391          * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
392          */
393
394         handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
395
396         /*
397          * Table(2) Rule #3
398          * ----------------
399          * Match: Any Remaining Flows w/a TunID
400          * Action: Drop w/ a low priority
401          * table=2,priority=8192,tun_id=0x5 actions=drop
402          */
403
404         handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
405
406         /*
407          * Table(0) Rule #2
408          * ----------------
409          * Match: Ingress Port, Tunnel ID
410          * Action: GOTO Local Table (10)
411          */
412
413         handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
414
415         /*
416          * Table(1) Rule #2
417          * ----------------
418          * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
419          * Action: Flood to selected destination TEPs
420          * -------------------------------------------
421          * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
422          * actions=output:10,output:11,goto_table:2
423          */
424
425         handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
426     }
427
428     private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
429         /*
430          * Table(0) Rule #1
431          * ----------------
432          * Tag traffic coming from the local port and vm srcmac
433          * Match: VM sMac and Local Ingress Port
434          * Action: Set VLAN ID and GOTO Local Table 1
435          */
436
437         handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
438                 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
439                 attachedMac, true);
440
441         /*
442          * Table(0) Rule #3
443          * ----------------
444          * Drop all other traffic coming from the local port
445          * Match: Drop any remaining Ingress Local VM Packets
446          * Action: Drop w/ a low priority
447          */
448
449         handleDropSrcIface(dpid, localPort, true);
450
451         /*
452          * Table(2) Rule #1
453          * ----------------
454          * Forward unicast traffic destined to the local port after stripping tag
455          * Match: Match VLAN ID and Destination DL/dMAC Addr
456          * Action: strip vlan, output to local port
457          * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
458          */
459
460         handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
461                 localPort, attachedMac, true);
462
463         /*
464          * Table(2) Rule #2
465          * ----------------
466          * Match: VLAN ID and dMAC (::::FF:FF)
467          * Action: strip vlan, output to all local ports in this vlan
468          * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
469          * actions= strip_vlan, output:2,3,4,5
470          */
471
472         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
473         //        localPort, ethPort, true);
474         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
475         //        segmentationId, localPort, ethport, true);
476
477         /*
478          * Table(2) Rule #3
479          * ----------------
480          * Match: Any Remaining Flows w/a VLAN ID
481          * Action: Drop w/ a low priority
482          * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
483          */
484
485         //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
486         //        true);
487     }
488
489     private void removeLocalVlanRules(Node node, Long dpid,
490                                       String segmentationId, String attachedMac, long localPort) {
491         /*
492          * Table(0) Rule #1
493          * ----------------
494          * Match: VM sMac and Local Ingress Port
495          * Action: Set VLAN ID and GOTO Local Table 1
496          */
497
498         handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
499                 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
500                 attachedMac, false);
501
502         /*
503          * Table(0) Rule #3
504          * ----------------
505          * Match: Drop any remaining Ingress Local VM Packets
506          * Action: Drop w/ a low priority
507          */
508
509         handleDropSrcIface(dpid, localPort, false);
510
511         /*
512          * Table(2) Rule #1
513          * ----------------
514          * Match: Match VLAN ID and Destination DL/dMAC Addr
515          * Action: strip vlan, output to local port
516          * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
517          */
518
519         handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
520                 localPort, attachedMac, false);
521
522         /*
523          * Table(2) Rule #2
524          * ----------------
525          * Match: VLAN ID and dMAC (::::FF:FF)
526          * Action: strip vlan, output to all local ports in this vlan
527          * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
528          * actions= strip_vlan, output:2,3,4,5
529          */
530
531         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
532         //        localPort, ethPort, false);
533         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
534         //        segmentationId, localPort, false);
535
536     }
537
538     private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
539                                               long localPort, long ethPort) {
540         /*
541          * Table(0) Rule #2
542          * ----------------
543          * Match: Ingress port = physical interface, Vlan ID
544          * Action: GOTO Local Table 2
545          */
546
547         handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
548                 segmentationId, ethPort, true);
549
550         /*
551          * Table(1) Rule #2
552          * ----------------
553          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
554          * Action: Flood to local and remote VLAN members
555          * -------------------------------------------
556          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
557          * actions=output:10 (eth port),goto_table:2
558          * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
559          */
560
561         handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
562
563         /*
564          * Table(1) Rule #2
565          * ----------------
566          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
567          * Action: Flood to local and remote VLAN members
568          * -------------------------------------------
569          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
570          * actions=output:10 (eth port),goto_table:2
571          */
572
573         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
574         //        segmentationId, ethPort, true);
575     }
576
577     private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
578                                               String attachedMac, long ethPort) {
579         /*
580          * Table(1) Rule #1
581          * ----------------
582          * Match: Destination MAC is local VM MAC and vlan id
583          * Action: go to table 2
584          * -------------------------------------------
585          * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
586          * actions=goto_table:2
587          */
588
589         //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
590         //        segmentationId, ethPort, attachedMac, true);
591
592         /*
593          * Table(1) Rule #3
594          * ----------------
595          * Match:  VLAN ID
596          * Action: Go to table 2
597          * -------------------------------------------
598          * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
599          * table=110,priority=8192,dl_vlan=2001 actions=output:2
600          */
601
602         handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
603     }
604
605     private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
606                                              String attachedMac, long localPort, long ethPort) {
607         /*
608          * Table(1) Rule #1
609          * ----------------
610          * Match: Destination MAC is local VM MAC and vlan id
611          * Action: go to table 2
612          * -------------------------------------------
613          * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
614          * actions=goto_table:2
615          */
616
617         //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
618         //        segmentationId, ethPort, attachedMac, false);
619
620         /*
621          * Table(1) Rule #2
622          * ----------------
623          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
624          * Action: Flood to local and remote VLAN members
625          * -------------------------------------------
626          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
627          * actions=output:10 (eth port),goto_table:2
628          * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
629          */
630
631         handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
632     }
633
634     private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
635         /*
636          * Table(2) Rule #3
637          * ----------------
638          * Match: Any Remaining Flows w/a VLAN ID
639          * Action: Drop w/ a low priority
640          * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
641          */
642
643         //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
644
645         /*
646          * Table(0) Rule #2
647          * ----------------
648          * Match: Ingress port = physical interface, Vlan ID
649          * Action: GOTO Local Table 2
650          */
651
652         handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
653
654         /*
655          * Table(1) Rule #2
656          * ----------------
657          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
658          * Action: Flood to local and remote VLAN members
659          * -------------------------------------------
660          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
661          * actions=output:10 (eth port),goto_table:2
662          * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
663          */
664
665         //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
666
667         /*
668          * Table(1) Rule #2
669          * ----------------
670          * Match: Match VLAN ID and L2 ::::FF:FF Flooding
671          * Action: Flood to local and remote VLAN members
672          * -------------------------------------------
673          * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
674          * actions=output:10 (eth port),goto_table:2
675          */
676
677         //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
678         //        segmentationId, ethPort, false);
679
680         /*
681          * Table(1) Rule #3
682          * ----------------
683          * Match:  VLAN ID
684          * Action: Go to table 2
685          * -------------------------------------------
686          * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
687          * table=110,priority=8192,dl_vlan=2001 actions=output:2
688          */
689
690         handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
691     }
692
693     private long getDpid(Node node) {
694         long dpid = southbound.getDataPathId(node);
695         if (dpid == 0) {
696             LOG.warn("getDpid: dpid not found: {}", node);
697         }
698         return dpid;
699     }
700
701     private long getIntegrationBridgeOFDPID(Node node) {
702         long dpid = 0L;
703         if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
704             dpid = getDpid(node);
705         }
706         return dpid;
707     }
708
709     /**
710      * Returns true is the network if of type GRE or VXLAN
711      *
712      * @param networkType The type of the network
713      * @return returns true if the network is a tunnel
714      */
715     private boolean isTunnel(String networkType)
716     {
717         return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
718                 (NetworkHandler.NETWORK_TYPE_VXLAN));
719     }
720
721     /**
722      * Returns true if the network is of type vlan.
723      *
724      * @param networkType The type of the network
725      * @return returns true if the network is a vlan
726      */
727     private boolean isVlan(String networkType)
728     {
729         return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
730     }
731
732     private void programLocalRules (String networkType, String segmentationId, Node node,
733                                     OvsdbTerminationPointAugmentation intf) {
734         LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
735                 node.getNodeId(), intf.getName(), networkType, segmentationId);
736         try {
737             long dpid = getIntegrationBridgeOFDPID(node);
738             if (dpid == 0L) {
739                 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
740                         node);
741                 return;
742             }
743
744             long localPort = southbound.getOFPort(intf);
745             if (localPort == 0) {
746                 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}", intf.getName(), node.getNodeId());
747                 return;
748             }
749
750             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
751             if (attachedMac == null) {
752                 LOG.warn("No AttachedMac seen in {}", intf);
753                 return;
754             }
755
756             /* Program local rules based on network type */
757             if (isVlan(networkType)) {
758                 LOG.debug("Program local vlan rules for interface {}", intf.getName());
759                 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
760             }
761             if ((isTunnel(networkType)|| isVlan(networkType))) {
762                 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
763                 // Get the DHCP port for the subnet to which  the interface belongs to.
764                 NeutronPort dhcpPort = securityServicesManager.getDHCPServerPort(intf);
765                 if (null != dhcpPort) {
766                     boolean isComputePort =securityServicesManager.isComputePort(intf);
767                     boolean isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
768                     boolean isLastPortinSubnet =false;
769                     List<Neutron_IPs> srcAddressList = null;
770                     if(isComputePort) {
771                         isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
772                         srcAddressList = securityServicesManager.getIpAddress(node, intf);
773                         if (null == srcAddressList) {
774                             LOG.warn("programLocalRules: No Ip address assigned {}", intf);
775                             return;
776                         }
777                     }
778                     ingressAclProvider.programFixedSecurityACL(dpid,segmentationId, dhcpPort.getMacAddress(), localPort,
779                             isLastPortinSubnet,isComputePort,   true);
780                     egressAclProvider.programFixedSecurityACL(dpid, segmentationId, attachedMac, localPort,
781                                                               srcAddressList, isLastPortinBridge, isComputePort,true);
782                 } else {
783                     LOG.warn("programLocalRules: No DCHP port seen in  network of {}", intf);
784                 }
785             }
786             /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
787             /* TODO SB_MIGRATION */
788             /*if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
789                     (NetworkHandler.NETWORK_TYPE_VXLAN)) && securityServicesManager.isPortSecurityReady(intf)) {
790                 LOG.debug("Neutron port has a Port Security Group");
791                 // Retrieve the security group UUID from the Neutron Port
792                 NeutronSecurityGroup securityGroupInPort = securityServicesManager.getSecurityGroupInPort(intf);
793                 LOG.debug("Program Local rules for networkType: {} does contain a Port Security Group: {} " +
794                         "to be installed on DPID: {}", networkType, securityGroupInPort, dpid);
795                 ingressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
796                         securityGroupInPort);
797                 egressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
798                         securityGroupInPort);
799             }*/
800             if (isTunnel(networkType)) {
801                 LOG.debug("Program local bridge rules for interface {}, "
802                                 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
803                         intf.getName(), dpid, segmentationId, attachedMac, localPort);
804                 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
805             }
806         } catch (Exception e) {
807             LOG.error("Exception in programming Local Rules for " + intf + " on " + node, e);
808         }
809     }
810
811     private void removeLocalRules (String networkType, String segmentationId, Node node,
812                                    OvsdbTerminationPointAugmentation intf) {
813         LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
814                 node.getNodeId(), intf.getName(), networkType, segmentationId);
815         try {
816             long dpid = getIntegrationBridgeOFDPID(node);
817             if (dpid == 0L) {
818                 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
819                 return;
820             }
821
822             long localPort = southbound.getOFPort(intf);
823             if (localPort == 0) {
824                 LOG.info("removeLocalRules: could not find ofPort");
825                 return;
826             }
827
828             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
829             if (attachedMac == null) {
830                 LOG.warn("No AttachedMac seen in {}", intf);
831                 return;
832             }
833
834             /* Program local rules based on network type */
835             if (isVlan(networkType)) {
836                 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
837                 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
838             } else if (isTunnel(networkType)) {
839                 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
840                 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
841             }
842             if (isTunnel(networkType)|| isVlan(networkType)) {
843                 LOG.debug("removeLocalRules: Remove fixed security group rules for interface {}", intf.getName());
844                 NeutronPort dhcpPort = securityServicesManager.getDHCPServerPort(intf);
845                 if (null != dhcpPort) {
846                     List<Neutron_IPs> srcAddressList = securityServicesManager.getIpAddress(node, intf);
847                     if (null == srcAddressList) {
848                         LOG.warn("removeLocalRules: No Ip address assigned {}", intf);
849                         return;
850                     }
851                     boolean isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
852                     boolean isComputePort =securityServicesManager.isComputePort(intf);
853                     boolean isLastPortinSubnet =false;
854                     if (isComputePort)
855                     {
856                         isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
857                     }
858                     ingressAclProvider.programFixedSecurityACL(dpid,    segmentationId, dhcpPort.getMacAddress(), localPort,
859                             isLastPortinSubnet, isComputePort, false);
860                     egressAclProvider.programFixedSecurityACL(dpid, segmentationId,     attachedMac, localPort,
861                                                               srcAddressList, isLastPortinBridge, isComputePort, false);
862                 }else{
863                     LOG.warn("removeLocalRules: No DCHP port seen in  network of {}", intf);
864                 }
865             }
866         } catch (Exception e) {
867             LOG.error("Exception in removing Local Rules for " + intf + " on " + node, e);
868         }
869     }
870
871     // TODO SB_MIGRATION
872     // Need to handle case where a node comes online after a network and tunnels have
873     // already been created. The interface update is what triggers creating the l2 forwarding flows
874     // so we don't see those updates in this case - we only see the new nodes interface updates.
875     private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
876                                      OvsdbTerminationPointAugmentation intf, boolean local) {
877         LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
878                         + "segmentationId: {}, dstAddr: {}",
879                 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
880         try {
881             long dpid = getIntegrationBridgeOFDPID(node);
882             if (dpid == 0L) {
883                 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
884                 return;
885             }
886
887             long localPort = southbound.getOFPort(intf);
888             if (localPort == 0) {
889                 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
890                 return;
891             }
892
893             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
894             if (attachedMac == null) {
895                 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
896                 return;
897             }
898
899             OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
900             if(tunnelPort != null){
901                 long tunnelOFPort = southbound.getOFPort(tunnelPort);
902                 if (tunnelOFPort == 0) {
903                     LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
904                             tunnelPort.getName(), tunnelOFPort, node);
905                     return;
906                 }
907                 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
908                         tunnelPort.getName(), tunnelOFPort, node);
909
910                 if (!local) {
911                     LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
912                             node.getNodeId().getValue(), intf.getName());
913                     programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
914                             tunnelOFPort, localPort);
915                 } else {
916                     LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
917                             node.getNodeId().getValue(), intf.getName());
918                     programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
919                             tunnelOFPort, localPort);
920                 }
921             }
922         } catch (Exception e) {
923             LOG.trace("", e);
924         }
925     }
926
927     private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
928                                     OvsdbTerminationPointAugmentation intf,
929                                     boolean local, boolean isLastInstanceOnNode) {
930         LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
931                         + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
932                 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
933         try {
934             long dpid = getIntegrationBridgeOFDPID(node);
935             if (dpid == 0L) {
936                 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
937                 return;
938             }
939
940             long localPort = southbound.getOFPort(intf);
941             if (localPort == 0) {
942                 LOG.info("removeTunnelRules: could not find ofPort");
943                 return;
944             }
945
946             String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
947             if (attachedMac == null) {
948                 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
949                 return;
950             }
951
952             List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
953             for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
954                 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
955                     long tunnelOFPort = southbound.getOFPort(tunIntf);
956                     if (tunnelOFPort == 0) {
957                         LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
958                                 tunIntf.getName(), tunnelOFPort, node);
959                         return;
960                     }
961                     LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
962                             tunIntf.getName(), tunnelOFPort, node);
963
964                     if (!local) {
965                         removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
966                                 tunnelOFPort, localPort);
967                     }
968                     if (local && isLastInstanceOnNode) {
969                         removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
970                     }
971                     return;
972                 }
973             }
974         } catch (Exception e) {
975             LOG.error("", e);
976         }
977     }
978
979     private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
980         LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
981                 node.getNodeId(), network.getNetworkUUID(), intf.getName());
982         long dpid = getIntegrationBridgeOFDPID(node);
983         if (dpid == 0L) {
984             LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
985             return;
986         }
987
988         long localPort = southbound.getOFPort(intf);
989         if (localPort == 0) {
990             LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
991             return;
992         }
993
994         String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
995         if (attachedMac == null) {
996             LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
997             return;
998         }
999
1000         String phyIfName =
1001                 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
1002         long ethOFPort = southbound.getOFPort(node, phyIfName);
1003         if (ethOFPort == 0) {
1004             LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
1005             return;
1006         }
1007         LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
1008                 phyIfName, ethOFPort, node);
1009         // TODO: add logic to only add rule on remote nodes
1010         programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
1011                 attachedMac, ethOFPort);
1012         programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
1013                 attachedMac, localPort, ethOFPort);
1014     }
1015
1016     private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
1017                                   boolean isLastInstanceOnNode) {
1018         LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
1019                 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
1020         long dpid = getIntegrationBridgeOFDPID(node);
1021         if (dpid == 0L) {
1022             LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
1023             return;
1024         }
1025
1026         long localPort = southbound.getOFPort(intf);
1027         if (localPort == 0) {
1028             LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
1029             return;
1030         }
1031
1032         String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
1033         if (attachedMac == null) {
1034             LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
1035             return;
1036         }
1037
1038         String phyIfName =
1039                 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
1040         long ethOFPort = southbound.getOFPort(node, phyIfName);
1041         if (ethOFPort == 0) {
1042             LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
1043             return;
1044         }
1045         LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
1046                 phyIfName, ethOFPort, node);
1047
1048         removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
1049                 attachedMac, localPort, ethOFPort);
1050         if (isLastInstanceOnNode) {
1051             removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1052         }
1053     }
1054
1055     @Override
1056     public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
1057                                          OvsdbTerminationPointAugmentation intf) {
1058         Preconditions.checkNotNull(nodeCacheManager);
1059         Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1060                 nodeCacheManager.getOvsdbNodes();
1061         nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1062         String networkType = network.getProviderNetworkType();
1063         String segmentationId = network.getProviderSegmentationID();
1064         Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1065         programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1066
1067         if (isVlan(networkType)) {
1068             programVlanRules(network, srcNode, intf);
1069         } else if (isTunnel(networkType)){
1070
1071             boolean sourceTunnelStatus;
1072             boolean destTunnelStatus = false;
1073             for (Node dstNode : nodes.values()) {
1074                 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1075                 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1076                 if ((src != null) && (dst != null)) {
1077                     sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1078
1079                     Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1080                             configurationService.getIntegrationBridgeName());
1081
1082                     if(dstBridgeNode != null){
1083                         destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1084                     }
1085
1086                     if (sourceTunnelStatus) {
1087                         programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1088                     }
1089                     if (destTunnelStatus) {
1090                         programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1091                     }
1092                 } else {
1093                     LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1094                                     + "Check source {} or destination {}",
1095                             src != null ? src.getHostAddress() : "null",
1096                             dst != null ? dst.getHostAddress() : "null");
1097                 }
1098             }
1099         }
1100
1101         return true;
1102     }
1103
1104     private void triggerInterfaceUpdates(Node node) {
1105         LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
1106         List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1107         if (ports != null && !ports.isEmpty()) {
1108             for (OvsdbTerminationPointAugmentation port : ports) {
1109                 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1110                 if (neutronNetwork != null) {
1111                     LOG.warn("Trigger Interface update for {}", port);
1112                     handleInterfaceUpdate(neutronNetwork, node, port);
1113                 }
1114             }
1115         } else {
1116             LOG.warn("triggerInterfaceUpdates: tps are null");
1117         }
1118         LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1119     }
1120
1121     @Override
1122     public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1123                                          OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1124         Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1125                 nodeCacheManager.getOvsdbNodes();
1126         nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1127
1128         LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1129         List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1130         if (southbound.isTunnel(intf)) {
1131             // Delete tunnel port
1132             try {
1133                 InetAddress src = InetAddress.getByName(
1134                         southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1135                 InetAddress dst = InetAddress.getByName(
1136                         southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1137                 deleteTunnelPort(srcNode,
1138                         MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1139                         src, dst);
1140             } catch (Exception e) {
1141                 LOG.error(e.getMessage(), e);
1142             }
1143         } else if (phyIfName.contains(intf.getName())) {
1144             deletePhysicalPort(srcNode, intf.getName());
1145         } else {
1146             // delete all other interfaces
1147             removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1148                     srcNode, intf);
1149
1150             if (isVlan(network.getProviderNetworkType())) {
1151                 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1152             } else if (isTunnel(network.getProviderNetworkType())) {
1153
1154                 for (Node dstNode : nodes.values()) {
1155                     InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1156                     InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1157                     if ((src != null) && (dst != null)) {
1158                         LOG.info("Remove tunnel rules for interface "
1159                                 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1160                         removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1161                                 dst, srcNode, intf, true, isLastInstanceOnNode);
1162                         Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1163                         if(dstBridgeNode != null){
1164                             LOG.info("Remove tunnel rules for interface "
1165                                     + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1166                             removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1167                                     src, dstBridgeNode, intf, false, isLastInstanceOnNode);
1168                         }
1169                     } else {
1170                         LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1171                                         + "OpenVSwitch Table. "
1172                                         + "Check source {} or destination {}",
1173                                 src != null ? src.getHostAddress() : "null",
1174                                 dst != null ? dst.getHostAddress() : "null");
1175                     }
1176                 }
1177             }
1178         }
1179         return true;
1180     }
1181
1182     @Override
1183     public void initializeFlowRules(Node node) {
1184         initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1185         initializeFlowRules(node, configurationService.getExternalBridgeName());
1186         triggerInterfaceUpdates(node);
1187     }
1188
1189     private void initializeFlowRules(Node node, String bridgeName) {
1190         Long dpid = southbound.getDataPathId(node);
1191         String datapathId = southbound.getDatapathId(node);
1192         LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
1193                 bridgeName, dpid, datapathId);
1194
1195         if (dpid == 0L) {
1196             LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1197             return;
1198         }
1199
1200         /*
1201          * Table(0) Rule #1
1202          * ----------------
1203          * Match: LLDP (0x88CCL)
1204          * Action: Packet_In to Controller Reserved Port
1205          */
1206
1207         writeLLDPRule(dpid);
1208
1209         if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1210             writeNormalRule(dpid);
1211         }
1212     }
1213
1214     /*
1215      * Create an LLDP Flow Rule to encapsulate into
1216      * a packet_in that is sent to the controller
1217      * for topology handling.
1218      * Match: Ethertype 0x88CCL
1219      * Action: Punt to Controller in a Packet_In msg
1220      */
1221
1222     private void writeLLDPRule(Long dpidLong) {
1223         classifierProvider.programLLDPPuntRule(dpidLong);
1224     }
1225
1226     /*
1227      * Create a NORMAL Table Miss Flow Rule
1228      * Match: any
1229      * Action: forward to NORMAL pipeline
1230      */
1231
1232     private void writeNormalRule(Long dpidLong) {
1233
1234         String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1235
1236         MatchBuilder matchBuilder = new MatchBuilder();
1237         NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1238         FlowBuilder flowBuilder = new FlowBuilder();
1239
1240         // Create the OF Actions and Instructions
1241         InstructionBuilder ib = new InstructionBuilder();
1242         InstructionsBuilder isb = new InstructionsBuilder();
1243
1244         // Instructions List Stores Individual Instructions
1245         List<Instruction> instructions = Lists.newArrayList();
1246
1247         // Call the InstructionBuilder Methods Containing Actions
1248         InstructionUtils.createNormalInstructions(nodeName, ib);
1249         ib.setOrder(0);
1250         ib.setKey(new InstructionKey(0));
1251         instructions.add(ib.build());
1252
1253         // Add InstructionBuilder to the Instruction(s)Builder List
1254         isb.setInstruction(instructions);
1255
1256         // Add InstructionsBuilder to FlowBuilder
1257         flowBuilder.setInstructions(isb.build());
1258
1259         String flowId = "NORMAL";
1260         flowBuilder.setId(new FlowId(flowId));
1261         FlowKey key = new FlowKey(new FlowId(flowId));
1262         flowBuilder.setMatch(matchBuilder.build());
1263         flowBuilder.setPriority(0);
1264         flowBuilder.setBarrier(true);
1265         flowBuilder.setTableId((short) 0);
1266         flowBuilder.setKey(key);
1267         flowBuilder.setFlowName(flowId);
1268         flowBuilder.setHardTimeout(0);
1269         flowBuilder.setIdleTimeout(0);
1270         writeFlow(flowBuilder, nodeBuilder);
1271     }
1272
1273     /*
1274      * (Table:0) Ingress Tunnel Traffic
1275      * Match: OpenFlow InPort and Tunnel ID
1276      * Action: GOTO Local Table (10)
1277      * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1278      */
1279
1280     private void handleTunnelIn(Long dpidLong, Short writeTable,
1281             Short goToTableId, String segmentationId,
1282             Long ofPort, boolean write) {
1283         classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1284     }
1285
1286     /*
1287      * (Table:0) Ingress VLAN Traffic
1288      * Match: OpenFlow InPort and vlan ID
1289      * Action: GOTO Local Table (20)
1290      * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1291      */
1292
1293     private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1294             String segmentationId,  Long ethPort, boolean write) {
1295         classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1296     }
1297
1298     /*
1299      * (Table:0) Egress VM Traffic Towards TEP
1300      * Match: Destination Ethernet Addr and OpenFlow InPort
1301      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1302      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1303      * actions=set_field:5->tun_id,goto_table=1"
1304      */
1305
1306     private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1307             String segmentationId, Long inPort, String attachedMac,
1308             boolean write) {
1309         classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1310     }
1311
1312     /*
1313      * (Table:0) Egress VM Traffic Towards TEP
1314      * Match: Source Ethernet Addr and OpenFlow InPort
1315      * Instruction: Set VLANID and GOTO Table Egress (n)
1316      * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1317      * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1318      */
1319
1320     private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1321             Short goToTableId, String segmentationId,
1322             Long inPort, String attachedMac,
1323             boolean write) {
1324         classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1325     }
1326
1327     /*
1328      * (Table:0) Drop frames source from a VM that do not
1329      * match the associated MAC address of the local VM.
1330      * Match: Low priority anything not matching the VM SMAC
1331      * Instruction: Drop
1332      * table=0,priority=16384,in_port=1 actions=drop"
1333      */
1334
1335     private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1336         classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1337     }
1338
1339     /*
1340      * (Table:1) Egress Tunnel Traffic
1341      * Match: Destination Ethernet Addr and Local InPort
1342      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1343      * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1344      * actions=output:10,goto_table:2"
1345      */
1346     private void handleTunnelOut(Long dpidLong, Short writeTable,
1347             Short goToTableId, String segmentationId,
1348             Long OFPortOut, String attachedMac,
1349             boolean write) {
1350         l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1351     }
1352
1353     /*
1354      * (Table:1) Egress VLAN Traffic
1355      * Match: Destination Ethernet Addr and VLAN id
1356      * Instruction: GOTO Table Table 2
1357      * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1358      * actions= goto_table:2"
1359      */
1360     // TODO This method is referenced from commented code above (which needs to be checked)
1361     @SuppressWarnings("unused")
1362     private void handleVlanOut(Long dpidLong, Short writeTable,
1363             Short goToTableId, String segmentationId,
1364             Long ethPort, String attachedMac, boolean write) {
1365         l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1366     }
1367
1368     /*
1369      * (Table:1) Egress Tunnel Traffic
1370      * Match: Destination Ethernet Addr and Local InPort
1371      * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1372      * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1373      * actions=output:10,output:11,goto_table:2
1374      */
1375
1376     private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1377             Short localTable, String segmentationId,
1378             Long OFPortOut, boolean write) {
1379         l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1380     }
1381
1382     /*
1383      * (Table:1) Egress VLAN Traffic
1384      * Match: Destination Ethernet Addr and VLAN id
1385      * Instruction: GOTO table 2 and Output port eth interface
1386      * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1387      * actions=output:eth1,goto_table:2
1388      */
1389     // TODO This method is referenced from commented code above (which needs to be checked)
1390     @SuppressWarnings("unused")
1391     private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1392             Short localTable, String segmentationId,
1393             Long localPort, Long ethPort, boolean write) {
1394         //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1395     }
1396
1397     /*
1398      * (Table:1) Table Drain w/ Catch All
1399      * Match: Tunnel ID
1400      * Action: GOTO Local Table (10)
1401      * table=2,priority=8192,tun_id=0x5 actions=drop
1402      */
1403
1404     private void handleTunnelMiss(Long dpidLong, Short writeTable,
1405             Short goToTableId, String segmentationId,
1406             boolean write) {
1407         l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1408     }
1409
1410
1411     /*
1412      * (Table:1) Table Drain w/ Catch All
1413      * Match: Vlan ID
1414      * Action: Output port eth interface
1415      * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1416      * table=110,priority=8192,dl_vlan=2001 actions=output:2
1417      */
1418
1419     private void handleVlanMiss(Long dpidLong, Short writeTable,
1420             Short goToTableId, String segmentationId,
1421             Long ethPort, boolean write) {
1422         l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1423     }
1424
1425     /*
1426      * (Table:1) Local Broadcast Flood
1427      * Match: Tunnel ID and dMAC
1428      * Action: Output Port
1429      * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1430      */
1431
1432     private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1433             String segmentationId, Long localPort,
1434             String attachedMac, boolean write) {
1435         l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1436     }
1437
1438     /*
1439      * (Table:2) Local VLAN unicast
1440      * Match: VLAN ID and dMAC
1441      * Action: Output Port
1442      * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1443      */
1444
1445     private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1446             String segmentationId, Long localPort,
1447             String attachedMac, boolean write) {
1448         l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1449     }
1450
1451     /*
1452      * (Table:2) Local Broadcast Flood
1453      * Match: Tunnel ID and dMAC (::::FF:FF)
1454      * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1455      * actions=output:2,3,4,5
1456      */
1457
1458     private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1459             String segmentationId, Long localPort,
1460             boolean write) {
1461         l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1462     }
1463
1464     /*
1465      * (Table:2) Local VLAN Broadcast Flood
1466      * Match: vlan ID and dMAC (::::FF:FF)
1467      * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1468      * actions=strip_vlan, output:2,3,4,5
1469      * table=110,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
1470      */
1471
1472     private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1473                                          Long localPort, Long ethPort, boolean write) {
1474         l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1475     }
1476
1477     /*
1478      * (Table:1) Local Table Miss
1479      * Match: Any Remaining Flows w/a TunID
1480      * Action: Drop w/ a low priority
1481      * table=2,priority=8192,tun_id=0x5 actions=drop
1482      */
1483
1484     private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1485             String segmentationId, boolean write) {
1486         l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1487     }
1488
1489     /*
1490      * (Table:1) Local Table Miss
1491      * Match: Any Remaining Flows w/a VLAN ID
1492      * Action: Drop w/ a low priority
1493      * table=2,priority=8192,vlan_id=0x5 actions=drop
1494      */
1495     // TODO This method is referenced from commented code above (which needs to be checked)
1496     @SuppressWarnings("unused")
1497     private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1498             String segmentationId, boolean write) {
1499         l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1500     }
1501
1502     private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1503         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1504                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1505                         new GroupKey(groupBuilder.getGroupId())).build();
1506         ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1507         try {
1508             Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1509             if (data.isPresent()) {
1510                 return data.get();
1511             }
1512         } catch (InterruptedException|ExecutionException e) {
1513             LOG.error(e.getMessage(), e);
1514         }
1515
1516         LOG.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1517         return null;
1518     }
1519
1520     private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1521         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1522         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1523                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1524                         new GroupKey(groupBuilder.getGroupId())).build();
1525         modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1526
1527         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1528         try {
1529             commitFuture.get();  // TODO: Make it async (See bug 1362)
1530             LOG.debug("Transaction success for write of Group " + groupBuilder.getGroupName());
1531         } catch (InterruptedException|ExecutionException e) {
1532             LOG.error(e.getMessage(), e);
1533         }
1534     }
1535
1536     private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1537         WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1538         InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1539                 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1540                         new GroupKey(groupBuilder.getGroupId())).build();
1541         modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1542         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1543
1544         try {
1545             commitFuture.get();  // TODO: Make it async (See bug 1362)
1546             LOG.debug("Transaction success for deletion of Group " + groupBuilder.getGroupName());
1547         } catch (InterruptedException|ExecutionException e) {
1548             LOG.error(e.getMessage(), e);
1549         }
1550     }
1551
1552     private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1553         ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1554         InstanceIdentifier<Flow> path1 =
1555                 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1556                                 .rev130819.nodes.Node.class,
1557                         nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1558                         new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1559
1560         //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1561         modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1562                 true);//createMissingParents
1563
1564
1565         CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1566         try {
1567             commitFuture.get();  // TODO: Make it async (See bug 1362)
1568             LOG.debug("Transaction success for write of Flow " + flowBuilder.getFlowName());
1569         } catch (InterruptedException|ExecutionException e) {
1570             LOG.error(e.getMessage(), e);
1571         }
1572     }
1573
1574     /**
1575      * Create Output Port Group Instruction
1576      *
1577      * @param ib       Map InstructionBuilder without any instructions
1578      * @param dpidLong Long the datapath ID of a switch/node
1579      * @param port     Long representing a port on a switch/node
1580      * @return ib InstructionBuilder Map with instructions
1581      */
1582     // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1583     @SuppressWarnings("unused")
1584     protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1585             InstructionBuilder ib,
1586             Long dpidLong, Long port ,
1587             List<Instruction> instructions) {
1588         NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1589         LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1590
1591         List<Action> actionList = Lists.newArrayList();
1592         ActionBuilder ab = new ActionBuilder();
1593
1594         List<Action> existingActions;
1595         if (instructions != null) {
1596             for (Instruction in : instructions) {
1597                 if (in.getInstruction() instanceof ApplyActionsCase) {
1598                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1599                     actionList.addAll(existingActions);
1600                 }
1601             }
1602         }
1603
1604         GroupBuilder groupBuilder = new GroupBuilder();
1605         Group group = null;
1606
1607         /* Create output action for this port*/
1608         OutputActionBuilder oab = new OutputActionBuilder();
1609         oab.setOutputNodeConnector(ncid);
1610         ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1611         LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1612         boolean addNew = true;
1613         boolean groupActionAdded = false;
1614
1615         /* Find the group action and get the group */
1616         for (Action action : actionList) {
1617             if (action.getAction() instanceof GroupActionCase) {
1618                 groupActionAdded = true;
1619                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1620                 Long id = groupAction.getGroupAction().getGroupId();
1621                 String groupName = groupAction.getGroupAction().getGroup();
1622                 GroupKey key = new GroupKey(new GroupId(id));
1623
1624                 groupBuilder.setGroupId(new GroupId(id));
1625                 groupBuilder.setGroupName(groupName);
1626                 groupBuilder.setGroupType(GroupTypes.GroupAll);
1627                 groupBuilder.setKey(key);
1628                 group = getGroup(groupBuilder, nodeBuilder);
1629                 LOG.debug("createOutputGroupInstructions: group {}", group);
1630                 break;
1631             }
1632         }
1633
1634         LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1635         if (groupActionAdded) {
1636             /* modify the action bucket in group */
1637             groupBuilder = new GroupBuilder(group);
1638             Buckets buckets = groupBuilder.getBuckets();
1639             for (Bucket bucket : buckets.getBucket()) {
1640                 List<Action> bucketActions = bucket.getAction();
1641                 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1642                 for (Action action : bucketActions) {
1643                     if (action.getAction() instanceof OutputActionCase) {
1644                         OutputActionCase opAction = (OutputActionCase)action.getAction();
1645                         /* If output port action already in the action list of one of the buckets, skip */
1646                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1647                             addNew = false;
1648                             break;
1649                         }
1650                     }
1651                 }
1652             }
1653             LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1654             if (addNew) {
1655                 /* the new output action is not in the bucket, add to bucket */
1656                 if (!buckets.getBucket().isEmpty()) {
1657                     Bucket bucket = buckets.getBucket().get(0);
1658                     List<Action> bucketActionList = Lists.newArrayList();
1659                     bucketActionList.addAll(bucket.getAction());
1660                     /* set order for new action and add to action list */
1661                     ab.setOrder(bucketActionList.size());
1662                     ab.setKey(new ActionKey(bucketActionList.size()));
1663                     bucketActionList.add(ab.build());
1664
1665                     /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1666                     BucketsBuilder bucketsBuilder = new BucketsBuilder();
1667                     List<Bucket> bucketList = Lists.newArrayList();
1668                     BucketBuilder bucketBuilder = new BucketBuilder();
1669                     bucketBuilder.setBucketId(new BucketId((long) 1));
1670                     bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1671                     bucketBuilder.setAction(bucketActionList);
1672                     bucketList.add(bucketBuilder.build());
1673                     bucketsBuilder.setBucket(bucketList);
1674                     groupBuilder.setBuckets(bucketsBuilder.build());
1675                     LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1676                 }
1677             }
1678         } else {
1679             /* create group */
1680             groupBuilder = new GroupBuilder();
1681             groupBuilder.setGroupType(GroupTypes.GroupAll);
1682             groupBuilder.setGroupId(new GroupId(groupId));
1683             groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1684             groupBuilder.setGroupName("Output port group " + groupId);
1685             groupBuilder.setBarrier(false);
1686
1687             BucketsBuilder bucketBuilder = new BucketsBuilder();
1688             List<Bucket> bucketList = Lists.newArrayList();
1689             BucketBuilder bucket = new BucketBuilder();
1690             bucket.setBucketId(new BucketId((long) 1));
1691             bucket.setKey(new BucketKey(new BucketId((long) 1)));
1692
1693             /* put output action to the bucket */
1694             List<Action> bucketActionList = Lists.newArrayList();
1695             /* set order for new action and add to action list */
1696             ab.setOrder(bucketActionList.size());
1697             ab.setKey(new ActionKey(bucketActionList.size()));
1698             bucketActionList.add(ab.build());
1699
1700             bucket.setAction(bucketActionList);
1701             bucketList.add(bucket.build());
1702             bucketBuilder.setBucket(bucketList);
1703             groupBuilder.setBuckets(bucketBuilder.build());
1704
1705             /* Add new group action */
1706             GroupActionBuilder groupActionB = new GroupActionBuilder();
1707             groupActionB.setGroupId(groupId);
1708             groupActionB.setGroup("Output port group " + groupId);
1709             ab = new ActionBuilder();
1710             ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1711             ab.setOrder(actionList.size());
1712             ab.setKey(new ActionKey(actionList.size()));
1713             actionList.add(ab.build());
1714
1715             groupId++;
1716         }
1717         LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1718         LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1719
1720         if (addNew) {
1721             /* rewrite the group to group table */
1722             writeGroup(groupBuilder, nodeBuilder);
1723         }
1724
1725         // Create an Apply Action
1726         ApplyActionsBuilder aab = new ApplyActionsBuilder();
1727         aab.setAction(actionList);
1728         ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1729
1730         return ib;
1731     }
1732
1733     /**
1734      * Remove Output Port from action list in group bucket
1735      *
1736      * @param ib       Map InstructionBuilder without any instructions
1737      * @param dpidLong Long the datapath ID of a switch/node
1738      * @param port     Long representing a port on a switch/node
1739      * @return ib InstructionBuilder Map with instructions
1740      */
1741     // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1742     @SuppressWarnings("unused")
1743     protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1744             Long dpidLong, Long port , List<Instruction> instructions) {
1745
1746         NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1747         LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1748
1749         List<Action> actionList = Lists.newArrayList();
1750         ActionBuilder ab;
1751
1752         List<Action> existingActions;
1753         if (instructions != null) {
1754             for (Instruction in : instructions) {
1755                 if (in.getInstruction() instanceof ApplyActionsCase) {
1756                     existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1757                     actionList.addAll(existingActions);
1758                     break;
1759                 }
1760             }
1761         }
1762
1763         GroupBuilder groupBuilder = new GroupBuilder();
1764         Group group = null;
1765         boolean groupActionAdded = false;
1766         /* Find the group action and get the group */
1767         for (Action action : actionList) {
1768             if (action.getAction() instanceof GroupActionCase) {
1769                 groupActionAdded = true;
1770                 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1771                 Long id = groupAction.getGroupAction().getGroupId();
1772                 String groupName = groupAction.getGroupAction().getGroup();
1773                 GroupKey key = new GroupKey(new GroupId(id));
1774
1775                 groupBuilder.setGroupId(new GroupId(id));
1776                 groupBuilder.setGroupName(groupName);
1777                 groupBuilder.setGroupType(GroupTypes.GroupAll);
1778                 groupBuilder.setKey(key);
1779                 group = getGroup(groupBuilder, nodeBuilder);
1780                 break;
1781             }
1782         }
1783
1784         if (groupActionAdded) {
1785             /* modify the action bucket in group */
1786             groupBuilder = new GroupBuilder(group);
1787             Buckets buckets = groupBuilder.getBuckets();
1788             List<Action> bucketActions = Lists.newArrayList();
1789             for (Bucket bucket : buckets.getBucket()) {
1790                 int index = 0;
1791                 boolean isPortDeleted = false;
1792                 bucketActions = bucket.getAction();
1793                 for (Action action : bucketActions) {
1794                     if (action.getAction() instanceof OutputActionCase) {
1795                         OutputActionCase opAction = (OutputActionCase)action.getAction();
1796                         if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1797                             /* Find the output port in action list and remove */
1798                             index = bucketActions.indexOf(action);
1799                             bucketActions.remove(action);
1800                             isPortDeleted = true;
1801                             break;
1802                         }
1803                     }
1804                 }
1805                 if (isPortDeleted && !bucketActions.isEmpty()) {
1806                     for (int i = index; i< bucketActions.size(); i++) {
1807                         Action action = bucketActions.get(i);
1808                         if (action.getOrder() != i) {
1809                             /* Shift the action order */
1810                             ab = new ActionBuilder();
1811                             ab.setAction(action.getAction());
1812                             ab.setOrder(i);
1813                             ab.setKey(new ActionKey(i));
1814                             Action actionNewOrder = ab.build();
1815                             bucketActions.remove(action);
1816                             bucketActions.add(i, actionNewOrder);
1817                         }
1818                     }
1819
1820                 } else if (bucketActions.isEmpty()) {
1821                     /* remove bucket with empty action list */
1822                     buckets.getBucket().remove(bucket);
1823                     break;
1824                 }
1825             }
1826             if (!buckets.getBucket().isEmpty()) {
1827                 /* rewrite the group to group table */
1828                 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1829                 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1830                 List<Bucket> bucketList = Lists.newArrayList();
1831                 BucketBuilder bucketBuilder = new BucketBuilder();
1832                 bucketBuilder.setBucketId(new BucketId((long) 1));
1833                 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1834                 bucketBuilder.setAction(bucketActions);
1835                 bucketList.add(bucketBuilder.build());
1836                 bucketsBuilder.setBucket(bucketList);
1837                 groupBuilder.setBuckets(bucketsBuilder.build());
1838                 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1839
1840                 writeGroup(groupBuilder, nodeBuilder);
1841                 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1842                 aab.setAction(actionList);
1843                 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1844                 return false;
1845             } else {
1846                 /* remove group with empty bucket. return true to delete flow */
1847                 removeGroup(groupBuilder, nodeBuilder);
1848                 return true;
1849             }
1850         } else {
1851             /* no group for port list. flow can be removed */
1852             return true;
1853         }
1854     }
1855
1856     @Override
1857     public void initializeOFFlowRules(Node openflowNode) {
1858         String bridgeName = southbound.getBridgeName(openflowNode);
1859         LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1860         if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1861             initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1862             triggerInterfaceUpdates(openflowNode);
1863         } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1864             initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1865             LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
1866             triggerInterfaceUpdates(openflowNode);
1867             LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
1868         }
1869     }
1870
1871     public static NodeBuilder createNodeBuilder(String nodeId) {
1872         NodeBuilder builder = new NodeBuilder();
1873         builder.setId(new NodeId(nodeId));
1874         builder.setKey(new NodeKey(builder.getId()));
1875         return builder;
1876     }
1877
1878     @Override
1879     public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1880         this.bundleContext = bundleContext;
1881         configurationService =
1882                 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1883         tenantNetworkManager =
1884                 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1885         bridgeConfigurationManager =
1886                 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1887         nodeCacheManager =
1888                 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1889         classifierProvider =
1890                 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
1891         ingressAclProvider =
1892                 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
1893         egressAclProvider =
1894                 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
1895         l2ForwardingProvider =
1896                 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
1897         securityServicesManager =
1898                 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1899         southbound =
1900                 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1901     }
1902
1903     @Override
1904     public void setDependencies(Object impl) {
1905         if (impl instanceof NetworkingProviderManager) {
1906             NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
1907             networkingProviderManager.providerAdded(
1908                     bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);
1909         }
1910     }
1911 }