2 * Copyright (c) 2013, 2015 Red Hat, Inc. and others. All rights reserved.
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
9 package org.opendaylight.ovsdb.openstack.netvirt.providers.openflow13;
11 import java.net.InetAddress;
12 import java.util.List;
14 import java.util.concurrent.ExecutionException;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
19 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronNetwork;
23 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronPort;
24 import org.opendaylight.ovsdb.openstack.netvirt.translator.NeutronSecurityGroup;
25 import org.opendaylight.ovsdb.openstack.netvirt.translator.Neutron_IPs;
26 import org.opendaylight.ovsdb.openstack.netvirt.MdsalHelper;
27 import org.opendaylight.ovsdb.openstack.netvirt.NetworkHandler;
28 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
29 import org.opendaylight.ovsdb.openstack.netvirt.api.ClassifierProvider;
30 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
31 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
32 import org.opendaylight.ovsdb.openstack.netvirt.api.EgressAclProvider;
33 import org.opendaylight.ovsdb.openstack.netvirt.api.IngressAclProvider;
34 import org.opendaylight.ovsdb.openstack.netvirt.api.L2ForwardingProvider;
35 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProvider;
36 import org.opendaylight.ovsdb.openstack.netvirt.api.NetworkingProviderManager;
37 import org.opendaylight.ovsdb.openstack.netvirt.api.NodeCacheManager;
38 import org.opendaylight.ovsdb.openstack.netvirt.api.SecurityServicesManager;
39 import org.opendaylight.ovsdb.openstack.netvirt.api.Southbound;
40 import org.opendaylight.ovsdb.openstack.netvirt.api.Status;
41 import org.opendaylight.ovsdb.openstack.netvirt.api.StatusCode;
42 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
43 import org.opendaylight.ovsdb.openstack.netvirt.providers.ConfigInterface;
44 import org.opendaylight.ovsdb.openstack.netvirt.providers.NetvirtProvidersProvider;
45 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
46 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
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.NodeBuilder;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
89 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
90 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
91 import org.osgi.framework.BundleContext;
92 import org.osgi.framework.ServiceReference;
93 import org.slf4j.Logger;
94 import org.slf4j.LoggerFactory;
96 import com.google.common.base.Optional;
97 import com.google.common.base.Preconditions;
98 import com.google.common.collect.Lists;
99 import com.google.common.collect.Maps;
100 import com.google.common.util.concurrent.CheckedFuture;
104 * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
106 * @author Madhu Venugopal
107 * @author Brent Salisbury
108 * @author Dave Tucker
111 // Methods' parameters in this class follow the same pattern to avoid confusion between same-typed parameters
112 // The patterns need to be preserved even though not all parameters are used in all methods
113 @SuppressWarnings("UnusedParameters")
114 public class OF13Provider implements ConfigInterface, NetworkingProvider {
115 private static final Logger LOG = LoggerFactory.getLogger(OF13Provider.class);
116 private static final short TABLE_0_DEFAULT_INGRESS = 0;
117 private static final short TABLE_1_ISOLATE_TENANT = 10;
118 private static final short TABLE_2_LOCAL_FORWARD = 20;
119 private static Long groupId = 1L;
120 private DataBroker dataBroker = null;
122 private volatile ConfigurationService configurationService;
123 private volatile BridgeConfigurationManager bridgeConfigurationManager;
124 private volatile TenantNetworkManager tenantNetworkManager;
125 private volatile SecurityServicesManager securityServicesManager;
126 private volatile ClassifierProvider classifierProvider;
127 private volatile IngressAclProvider ingressAclProvider;
128 private volatile EgressAclProvider egressAclProvider;
129 private volatile NodeCacheManager nodeCacheManager;
130 private volatile L2ForwardingProvider l2ForwardingProvider;
132 public static final String NAME = "OF13Provider";
133 private volatile BundleContext bundleContext;
134 private volatile Southbound southbound;
136 public OF13Provider() {
137 this.dataBroker = NetvirtProvidersProvider.getDataBroker();
141 public String getName() {
146 public boolean supportsServices() {
151 public boolean hasPerTenantTunneling() {
155 // The method is tested for in OF13ProviderTest
156 @SuppressWarnings("unused")
157 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
158 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
159 if (srcTunnelEndPoint == null) {
160 LOG.error("Tunnel Endpoint not configured for Node {}", node);
161 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
164 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
165 LOG.error("{} is not Overlay ready", node);
166 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
169 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
170 LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
171 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
173 return new Status(StatusCode.SUCCESS);
176 private String getTunnelName(String tunnelType, InetAddress dst) {
177 return tunnelType+"-"+dst.getHostAddress();
180 private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
181 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
182 String portName = getTunnelName(tunnelType, dst);
183 LOG.info("addTunnelPort enter: portName: {}", portName);
184 if (southbound.extractTerminationPointAugmentation(node, portName) != null
185 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
186 LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
190 Map<String, String> options = Maps.newHashMap();
191 options.put("key", "flow");
192 options.put("local_ip", src.getHostAddress());
193 options.put("remote_ip", dst.getHostAddress());
195 if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
196 LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
200 LOG.info("addTunnelPort exit: portName: {}", portName);
204 /* delete port from ovsdb port table */
205 private boolean deletePort(Node node, String bridgeName, String portName) {
207 // might need to convert from ovsdb node to bridge node
208 return southbound.deleteTerminationPoint(node, portName);
211 private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
212 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
213 String portName = getTunnelName(tunnelType, dst);
214 return deletePort(node, tunnelBridgeName, portName);
217 private boolean deletePhysicalPort(Node node, String phyIntfName) {
218 String intBridgeName = configurationService.getIntegrationBridgeName();
219 return deletePort(node, intBridgeName, phyIntfName);
222 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
223 String attachedMac, long localPort) {
227 * Match: VM sMac and Local Ingress Port
228 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
231 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
232 segmentationId, localPort, attachedMac, true);
237 * Match: Drop any remaining Ingress Local VM Packets
238 * Action: Drop w/ a low priority
241 handleDropSrcIface(dpid, localPort, true);
246 * Match: Match TunID and Destination DL/dMAC Addr
247 * Action: Output Port
248 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
251 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
256 * Match: Tunnel ID and dMAC (::::FF:FF)
257 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
258 * actions=output:2,3,4,5
261 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
262 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
265 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
270 * Match: Any remaining Ingress Local VM Packets
271 * Action: Drop w/ a low priority
272 * -------------------------------------------
273 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
276 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
281 * Match: Any Remaining Flows w/a TunID
282 * Action: Drop w/ a low priority
283 * table=2,priority=8192,tun_id=0x5 actions=drop
286 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
289 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
293 * Match: VM sMac and Local Ingress Port
294 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
297 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
302 * Match: Drop any remaining Ingress Local VM Packets
303 * Action: Drop w/ a low priority
306 handleDropSrcIface(dpid, localPort, false);
311 * Match: Match TunID and Destination DL/dMAC Addr
312 * Action: Output Port
313 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
316 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
321 * Match: Tunnel ID and dMAC (::::FF:FF)
322 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
323 * actions=output:2,3,4,5
326 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
327 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
330 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
334 * Match: Ingress Port, Tunnel ID
335 * Action: GOTO Local Table (20)
338 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
343 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
344 * Action: Flood to selected destination TEPs
345 * -------------------------------------------
346 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
347 * actions=output:10,output:11,goto_table:2
350 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
354 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
358 * Match: Drop any remaining Ingress Local VM Packets
359 * Action: Drop w/ a low priority
360 * -------------------------------------------
361 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
362 * actions=output:11,goto_table:2
365 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
368 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
372 * Match: Drop any remaining Ingress Local VM Packets
373 * Action: Drop w/ a low priority
374 * -------------------------------------------
375 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
376 * actions=output:11,goto_table:2
379 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
382 /* Remove tunnel rules if last node in this tenant network */
383 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
385 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
390 * Match: Any remaining Ingress Local VM Packets
391 * Action: Drop w/ a low priority
392 * -------------------------------------------
393 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
396 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
401 * Match: Any Remaining Flows w/a TunID
402 * Action: Drop w/ a low priority
403 * table=2,priority=8192,tun_id=0x5 actions=drop
406 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
411 * Match: Ingress Port, Tunnel ID
412 * Action: GOTO Local Table (10)
415 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
420 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
421 * Action: Flood to selected destination TEPs
422 * -------------------------------------------
423 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
424 * actions=output:10,output:11,goto_table:2
427 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
430 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
434 * Tag traffic coming from the local port and vm srcmac
435 * Match: VM sMac and Local Ingress Port
436 * Action: Set VLAN ID and GOTO Local Table 1
439 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
440 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
446 * Drop all other traffic coming from the local port
447 * Match: Drop any remaining Ingress Local VM Packets
448 * Action: Drop w/ a low priority
451 handleDropSrcIface(dpid, localPort, true);
456 * Forward unicast traffic destined to the local port after stripping tag
457 * Match: Match VLAN ID and Destination DL/dMAC Addr
458 * Action: strip vlan, output to local port
459 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
462 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
463 localPort, attachedMac, true);
468 * Match: VLAN ID and dMAC (::::FF:FF)
469 * Action: strip vlan, output to all local ports in this vlan
470 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
471 * actions= strip_vlan, output:2,3,4,5
474 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
475 // localPort, ethPort, true);
476 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
477 // segmentationId, localPort, ethport, true);
482 * Match: Any Remaining Flows w/a VLAN ID
483 * Action: Drop w/ a low priority
484 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
487 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
491 private void removeLocalVlanRules(Node node, Long dpid,
492 String segmentationId, String attachedMac, long localPort) {
496 * Match: VM sMac and Local Ingress Port
497 * Action: Set VLAN ID and GOTO Local Table 1
500 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
501 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
507 * Match: Drop any remaining Ingress Local VM Packets
508 * Action: Drop w/ a low priority
511 handleDropSrcIface(dpid, localPort, false);
516 * Match: Match VLAN ID and Destination DL/dMAC Addr
517 * Action: strip vlan, output to local port
518 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
521 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
522 localPort, attachedMac, false);
527 * Match: VLAN ID and dMAC (::::FF:FF)
528 * Action: strip vlan, output to all local ports in this vlan
529 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
530 * actions= strip_vlan, output:2,3,4,5
533 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
534 // localPort, ethPort, false);
535 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
536 // segmentationId, localPort, false);
540 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
541 long localPort, long ethPort) {
545 * Match: Ingress port = physical interface, Vlan ID
546 * Action: GOTO Local Table 2
549 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
550 segmentationId, ethPort, true);
555 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
556 * Action: Flood to local and remote VLAN members
557 * -------------------------------------------
558 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
559 * actions=output:10 (eth port),goto_table:2
560 * 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
563 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
568 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
569 * Action: Flood to local and remote VLAN members
570 * -------------------------------------------
571 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
572 * actions=output:10 (eth port),goto_table:2
575 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
576 // segmentationId, ethPort, true);
579 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
580 String attachedMac, long ethPort) {
584 * Match: Destination MAC is local VM MAC and vlan id
585 * Action: go to table 2
586 * -------------------------------------------
587 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
588 * actions=goto_table:2
591 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
592 // segmentationId, ethPort, attachedMac, true);
598 * Action: Go to table 2
599 * -------------------------------------------
600 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
601 * table=110,priority=8192,dl_vlan=2001 actions=output:2
604 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
607 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
608 String attachedMac, long localPort, long ethPort) {
612 * Match: Destination MAC is local VM MAC and vlan id
613 * Action: go to table 2
614 * -------------------------------------------
615 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
616 * actions=goto_table:2
619 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
620 // segmentationId, ethPort, attachedMac, false);
625 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
626 * Action: Flood to local and remote VLAN members
627 * -------------------------------------------
628 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
629 * actions=output:10 (eth port),goto_table:2
630 * 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
633 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
636 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
640 * Match: Any Remaining Flows w/a VLAN ID
641 * Action: Drop w/ a low priority
642 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
645 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
650 * Match: Ingress port = physical interface, Vlan ID
651 * Action: GOTO Local Table 2
654 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
659 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
660 * Action: Flood to local and remote VLAN members
661 * -------------------------------------------
662 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
663 * actions=output:10 (eth port),goto_table:2
664 * 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
667 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
672 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
673 * Action: Flood to local and remote VLAN members
674 * -------------------------------------------
675 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
676 * actions=output:10 (eth port),goto_table:2
679 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
680 // segmentationId, ethPort, false);
686 * Action: Go to table 2
687 * -------------------------------------------
688 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
689 * table=110,priority=8192,dl_vlan=2001 actions=output:2
692 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
695 private long getDpid(Node node) {
696 long dpid = southbound.getDataPathId(node);
698 LOG.warn("getDpid: dpid not found: {}", node);
703 private long getIntegrationBridgeOFDPID(Node node) {
705 if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
706 dpid = getDpid(node);
712 * Returns true is the network if of type GRE or VXLAN
714 * @param networkType The type of the network
715 * @return returns true if the network is a tunnel
717 private boolean isTunnel(String networkType)
719 return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
720 (NetworkHandler.NETWORK_TYPE_VXLAN));
724 * Returns true if the network is of type vlan.
726 * @param networkType The type of the network
727 * @return returns true if the network is a vlan
729 private boolean isVlan(String networkType)
731 return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
734 private void programLocalRules(String networkType, String segmentationId, Node node,
735 OvsdbTerminationPointAugmentation intf) {
736 LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
737 node.getNodeId(), intf.getName(), networkType, segmentationId);
739 long dpid = getIntegrationBridgeOFDPID(node);
741 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
746 long localPort = southbound.getOFPort(intf);
747 if (localPort == 0) {
748 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
749 intf.getName(), node.getNodeId());
753 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
754 if (attachedMac == null) {
755 LOG.warn("No AttachedMac seen in {}", intf);
759 /* Program local rules based on network type */
760 if (isVlan(networkType)) {
761 LOG.debug("Program local vlan rules for interface {}", intf.getName());
762 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
764 if ((isTunnel(networkType) || isVlan(networkType))) {
765 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
767 if (isTunnel(networkType)) {
768 LOG.debug("Program local bridge rules for interface {}, "
769 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
770 intf.getName(), dpid, segmentationId, attachedMac, localPort);
771 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
773 } catch (Exception e) {
774 LOG.error("Exception in programming Local Rules for " + intf + " on " + node, e);
778 private void removeLocalRules(String networkType, String segmentationId, Node node,
779 OvsdbTerminationPointAugmentation intf) {
780 LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
781 node.getNodeId(), intf.getName(), networkType, segmentationId);
783 long dpid = getIntegrationBridgeOFDPID(node);
785 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
789 long localPort = southbound.getOFPort(intf);
790 if (localPort == 0) {
791 LOG.info("removeLocalRules: could not find ofPort");
795 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
796 if (attachedMac == null) {
797 LOG.warn("No AttachedMac seen in {}", intf);
801 /* Program local rules based on network type */
802 if (isVlan(networkType)) {
803 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
804 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
805 } else if (isTunnel(networkType)) {
806 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
807 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
809 if (isTunnel(networkType) || isVlan(networkType)) {
810 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
812 } catch (Exception e) {
813 LOG.error("Exception in removing Local Rules for " + intf + " on " + node, e);
818 // Need to handle case where a node comes online after a network and tunnels have
819 // already been created. The interface update is what triggers creating the l2 forwarding flows
820 // so we don't see those updates in this case - we only see the new nodes interface updates.
821 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
822 OvsdbTerminationPointAugmentation intf, boolean local) {
823 LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
824 + "segmentationId: {}, dstAddr: {}",
825 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
827 long dpid = getIntegrationBridgeOFDPID(node);
829 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
833 long localPort = southbound.getOFPort(intf);
834 if (localPort == 0) {
835 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
839 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
840 if (attachedMac == null) {
841 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
845 OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
846 if(tunnelPort != null){
847 long tunnelOFPort = southbound.getOFPort(tunnelPort);
848 if (tunnelOFPort == 0) {
849 LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
850 tunnelPort.getName(), tunnelOFPort, node);
853 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
854 tunnelPort.getName(), tunnelOFPort, node);
857 LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
858 node.getNodeId().getValue(), intf.getName());
859 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
860 tunnelOFPort, localPort);
862 LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
863 node.getNodeId().getValue(), intf.getName());
864 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
865 tunnelOFPort, localPort);
868 } catch (Exception e) {
873 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
874 OvsdbTerminationPointAugmentation intf,
875 boolean local, boolean isLastInstanceOnNode) {
876 LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
877 + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
878 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
880 long dpid = getIntegrationBridgeOFDPID(node);
882 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
886 long localPort = southbound.getOFPort(intf);
887 if (localPort == 0) {
888 LOG.info("removeTunnelRules: could not find ofPort");
892 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
893 if (attachedMac == null) {
894 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
898 List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
899 for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
900 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
901 long tunnelOFPort = southbound.getOFPort(tunIntf);
902 if (tunnelOFPort == 0) {
903 LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
904 tunIntf.getName(), tunnelOFPort, node);
907 LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
908 tunIntf.getName(), tunnelOFPort, node);
911 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
912 tunnelOFPort, localPort);
914 if (local && isLastInstanceOnNode) {
915 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
920 } catch (Exception e) {
925 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
926 LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
927 node.getNodeId(), network.getNetworkUUID(), intf.getName());
928 long dpid = getIntegrationBridgeOFDPID(node);
930 LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
934 long localPort = southbound.getOFPort(intf);
935 if (localPort == 0) {
936 LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
940 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
941 if (attachedMac == null) {
942 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
947 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
948 long ethOFPort = southbound.getOFPort(node, phyIfName);
949 if (ethOFPort == 0) {
950 LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
953 LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
954 phyIfName, ethOFPort, node);
955 // TODO: add logic to only add rule on remote nodes
956 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
957 attachedMac, ethOFPort);
958 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
959 attachedMac, localPort, ethOFPort);
962 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
963 boolean isLastInstanceOnNode) {
964 LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
965 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
966 long dpid = getIntegrationBridgeOFDPID(node);
968 LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
972 long localPort = southbound.getOFPort(intf);
973 if (localPort == 0) {
974 LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
978 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
979 if (attachedMac == null) {
980 LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
985 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
986 long ethOFPort = southbound.getOFPort(node, phyIfName);
987 if (ethOFPort == 0) {
988 LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
991 LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
992 phyIfName, ethOFPort, node);
994 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
995 attachedMac, localPort, ethOFPort);
996 if (isLastInstanceOnNode) {
997 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1001 private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
1002 Long dpid,long localPort, String segmentationId,
1005 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
1006 NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
1007 boolean isComputePort = false;
1008 boolean isLastPortinBridge = false;
1009 boolean isLastPortinSubnet = false;
1010 List<Neutron_IPs> srcAddressList = null;
1011 if (null != dhcpPort) {
1012 isComputePort = securityServicesManager.isComputePort(intf);
1013 isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
1014 isLastPortinSubnet = false;
1015 if (isComputePort) {
1016 isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
1017 srcAddressList = securityServicesManager.getIpAddressList(intf);
1018 if (null == srcAddressList) {
1019 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1023 ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1024 isLastPortinSubnet, isComputePort, write);
1025 egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1026 srcAddressList, isLastPortinBridge, isComputePort,write);
1027 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
1028 /* TODO SB_MIGRATION */
1030 LOG.debug("Neutron port has a Port Security Group");
1031 // Retrieve the security group from the Neutron Port and apply the rules
1032 if (securityServicesManager.isPortSecurityReady(intf)) {
1033 //Associate the security group flows.
1034 List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
1035 .getSecurityGroupInPortList(intf);
1036 String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
1037 Constants.EXTERNAL_ID_INTERFACE_ID);
1038 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1039 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1040 securityGroupInPort, neutronPortId, write);
1041 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1042 securityGroupInPort, neutronPortId, write);
1046 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1051 * The function is for the new compute node joining the existing network.
1052 * When a new VM is instantiated in the new compute node, neutron port add
1053 * event is generated. This event is processed only for that node. So,
1054 * loop through all the ports of the same network and install unicast mac
1055 * flow for the VM's created on the TEP of the destination node in src node.
1056 * This function will be executed even for any new VM creation in an existing
1057 * network. If a cache is maintained to optimize the below flow addition, it will
1058 * work only for one unstack and restack. For the next unstack and restack,
1059 * it will not work since the cache would have been already deleted.
1061 private void programTunnelRulesInNewNode(NeutronNetwork network,
1062 String networkType, String segmentationId,
1063 InetAddress src, InetAddress dst,
1064 Node srcBridgeNode, Node dstBridgeNode,
1065 OvsdbTerminationPointAugmentation intf){
1067 long localPort = southbound.getOFPort(intf);
1070 LOG.debug("Interface update details {}", intf);
1073 * When a network is added and the TEP destination is not present in a
1074 * node C1, tunnelin and broadcast rules will not be programmed, since
1075 * OF port is not created. So, when a new node C2 joins and create a new
1076 * VM, the tunnelin and broadcast rule will not be present in C1.
1077 * So, handling it in the case below to make ping work.
1079 if(securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1080 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1084 * FIX for 4208 - loop through all the ports and add the VM's
1085 * unicast mac rule of the destination node in the source node.
1086 * When a new node is added, it needs to configure the VM unicast mac
1087 * flow rules which were created before it was joined to an existing
1090 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1091 for (OvsdbTerminationPointAugmentation port : ports) {
1092 if(network == tenantNetworkManager.getTenantNetwork(port)){
1093 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1096 LOG.trace("Port {} is not part of network {}", port, network);
1100 } catch (Exception e) {
1101 LOG.error("Exception during handlingNeutron network add", e);
1106 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
1107 OvsdbTerminationPointAugmentation intf) {
1108 Preconditions.checkNotNull(nodeCacheManager);
1109 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1110 nodeCacheManager.getOvsdbNodes();
1111 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1112 String networkType = network.getProviderNetworkType();
1113 String segmentationId = network.getProviderSegmentationID();
1114 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1115 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1117 if (isVlan(networkType)) {
1118 programVlanRules(network, srcNode, intf);
1119 } else if (isTunnel(networkType)){
1121 boolean sourceTunnelStatus = false;
1122 boolean destTunnelStatus = false;
1123 for (Node dstNode : nodes.values()) {
1124 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1125 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1126 if ((src != null) && (dst != null)) {
1127 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1129 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1130 configurationService.getIntegrationBridgeName());
1132 if(dstBridgeNode != null){
1133 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1136 if (sourceTunnelStatus) {
1137 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1139 if (destTunnelStatus) {
1140 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1141 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1142 srcBridgeNode, dstBridgeNode, intf);
1145 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1146 + "Check source {} or destination {}",
1147 src != null ? src.getHostAddress() : "null",
1148 dst != null ? dst.getHostAddress() : "null");
1156 private void triggerInterfaceUpdates(Node node) {
1157 LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
1158 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1159 if (ports != null && !ports.isEmpty()) {
1160 for (OvsdbTerminationPointAugmentation port : ports) {
1161 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1162 if (neutronNetwork != null) {
1163 LOG.warn("Trigger Interface update for {}", port);
1164 handleInterfaceUpdate(neutronNetwork, node, port);
1168 LOG.warn("triggerInterfaceUpdates: tps are null");
1170 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1174 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1175 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1176 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1177 nodeCacheManager.getOvsdbNodes();
1178 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1180 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1181 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1182 if (southbound.isTunnel(intf)) {
1183 // Delete tunnel port
1185 InetAddress src = InetAddress.getByName(
1186 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1187 InetAddress dst = InetAddress.getByName(
1188 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1189 deleteTunnelPort(srcNode,
1190 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1192 } catch (Exception e) {
1193 LOG.error(e.getMessage(), e);
1195 } else if (phyIfName.contains(intf.getName())) {
1196 deletePhysicalPort(srcNode, intf.getName());
1198 // delete all other interfaces
1199 removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1202 if (isVlan(network.getProviderNetworkType())) {
1203 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1204 } else if (isTunnel(network.getProviderNetworkType())) {
1206 for (Node dstNode : nodes.values()) {
1207 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1208 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1209 if ((src != null) && (dst != null)) {
1210 LOG.info("Remove tunnel rules for interface "
1211 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1212 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1213 dst, srcNode, intf, true, isLastInstanceOnNode);
1214 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1215 if(dstBridgeNode != null){
1216 LOG.info("Remove tunnel rules for interface "
1217 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1218 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1219 src, dstBridgeNode, intf, false, isLastInstanceOnNode);
1222 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1223 + "OpenVSwitch Table. "
1224 + "Check source {} or destination {}",
1225 src != null ? src.getHostAddress() : "null",
1226 dst != null ? dst.getHostAddress() : "null");
1235 public void initializeFlowRules(Node node) {
1236 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1237 initializeFlowRules(node, configurationService.getExternalBridgeName());
1238 triggerInterfaceUpdates(node);
1241 private void initializeFlowRules(Node node, String bridgeName) {
1242 Long dpid = southbound.getDataPathId(node);
1243 String datapathId = southbound.getDatapathId(node);
1244 LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
1245 bridgeName, dpid, datapathId);
1248 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1255 * Match: LLDP (0x88CCL)
1256 * Action: Packet_In to Controller Reserved Port
1259 writeLLDPRule(dpid);
1261 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1262 writeNormalRule(dpid);
1267 * Create an LLDP Flow Rule to encapsulate into
1268 * a packet_in that is sent to the controller
1269 * for topology handling.
1270 * Match: Ethertype 0x88CCL
1271 * Action: Punt to Controller in a Packet_In msg
1274 private void writeLLDPRule(Long dpidLong) {
1275 classifierProvider.programLLDPPuntRule(dpidLong);
1279 * Create a NORMAL Table Miss Flow Rule
1281 * Action: forward to NORMAL pipeline
1284 private void writeNormalRule(Long dpidLong) {
1286 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1288 MatchBuilder matchBuilder = new MatchBuilder();
1289 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1290 FlowBuilder flowBuilder = new FlowBuilder();
1292 // Create the OF Actions and Instructions
1293 InstructionBuilder ib = new InstructionBuilder();
1294 InstructionsBuilder isb = new InstructionsBuilder();
1296 // Instructions List Stores Individual Instructions
1297 List<Instruction> instructions = Lists.newArrayList();
1299 // Call the InstructionBuilder Methods Containing Actions
1300 InstructionUtils.createNormalInstructions(nodeName, ib);
1302 ib.setKey(new InstructionKey(0));
1303 instructions.add(ib.build());
1305 // Add InstructionBuilder to the Instruction(s)Builder List
1306 isb.setInstruction(instructions);
1308 // Add InstructionsBuilder to FlowBuilder
1309 flowBuilder.setInstructions(isb.build());
1311 String flowId = "NORMAL";
1312 flowBuilder.setId(new FlowId(flowId));
1313 FlowKey key = new FlowKey(new FlowId(flowId));
1314 flowBuilder.setMatch(matchBuilder.build());
1315 flowBuilder.setPriority(0);
1316 flowBuilder.setBarrier(true);
1317 flowBuilder.setTableId((short) 0);
1318 flowBuilder.setKey(key);
1319 flowBuilder.setFlowName(flowId);
1320 flowBuilder.setHardTimeout(0);
1321 flowBuilder.setIdleTimeout(0);
1322 writeFlow(flowBuilder, nodeBuilder);
1326 * (Table:0) Ingress Tunnel Traffic
1327 * Match: OpenFlow InPort and Tunnel ID
1328 * Action: GOTO Local Table (10)
1329 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1332 private void handleTunnelIn(Long dpidLong, Short writeTable,
1333 Short goToTableId, String segmentationId,
1334 Long ofPort, boolean write) {
1335 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1339 * (Table:0) Ingress VLAN Traffic
1340 * Match: OpenFlow InPort and vlan ID
1341 * Action: GOTO Local Table (20)
1342 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1345 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1346 String segmentationId, Long ethPort, boolean write) {
1347 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1351 * (Table:0) Egress VM Traffic Towards TEP
1352 * Match: Destination Ethernet Addr and OpenFlow InPort
1353 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1354 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1355 * actions=set_field:5->tun_id,goto_table=1"
1358 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1359 String segmentationId, Long inPort, String attachedMac,
1361 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1365 * (Table:0) Egress VM Traffic Towards TEP
1366 * Match: Source Ethernet Addr and OpenFlow InPort
1367 * Instruction: Set VLANID and GOTO Table Egress (n)
1368 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1369 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1372 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1373 Short goToTableId, String segmentationId,
1374 Long inPort, String attachedMac,
1376 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1380 * (Table:0) Drop frames source from a VM that do not
1381 * match the associated MAC address of the local VM.
1382 * Match: Low priority anything not matching the VM SMAC
1384 * table=0,priority=16384,in_port=1 actions=drop"
1387 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1388 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1392 * (Table:1) Egress Tunnel Traffic
1393 * Match: Destination Ethernet Addr and Local InPort
1394 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1395 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1396 * actions=output:10,goto_table:2"
1398 private void handleTunnelOut(Long dpidLong, Short writeTable,
1399 Short goToTableId, String segmentationId,
1400 Long OFPortOut, String attachedMac,
1402 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1406 * (Table:1) Egress VLAN Traffic
1407 * Match: Destination Ethernet Addr and VLAN id
1408 * Instruction: GOTO Table Table 2
1409 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1410 * actions= goto_table:2"
1412 // TODO This method is referenced from commented code above (which needs to be checked)
1413 @SuppressWarnings("unused")
1414 private void handleVlanOut(Long dpidLong, Short writeTable,
1415 Short goToTableId, String segmentationId,
1416 Long ethPort, String attachedMac, boolean write) {
1417 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1421 * (Table:1) Egress Tunnel Traffic
1422 * Match: Destination Ethernet Addr and Local InPort
1423 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1424 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1425 * actions=output:10,output:11,goto_table:2
1428 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1429 Short localTable, String segmentationId,
1430 Long OFPortOut, boolean write) {
1431 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1435 * (Table:1) Egress VLAN Traffic
1436 * Match: Destination Ethernet Addr and VLAN id
1437 * Instruction: GOTO table 2 and Output port eth interface
1438 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1439 * actions=output:eth1,goto_table:2
1441 // TODO This method is referenced from commented code above (which needs to be checked)
1442 @SuppressWarnings("unused")
1443 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1444 Short localTable, String segmentationId,
1445 Long localPort, Long ethPort, boolean write) {
1446 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1450 * (Table:1) Table Drain w/ Catch All
1452 * Action: GOTO Local Table (10)
1453 * table=2,priority=8192,tun_id=0x5 actions=drop
1456 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1457 Short goToTableId, String segmentationId,
1459 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1464 * (Table:1) Table Drain w/ Catch All
1466 * Action: Output port eth interface
1467 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1468 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1471 private void handleVlanMiss(Long dpidLong, Short writeTable,
1472 Short goToTableId, String segmentationId,
1473 Long ethPort, boolean write) {
1474 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1478 * (Table:1) Local Broadcast Flood
1479 * Match: Tunnel ID and dMAC
1480 * Action: Output Port
1481 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1484 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1485 String segmentationId, Long localPort,
1486 String attachedMac, boolean write) {
1487 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1491 * (Table:2) Local VLAN unicast
1492 * Match: VLAN ID and dMAC
1493 * Action: Output Port
1494 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1497 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1498 String segmentationId, Long localPort,
1499 String attachedMac, boolean write) {
1500 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1504 * (Table:2) Local Broadcast Flood
1505 * Match: Tunnel ID and dMAC (::::FF:FF)
1506 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1507 * actions=output:2,3,4,5
1510 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1511 String segmentationId, Long localPort,
1513 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1517 * (Table:2) Local VLAN Broadcast Flood
1518 * Match: vlan ID and dMAC (::::FF:FF)
1519 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1520 * actions=strip_vlan, output:2,3,4,5
1521 * 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
1524 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1525 Long localPort, Long ethPort, boolean write) {
1526 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1530 * (Table:1) Local Table Miss
1531 * Match: Any Remaining Flows w/a TunID
1532 * Action: Drop w/ a low priority
1533 * table=2,priority=8192,tun_id=0x5 actions=drop
1536 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1537 String segmentationId, boolean write) {
1538 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1542 * (Table:1) Local Table Miss
1543 * Match: Any Remaining Flows w/a VLAN ID
1544 * Action: Drop w/ a low priority
1545 * table=2,priority=8192,vlan_id=0x5 actions=drop
1547 // TODO This method is referenced from commented code above (which needs to be checked)
1548 @SuppressWarnings("unused")
1549 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1550 String segmentationId, boolean write) {
1551 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1554 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1555 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1556 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1557 new GroupKey(groupBuilder.getGroupId())).build();
1558 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1560 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1561 if (data.isPresent()) {
1564 } catch (InterruptedException|ExecutionException e) {
1565 LOG.error(e.getMessage(), e);
1568 LOG.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1572 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1573 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1574 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1575 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1576 new GroupKey(groupBuilder.getGroupId())).build();
1577 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1579 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1581 commitFuture.get(); // TODO: Make it async (See bug 1362)
1582 LOG.debug("Transaction success for write of Group " + groupBuilder.getGroupName());
1583 } catch (InterruptedException|ExecutionException e) {
1584 LOG.error(e.getMessage(), e);
1588 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1589 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1590 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1591 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1592 new GroupKey(groupBuilder.getGroupId())).build();
1593 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1594 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1597 commitFuture.get(); // TODO: Make it async (See bug 1362)
1598 LOG.debug("Transaction success for deletion of Group " + groupBuilder.getGroupName());
1599 } catch (InterruptedException|ExecutionException e) {
1600 LOG.error(e.getMessage(), e);
1604 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1605 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1606 InstanceIdentifier<Flow> path1 =
1607 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1608 .rev130819.nodes.Node.class,
1609 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1610 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1612 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1613 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1614 true);//createMissingParents
1617 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1619 commitFuture.get(); // TODO: Make it async (See bug 1362)
1620 LOG.debug("Transaction success for write of Flow " + flowBuilder.getFlowName());
1621 } catch (InterruptedException|ExecutionException e) {
1622 LOG.error(e.getMessage(), e);
1627 * Create Output Port Group Instruction
1629 * @param ib Map InstructionBuilder without any instructions
1630 * @param dpidLong Long the datapath ID of a switch/node
1631 * @param port Long representing a port on a switch/node
1632 * @return ib InstructionBuilder Map with instructions
1634 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1635 @SuppressWarnings("unused")
1636 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1637 InstructionBuilder ib,
1638 Long dpidLong, Long port ,
1639 List<Instruction> instructions) {
1640 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1641 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1643 List<Action> actionList = Lists.newArrayList();
1644 ActionBuilder ab = new ActionBuilder();
1646 List<Action> existingActions;
1647 if (instructions != null) {
1648 for (Instruction in : instructions) {
1649 if (in.getInstruction() instanceof ApplyActionsCase) {
1650 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1651 actionList.addAll(existingActions);
1656 GroupBuilder groupBuilder = new GroupBuilder();
1659 /* Create output action for this port*/
1660 OutputActionBuilder oab = new OutputActionBuilder();
1661 oab.setOutputNodeConnector(ncid);
1662 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1663 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1664 boolean addNew = true;
1665 boolean groupActionAdded = false;
1667 /* Find the group action and get the group */
1668 for (Action action : actionList) {
1669 if (action.getAction() instanceof GroupActionCase) {
1670 groupActionAdded = true;
1671 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1672 Long id = groupAction.getGroupAction().getGroupId();
1673 String groupName = groupAction.getGroupAction().getGroup();
1674 GroupKey key = new GroupKey(new GroupId(id));
1676 groupBuilder.setGroupId(new GroupId(id));
1677 groupBuilder.setGroupName(groupName);
1678 groupBuilder.setGroupType(GroupTypes.GroupAll);
1679 groupBuilder.setKey(key);
1680 group = getGroup(groupBuilder, nodeBuilder);
1681 LOG.debug("createOutputGroupInstructions: group {}", group);
1686 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1687 if (groupActionAdded) {
1688 /* modify the action bucket in group */
1689 groupBuilder = new GroupBuilder(group);
1690 Buckets buckets = groupBuilder.getBuckets();
1691 for (Bucket bucket : buckets.getBucket()) {
1692 List<Action> bucketActions = bucket.getAction();
1693 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1694 for (Action action : bucketActions) {
1695 if (action.getAction() instanceof OutputActionCase) {
1696 OutputActionCase opAction = (OutputActionCase)action.getAction();
1697 /* If output port action already in the action list of one of the buckets, skip */
1698 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1705 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1706 if (addNew && !buckets.getBucket().isEmpty()) {
1707 /* the new output action is not in the bucket, add to bucket */
1708 Bucket bucket = buckets.getBucket().get(0);
1709 List<Action> bucketActionList = Lists.newArrayList();
1710 bucketActionList.addAll(bucket.getAction());
1711 /* set order for new action and add to action list */
1712 ab.setOrder(bucketActionList.size());
1713 ab.setKey(new ActionKey(bucketActionList.size()));
1714 bucketActionList.add(ab.build());
1716 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1717 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1718 List<Bucket> bucketList = Lists.newArrayList();
1719 BucketBuilder bucketBuilder = new BucketBuilder();
1720 bucketBuilder.setBucketId(new BucketId((long) 1));
1721 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1722 bucketBuilder.setAction(bucketActionList);
1723 bucketList.add(bucketBuilder.build());
1724 bucketsBuilder.setBucket(bucketList);
1725 groupBuilder.setBuckets(bucketsBuilder.build());
1726 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1730 groupBuilder = new GroupBuilder();
1731 groupBuilder.setGroupType(GroupTypes.GroupAll);
1732 groupBuilder.setGroupId(new GroupId(groupId));
1733 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1734 groupBuilder.setGroupName("Output port group " + groupId);
1735 groupBuilder.setBarrier(false);
1737 BucketsBuilder bucketBuilder = new BucketsBuilder();
1738 List<Bucket> bucketList = Lists.newArrayList();
1739 BucketBuilder bucket = new BucketBuilder();
1740 bucket.setBucketId(new BucketId((long) 1));
1741 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1743 /* put output action to the bucket */
1744 List<Action> bucketActionList = Lists.newArrayList();
1745 /* set order for new action and add to action list */
1746 ab.setOrder(bucketActionList.size());
1747 ab.setKey(new ActionKey(bucketActionList.size()));
1748 bucketActionList.add(ab.build());
1750 bucket.setAction(bucketActionList);
1751 bucketList.add(bucket.build());
1752 bucketBuilder.setBucket(bucketList);
1753 groupBuilder.setBuckets(bucketBuilder.build());
1755 /* Add new group action */
1756 GroupActionBuilder groupActionB = new GroupActionBuilder();
1757 groupActionB.setGroupId(groupId);
1758 groupActionB.setGroup("Output port group " + groupId);
1759 ab = new ActionBuilder();
1760 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1761 ab.setOrder(actionList.size());
1762 ab.setKey(new ActionKey(actionList.size()));
1763 actionList.add(ab.build());
1767 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1768 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1771 /* rewrite the group to group table */
1772 writeGroup(groupBuilder, nodeBuilder);
1775 // Create an Apply Action
1776 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1777 aab.setAction(actionList);
1778 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1784 * Remove Output Port from action list in group bucket
1786 * @param ib Map InstructionBuilder without any instructions
1787 * @param dpidLong Long the datapath ID of a switch/node
1788 * @param port Long representing a port on a switch/node
1789 * @return ib InstructionBuilder Map with instructions
1791 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1792 @SuppressWarnings("unused")
1793 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1794 Long dpidLong, Long port , List<Instruction> instructions) {
1796 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1797 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1799 List<Action> actionList = Lists.newArrayList();
1802 List<Action> existingActions;
1803 if (instructions != null) {
1804 for (Instruction in : instructions) {
1805 if (in.getInstruction() instanceof ApplyActionsCase) {
1806 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1807 actionList.addAll(existingActions);
1813 GroupBuilder groupBuilder = new GroupBuilder();
1815 boolean groupActionAdded = false;
1816 /* Find the group action and get the group */
1817 for (Action action : actionList) {
1818 if (action.getAction() instanceof GroupActionCase) {
1819 groupActionAdded = true;
1820 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1821 Long id = groupAction.getGroupAction().getGroupId();
1822 String groupName = groupAction.getGroupAction().getGroup();
1823 GroupKey key = new GroupKey(new GroupId(id));
1825 groupBuilder.setGroupId(new GroupId(id));
1826 groupBuilder.setGroupName(groupName);
1827 groupBuilder.setGroupType(GroupTypes.GroupAll);
1828 groupBuilder.setKey(key);
1829 group = getGroup(groupBuilder, nodeBuilder);
1834 if (groupActionAdded) {
1835 /* modify the action bucket in group */
1836 groupBuilder = new GroupBuilder(group);
1837 Buckets buckets = groupBuilder.getBuckets();
1838 List<Action> bucketActions = Lists.newArrayList();
1839 for (Bucket bucket : buckets.getBucket()) {
1841 boolean isPortDeleted = false;
1842 bucketActions = bucket.getAction();
1843 for (Action action : bucketActions) {
1844 if (action.getAction() instanceof OutputActionCase) {
1845 OutputActionCase opAction = (OutputActionCase)action.getAction();
1846 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1847 /* Find the output port in action list and remove */
1848 index = bucketActions.indexOf(action);
1849 bucketActions.remove(action);
1850 isPortDeleted = true;
1855 if (isPortDeleted && !bucketActions.isEmpty()) {
1856 for (int i = index; i< bucketActions.size(); i++) {
1857 Action action = bucketActions.get(i);
1858 if (action.getOrder() != i) {
1859 /* Shift the action order */
1860 ab = new ActionBuilder();
1861 ab.setAction(action.getAction());
1863 ab.setKey(new ActionKey(i));
1864 Action actionNewOrder = ab.build();
1865 bucketActions.remove(action);
1866 bucketActions.add(i, actionNewOrder);
1870 } else if (bucketActions.isEmpty()) {
1871 /* remove bucket with empty action list */
1872 buckets.getBucket().remove(bucket);
1876 if (!buckets.getBucket().isEmpty()) {
1877 /* rewrite the group to group table */
1878 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1879 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1880 List<Bucket> bucketList = Lists.newArrayList();
1881 BucketBuilder bucketBuilder = new BucketBuilder();
1882 bucketBuilder.setBucketId(new BucketId((long) 1));
1883 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1884 bucketBuilder.setAction(bucketActions);
1885 bucketList.add(bucketBuilder.build());
1886 bucketsBuilder.setBucket(bucketList);
1887 groupBuilder.setBuckets(bucketsBuilder.build());
1888 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1890 writeGroup(groupBuilder, nodeBuilder);
1891 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1892 aab.setAction(actionList);
1893 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1896 /* remove group with empty bucket. return true to delete flow */
1897 removeGroup(groupBuilder, nodeBuilder);
1901 /* no group for port list. flow can be removed */
1907 public void initializeOFFlowRules(Node openflowNode) {
1908 String bridgeName = southbound.getBridgeName(openflowNode);
1909 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1910 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1911 initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1912 triggerInterfaceUpdates(openflowNode);
1913 } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1914 initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1915 LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
1916 triggerInterfaceUpdates(openflowNode);
1917 LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
1921 public static NodeBuilder createNodeBuilder(String nodeId) {
1922 NodeBuilder builder = new NodeBuilder();
1923 builder.setId(new NodeId(nodeId));
1924 builder.setKey(new NodeKey(builder.getId()));
1929 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1930 this.bundleContext = bundleContext;
1931 configurationService =
1932 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1933 tenantNetworkManager =
1934 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1935 bridgeConfigurationManager =
1936 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1938 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1939 classifierProvider =
1940 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
1941 ingressAclProvider =
1942 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
1944 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
1945 l2ForwardingProvider =
1946 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
1947 securityServicesManager =
1948 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1950 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1954 public void setDependencies(Object impl) {
1955 if (impl instanceof NetworkingProviderManager) {
1956 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
1957 networkingProviderManager.providerAdded(
1958 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);