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.BridgeConfigurationManager;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.ClassifierProvider;
31 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
32 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
33 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
34 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
35 import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
36 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
37 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
38 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
39 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
40 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusWithUuid;
41 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
42 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
43 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
44 import org.opendaylight.ovsdb.schema.openvswitch.Port;
45 import org.opendaylight.ovsdb.utils.mdsal.node.StringConvertor;
46 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
89 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
90 import org.slf4j.Logger;
91 import org.slf4j.LoggerFactory;
93 import com.google.common.base.Optional;
94 import com.google.common.base.Preconditions;
95 import com.google.common.collect.Lists;
96 import com.google.common.collect.Maps;
97 import com.google.common.util.concurrent.CheckedFuture;
100 * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
102 public class OF13Provider implements NetworkingProvider {
103 private static final Logger logger = LoggerFactory.getLogger(OF13Provider.class);
104 private DataBroker dataBroker;
105 private static final short TABLE_0_DEFAULT_INGRESS = 0;
106 private static final short TABLE_1_ISOLATE_TENANT = 10;
107 private static final short TABLE_2_LOCAL_FORWARD = 20;
108 private static Long groupId = 1L;
110 private volatile ConfigurationService configurationService;
111 private volatile BridgeConfigurationManager bridgeConfigurationManager;
112 private volatile TenantNetworkManager tenantNetworkManager;
113 private volatile MdsalConsumer mdsalConsumer;
114 private volatile SecurityServicesManager securityServicesManager;
115 private volatile IngressAclProvider ingressAclProvider;
116 private volatile EgressAclProvider egressAclProvider;
117 private volatile ClassifierProvider classifierProvider;
118 private volatile L2ForwardingProvider l2ForwardingProvider;
120 public static final String NAME = "OF13Provider";
122 public OF13Provider(){
127 public String getName() {
132 public boolean supportsServices() {
137 public boolean hasPerTenantTunneling() {
141 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
142 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
143 if (srcTunnelEndPoint == null) {
144 logger.error("Tunnel Endpoint not configured for Node {}", node);
145 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
148 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
149 logger.error(node+" is not Overlay ready");
150 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
153 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
154 logger.debug(node+" has no VM corresponding to segment "+ tunnelKey);
155 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
157 return new Status(StatusCode.SUCCESS);
160 private String getTunnelName(String tunnelType, InetAddress dst) {
161 return tunnelType+"-"+dst.getHostAddress();
164 private boolean isTunnelPresent(Node node, String tunnelName, String bridgeUUID) throws Exception {
166 Preconditions.checkNotNull(ovsdbConfigurationService);
167 Row bridgeRow = ovsdbConfigurationService
168 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
169 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
170 if (bridge != null) {
171 Set<UUID> ports = bridge.getPortsColumn().getData();
172 for (UUID portUUID : ports) {
173 Row portRow = ovsdbConfigurationService
174 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
175 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
176 if (port != null && tunnelName.equalsIgnoreCase(port.getName())) return true;
182 private String getPortUuid(Node node, String name, String bridgeUUID) throws Exception {
184 Preconditions.checkNotNull(ovsdbConfigurationService);
185 Row bridgeRow = ovsdbConfigurationService
186 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUUID);
187 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
188 if (bridge != null) {
189 Set<UUID> ports = bridge.getPortsColumn().getData();
190 for (UUID portUUID : ports) {
191 Row portRow = ovsdbConfigurationService
192 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID.toString());
193 Port port = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
194 if (port != null && name.equalsIgnoreCase(port.getName())) return portUUID.toString();
200 private Status addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
202 Preconditions.checkNotNull(ovsdbConfigurationService);
204 String bridgeUUID = null;
205 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
206 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
207 if (bridgeTable != null) {
208 for (String uuid : bridgeTable.keySet()) {
209 Bridge bridge = ovsdbConfigurationService.getTypedRow(node,Bridge.class, bridgeTable.get(uuid));
210 if (bridge.getName().equals(tunnelBridgeName)) {
216 if (bridgeUUID == null) {
217 logger.error("Could not find Bridge {} in {}", tunnelBridgeName, node);
218 return new Status(StatusCode.NOTFOUND, "Could not find "+tunnelBridgeName+" in "+node);
220 String portName = getTunnelName(tunnelType, dst);
222 if (this.isTunnelPresent(node, portName, bridgeUUID)) {
223 logger.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node);
224 return new Status(StatusCode.SUCCESS);
227 Port tunnelPort = ovsdbConfigurationService.createTypedRow(node, Port.class);
228 tunnelPort.setName(portName);
229 StatusWithUuid statusWithUuid = ovsdbConfigurationService
230 .insertRow(node, ovsdbConfigurationService.getTableName(node, Port.class), bridgeUUID, tunnelPort.getRow());
231 if (!statusWithUuid.isSuccess()) {
232 logger.error("Failed to insert Tunnel port {} in {}", portName, bridgeUUID);
233 return statusWithUuid;
236 String tunnelPortUUID = statusWithUuid.getUuid().toString();
237 String interfaceUUID = null;
239 while ((interfaceUUID == null) && (timeout > 0)) {
240 Row portRow = ovsdbConfigurationService
241 .getRow(node, ovsdbConfigurationService.getTableName(node, Port.class), tunnelPortUUID);
242 tunnelPort = ovsdbConfigurationService.getTypedRow(node, Port.class, portRow);
243 Set<UUID> interfaces = tunnelPort.getInterfacesColumn().getData();
244 if (interfaces == null || interfaces.size() == 0) {
245 // Wait for the OVSDB update to sync up the Local cache.
250 interfaceUUID = interfaces.toArray()[0].toString();
251 Row intfRow = ovsdbConfigurationService
252 .getRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), interfaceUUID);
253 Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, intfRow);
254 if (intf == null) interfaceUUID = null;
257 if (interfaceUUID == null) {
258 logger.error("Cannot identify Tunnel Interface for port {}/{}", portName, tunnelPortUUID);
259 return new Status(StatusCode.INTERNALERROR);
262 Interface tunInterface = ovsdbConfigurationService.createTypedRow(node, Interface.class);
263 tunInterface.setType(tunnelType);
264 Map<String, String> options = Maps.newHashMap();
265 options.put("key", "flow");
266 options.put("local_ip", src.getHostAddress());
267 options.put("remote_ip", dst.getHostAddress());
268 tunInterface.setOptions(options);
269 Status status = ovsdbConfigurationService
270 .updateRow(node, ovsdbConfigurationService.getTableName(node, Interface.class), tunnelPortUUID, interfaceUUID, tunInterface.getRow());
271 logger.debug("Tunnel {} add status : {}", tunInterface, status);
273 } catch (Exception e) {
274 logger.error("Exception in addTunnelPort", e);
275 return new Status(StatusCode.INTERNALERROR);
277 return new Status(StatusCode.INTERNALERROR);
280 /* delete port from ovsdb port table */
281 private Status deletePort(Node node, String bridgeName, String portName) {
283 Preconditions.checkNotNull(ovsdbConfigurationService);
285 String bridgeUUID = null;
286 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
287 if (bridgeTable != null) {
288 for (String uuid : bridgeTable.keySet()) {
289 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(uuid));
290 if (bridge.getName().equals(bridgeName)) {
296 if (bridgeUUID == null) {
297 logger.debug("Could not find Bridge {} in {}", bridgeName, node);
298 return new Status(StatusCode.SUCCESS);
301 String portUUID = this.getPortUuid(node, portName, bridgeUUID);
302 Status status = new Status(StatusCode.SUCCESS);
303 if (portUUID != null) {
304 status = ovsdbConfigurationService
305 .deleteRow(node, ovsdbConfigurationService.getTableName(node, Port.class), portUUID);
306 if (!status.isSuccess()) {
307 logger.error("Failed to delete port {} in {} status : {}", portName, bridgeUUID,
311 logger.debug("Port {} delete status : {}", portName, status);
314 } catch (Exception e) {
315 logger.error("Exception in deletePort", e);
316 return new Status(StatusCode.INTERNALERROR);
318 return new Status(StatusCode.INTERNALERROR);
321 private Status deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
322 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
323 String portName = getTunnelName(tunnelType, dst);
324 return deletePort(node, tunnelBridgeName, portName);
327 private Status deletePhysicalPort(Node node, String phyIntfName) {
328 String intBridgeName = configurationService.getIntegrationBridgeName();
329 return deletePort(node, intBridgeName, phyIntfName);
332 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
336 * Match: VM sMac and Local Ingress Port
337 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
340 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, true);
345 * Match: Drop any remaining Ingress Local VM Packets
346 * Action: Drop w/ a low priority
349 handleDropSrcIface(dpid, localPort, true);
354 * Match: Match TunID and Destination DL/dMAC Addr
355 * Action: Output Port
356 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
359 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
364 * Match: Tunnel ID and dMAC (::::FF:FF)
365 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
366 * actions=output:2,3,4,5
369 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
370 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
373 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
378 * Match: Any remaining Ingress Local VM Packets
379 * Action: Drop w/ a low priority
380 * -------------------------------------------
381 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
384 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
389 * Match: Any Remaining Flows w/a TunID
390 * Action: Drop w/ a low priority
391 * table=2,priority=8192,tun_id=0x5 actions=drop
394 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
397 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
401 * Match: VM sMac and Local Ingress Port
402 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
405 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
410 * Match: Drop any remaining Ingress Local VM Packets
411 * Action: Drop w/ a low priority
414 handleDropSrcIface(dpid, localPort, false);
419 * Match: Match TunID and Destination DL/dMAC Addr
420 * Action: Output Port
421 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
424 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
429 * Match: Tunnel ID and dMAC (::::FF:FF)
430 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
431 * actions=output:2,3,4,5
434 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
435 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
438 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
442 * Match: Ingress Port, Tunnel ID
443 * Action: GOTO Local Table (20)
446 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
451 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
452 * Action: Flood to selected destination TEPs
453 * -------------------------------------------
454 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
455 * actions=output:10,output:11,goto_table:2
458 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
462 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
466 * Match: Drop any remaining Ingress Local VM Packets
467 * Action: Drop w/ a low priority
468 * -------------------------------------------
469 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
470 * actions=output:11,goto_table:2
473 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
476 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
480 * Match: Drop any remaining Ingress Local VM Packets
481 * Action: Drop w/ a low priority
482 * -------------------------------------------
483 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
484 * actions=output:11,goto_table:2
487 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
490 /* Remove tunnel rules if last node in this tenant network */
491 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
493 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
498 * Match: Any remaining Ingress Local VM Packets
499 * Action: Drop w/ a low priority
500 * -------------------------------------------
501 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
504 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
509 * Match: Any Remaining Flows w/a TunID
510 * Action: Drop w/ a low priority
511 * table=2,priority=8192,tun_id=0x5 actions=drop
514 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
519 * Match: Ingress Port, Tunnel ID
520 * Action: GOTO Local Table (10)
523 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
528 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
529 * Action: Flood to selected destination TEPs
530 * -------------------------------------------
531 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
532 * actions=output:10,output:11,goto_table:2
535 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
538 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
542 * Tag traffic coming from the local port and vm srcmac
543 * Match: VM sMac and Local Ingress Port
544 * Action: Set VLAN ID and GOTO Local Table 1
547 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
548 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
554 * Drop all other traffic coming from the local port
555 * Match: Drop any remaining Ingress Local VM Packets
556 * Action: Drop w/ a low priority
559 handleDropSrcIface(dpid, localPort, true);
564 * Forward unicast traffic destined to the local port after stripping tag
565 * Match: Match VLAN ID and Destination DL/dMAC Addr
566 * Action: strip vlan, output to local port
567 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
570 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
571 localPort, attachedMac, true);
576 * Match: VLAN ID and dMAC (::::FF:FF)
577 * Action: strip vlan, output to all local ports in this vlan
578 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
579 * actions= strip_vlan, output:2,3,4,5
582 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
583 // localPort, ethPort, true);
584 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
585 // segmentationId, localPort, ethport, true);
590 * Match: Any Remaining Flows w/a VLAN ID
591 * Action: Drop w/ a low priority
592 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
595 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
599 private void removeLocalVlanRules(Node node, Long dpid,
600 String segmentationId, String attachedMac, long localPort) {
604 * Match: VM sMac and Local Ingress Port
605 * Action: Set VLAN ID and GOTO Local Table 1
608 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
609 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
615 * Match: Drop any remaining Ingress Local VM Packets
616 * Action: Drop w/ a low priority
619 handleDropSrcIface(dpid, localPort, false);
624 * Match: Match VLAN ID and Destination DL/dMAC Addr
625 * Action: strip vlan, output to local port
626 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
629 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
630 localPort, attachedMac, false);
635 * Match: VLAN ID and dMAC (::::FF:FF)
636 * Action: strip vlan, output to all local ports in this vlan
637 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
638 * actions= strip_vlan, output:2,3,4,5
641 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
642 // localPort, ethPort, false);
643 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
644 // segmentationId, localPort, false);
648 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
649 long localPort, long ethPort) {
653 * Match: Ingress port = physical interface, Vlan ID
654 * Action: GOTO Local Table 2
657 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
658 segmentationId, ethPort, true);
663 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
664 * Action: Flood to local and remote VLAN members
665 * -------------------------------------------
666 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
667 * actions=output:10 (eth port),goto_table:2
668 * 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
671 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
676 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
677 * Action: Flood to local and remote VLAN members
678 * -------------------------------------------
679 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
680 * actions=output:10 (eth port),goto_table:2
683 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
684 // segmentationId, ethPort, true);
687 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
688 String attachedMac, long ethPort) {
692 * Match: Destination MAC is local VM MAC and vlan id
693 * Action: go to table 2
694 * -------------------------------------------
695 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
696 * actions=goto_table:2
699 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
700 // segmentationId, ethPort, attachedMac, true);
706 * Action: Go to table 2
707 * -------------------------------------------
708 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
709 * table=110,priority=8192,dl_vlan=2001 actions=output:2
712 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
715 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
716 String attachedMac, long localPort, long ethPort) {
720 * Match: Destination MAC is local VM MAC and vlan id
721 * Action: go to table 2
722 * -------------------------------------------
723 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
724 * actions=goto_table:2
727 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
728 // segmentationId, ethPort, attachedMac, false);
733 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
734 * Action: Flood to local and remote VLAN members
735 * -------------------------------------------
736 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
737 * actions=output:10 (eth port),goto_table:2
738 * 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
741 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
744 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
748 * Match: Any Remaining Flows w/a VLAN ID
749 * Action: Drop w/ a low priority
750 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
753 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
758 * Match: Ingress port = physical interface, Vlan ID
759 * Action: GOTO Local Table 2
762 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
767 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
768 * Action: Flood to local and remote VLAN members
769 * -------------------------------------------
770 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
771 * actions=output:10 (eth port),goto_table:2
772 * 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
775 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
780 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
781 * Action: Flood to local and remote VLAN members
782 * -------------------------------------------
783 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
784 * actions=output:10 (eth port),goto_table:2
787 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
788 // segmentationId, ethPort, false);
794 * Action: Go to table 2
795 * -------------------------------------------
796 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
797 * table=110,priority=8192,dl_vlan=2001 actions=output:2
800 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
803 private Long getDpid (Node node, String bridgeUuid) {
805 Preconditions.checkNotNull(ovsdbConfigurationService);
807 Row bridgeRow = ovsdbConfigurationService
808 .getRow(node, ovsdbConfigurationService.getTableName(node, Bridge.class), bridgeUuid);
809 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeRow);
810 Set<String> dpids = bridge.getDatapathIdColumn().getData();
811 if (dpids == null || dpids.size() == 0) return 0L;
812 return StringConvertor.dpidStringToLong((String) dpids.toArray()[0]);
813 } catch (Exception e) {
814 logger.error("Error finding Bridge's OF DPID", e);
819 private Long getIntegrationBridgeOFDPID (Node node) {
821 String bridgeName = configurationService.getIntegrationBridgeName();
822 String brIntId = this.getInternalBridgeUUID(node, bridgeName);
823 if (brIntId == null) {
824 logger.error("Unable to spot Bridge Identifier for {} in {}", bridgeName, node);
828 return getDpid(node, brIntId);
829 } catch (Exception e) {
830 logger.error("Error finding Integration Bridge's OF DPID", e);
835 private Long getExternalBridgeDpid (Node node) {
837 String bridgeName = configurationService.getExternalBridgeName();
838 String brUuid = this.getInternalBridgeUUID(node, bridgeName);
839 if (brUuid == null) {
840 // Note: it is okay for certain nodes to not have br-ex configured; not an error
841 logger.info("Unable to spot Bridge Identifier for {} in {}", bridgeName, node);
845 return getDpid(node, brUuid);
846 } catch (Exception e) {
847 logger.error("Error finding External Bridge's OF DPID", e);
852 private void programLocalRules (String networkType, String segmentationId, Node node, Interface intf) {
854 Long dpid = this.getIntegrationBridgeOFDPID(node);
856 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
860 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
861 if (of_ports == null || of_ports.size() <= 0) {
862 logger.debug("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
865 long localPort = (Long)of_ports.toArray()[0];
867 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
868 if (externalIds == null) {
869 logger.error("No external_ids seen in {}", intf);
873 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
874 if (attachedMac == null) {
875 logger.error("No AttachedMac seen in {}", intf);
879 /* Program local rules based on network type */
880 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
881 logger.debug("Program local vlan rules for interface {}", intf.getName());
882 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
884 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
885 if ((networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
886 (NetworkHandler.NETWORK_TYPE_VXLAN)) && securityServicesManager.isPortSecurityReady(intf)) {
887 logger.debug("Neutron port has a Port Security Group");
888 /* Retrieve the security group UUID from the Neutron Port */
889 NeutronSecurityGroup securityGroupInPort = securityServicesManager.getSecurityGroupInPort(intf);
890 logger.debug("Program Local rules for networkType: {} does contain a Port Security Group: {} " +
891 "to be installed on DPID: {}", networkType, securityGroupInPort, dpid);
892 ingressAclProvider.programPortSecurityACL(node, dpid, segmentationId, attachedMac, localPort,
893 securityGroupInPort);
894 egressAclProvider.programPortSecurityACL(node, dpid, segmentationId, attachedMac, localPort,
895 securityGroupInPort);
897 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
898 networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
899 logger.debug("Program local bridge rules for interface {}", intf.getName());
900 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
902 } catch (Exception e) {
903 logger.error("Exception in programming Local Rules for "+intf+" on "+node, e);
907 private void removeLocalRules (String networkType, String segmentationId, Node node, Interface intf) {
909 Long dpid = this.getIntegrationBridgeOFDPID(node);
911 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
915 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
916 if (of_ports == null || of_ports.size() <= 0) {
917 logger.debug("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
920 long localPort = (Long)of_ports.toArray()[0];
922 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
923 if (externalIds == null) {
924 logger.error("No external_ids seen in {}", intf);
928 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
929 if (attachedMac == null) {
930 logger.error("No AttachedMac seen in {}", intf);
934 /* Program local rules based on network type */
935 if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
936 logger.debug("Remove local vlan rules for interface {}", intf.getName());
937 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
938 } else if (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) ||
939 networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
940 logger.debug("Remove local bridge rules for interface {}", intf.getName());
941 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
943 } catch (Exception e) {
944 logger.error("Exception in removing Local Rules for "+intf+" on "+node, e);
948 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
949 Interface intf, boolean local) {
951 Preconditions.checkNotNull(ovsdbConfigurationService);
955 Long dpid = this.getIntegrationBridgeOFDPID(node);
957 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
961 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
962 if (of_ports == null || of_ports.size() <= 0) {
963 logger.debug("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
966 long localPort = (Long)of_ports.toArray()[0];
968 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
969 if (externalIds == null) {
970 logger.error("No external_ids seen in {}", intf);
974 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
975 if (attachedMac == null) {
976 logger.error("No AttachedMac seen in {}", intf);
980 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
982 for (Row row : intfs.values()) {
983 Interface tunIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
984 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
985 of_ports = tunIntf.getOpenFlowPortColumn().getData();
986 if (of_ports == null || of_ports.size() <= 0) {
987 logger.debug("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
990 long tunnelOFPort = (Long)of_ports.toArray()[0];
992 if (tunnelOFPort == -1) {
993 logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
996 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
999 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
1001 logger.trace("program local ingress tunnel rules: node"
1002 + node.getId().getValue() + " intf " + intf.getName());
1004 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
1010 } catch (Exception e) {
1011 logger.error("", e);
1016 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
1017 Interface intf, boolean local, boolean isLastInstanceOnNode) {
1018 /* TODO SB_MIGRATION
1019 Preconditions.checkNotNull(ovsdbConfigurationService);
1022 Long dpid = this.getIntegrationBridgeOFDPID(node);
1024 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1028 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1029 if (of_ports == null || of_ports.size() <= 0) {
1030 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1033 long localPort = (Long)of_ports.toArray()[0];
1035 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1036 if (externalIds == null) {
1037 logger.error("No external_ids seen in {}", intf);
1041 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1042 if (attachedMac == null) {
1043 logger.error("No AttachedMac seen in {}", intf);
1047 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1048 if (intfs != null) {
1049 for (Row row : intfs.values()) {
1050 Interface tunIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1051 if (tunIntf.getName().equals(this.getTunnelName(tunnelType, dst))) {
1052 of_ports = tunIntf.getOpenFlowPortColumn().getData();
1053 if (of_ports == null || of_ports.size() <= 0) {
1054 logger.error("Could NOT Identify Tunnel port {} on {}", tunIntf.getName(), node);
1057 long tunnelOFPort = (Long)of_ports.toArray()[0];
1059 if (tunnelOFPort == -1) {
1060 logger.error("Could NOT Identify Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
1063 logger.debug("Identified Tunnel port {} -> OF ({}) on {}", tunIntf.getName(), tunnelOFPort, node);
1066 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac, tunnelOFPort, localPort);
1068 if (local && isLastInstanceOnNode) {
1069 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
1075 } catch (Exception e) {
1076 logger.error("", e);
1080 private void programVlanRules (NeutronNetwork network, Node node, Interface intf) {
1081 /* TODO SB_MIGRATION
1082 Preconditions.checkNotNull(ovsdbConfigurationService);
1083 logger.debug("Program vlan rules for interface {}", intf.getName());
1086 Long dpid = this.getIntegrationBridgeOFDPID(node);
1088 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1092 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1094 while ((of_ports == null) && (timeout > 0)) {
1095 of_ports = intf.getOpenFlowPortColumn().getData();
1096 if (of_ports == null || of_ports.size() <= 0) {
1097 // Wait for the OVSDB update to sync up the Local cache.
1102 if (of_ports == null || of_ports.size() <= 0) {
1103 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1106 long localPort = (Long)of_ports.toArray()[0];
1108 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1109 if (externalIds == null) {
1110 logger.error("No external_ids seen in {}", intf);
1114 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1115 if (attachedMac == null) {
1116 logger.error("No AttachedMac seen in {}", intf);
1120 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1121 if (intfs != null) {
1122 for (Row row : intfs.values()) {
1123 Interface ethIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1124 if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork()))) {
1125 of_ports = ethIntf.getOpenFlowPortColumn().getData();
1127 while ((of_ports == null) && (timeout > 0)) {
1128 of_ports = ethIntf.getOpenFlowPortColumn().getData();
1129 if (of_ports == null || of_ports.size() <= 0) {
1130 // Wait for the OVSDB update to sync up the Local cache.
1136 if (of_ports == null || of_ports.size() <= 0) {
1137 logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
1140 long ethOFPort = (Long)of_ports.toArray()[0];
1142 if (ethOFPort == -1) {
1143 logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1144 throw new Exception("port number < 0");
1146 logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1147 // TODO: add logic to only add rule on remote nodes
1148 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, ethOFPort);
1149 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, localPort, ethOFPort);
1154 } catch (Exception e) {
1155 logger.error("", e);
1159 private void removeVlanRules (NeutronNetwork network, Node node,
1160 Interface intf, boolean isLastInstanceOnNode) {
1161 /* TODO SB_MIGRATION
1162 Preconditions.checkNotNull(ovsdbConfigurationService);
1163 logger.debug("Remove vlan rules for interface {}", intf.getName());
1167 Long dpid = this.getIntegrationBridgeOFDPID(node);
1169 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1173 Set<Long> of_ports = intf.getOpenFlowPortColumn().getData();
1174 if (of_ports == null || of_ports.size() <= 0) {
1175 logger.error("Could NOT Identify OF value for port {} on {}", intf.getName(), node);
1178 long localPort = (Long)of_ports.toArray()[0];
1180 Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
1181 if (externalIds == null) {
1182 logger.error("No external_ids seen in {}", intf);
1186 String attachedMac = externalIds.get(Constants.EXTERNAL_ID_VM_MAC);
1187 if (attachedMac == null) {
1188 logger.error("No AttachedMac seen in {}", intf);
1192 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1193 if (intfs != null) {
1194 for (Row row : intfs.values()) {
1195 Interface ethIntf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1196 if (ethIntf.getName().equalsIgnoreCase(bridgeConfigurationManager.getPhysicalInterfaceName(node,
1197 network.getProviderPhysicalNetwork()))) {
1198 of_ports = ethIntf.getOpenFlowPortColumn().getData();
1199 if (of_ports == null || of_ports.size() <= 0) {
1200 logger.error("Could NOT Identify eth port {} on {}", ethIntf.getName(), node);
1203 long ethOFPort = (Long)of_ports.toArray()[0];
1205 if (ethOFPort == -1) {
1206 logger.error("Could NOT Identify eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1207 throw new Exception("port number < 0");
1209 logger.debug("Identified eth port {} -> OF ({}) on {}", ethIntf.getName(), ethOFPort, node);
1211 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(), attachedMac, localPort, ethOFPort);
1212 if (isLastInstanceOnNode) {
1213 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1219 } catch (Exception e) {
1220 logger.error("", e);
1225 public Status handleInterfaceUpdate(NeutronNetwork network, Node srcNode, Interface intf) {
1226 /* TODO SB_MIGRATION
1227 Preconditions.checkNotNull(connectionService);
1228 List<Node> nodes = connectionService.getNodes();
1229 nodes.remove(srcNode);
1230 this.programLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), srcNode, intf);
1232 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1233 this.programVlanRules(network, srcNode, intf);
1234 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1235 || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)){
1236 for (Node dstNode : nodes) {
1237 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1238 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1239 if ((src != null) && (dst != null)) {
1240 Status status = addTunnelPort(srcNode, network.getProviderNetworkType(), src, dst);
1241 if (status.isSuccess()) {
1242 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), dst, srcNode, intf, true);
1244 addTunnelPort(dstNode, network.getProviderNetworkType(), dst, src);
1245 if (status.isSuccess()) {
1246 this.programTunnelRules(network.getProviderNetworkType(), network.getProviderSegmentationID(), src, dstNode, intf, false);
1249 logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. " +
1250 "Check source {} or destination {}",
1251 src != null ? src.getHostAddress() : "null",
1252 dst != null ? dst.getHostAddress() : "null");
1257 return new Status(StatusCode.SUCCESS);
1260 private Status triggerInterfaceUpdates(Node node) {
1261 /* TODO SB_MIGRATION
1262 Preconditions.checkNotNull(ovsdbConfigurationService);
1264 Map<String, Row> intfs = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Interface.class));
1265 if (intfs != null) {
1266 for (Row row : intfs.values()) {
1267 Interface intf = ovsdbConfigurationService.getTypedRow(node, Interface.class, row);
1268 NeutronNetwork network = tenantNetworkManager.getTenantNetwork(intf);
1269 logger.debug("Trigger Interface update for {}", intf);
1270 if (network != null) {
1271 this.handleInterfaceUpdate(network, node, intf);
1275 } catch (Exception e) {
1276 logger.error("Error Triggering the lost interface updates for "+ node, e);
1277 return new Status(StatusCode.INTERNALERROR, e.getLocalizedMessage());
1279 return new Status(StatusCode.SUCCESS);
1282 public Status handleInterfaceUpdate(String tunnelType, String tunnelKey) {
1283 // TODO Auto-generated method stub
1288 public Status handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode, Interface intf,
1289 boolean isLastInstanceOnNode) {
1290 /* TODO SB_MIGRATION
1291 Preconditions.checkNotNull(connectionService);
1292 Status status = new Status(StatusCode.SUCCESS);
1293 List<Node> nodes = connectionService.getNodes();
1294 nodes.remove(srcNode);
1296 logger.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1297 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1298 if (intf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)
1299 || intf.getTypeColumn().getData().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
1300 // Delete tunnel port
1302 Map<String, String> options = intf.getOptionsColumn().getData();
1303 InetAddress src = InetAddress.getByName(options.get("local_ip"));
1304 InetAddress dst = InetAddress.getByName(options.get("remote_ip"));
1305 status = deleteTunnelPort(srcNode, intf.getTypeColumn().getData(), src, dst);
1306 } catch (Exception e) {
1307 logger.error(e.getMessage(), e);
1309 } else if (phyIfName.contains(intf.getName())) {
1310 deletePhysicalPort(srcNode, intf.getName());
1312 // delete all other interfaces
1313 this.removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1316 if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN)) {
1317 this.removeVlanRules(network, srcNode,
1318 intf, isLastInstanceOnNode);
1319 } else if (network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)
1320 || network.getProviderNetworkType().equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)) {
1322 for (Node dstNode : nodes) {
1323 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1324 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1325 if ((src != null) && (dst != null)) {
1326 logger.info("Remove tunnel rules for interface "
1327 + intf.getName() + " on srcNode " + srcNode.getId().getValue());
1328 this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1329 dst, srcNode, intf, true, isLastInstanceOnNode);
1330 logger.info("Remove tunnel rules for interface "
1331 + intf.getName() + " on dstNode " + dstNode.getId().getValue());
1332 this.removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1333 src, dstNode, intf, false, isLastInstanceOnNode);
1335 logger.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. ",
1336 "Check source {} or destination {}",
1337 src != null ? src.getHostAddress() : "null",
1338 dst != null ? dst.getHostAddress() : "null");
1344 return new Status(StatusCode.SUCCESS);
1348 public void initializeFlowRules(Node node) {
1349 this.initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1350 this.initializeFlowRules(node, configurationService.getExternalBridgeName());
1351 this.triggerInterfaceUpdates(node);
1354 private void initializeFlowRules(Node node, String bridgeName) {
1355 String bridgeUuid = this.getInternalBridgeUUID(node, bridgeName);
1356 if (bridgeUuid == null) {
1360 Long dpid = getDpid(node, bridgeUuid);
1363 logger.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1370 * Match: LLDP (0x88CCL)
1371 * Action: Packet_In to Controller Reserved Port
1374 writeLLDPRule(dpid);
1375 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1376 writeNormalRule(dpid);
1381 * Create an LLDP Flow Rule to encapsulate into
1382 * a packet_in that is sent to the controller
1383 * for topology handling.
1384 * Match: Ethertype 0x88CCL
1385 * Action: Punt to Controller in a Packet_In msg
1388 private void writeLLDPRule(Long dpidLong) {
1389 classifierProvider.programLLDPPuntRule(dpidLong);
1393 * Create a NORMAL Table Miss Flow Rule
1395 * Action: forward to NORMAL pipeline
1398 private void writeNormalRule(Long dpidLong) {
1400 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1402 MatchBuilder matchBuilder = new MatchBuilder();
1403 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1404 FlowBuilder flowBuilder = new FlowBuilder();
1406 // Create the OF Actions and Instructions
1407 InstructionBuilder ib = new InstructionBuilder();
1408 InstructionsBuilder isb = new InstructionsBuilder();
1410 // Instructions List Stores Individual Instructions
1411 List<Instruction> instructions = Lists.newArrayList();
1413 // Call the InstructionBuilder Methods Containing Actions
1414 InstructionUtils.createNormalInstructions(nodeName, ib);
1416 ib.setKey(new InstructionKey(0));
1417 instructions.add(ib.build());
1419 // Add InstructionBuilder to the Instruction(s)Builder List
1420 isb.setInstruction(instructions);
1422 // Add InstructionsBuilder to FlowBuilder
1423 flowBuilder.setInstructions(isb.build());
1425 String flowId = "NORMAL";
1426 flowBuilder.setId(new FlowId(flowId));
1427 FlowKey key = new FlowKey(new FlowId(flowId));
1428 flowBuilder.setMatch(matchBuilder.build());
1429 flowBuilder.setPriority(0);
1430 flowBuilder.setBarrier(true);
1431 flowBuilder.setTableId((short) 0);
1432 flowBuilder.setKey(key);
1433 flowBuilder.setFlowName(flowId);
1434 flowBuilder.setHardTimeout(0);
1435 flowBuilder.setIdleTimeout(0);
1436 writeFlow(flowBuilder, nodeBuilder);
1440 * (Table:0) Ingress Tunnel Traffic
1441 * Match: OpenFlow InPort and Tunnel ID
1442 * Action: GOTO Local Table (10)
1443 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1446 private void handleTunnelIn(Long dpidLong, Short writeTable,
1447 Short goToTableId, String segmentationId,
1448 Long ofPort, boolean write) {
1449 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1453 * (Table:0) Ingress VLAN Traffic
1454 * Match: OpenFlow InPort and vlan ID
1455 * Action: GOTO Local Table (20)
1456 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1459 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1460 String segmentationId, Long ethPort, boolean write) {
1461 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1465 * (Table:0) Egress VM Traffic Towards TEP
1466 * Match: Destination Ethernet Addr and OpenFlow InPort
1467 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1468 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1469 * actions=set_field:5->tun_id,goto_table=1"
1472 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1473 String segmentationId, Long inPort, String attachedMac,
1475 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1479 * (Table:0) Egress VM Traffic Towards TEP
1480 * Match: Source Ethernet Addr and OpenFlow InPort
1481 * Instruction: Set VLANID and GOTO Table Egress (n)
1482 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1483 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1486 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1487 Short goToTableId, String segmentationId,
1488 Long inPort, String attachedMac,
1490 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1494 * (Table:0) Drop frames source from a VM that do not
1495 * match the associated MAC address of the local VM.
1496 * Match: Low priority anything not matching the VM SMAC
1498 * table=0,priority=16384,in_port=1 actions=drop"
1501 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1502 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1506 * (Table:1) Egress Tunnel Traffic
1507 * Match: Destination Ethernet Addr and Local InPort
1508 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1509 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1510 * actions=output:10,goto_table:2"
1512 private void handleTunnelOut(Long dpidLong, Short writeTable,
1513 Short goToTableId, String segmentationId,
1514 Long OFPortOut, String attachedMac,
1516 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1520 * (Table:1) Egress VLAN Traffic
1521 * Match: Destination Ethernet Addr and VLAN id
1522 * Instruction: GOTO Table Table 2
1523 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1524 * actions= goto_table:2"
1527 private void handleVlanOut(Long dpidLong, Short writeTable,
1528 Short goToTableId, String segmentationId,
1529 Long ethPort, String attachedMac, boolean write) {
1530 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1534 * (Table:1) Egress Tunnel Traffic
1535 * Match: Destination Ethernet Addr and Local InPort
1536 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1537 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1538 * actions=output:10,output:11,goto_table:2
1541 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1542 Short localTable, String segmentationId,
1543 Long OFPortOut, boolean write) {
1544 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1548 * (Table:1) Egress VLAN Traffic
1549 * Match: Destination Ethernet Addr and VLAN id
1550 * Instruction: GOTO table 2 and Output port eth interface
1551 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1552 * actions=output:eth1,goto_table:2
1555 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1556 Short localTable, String segmentationId,
1557 Long localPort, Long ethPort, boolean write) {
1558 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1562 * (Table:1) Table Drain w/ Catch All
1564 * Action: GOTO Local Table (10)
1565 * table=2,priority=8192,tun_id=0x5 actions=drop
1568 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1569 Short goToTableId, String segmentationId,
1571 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1576 * (Table:1) Table Drain w/ Catch All
1578 * Action: Output port eth interface
1579 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1580 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1583 private void handleVlanMiss(Long dpidLong, Short writeTable,
1584 Short goToTableId, String segmentationId,
1585 Long ethPort, boolean write) {
1586 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1590 * (Table:1) Local Broadcast Flood
1591 * Match: Tunnel ID and dMAC
1592 * Action: Output Port
1593 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1596 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1597 String segmentationId, Long localPort,
1598 String attachedMac, boolean write) {
1599 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1603 * (Table:2) Local VLAN unicast
1604 * Match: VLAN ID and dMAC
1605 * Action: Output Port
1606 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1609 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1610 String segmentationId, Long localPort,
1611 String attachedMac, boolean write) {
1612 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1616 * (Table:2) Local Broadcast Flood
1617 * Match: Tunnel ID and dMAC (::::FF:FF)
1618 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1619 * actions=output:2,3,4,5
1622 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1623 String segmentationId, Long localPort,
1625 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1629 * (Table:2) Local VLAN Broadcast Flood
1630 * Match: vlan ID and dMAC (::::FF:FF)
1631 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1632 * actions=strip_vlan, output:2,3,4,5
1633 * 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
1636 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1637 Long localPort, Long ethPort, boolean write) {
1638 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1642 * (Table:1) Local Table Miss
1643 * Match: Any Remaining Flows w/a TunID
1644 * Action: Drop w/ a low priority
1645 * table=2,priority=8192,tun_id=0x5 actions=drop
1648 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1649 String segmentationId, boolean write) {
1650 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1654 * (Table:1) Local Table Miss
1655 * Match: Any Remaining Flows w/a VLAN ID
1656 * Action: Drop w/ a low priority
1657 * table=2,priority=8192,vlan_id=0x5 actions=drop
1660 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1661 String segmentationId, boolean write) {
1662 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1665 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1666 Preconditions.checkNotNull(mdsalConsumer);
1667 if (mdsalConsumer == null) {
1668 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1672 dataBroker = mdsalConsumer.getDataBroker();
1673 if (dataBroker == null) {
1674 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1678 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1679 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1680 new GroupKey(groupBuilder.getGroupId())).build();
1681 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1683 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1684 if (data.isPresent()) {
1687 } catch (InterruptedException|ExecutionException e) {
1688 logger.error(e.getMessage(), e);
1691 logger.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1695 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1696 Preconditions.checkNotNull(mdsalConsumer);
1697 if (mdsalConsumer == null) {
1698 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1702 dataBroker = mdsalConsumer.getDataBroker();
1703 if (dataBroker == null) {
1704 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1708 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1709 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1710 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1711 new GroupKey(groupBuilder.getGroupId())).build();
1712 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1714 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1716 commitFuture.get(); // TODO: Make it async (See bug 1362)
1717 logger.debug("Transaction success for write of Group "+groupBuilder.getGroupName());
1718 } catch (InterruptedException|ExecutionException e) {
1719 logger.error(e.getMessage(), e);
1723 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1724 Preconditions.checkNotNull(mdsalConsumer);
1725 if (mdsalConsumer == null) {
1726 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1730 dataBroker = mdsalConsumer.getDataBroker();
1731 if (dataBroker == null) {
1732 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1736 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1737 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1738 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1739 new GroupKey(groupBuilder.getGroupId())).build();
1740 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1741 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1744 commitFuture.get(); // TODO: Make it async (See bug 1362)
1745 logger.debug("Transaction success for deletion of Group "+groupBuilder.getGroupName());
1746 } catch (InterruptedException|ExecutionException e) {
1747 logger.error(e.getMessage(), e);
1750 private Flow getFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1751 Preconditions.checkNotNull(mdsalConsumer);
1752 if (mdsalConsumer == null) {
1753 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1757 dataBroker = mdsalConsumer.getDataBroker();
1758 if (dataBroker == null) {
1759 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1763 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1764 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1765 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1767 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1769 Optional<Flow> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1770 if (data.isPresent()) {
1773 } catch (InterruptedException|ExecutionException e) {
1774 logger.error(e.getMessage(), e);
1777 logger.debug("Cannot find data for Flow " + flowBuilder.getFlowName());
1781 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1782 Preconditions.checkNotNull(mdsalConsumer);
1783 if (mdsalConsumer == null) {
1784 logger.error("ERROR finding MDSAL Service. Its possible that writeFlow is called too soon ?");
1788 dataBroker = mdsalConsumer.getDataBroker();
1789 if (dataBroker == null) {
1790 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1794 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1795 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1796 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1797 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1799 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1800 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(), true /*createMissingParents*/);
1803 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1805 commitFuture.get(); // TODO: Make it async (See bug 1362)
1806 logger.debug("Transaction success for write of Flow "+flowBuilder.getFlowName());
1807 } catch (InterruptedException|ExecutionException e) {
1808 logger.error(e.getMessage(), e);
1812 private void removeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1813 Preconditions.checkNotNull(mdsalConsumer);
1814 if (mdsalConsumer == null) {
1815 logger.error("ERROR finding MDSAL Service.");
1819 dataBroker = mdsalConsumer.getDataBroker();
1820 if (dataBroker == null) {
1821 logger.error("ERROR finding reference for DataBroker. Please check MD-SAL support on the Controller.");
1825 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1826 InstanceIdentifier<Flow> path1 = InstanceIdentifier.builder(Nodes.class)
1827 .child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1828 .rev130819.nodes.Node.class, nodeBuilder.getKey())
1829 .augmentation(FlowCapableNode.class).child(Table.class,
1830 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1831 //modification.delete(LogicalDatastoreType.OPERATIONAL, nodeBuilderToInstanceId(nodeBuilder));
1832 //modification.delete(LogicalDatastoreType.OPERATIONAL, path1);
1833 //modification.delete(LogicalDatastoreType.CONFIGURATION, nodeBuilderToInstanceId(nodeBuilder));
1834 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1836 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1838 commitFuture.get(); // TODO: Make it async (See bug 1362)
1839 logger.debug("Transaction success for deletion of Flow "+flowBuilder.getFlowName());
1840 } catch (InterruptedException|ExecutionException e) {
1841 logger.error(e.getMessage(), e);
1846 * Create Output Port Group Instruction
1848 * @param ib Map InstructionBuilder without any instructions
1849 * @param dpidLong Long the datapath ID of a switch/node
1850 * @param port Long representing a port on a switch/node
1851 * @return ib InstructionBuilder Map with instructions
1853 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1854 InstructionBuilder ib,
1855 Long dpidLong, Long port ,
1856 List<Instruction> instructions) {
1857 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1858 logger.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1860 List<Action> actionList = Lists.newArrayList();
1861 ActionBuilder ab = new ActionBuilder();
1863 List<Action> existingActions;
1864 if (instructions != null) {
1865 for (Instruction in : instructions) {
1866 if (in.getInstruction() instanceof ApplyActionsCase) {
1867 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1868 actionList.addAll(existingActions);
1873 GroupBuilder groupBuilder = new GroupBuilder();
1876 /* Create output action for this port*/
1877 OutputActionBuilder oab = new OutputActionBuilder();
1878 oab.setOutputNodeConnector(ncid);
1879 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1880 logger.debug("createOutputGroupInstructions(): output action {}", ab.build());
1881 boolean addNew = true;
1882 boolean groupActionAdded = false;
1884 /* Find the group action and get the group */
1885 for (Action action : actionList) {
1886 if (action.getAction() instanceof GroupActionCase) {
1887 groupActionAdded = true;
1888 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1889 Long id = groupAction.getGroupAction().getGroupId();
1890 String groupName = groupAction.getGroupAction().getGroup();
1891 GroupKey key = new GroupKey(new GroupId(id));
1893 groupBuilder.setGroupId(new GroupId(id));
1894 groupBuilder.setGroupName(groupName);
1895 groupBuilder.setGroupType(GroupTypes.GroupAll);
1896 groupBuilder.setKey(key);
1897 group = getGroup(groupBuilder, nodeBuilder);
1898 logger.debug("createOutputGroupInstructions: group {}", group);
1903 logger.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1904 if (groupActionAdded) {
1905 /* modify the action bucket in group */
1906 groupBuilder = new GroupBuilder(group);
1907 Buckets buckets = groupBuilder.getBuckets();
1908 for (Bucket bucket : buckets.getBucket()) {
1909 List<Action> bucketActions = bucket.getAction();
1910 logger.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1911 for (Action action : bucketActions) {
1912 if (action.getAction() instanceof OutputActionCase) {
1913 OutputActionCase opAction = (OutputActionCase)action.getAction();
1914 /* If output port action already in the action list of one of the buckets, skip */
1915 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1922 logger.debug("createOutputGroupInstructions: addNew {}", addNew);
1924 /* the new output action is not in the bucket, add to bucket */
1925 if (!buckets.getBucket().isEmpty()) {
1926 Bucket bucket = buckets.getBucket().get(0);
1927 List<Action> bucketActionList = Lists.newArrayList();
1928 bucketActionList.addAll(bucket.getAction());
1929 /* set order for new action and add to action list */
1930 ab.setOrder(bucketActionList.size());
1931 ab.setKey(new ActionKey(bucketActionList.size()));
1932 bucketActionList.add(ab.build());
1934 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1935 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1936 List<Bucket> bucketList = Lists.newArrayList();
1937 BucketBuilder bucketBuilder = new BucketBuilder();
1938 bucketBuilder.setBucketId(new BucketId((long) 1));
1939 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1940 bucketBuilder.setAction(bucketActionList);
1941 bucketList.add(bucketBuilder.build());
1942 bucketsBuilder.setBucket(bucketList);
1943 groupBuilder.setBuckets(bucketsBuilder.build());
1944 logger.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1949 groupBuilder = new GroupBuilder();
1950 groupBuilder.setGroupType(GroupTypes.GroupAll);
1951 groupBuilder.setGroupId(new GroupId(groupId));
1952 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1953 groupBuilder.setGroupName("Output port group " + groupId);
1954 groupBuilder.setBarrier(false);
1956 BucketsBuilder bucketBuilder = new BucketsBuilder();
1957 List<Bucket> bucketList = Lists.newArrayList();
1958 BucketBuilder bucket = new BucketBuilder();
1959 bucket.setBucketId(new BucketId((long) 1));
1960 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1962 /* put output action to the bucket */
1963 List<Action> bucketActionList = Lists.newArrayList();
1964 /* set order for new action and add to action list */
1965 ab.setOrder(bucketActionList.size());
1966 ab.setKey(new ActionKey(bucketActionList.size()));
1967 bucketActionList.add(ab.build());
1969 bucket.setAction(bucketActionList);
1970 bucketList.add(bucket.build());
1971 bucketBuilder.setBucket(bucketList);
1972 groupBuilder.setBuckets(bucketBuilder.build());
1974 /* Add new group action */
1975 GroupActionBuilder groupActionB = new GroupActionBuilder();
1976 groupActionB.setGroupId(groupId);
1977 groupActionB.setGroup("Output port group " + groupId);
1978 ab = new ActionBuilder();
1979 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1980 ab.setOrder(actionList.size());
1981 ab.setKey(new ActionKey(actionList.size()));
1982 actionList.add(ab.build());
1986 logger.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1987 logger.debug("createOutputGroupInstructions: actionList {}", actionList);
1990 /* rewrite the group to group table */
1991 writeGroup(groupBuilder, nodeBuilder);
1994 // Create an Apply Action
1995 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1996 aab.setAction(actionList);
1997 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
2003 * Remove Output Port from action list in group bucket
2005 * @param ib Map InstructionBuilder without any instructions
2006 * @param dpidLong Long the datapath ID of a switch/node
2007 * @param port Long representing a port on a switch/node
2008 * @return ib InstructionBuilder Map with instructions
2010 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
2011 Long dpidLong, Long port , List<Instruction> instructions) {
2013 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
2014 logger.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
2016 List<Action> actionList = Lists.newArrayList();
2019 List<Action> existingActions;
2020 if (instructions != null) {
2021 for (Instruction in : instructions) {
2022 if (in.getInstruction() instanceof ApplyActionsCase) {
2023 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
2024 actionList.addAll(existingActions);
2030 GroupBuilder groupBuilder = new GroupBuilder();
2032 boolean groupActionAdded = false;
2033 /* Find the group action and get the group */
2034 for (Action action : actionList) {
2035 if (action.getAction() instanceof GroupActionCase) {
2036 groupActionAdded = true;
2037 GroupActionCase groupAction = (GroupActionCase) action.getAction();
2038 Long id = groupAction.getGroupAction().getGroupId();
2039 String groupName = groupAction.getGroupAction().getGroup();
2040 GroupKey key = new GroupKey(new GroupId(id));
2042 groupBuilder.setGroupId(new GroupId(id));
2043 groupBuilder.setGroupName(groupName);
2044 groupBuilder.setGroupType(GroupTypes.GroupAll);
2045 groupBuilder.setKey(key);
2046 group = getGroup(groupBuilder, nodeBuilder);
2051 if (groupActionAdded) {
2052 /* modify the action bucket in group */
2053 groupBuilder = new GroupBuilder(group);
2054 Buckets buckets = groupBuilder.getBuckets();
2055 List<Action> bucketActions = Lists.newArrayList();
2056 for (Bucket bucket : buckets.getBucket()) {
2058 boolean isPortDeleted = false;
2059 bucketActions = bucket.getAction();
2060 for (Action action : bucketActions) {
2061 if (action.getAction() instanceof OutputActionCase) {
2062 OutputActionCase opAction = (OutputActionCase)action.getAction();
2063 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
2064 /* Find the output port in action list and remove */
2065 index = bucketActions.indexOf(action);
2066 bucketActions.remove(action);
2067 isPortDeleted = true;
2072 if (isPortDeleted && !bucketActions.isEmpty()) {
2073 for (int i = index; i< bucketActions.size(); i++) {
2074 Action action = bucketActions.get(i);
2075 if (action.getOrder() != i) {
2076 /* Shift the action order */
2077 ab = new ActionBuilder();
2078 ab.setAction(action.getAction());
2080 ab.setKey(new ActionKey(i));
2081 Action actionNewOrder = ab.build();
2082 bucketActions.remove(action);
2083 bucketActions.add(i, actionNewOrder);
2087 } else if (bucketActions.isEmpty()) {
2088 /* remove bucket with empty action list */
2089 buckets.getBucket().remove(bucket);
2093 if (!buckets.getBucket().isEmpty()) {
2094 /* rewrite the group to group table */
2095 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
2096 BucketsBuilder bucketsBuilder = new BucketsBuilder();
2097 List<Bucket> bucketList = Lists.newArrayList();
2098 BucketBuilder bucketBuilder = new BucketBuilder();
2099 bucketBuilder.setBucketId(new BucketId((long) 1));
2100 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
2101 bucketBuilder.setAction(bucketActions);
2102 bucketList.add(bucketBuilder.build());
2103 bucketsBuilder.setBucket(bucketList);
2104 groupBuilder.setBuckets(bucketsBuilder.build());
2105 logger.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
2107 writeGroup(groupBuilder, nodeBuilder);
2108 ApplyActionsBuilder aab = new ApplyActionsBuilder();
2109 aab.setAction(actionList);
2110 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
2113 /* remove group with empty bucket. return true to delete flow */
2114 removeGroup(groupBuilder, nodeBuilder);
2118 /* no group for port list. flow can be removed */
2124 public void initializeOFFlowRules(Node openflowNode) {
2125 /* TODO SB_MIGRATION
2126 Preconditions.checkNotNull(connectionService);
2127 List<Node> ovsNodes = connectionService.getNodes();
2128 if (ovsNodes == null) return;
2129 for (Node ovsNode : ovsNodes) {
2130 Long brIntDpid = this.getIntegrationBridgeOFDPID(ovsNode);
2131 Long brExDpid = this.getExternalBridgeDpid(ovsNode);
2132 logger.debug("Compare openflowNode to OVS node {} vs {} and {}",
2133 openflowNode.getId().getValue(), brIntDpid, brExDpid);
2134 String openflowID = openflowNode.getId().getValue();
2135 if (openflowID.contains(brExDpid.toString())) {
2136 this.initializeFlowRules(ovsNode, configurationService.getExternalBridgeName());
2137 this.triggerInterfaceUpdates(ovsNode);
2139 if (openflowID.contains(brIntDpid.toString())) {
2140 this.initializeFlowRules(ovsNode, configurationService.getIntegrationBridgeName());
2141 this.triggerInterfaceUpdates(ovsNode);
2147 public void notifyFlowCapableNodeEvent(Long dpid, org.opendaylight.ovsdb.openstack.netvirt.api.Action action) {
2148 mdsalConsumer.notifyFlowCapableNodeCreateEvent(Constants.OPENFLOW_NODE_PREFIX + dpid, action);
2151 public static NodeBuilder createNodeBuilder(String nodeId) {
2152 NodeBuilder builder = new NodeBuilder();
2153 builder.setId(new NodeId(nodeId));
2154 builder.setKey(new NodeKey(builder.getId()));
2158 private InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node> nodeBuilderToInstanceId(NodeBuilder
2160 return InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node.class,
2161 node.getKey()).toInstance();
2164 private String getInternalBridgeUUID (Node node, String bridgeName) {
2165 /* TODO SB_MIGRATION
2166 Preconditions.checkNotNull(ovsdbConfigurationService);
2168 Map<String, Row> bridgeTable = ovsdbConfigurationService.getRows(node, ovsdbConfigurationService.getTableName(node, Bridge.class));
2169 if (bridgeTable == null) return null;
2170 for (String key : bridgeTable.keySet()) {
2171 Bridge bridge = ovsdbConfigurationService.getTypedRow(node, Bridge.class, bridgeTable.get(key));
2172 if (bridge.getName().equals(bridgeName)) return key;
2174 } catch (Exception e) {
2175 logger.error("Error getting Bridge Identifier for {} / {}", node, bridgeName, e);