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