2 * Copyright (C) 2013 Red Hat, Inc.
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
8 * Authors : Madhu Venugopal, Brent Salisbury, Dave Tucker
10 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
12 import java.net.InetAddress;
13 import java.util.List;
16 import java.util.concurrent.ExecutionException;
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.openflow.InstructionUtils;
36 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
76 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
79 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
80 import org.slf4j.Logger;
81 import org.slf4j.LoggerFactory;
83 import com.google.common.base.Optional;
84 import com.google.common.base.Preconditions;
85 import com.google.common.collect.Lists;
86 import com.google.common.collect.Maps;
87 import com.google.common.util.concurrent.CheckedFuture;
90 * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
92 public class OF13Provider implements NetworkingProvider {
93 private static final Logger logger = LoggerFactory.getLogger(OF13Provider.class);
94 private DataBroker dataBroker;
95 private static final short TABLE_0_DEFAULT_INGRESS = 0;
96 private static final short TABLE_1_ISOLATE_TENANT = 10;
97 private static final short TABLE_2_LOCAL_FORWARD = 20;
98 private static Long groupId = 1L;
100 private volatile ConfigurationService configurationService;
101 private volatile BridgeConfigurationManager bridgeConfigurationManager;
102 private volatile TenantNetworkManager tenantNetworkManager;
103 private volatile OvsdbConfigurationService ovsdbConfigurationService;
104 private volatile OvsdbConnectionService connectionService;
105 private volatile MdsalConsumer mdsalConsumer;
106 private volatile SecurityServicesManager securityServicesManager;
107 private volatile IngressAclProvider ingressAclProvider;
108 private volatile EgressAclProvider egressAclProvider;
109 private volatile ClassifierProvider classifierProvider;
110 private volatile L2ForwardingProvider l2ForwardingProvider;
112 public static final String NAME = "OF13Provider";
114 public OF13Provider(){
119 public String getName() {
124 public boolean supportsServices() {
129 public boolean hasPerTenantTunneling() {
133 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
134 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
135 if (srcTunnelEndPoint == null) {
136 logger.error("Tunnel Endpoint not configured for Node {}", node);
137 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
140 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
141 logger.error(node+" is not Overlay ready");
142 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
145 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
146 logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
147 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
149 return new Status(StatusCode.SUCCESS);
152 private String getTunnelName(String tunnelType, InetAddress dst) {
153 return tunnelType+"-"+dst.getHostAddress();
156 private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
157 /* TODO SB_MIGRATION */
158 Preconditions.checkNotNull(ovsdbConfigurationService);
159 Row bridgeRow = ovsdbConfigurationService
160 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
161 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
162 if (bridge != null) {
163 Set<UUID> ports = bridge.getPortsColumn().getData();
164 for (UUID portUUID : ports) {
165 Row portRow = ovsdbConfigurationService
166 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
167 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
168 if (port != null && tunnelName.equalsIgnoreCase(port.getName())) return true;
174 private String getPortUuid(Node node, String name, String bridgeUUID) throws Exception {
175 /* TODO SB_MIGRATION */
176 Preconditions.checkNotNull(ovsdbConfigurationService);
177 Row bridgeRow = ovsdbConfigurationService
178 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
179 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
180 if (bridge != null) {
181 Set<UUID> ports = bridge.getPortsColumn().getData();
182 for (UUID portUUID : ports) {
183 Row portRow = ovsdbConfigurationService
184 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
185 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
186 if (port != null && name.equalsIgnoreCase(port.getName())) return portUUID.toString();
192 private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
193 /* TODO SB_MIGRATION */
194 Preconditions.checkNotNull(ovsdbConfigurationService);
196 String bridgeUUID = null;
197 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
198 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
199 if (bridgeTable != null) {
200 for (String uuid : bridgeTable.keySet()) {
201 Bridge bridge = ovsdbConfigurationService.getTypedRow(node,Bridge.class, bridgeTable.get(uuid));
202 if (bridge.getName().equals(tunnelBridgeName)) {
208 if (bridgeUUID == null) {
209 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
210 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
212 String portName = getTunnelName(tunnelType, dst);
214 if (this.isTunnelPresent(node, portName, bridgeUUID)) {
215 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
216 return new Status(StatusCode.SUCCESS);
219 Port tunnelPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
220 tunnelPort.setName(portName);
221 StatusWithUuid statusWithUuid = ovsdbConfigurationService
222 .insertRow(node, ovsdbConfigurationService.getTableName(node, Port.class), bridgeUUID, tunnelPort.getRow());
223 if (!statusWithUuid.isSuccess()) {
224 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
225 return statusWithUuid;
228 String tunnelPortUUID = statusWithUuid.getUuid().toString();
229 String interfaceUUID = null;
231 while ((interfaceUUID == null) && (timeout > 0)) {
232 Row portRow = ovsdbConfigurationService
233 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), tunnelPortUUID);
234 tunnelPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
235 Set<UUID> interfaces = tunnelPort.getInterfacesColumn().getData();
236 if (interfaces == null || interfaces.size() == 0) {
237 // Wait for the OVSDB update to sync up the Local cache.
242 interfaceUUID = interfaces.toArray()[0].toString();
243 Row intfRow = ovsdbConfigurationService
244 .getRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
245 Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, intfRow);
246 if (intf == null) interfaceUUID = null;
249 if (interfaceUUID == null) {
250 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
251 return new Status(StatusCode.INTERNALERROR);
254 Interface tunInterface = ovsdbConfigurationService.createTypedRow(node, Interface.class);
255 tunInterface.setType(tunnelType);
256 Map<String, String> options = Maps.newHashMap();
257 options.put("key", "flow");
258 options.put("local_ip", src.getHostAddress());
259 options.put("remote_ip", dst.getHostAddress());
260 tunInterface.setOptions(options);
261 Status status = ovsdbConfigurationService
262 .updateRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), tunnelPortUUID, interfaceUUID, tunInterface.getRow());
263 logger.debug("Tunnel {} add status : {}", tunInterface, status);
265 } catch (Exception e) {
266 logger.error("Exception in addTunnelPort", e);
267 return new Status(StatusCode.INTERNALERROR);
271 /* delete port from ovsdb port table */
272 private Status deletePort(Node node, String bridgeName, String portName) {
273 /* TODO SB_MIGRATION */
274 Preconditions.checkNotNull(ovsdbConfigurationService);
276 String bridgeUUID = null;
277 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
278 if (bridgeTable != null) {
279 for (String uuid : bridgeTable.keySet()) {
280 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
281 if (bridge.getName().equals(bridgeName)) {
287 if (bridgeUUID == null) {
288 logger.debug("Could not find Bridge {} in {}", bridgeName, node);
289 return new Status(StatusCode.SUCCESS);
292 String portUUID = this.getPortUuid(node, portName, bridgeUUID);
293 Status status = new Status(StatusCode.SUCCESS);
294 if (portUUID != null) {
295 status = ovsdbConfigurationService
296 .deleteRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID);
297 if (!status.isSuccess()) {
298 logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID,
302 logger.debug("Port {} delete status : {}", portName, status);
305 } catch (Exception e) {
306 logger.error("Exception in deletePort", e);
307 return new Status(StatusCode.INTERNALERROR);
311 private Status deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
312 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
313 String portName = getTunnelName(tunnelType, dst);
314 return deletePort(node, tunnelBridgeName, portName);
317 private Status deletePhysicalPort(Node node, String phyIntfName) {
318 String intBridgeName = configurationService.getIntegrationBridgeName();
319 return deletePort(node, intBridgeName, phyIntfName);
322 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
326 * Match: VM sMac and Local Ingress Port
327 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
330 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, true);
335 * Match: Drop any remaining Ingress Local VM Packets
336 * Action: Drop w/ a low priority
339 handleDropSrcIface(dpid, localPort, true);
344 * Match: Match TunID and Destination DL/dMAC Addr
345 * Action: Output Port
346 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
349 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
354 * Match: Tunnel ID and dMAC (::::FF:FF)
355 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
356 * actions=output:2,3,4,5
359 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
360 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
363 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
368 * Match: Any remaining Ingress Local VM Packets
369 * Action: Drop w/ a low priority
370 * -------------------------------------------
371 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
374 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
379 * Match: Any Remaining Flows w/a TunID
380 * Action: Drop w/ a low priority
381 * table=2,priority=8192,tun_id=0x5 actions=drop
384 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
387 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
391 * Match: VM sMac and Local Ingress Port
392 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
395 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
400 * Match: Drop any remaining Ingress Local VM Packets
401 * Action: Drop w/ a low priority
404 handleDropSrcIface(dpid, localPort, false);
409 * Match: Match TunID and Destination DL/dMAC Addr
410 * Action: Output Port
411 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
414 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
419 * Match: Tunnel ID and dMAC (::::FF:FF)
420 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
421 * actions=output:2,3,4,5
424 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
425 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
428 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
432 * Match: Ingress Port, Tunnel ID
433 * Action: GOTO Local Table (20)
436 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
441 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
442 * Action: Flood to selected destination TEPs
443 * -------------------------------------------
444 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
445 * actions=output:10,output:11,goto_table:2
448 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
452 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
456 * Match: Drop any remaining Ingress Local VM Packets
457 * Action: Drop w/ a low priority
458 * -------------------------------------------
459 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
460 * actions=output:11,goto_table:2
463 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
466 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
470 * Match: Drop any remaining Ingress Local VM Packets
471 * Action: Drop w/ a low priority
472 * -------------------------------------------
473 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
474 * actions=output:11,goto_table:2
477 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
480 /* Remove tunnel rules if last node in this tenant network */
481 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
483 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
488 * Match: Any remaining Ingress Local VM Packets
489 * Action: Drop w/ a low priority
490 * -------------------------------------------
491 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
494 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
499 * Match: Any Remaining Flows w/a TunID
500 * Action: Drop w/ a low priority
501 * table=2,priority=8192,tun_id=0x5 actions=drop
504 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
509 * Match: Ingress Port, Tunnel ID
510 * Action: GOTO Local Table (10)
513 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
518 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
519 * Action: Flood to selected destination TEPs
520 * -------------------------------------------
521 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
522 * actions=output:10,output:11,goto_table:2
525 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
528 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
532 * Tag traffic coming from the local port and vm srcmac
533 * Match: VM sMac and Local Ingress Port
534 * Action: Set VLAN ID and GOTO Local Table 1
537 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
538 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
544 * Drop all other traffic coming from the local port
545 * Match: Drop any remaining Ingress Local VM Packets
546 * Action: Drop w/ a low priority
549 handleDropSrcIface(dpid, localPort, true);
554 * Forward unicast traffic destined to the local port after stripping tag
555 * Match: Match VLAN ID and Destination DL/dMAC Addr
556 * Action: strip vlan, output to local port
557 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
560 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
561 localPort, attachedMac, true);
566 * Match: VLAN ID and dMAC (::::FF:FF)
567 * Action: strip vlan, output to all local ports in this vlan
568 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
569 * actions= strip_vlan, output:2,3,4,5
572 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
573 // localPort, ethPort, true);
574 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
575 // segmentationId, localPort, ethport, true);
580 * Match: Any Remaining Flows w/a VLAN ID
581 * Action: Drop w/ a low priority
582 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
585 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
589 private void removeLocalVlanRules(Node node, Long dpid,
590 String segmentationId, String attachedMac, long localPort) {
594 * Match: VM sMac and Local Ingress Port
595 * Action: Set VLAN ID and GOTO Local Table 1
598 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
599 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
605 * Match: Drop any remaining Ingress Local VM Packets
606 * Action: Drop w/ a low priority
609 handleDropSrcIface(dpid, localPort, false);
614 * Match: Match VLAN ID and Destination DL/dMAC Addr
615 * Action: strip vlan, output to local port
616 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
619 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
620 localPort, attachedMac, false);
625 * Match: VLAN ID and dMAC (::::FF:FF)
626 * Action: strip vlan, output to all local ports in this vlan
627 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
628 * actions= strip_vlan, output:2,3,4,5
631 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
632 // localPort, ethPort, false);
633 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
634 // segmentationId, localPort, false);
638 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
639 long localPort, long ethPort) {
643 * Match: Ingress port = physical interface, Vlan ID
644 * Action: GOTO Local Table 2
647 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
648 segmentationId, ethPort, true);
653 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
654 * Action: Flood to local and remote VLAN members
655 * -------------------------------------------
656 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
657 * actions=output:10 (eth port),goto_table:2
658 * 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
661 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
666 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
667 * Action: Flood to local and remote VLAN members
668 * -------------------------------------------
669 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
670 * actions=output:10 (eth port),goto_table:2
673 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
674 // segmentationId, ethPort, true);
677 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
678 String attachedMac, long ethPort) {
682 * Match: Destination MAC is local VM MAC and vlan id
683 * Action: go to table 2
684 * -------------------------------------------
685 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
686 * actions=goto_table:2
689 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
690 // segmentationId, ethPort, attachedMac, true);
696 * Action: Go to table 2
697 * -------------------------------------------
698 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
699 * table=110,priority=8192,dl_vlan=2001 actions=output:2
702 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
705 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
706 String attachedMac, long localPort, long ethPort) {
710 * Match: Destination MAC is local VM MAC and vlan id
711 * Action: go to table 2
712 * -------------------------------------------
713 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
714 * actions=goto_table:2
717 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
718 // segmentationId, ethPort, attachedMac, false);
723 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
724 * Action: Flood to local and remote VLAN members
725 * -------------------------------------------
726 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
727 * actions=output:10 (eth port),goto_table:2
728 * 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
731 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
734 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
738 * Match: Any Remaining Flows w/a VLAN ID
739 * Action: Drop w/ a low priority
740 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
743 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
748 * Match: Ingress port = physical interface, Vlan ID
749 * Action: GOTO Local Table 2
752 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
757 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
758 * Action: Flood to local and remote VLAN members
759 * -------------------------------------------
760 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
761 * actions=output:10 (eth port),goto_table:2
762 * 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
765 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
770 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
771 * Action: Flood to local and remote VLAN members
772 * -------------------------------------------
773 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
774 * actions=output:10 (eth port),goto_table:2
777 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
778 // segmentationId, ethPort, false);
784 * Action: Go to table 2
785 * -------------------------------------------
786 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
787 * table=110,priority=8192,dl_vlan=2001 actions=output:2
790 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
793 private Long getDpid (Node node, String bridgeUuid) {
795 Preconditions.checkNotNull(ovsdbConfigurationService);
797 Row bridgeRow = ovsdbConfigurationService
798 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUuid);
799 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
800 Set<String> dpids = bridge.getDatapathIdColumn().getData();
801 if (dpids == null || dpids.size() == 0) return 0L;
802 return StringConvertor.dpidStringToLong((String) dpids.toArray()[0]);
803 } catch (Exception e) {
804 logger.error("Error finding Bridge's OF DPID", e);
809 private Long getIntegrationBridgeOFDPID (Node node) {
811 String bridgeName = configurationService.getIntegrationBridgeName();
812 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
813 if (brIntId == null) {
814 logger.error("Unable to spot Bridge Identifier for {} in {}", bridgeName, node);
818 return getDpid(node, brIntId);
819 } catch (Exception e) {
820 logger.error("Error finding Integration Bridge's OF DPID", e);
825 private Long getExternalBridgeDpid (Node node) {
827 String bridgeName = configurationService.getExternalBridgeName();
828 String brUuid = this.getInternalBridgeUUID(node, bridgeName);
829 if (brUuid == null) {
830 // Note: it is okay for certain nodes to not have br-ex configured; not an error
831 logger.info("Unable to spot Bridge Identifier for {} in {}", bridgeName, node);
835 return getDpid(node, brUuid);
836 } catch (Exception e) {
837 logger.error("Error finding External Bridge's OF DPID", e);
842 private void programLocalRules (String networkType, String segmentationId, Node node,
843 OvsdbTerminationPointAugmentation intf) {
845 Long dpid = this.getIntegrationBridgeOFDPID(node);
847 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
851 long localPort = (Long)intf.getOfport();
853 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
854 if (attachedMac == null) {
855 logger.warn("No AttachedMac seen in {}", intf);
859 /* Program local rules based on network type */
860 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
861 logger.debug("Program local vlan rules for interface {}", intf.getName());
862 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
864 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
865 /* TODO SB_MIGRATION */
866 /*if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
867 (NetworkHandler.NETWORK_TYPE_VXLAN)) && securityServicesManager.isPortSecurityReady(intf)) {
868 logger.debug("Neutron port has a Port Security Group");
869 // Retrieve the security group UUID from the Neutron Port
870 NeutronSecurityGroup securityGroupInPort = securityServicesManager.getSecurityGroupInPort(intf);
871 logger.debug("Program Local rules for networkType: {} does contain a Port Security Group: {} " +
872 "to be installed on DPID: {}", networkType, securityGroupInPort, dpid);
873 ingressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
874 securityGroupInPort);
875 egressAclProvider.programPortSecurityACL(dpid, segmentationId, attachedMac, localPort,
876 securityGroupInPort);
878 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
879 networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
880 logger.debug("Program local bridge rules for interface {}", intf.getName());
881 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
883 } catch (Exception e) {
884 logger.error("Exception in programming Local Rules for "+intf+" on "+node, e);
888 private void removeLocalRules (String networkType, String segmentationId, Node node,
889 OvsdbTerminationPointAugmentation intf) {
891 Long dpid = this.getIntegrationBridgeOFDPID(node);
893 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
897 long localPort = (Long)intf.getOfport();
899 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
900 if (attachedMac == null) {
901 logger.warn("No AttachedMac seen in {}", intf);
905 /* Program local rules based on network type */
906 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
907 logger.debug("Remove local vlan rules for interface {}", intf.getName());
908 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
909 } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
910 networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
911 logger.debug("Remove local bridge rules for interface {}", intf.getName());
912 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
914 } catch (Exception e) {
915 logger.error("Exception in removing Local Rules for "+intf+" on "+node, e);
919 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
920 OvsdbTerminationPointAugmentation intf, boolean local) {
921 /* TODO SB_MIGRATION */
922 Preconditions.checkNotNull(ovsdbConfigurationService);
925 Long dpid = this.getIntegrationBridgeOFDPID(node);
927 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
931 long localPort = (Long)intf.getOfport();
933 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
934 if (attachedMac == null) {
935 logger.warn("No AttachedMac seen in {}", intf);
939 Map<String, OvsdbTerminationPointAugmentation> intfs = ovsdbConfigurationService.getInterfaces(node);
941 for (OvsdbTerminationPointAugmentation tunIntf : intfs.values()) {
943 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
944 long tunnelOFPort = (Long)intf.getOfport();
946 if (tunnelOFPort == -1) {
947 logger.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
948 tunIntf.getName(), tunnelOFPort, node);
951 logger.debug("Identified Tunnel port {} -> OF ({}) on {}",
952 tunIntf.getName(), tunnelOFPort, node);
955 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
956 tunnelOFPort, localPort);
958 logger.trace("program local ingress tunnel rules: node {}, intf {}",
959 node.getNodeId().getValue(), intf.getName() );
961 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
962 tunnelOFPort, localPort);
968 } catch (Exception e) {
973 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
974 OvsdbTerminationPointAugmentation intf,
975 boolean local, boolean isLastInstanceOnNode) {
976 /* TODO SB_MIGRATION */
977 Preconditions.checkNotNull(ovsdbConfigurationService);
979 Long dpid = this.getIntegrationBridgeOFDPID(node);
981 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
985 long localPort = (Long)intf.getOfport();
987 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
988 if (attachedMac == null) {
989 logger.error("No AttachedMac seen in {}", intf);
993 Map<String, OvsdbTerminationPointAugmentation> intfs = ovsdbConfigurationService.getInterfaces(node);
995 for (OvsdbTerminationPointAugmentation tunIntf : intfs.values()) {
997 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
998 long tunnelOFPort = (Long)intf.getOfport();
1000 if (tunnelOFPort == -1) {
1001 logger.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
1002 tunIntf.getName(), tunnelOFPort, node);
1005 logger.debug("Identified Tunnel port {} -> OF ({}) on {}",
1006 tunIntf.getName(), tunnelOFPort, node);
1009 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
1010 tunnelOFPort, localPort);
1012 if (local && isLastInstanceOnNode) {
1013 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
1019 } catch (Exception e) {
1020 logger.error("", e);
1024 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
1025 /* TODO SB_MIGRATION */
1026 Preconditions.checkNotNull(ovsdbConfigurationService);
1027 logger.debug("Program vlan rules for interface {}", intf.getName());
1029 Long dpid = this.getIntegrationBridgeOFDPID(node);
1031 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1035 long localPort = (Long)intf.getOfport();
1037 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
1038 if (attachedMac == null) {
1039 logger.error("No AttachedMac seen in {}", intf);
1043 Map<String, OvsdbTerminationPointAugmentation> intfs = ovsdbConfigurationService.getInterfaces(node);
1044 if (intfs != null) {
1045 for (OvsdbTerminationPointAugmentation ethIntf : intfs.values()) {
1047 if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(
1048 node, network.getProviderPhysicalNetwork()))) {
1049 long ethOFPort = (Long)ethIntf.getOfport();
1051 if (ethOFPort == -1) {
1052 logger.error("Could Not Identify eth port {} -> OF ({}) on {}",
1053 ethIntf.getName(), ethOFPort, node);
1054 throw new Exception("port number < 0");
1056 logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1057 // TODO: add logic to only add rule on remote nodes
1058 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
1059 attachedMac, ethOFPort);
1060 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
1061 attachedMac, localPort, ethOFPort);
1066 } catch (Exception e) {
1067 logger.error("", e);
1071 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
1072 boolean isLastInstanceOnNode) {
1073 /* TODO SB_MIGRATION */
1074 Preconditions.checkNotNull(ovsdbConfigurationService);
1075 logger.debug("Remove vlan rules for interface {}", intf.getName());
1077 Long dpid = this.getIntegrationBridgeOFDPID(node);
1079 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1083 long localPort = (Long)intf.getOfport();
1085 String attachedMac = MdsalUtils.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
1086 if (attachedMac == null) {
1087 logger.error("No AttachedMac seen in {}", intf);
1091 Map<String, OvsdbTerminationPointAugmentation> intfs = ovsdbConfigurationService.getInterfaces(node);
1092 if (intfs != null) {
1093 for (OvsdbTerminationPointAugmentation ethIntf : intfs.values()) {
1095 if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(
1096 node, network.getProviderPhysicalNetwork()))) {
1097 long ethOFPort = (Long)ethIntf.getOfport();
1099 if (ethOFPort == -1) {
1100 logger.error("Could Not Identify eth port {} -> OF ({}) on {}",
1101 ethIntf.getName(), ethOFPort, node);
1102 throw new Exception("port number < 0");
1104 logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1105 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
1106 attachedMac, localPort, ethOFPort);
1107 if (isLastInstanceOnNode) {
1108 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1114 } catch (Exception e) {
1115 logger.error("", e);
1120 public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
1121 /* TODO SB_MIGRATION */
1122 Preconditions.checkNotNull(connectionService);
1123 List<Node> nodes = connectionService.getNodes();
1124 nodes.remove(srcNode);
1125 this.programLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, intf);
1127 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1128 this.programVlanRules(network, srcNode, intf);
1129 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1130 || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
1131 for (Node dstNode : nodes) {
1132 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1133 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1134 if ((src != null) && (dst != null)) {
1135 Status status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst);
1136 if (status.isSuccess()) {
1137 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
1139 addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src);
1140 if (status.isSuccess()) {
1141 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
1144 logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. " +
1145 "Check source {} or destination {}",
1146 src != null ? src.getHostAddress() : "null",
1147 dst != null ? dst.getHostAddress() : "null");
1152 return new Status(StatusCode.SUCCESS);
1155 private Status triggerInterfaceUpdates(Node node) {
1156 /* TODO SB_MIGRATION */
1157 Preconditions.checkNotNull(ovsdbConfigurationService);
1159 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1160 if (intfs != null) {
1161 for (Row row : intfs.values()) {
1162 Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1163 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(intf);
1164 logger.debug("Trigger Interface update for {}", intf);
1165 if (network != null) {
1166 /* TODO SB_MIGRATION */
1167 //this.handleInterfaceUpdate(network, node, intf);
1171 } catch (Exception e) {
1172 logger.error("Error Triggering the lost interface updates for "+ node, e);
1173 return new Status(StatusCode.INTERNALERROR, e.getLocalizedMessage());
1175 return new Status(StatusCode.SUCCESS);
1178 public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1179 // TODO Auto-generated method stub
1183 private boolean isInterfaceOfInterest(OvsdbTerminationPointAugmentation terminationPoint) {
1184 return (SouthboundMapper.createOvsdbInterfaceType(
1185 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_VXLAN)
1187 SouthboundMapper.createOvsdbInterfaceType(
1188 terminationPoint.getInterfaceType()).equals(NetworkHandler.NETWORK_TYPE_GRE));
1192 public Status handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1193 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1194 /* TODO SB_MIGRATION */
1195 Preconditions.checkNotNull(connectionService);
1196 Status status = new Status(StatusCode.SUCCESS);
1197 List<Node> nodes = connectionService.getNodes();
1198 nodes.remove(srcNode);
1200 logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1201 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1202 if (isInterfaceOfInterest(intf)) {
1203 // Delete tunnel port
1205 InetAddress src = InetAddress.getByName(MdsalUtils.getOptionsValue(intf.getOptions(), "local_ip"));
1206 InetAddress dst = InetAddress.getByName(MdsalUtils.getOptionsValue(intf.getOptions(), "remote_ip"));
1207 status = deleteTunnelPort(srcNode,
1208 SouthboundMapper.createOvsdbInterfaceType(intf.getInterfaceType()),
1210 } catch (Exception e) {
1211 logger.error(e.getMessage(), e);
1213 } else if (phyIfName.contains(intf.getName())) {
1214 deletePhysicalPort(srcNode, intf.getName());
1216 // delete all other interfaces
1217 this.removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1220 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1221 this.removeVlanRules(network, srcNode,
1222 intf, isLastInstanceOnNode);
1223 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1224 || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
1226 for (Node dstNode : nodes) {
1227 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1228 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1229 if ((src != null) && (dst != null)) {
1230 logger.info("Remove tunnel rules for interface "
1231 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1232 this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1233 dst, srcNode, intf, true, isLastInstanceOnNode);
1234 logger.info("Remove tunnel rules for interface "
1235 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1236 this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1237 src, dstNode, intf, false, isLastInstanceOnNode);
1239 logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. ",
1240 "Check source {} or destination {}",
1241 src != null ? src.getHostAddress() : "null",
1242 dst != null ? dst.getHostAddress() : "null");
1251 public void initializeFlowRules(Node node) {
1252 this.initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1253 this.initializeFlowRules(node, configurationService.getExternalBridgeName());
1254 this.triggerInterfaceUpdates(node);
1257 private void initializeFlowRules(Node node, String bridgeName) {
1258 String bridgeUuid = this.getInternalBridgeUUID(node, bridgeName);
1259 if (bridgeUuid == null) {
1263 Long dpid = getDpid(node, bridgeUuid);
1266 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1273 * Match: LLDP (0x88CCL)
1274 * Action: Packet_In to Controller Reserved Port
1277 writeLLDPRule(dpid);
1278 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1279 writeNormalRule(dpid);
1284 * Create an LLDP Flow Rule to encapsulate into
1285 * a packet_in that is sent to the controller
1286 * for topology handling.
1287 * Match: Ethertype 0x88CCL
1288 * Action: Punt to Controller in a Packet_In msg
1291 private void writeLLDPRule(Long dpidLong) {
1292 classifierProvider.programLLDPPuntRule(dpidLong);
1296 * Create a NORMAL Table Miss Flow Rule
1298 * Action: forward to NORMAL pipeline
1301 private void writeNormalRule(Long dpidLong) {
1303 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1305 MatchBuilder matchBuilder = new MatchBuilder();
1306 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1307 FlowBuilder flowBuilder = new FlowBuilder();
1309 // Create the OF Actions and Instructions
1310 InstructionBuilder ib = new InstructionBuilder();
1311 InstructionsBuilder isb = new InstructionsBuilder();
1313 // Instructions List Stores Individual Instructions
1314 List<Instruction> instructions = Lists.newArrayList();
1316 // Call the InstructionBuilder Methods Containing Actions
1317 InstructionUtils.createNormalInstructions(nodeName, ib);
1319 ib.setKey(new InstructionKey(0));
1320 instructions.add(ib.build());
1322 // Add InstructionBuilder to the Instruction(s)Builder List
1323 isb.setInstruction(instructions);
1325 // Add InstructionsBuilder to FlowBuilder
1326 flowBuilder.setInstructions(isb.build());
1328 String flowId = "NORMAL";
1329 flowBuilder.setId(new FlowId(flowId));
1330 FlowKey key = new FlowKey(new FlowId(flowId));
1331 flowBuilder.setMatch(matchBuilder.build());
1332 flowBuilder.setPriority(0);
1333 flowBuilder.setBarrier(true);
1334 flowBuilder.setTableId((short) 0);
1335 flowBuilder.setKey(key);
1336 flowBuilder.setFlowName(flowId);
1337 flowBuilder.setHardTimeout(0);
1338 flowBuilder.setIdleTimeout(0);
1339 writeFlow(flowBuilder, nodeBuilder);
1343 * (Table:0) Ingress Tunnel Traffic
1344 * Match: OpenFlow InPort and Tunnel ID
1345 * Action: GOTO Local Table (10)
1346 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1349 private void handleTunnelIn(Long dpidLong, Short writeTable,
1350 Short goToTableId, String segmentationId,
1351 Long ofPort, boolean write) {
1352 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1356 * (Table:0) Ingress VLAN Traffic
1357 * Match: OpenFlow InPort and vlan ID
1358 * Action: GOTO Local Table (20)
1359 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1362 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1363 String segmentationId, Long ethPort, boolean write) {
1364 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1368 * (Table:0) Egress VM Traffic Towards TEP
1369 * Match: Destination Ethernet Addr and OpenFlow InPort
1370 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1371 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1372 * actions=set_field:5->tun_id,goto_table=1"
1375 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1376 String segmentationId, Long inPort, String attachedMac,
1378 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1382 * (Table:0) Egress VM Traffic Towards TEP
1383 * Match: Source Ethernet Addr and OpenFlow InPort
1384 * Instruction: Set VLANID and GOTO Table Egress (n)
1385 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1386 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1389 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1390 Short goToTableId, String segmentationId,
1391 Long inPort, String attachedMac,
1393 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1397 * (Table:0) Drop frames source from a VM that do not
1398 * match the associated MAC address of the local VM.
1399 * Match: Low priority anything not matching the VM SMAC
1401 * table=0,priority=16384,in_port=1 actions=drop"
1404 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1405 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1409 * (Table:1) Egress Tunnel Traffic
1410 * Match: Destination Ethernet Addr and Local InPort
1411 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1412 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1413 * actions=output:10,goto_table:2"
1415 private void handleTunnelOut(Long dpidLong, Short writeTable,
1416 Short goToTableId, String segmentationId,
1417 Long OFPortOut, String attachedMac,
1419 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1423 * (Table:1) Egress VLAN Traffic
1424 * Match: Destination Ethernet Addr and VLAN id
1425 * Instruction: GOTO Table Table 2
1426 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1427 * actions= goto_table:2"
1430 private void handleVlanOut(Long dpidLong, Short writeTable,
1431 Short goToTableId, String segmentationId,
1432 Long ethPort, String attachedMac, boolean write) {
1433 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1437 * (Table:1) Egress Tunnel Traffic
1438 * Match: Destination Ethernet Addr and Local InPort
1439 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1440 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1441 * actions=output:10,output:11,goto_table:2
1444 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1445 Short localTable, String segmentationId,
1446 Long OFPortOut, boolean write) {
1447 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1451 * (Table:1) Egress VLAN Traffic
1452 * Match: Destination Ethernet Addr and VLAN id
1453 * Instruction: GOTO table 2 and Output port eth interface
1454 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1455 * actions=output:eth1,goto_table:2
1458 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1459 Short localTable, String segmentationId,
1460 Long localPort, Long ethPort, boolean write) {
1461 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1465 * (Table:1) Table Drain w/ Catch All
1467 * Action: GOTO Local Table (10)
1468 * table=2,priority=8192,tun_id=0x5 actions=drop
1471 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1472 Short goToTableId, String segmentationId,
1474 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1479 * (Table:1) Table Drain w/ Catch All
1481 * Action: Output port eth interface
1482 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1483 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1486 private void handleVlanMiss(Long dpidLong, Short writeTable,
1487 Short goToTableId, String segmentationId,
1488 Long ethPort, boolean write) {
1489 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1493 * (Table:1) Local Broadcast Flood
1494 * Match: Tunnel ID and dMAC
1495 * Action: Output Port
1496 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1499 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1500 String segmentationId, Long localPort,
1501 String attachedMac, boolean write) {
1502 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1506 * (Table:2) Local VLAN unicast
1507 * Match: VLAN ID and dMAC
1508 * Action: Output Port
1509 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1512 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1513 String segmentationId, Long localPort,
1514 String attachedMac, boolean write) {
1515 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1519 * (Table:2) Local Broadcast Flood
1520 * Match: Tunnel ID and dMAC (::::FF:FF)
1521 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1522 * actions=output:2,3,4,5
1525 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1526 String segmentationId, Long localPort,
1528 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1532 * (Table:2) Local VLAN Broadcast Flood
1533 * Match: vlan ID and dMAC (::::FF:FF)
1534 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1535 * actions=strip_vlan, output:2,3,4,5
1536 * 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
1539 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1540 Long localPort, Long ethPort, boolean write) {
1541 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1545 * (Table:1) Local Table Miss
1546 * Match: Any Remaining Flows w/a TunID
1547 * Action: Drop w/ a low priority
1548 * table=2,priority=8192,tun_id=0x5 actions=drop
1551 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1552 String segmentationId, boolean write) {
1553 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1557 * (Table:1) Local Table Miss
1558 * Match: Any Remaining Flows w/a VLAN ID
1559 * Action: Drop w/ a low priority
1560 * table=2,priority=8192,vlan_id=0x5 actions=drop
1563 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1564 String segmentationId, boolean write) {
1565 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1568 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1569 Preconditions.checkNotNull(mdsalConsumer);
1570 if (mdsalConsumer == null) {
1571 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1575 dataBroker = mdsalConsumer.getDataBroker();
1576 if (dataBroker == null) {
1577 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1581 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1582 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1583 new GroupKey(groupBuilder.getGroupId())).build();
1584 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1586 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1587 if (data.isPresent()) {
1590 } catch (InterruptedException|ExecutionException e) {
1591 logger.error(e.getMessage(), e);
1594 logger.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1598 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1599 Preconditions.checkNotNull(mdsalConsumer);
1600 if (mdsalConsumer == null) {
1601 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1605 dataBroker = mdsalConsumer.getDataBroker();
1606 if (dataBroker == null) {
1607 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1611 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1612 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1613 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1614 new GroupKey(groupBuilder.getGroupId())).build();
1615 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1617 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1619 commitFuture.get(); // TODO: Make it async (See bug 1362)
1620 logger.debug("Transaction success for write of Group "+groupBuilder.getGroupName());
1621 } catch (InterruptedException|ExecutionException e) {
1622 logger.error(e.getMessage(), e);
1626 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1627 Preconditions.checkNotNull(mdsalConsumer);
1628 if (mdsalConsumer == null) {
1629 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1633 dataBroker = mdsalConsumer.getDataBroker();
1634 if (dataBroker == null) {
1635 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1639 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1640 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1641 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1642 new GroupKey(groupBuilder.getGroupId())).build();
1643 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1644 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1647 commitFuture.get(); // TODO: Make it async (See bug 1362)
1648 logger.debug("Transaction success for deletion of Group "+groupBuilder.getGroupName());
1649 } catch (InterruptedException|ExecutionException e) {
1650 logger.error(e.getMessage(), e);
1653 private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1654 Preconditions.checkNotNull(mdsalConsumer);
1655 if (mdsalConsumer == null) {
1656 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1660 dataBroker = mdsalConsumer.getDataBroker();
1661 if (dataBroker == null) {
1662 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1666 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1667 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1668 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1670 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1672 Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1673 if (data.isPresent()) {
1676 } catch (InterruptedException|ExecutionException e) {
1677 logger.error(e.getMessage(), e);
1680 logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
1684 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1685 Preconditions.checkNotNull(mdsalConsumer);
1686 if (mdsalConsumer == null) {
1687 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1691 dataBroker = mdsalConsumer.getDataBroker();
1692 if (dataBroker == null) {
1693 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1697 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1698 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1699 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1700 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1702 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1703 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
1706 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1708 commitFuture.get(); // TODO: Make it async (See bug 1362)
1709 logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
1710 } catch (InterruptedException|ExecutionException e) {
1711 logger.error(e.getMessage(), e);
1715 private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1716 Preconditions.checkNotNull(mdsalConsumer);
1717 if (mdsalConsumer == null) {
1718 logger.error("ERROR finding MDSAL Service.");
1722 dataBroker = mdsalConsumer.getDataBroker();
1723 if (dataBroker == null) {
1724 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1728 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1729 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
1730 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1731 .rev130819.nodes.Node.class, nodeBuilder.getKey())
1732 .augmentation(FlowCapableNode.class).child(Table.class,
1733 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1734 //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
1735 //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
1736 //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
1737 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1739 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1741 commitFuture.get(); // TODO: Make it async (See bug 1362)
1742 logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
1743 } catch (InterruptedException|ExecutionException e) {
1744 logger.error(e.getMessage(), e);
1749 * Create Output Port Group Instruction
1751 * @param ib Map InstructionBuilder without any instructions
1752 * @param dpidLong Long the datapath ID of a switch/node
1753 * @param port Long representing a port on a switch/node
1754 * @return ib InstructionBuilder Map with instructions
1756 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1757 InstructionBuilder ib,
1758 Long dpidLong, Long port ,
1759 List<Instruction> instructions) {
1760 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1761 logger.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1763 List<Action> actionList = Lists.newArrayList();
1764 ActionBuilder ab = new ActionBuilder();
1766 List<Action> existingActions;
1767 if (instructions != null) {
1768 for (Instruction in : instructions) {
1769 if (in.getInstruction() instanceof ApplyActionsCase) {
1770 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1771 actionList.addAll(existingActions);
1776 GroupBuilder groupBuilder = new GroupBuilder();
1779 /* Create output action for this port*/
1780 OutputActionBuilder oab = new OutputActionBuilder();
1781 oab.setOutputNodeConnector(ncid);
1782 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1783 logger.debug("createOutputGroupInstructions(): output action {}", ab.build());
1784 boolean addNew = true;
1785 boolean groupActionAdded = false;
1787 /* Find the group action and get the group */
1788 for (Action action : actionList) {
1789 if (action.getAction() instanceof GroupActionCase) {
1790 groupActionAdded = true;
1791 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1792 Long id = groupAction.getGroupAction().getGroupId();
1793 String groupName = groupAction.getGroupAction().getGroup();
1794 GroupKey key = new GroupKey(new GroupId(id));
1796 groupBuilder.setGroupId(new GroupId(id));
1797 groupBuilder.setGroupName(groupName);
1798 groupBuilder.setGroupType(GroupTypes.GroupAll);
1799 groupBuilder.setKey(key);
1800 group = getGroup(groupBuilder, nodeBuilder);
1801 logger.debug("createOutputGroupInstructions: group {}", group);
1806 logger.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1807 if (groupActionAdded) {
1808 /* modify the action bucket in group */
1809 groupBuilder = new GroupBuilder(group);
1810 Buckets buckets = groupBuilder.getBuckets();
1811 for (Bucket bucket : buckets.getBucket()) {
1812 List<Action> bucketActions = bucket.getAction();
1813 logger.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1814 for (Action action : bucketActions) {
1815 if (action.getAction() instanceof OutputActionCase) {
1816 OutputActionCase opAction = (OutputActionCase)action.getAction();
1817 /* If output port action already in the action list of one of the buckets, skip */
1818 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1825 logger.debug("createOutputGroupInstructions: addNew {}", addNew);
1827 /* the new output action is not in the bucket, add to bucket */
1828 if (!buckets.getBucket().isEmpty()) {
1829 Bucket bucket = buckets.getBucket().get(0);
1830 List<Action> bucketActionList = Lists.newArrayList();
1831 bucketActionList.addAll(bucket.getAction());
1832 /* set order for new action and add to action list */
1833 ab.setOrder(bucketActionList.size());
1834 ab.setKey(new ActionKey(bucketActionList.size()));
1835 bucketActionList.add(ab.build());
1837 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1838 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1839 List<Bucket> bucketList = Lists.newArrayList();
1840 BucketBuilder bucketBuilder = new BucketBuilder();
1841 bucketBuilder.setBucketId(new BucketId((long) 1));
1842 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1843 bucketBuilder.setAction(bucketActionList);
1844 bucketList.add(bucketBuilder.build());
1845 bucketsBuilder.setBucket(bucketList);
1846 groupBuilder.setBuckets(bucketsBuilder.build());
1847 logger.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1852 groupBuilder = new GroupBuilder();
1853 groupBuilder.setGroupType(GroupTypes.GroupAll);
1854 groupBuilder.setGroupId(new GroupId(groupId));
1855 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1856 groupBuilder.setGroupName("Output port group " + groupId);
1857 groupBuilder.setBarrier(false);
1859 BucketsBuilder bucketBuilder = new BucketsBuilder();
1860 List<Bucket> bucketList = Lists.newArrayList();
1861 BucketBuilder bucket = new BucketBuilder();
1862 bucket.setBucketId(new BucketId((long) 1));
1863 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1865 /* put output action to the bucket */
1866 List<Action> bucketActionList = Lists.newArrayList();
1867 /* set order for new action and add to action list */
1868 ab.setOrder(bucketActionList.size());
1869 ab.setKey(new ActionKey(bucketActionList.size()));
1870 bucketActionList.add(ab.build());
1872 bucket.setAction(bucketActionList);
1873 bucketList.add(bucket.build());
1874 bucketBuilder.setBucket(bucketList);
1875 groupBuilder.setBuckets(bucketBuilder.build());
1877 /* Add new group action */
1878 GroupActionBuilder groupActionB = new GroupActionBuilder();
1879 groupActionB.setGroupId(groupId);
1880 groupActionB.setGroup("Output port group " + groupId);
1881 ab = new ActionBuilder();
1882 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1883 ab.setOrder(actionList.size());
1884 ab.setKey(new ActionKey(actionList.size()));
1885 actionList.add(ab.build());
1889 logger.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1890 logger.debug("createOutputGroupInstructions: actionList {}", actionList);
1893 /* rewrite the group to group table */
1894 writeGroup(groupBuilder, nodeBuilder);
1897 // Create an Apply Action
1898 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1899 aab.setAction(actionList);
1900 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1906 * Remove Output Port from action list in group bucket
1908 * @param ib Map InstructionBuilder without any instructions
1909 * @param dpidLong Long the datapath ID of a switch/node
1910 * @param port Long representing a port on a switch/node
1911 * @return ib InstructionBuilder Map with instructions
1913 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1914 Long dpidLong, Long port , List<Instruction> instructions) {
1916 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1917 logger.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1919 List<Action> actionList = Lists.newArrayList();
1922 List<Action> existingActions;
1923 if (instructions != null) {
1924 for (Instruction in : instructions) {
1925 if (in.getInstruction() instanceof ApplyActionsCase) {
1926 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1927 actionList.addAll(existingActions);
1933 GroupBuilder groupBuilder = new GroupBuilder();
1935 boolean groupActionAdded = false;
1936 /* Find the group action and get the group */
1937 for (Action action : actionList) {
1938 if (action.getAction() instanceof GroupActionCase) {
1939 groupActionAdded = true;
1940 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1941 Long id = groupAction.getGroupAction().getGroupId();
1942 String groupName = groupAction.getGroupAction().getGroup();
1943 GroupKey key = new GroupKey(new GroupId(id));
1945 groupBuilder.setGroupId(new GroupId(id));
1946 groupBuilder.setGroupName(groupName);
1947 groupBuilder.setGroupType(GroupTypes.GroupAll);
1948 groupBuilder.setKey(key);
1949 group = getGroup(groupBuilder, nodeBuilder);
1954 if (groupActionAdded) {
1955 /* modify the action bucket in group */
1956 groupBuilder = new GroupBuilder(group);
1957 Buckets buckets = groupBuilder.getBuckets();
1958 List<Action> bucketActions = Lists.newArrayList();
1959 for (Bucket bucket : buckets.getBucket()) {
1961 boolean isPortDeleted = false;
1962 bucketActions = bucket.getAction();
1963 for (Action action : bucketActions) {
1964 if (action.getAction() instanceof OutputActionCase) {
1965 OutputActionCase opAction = (OutputActionCase)action.getAction();
1966 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1967 /* Find the output port in action list and remove */
1968 index = bucketActions.indexOf(action);
1969 bucketActions.remove(action);
1970 isPortDeleted = true;
1975 if (isPortDeleted && !bucketActions.isEmpty()) {
1976 for (int i = index; i< bucketActions.size(); i++) {
1977 Action action = bucketActions.get(i);
1978 if (action.getOrder() != i) {
1979 /* Shift the action order */
1980 ab = new ActionBuilder();
1981 ab.setAction(action.getAction());
1983 ab.setKey(new ActionKey(i));
1984 Action actionNewOrder = ab.build();
1985 bucketActions.remove(action);
1986 bucketActions.add(i, actionNewOrder);
1990 } else if (bucketActions.isEmpty()) {
1991 /* remove bucket with empty action list */
1992 buckets.getBucket().remove(bucket);
1996 if (!buckets.getBucket().isEmpty()) {
1997 /* rewrite the group to group table */
1998 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1999 BucketsBuilder bucketsBuilder = new BucketsBuilder();
2000 List<Bucket> bucketList = Lists.newArrayList();
2001 BucketBuilder bucketBuilder = new BucketBuilder();
2002 bucketBuilder.setBucketId(new BucketId((long) 1));
2003 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
2004 bucketBuilder.setAction(bucketActions);
2005 bucketList.add(bucketBuilder.build());
2006 bucketsBuilder.setBucket(bucketList);
2007 groupBuilder.setBuckets(bucketsBuilder.build());
2008 logger.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
2010 writeGroup(groupBuilder, nodeBuilder);
2011 ApplyActionsBuilder aab = new ApplyActionsBuilder();
2012 aab.setAction(actionList);
2013 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
2016 /* remove group with empty bucket. return true to delete flow */
2017 removeGroup(groupBuilder, nodeBuilder);
2021 /* no group for port list. flow can be removed */
2027 public void initializeOFFlowRules(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node openflowNode) {
2028 /* TODO SB_MIGRATION */
2029 Preconditions.checkNotNull(connectionService);
2030 List<Node> ovsNodes = connectionService.getNodes();
2031 if (ovsNodes == null) return;
2032 for (Node ovsNode : ovsNodes) {
2033 Long brIntDpid = this.getIntegrationBridgeOFDPID(ovsNode);
2034 Long brExDpid = this.getExternalBridgeDpid(ovsNode);
2035 logger.debug("Compare openflowNode to OVS node {} vs {} and {}",
2036 openflowNode.getId().getValue(), brIntDpid, brExDpid);
2037 String openflowID = openflowNode.getId().getValue();
2038 if (openflowID.contains(brExDpid.toString())) {
2039 this.initializeFlowRules(ovsNode, configurationService.getExternalBridgeName());
2040 this.triggerInterfaceUpdates(ovsNode);
2042 if (openflowID.contains(brIntDpid.toString())) {
2043 this.initializeFlowRules(ovsNode, configurationService.getIntegrationBridgeName());
2044 this.triggerInterfaceUpdates(ovsNode);
2050 public void notifyFlowCapableNodeEvent(Long dpid, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
2051 mdsalConsumer.notifyFlowCapableNodeCreateEvent(Constants.OPENFLOW_NODE_PREFIX + dpid, action);
2054 public static NodeBuilder createNodeBuilder(String nodeId) {
2055 NodeBuilder builder = new NodeBuilder();
2056 builder.setId(new NodeId(nodeId));
2057 builder.setKey(new NodeKey(builder.getId()));
2061 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeBuilderToInstanceId(NodeBuilder
2063 return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
2064 node.getKey()).toInstance();
2067 private String getInternalBridgeUUID (Node node, String bridgeName) {
2068 /* TODO SB_MIGRATION */
2069 Preconditions.checkNotNull(ovsdbConfigurationService);
2071 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
2072 if (bridgeTable == null) return null;
2073 for (String key : bridgeTable.keySet()) {
2074 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
2075 if (bridge.getName().equals(bridgeName)) return key;
2077 } catch (Exception e) {
2078 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);