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