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.neutron.spi.NeutronNetwork;
23 import org.opendaylight.neutron.spi.NeutronPort;
24 import org.opendaylight.neutron.spi.NeutronSecurityGroup;
25 import org.opendaylight.neutron.spi.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(node, intf);
1018 if (null == srcAddressList) {
1019 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1023 ingressAclProvider.programFixedSecurityAcl(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1024 isLastPortinSubnet, isComputePort, write);
1025 egressAclProvider.programFixedSecurityAcl(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 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1037 ingressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
1038 securityGroupInPort,srcAddressList, write);
1039 egressAclProvider.programPortSecurityAcl(dpid, segmentationId, attachedMac, localPort,
1040 securityGroupInPort,srcAddressList, write);
1044 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1049 * The function is for the new compute node joining the existing network.
1050 * When a new VM is instantiated in the new compute node, neutron port add
1051 * event is generated. This event is processed only for that node. So,
1052 * loop through all the ports of the same network and install unicast mac
1053 * flow for the VM's created on the TEP of the destination node in src node.
1054 * This function will be executed even for any new VM creation in an existing
1055 * network. If a cache is maintained to optimize the below flow addition, it will
1056 * work only for one unstack and restack. For the next unstack and restack,
1057 * it will not work since the cache would have been already deleted.
1059 private void programTunnelRulesInNewNode(NeutronNetwork network,
1060 String networkType, String segmentationId,
1061 InetAddress src, InetAddress dst,
1062 Node srcBridgeNode, Node dstBridgeNode,
1063 OvsdbTerminationPointAugmentation intf){
1065 long localPort = southbound.getOFPort(intf);
1068 LOG.debug("Interface update details {}", intf);
1071 * When a network is added and the TEP destination is not present in a
1072 * node C1, tunnelin and broadcast rules will not be programmed, since
1073 * OF port is not created. So, when a new node C2 joins and create a new
1074 * VM, the tunnelin and broadcast rule will not be present in C1.
1075 * So, handling it in the case below to make ping work.
1077 if(securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1078 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1082 * FIX for 4208 - loop through all the ports and add the VM's
1083 * unicast mac rule of the destination node in the source node.
1084 * When a new node is added, it needs to configure the VM unicast mac
1085 * flow rules which were created before it was joined to an existing
1088 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1089 for (OvsdbTerminationPointAugmentation port : ports) {
1090 if(network == tenantNetworkManager.getTenantNetwork(port)){
1091 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1094 LOG.trace("Port {} is not part of network {}", port, network);
1098 } catch (Exception e) {
1099 LOG.error("Exception during handlingNeutron network add", e);
1104 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
1105 OvsdbTerminationPointAugmentation intf) {
1106 Preconditions.checkNotNull(nodeCacheManager);
1107 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1108 nodeCacheManager.getOvsdbNodes();
1109 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1110 String networkType = network.getProviderNetworkType();
1111 String segmentationId = network.getProviderSegmentationID();
1112 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1113 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1115 if (isVlan(networkType)) {
1116 programVlanRules(network, srcNode, intf);
1117 } else if (isTunnel(networkType)){
1119 boolean sourceTunnelStatus = false;
1120 boolean destTunnelStatus = false;
1121 for (Node dstNode : nodes.values()) {
1122 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1123 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1124 if ((src != null) && (dst != null)) {
1125 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1127 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1128 configurationService.getIntegrationBridgeName());
1130 if(dstBridgeNode != null){
1131 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1134 if (sourceTunnelStatus) {
1135 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1137 if (destTunnelStatus) {
1138 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1139 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1140 srcBridgeNode, dstBridgeNode, intf);
1143 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1144 + "Check source {} or destination {}",
1145 src != null ? src.getHostAddress() : "null",
1146 dst != null ? dst.getHostAddress() : "null");
1154 private void triggerInterfaceUpdates(Node node) {
1155 LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
1156 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1157 if (ports != null && !ports.isEmpty()) {
1158 for (OvsdbTerminationPointAugmentation port : ports) {
1159 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1160 if (neutronNetwork != null) {
1161 LOG.warn("Trigger Interface update for {}", port);
1162 handleInterfaceUpdate(neutronNetwork, node, port);
1166 LOG.warn("triggerInterfaceUpdates: tps are null");
1168 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1172 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1173 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1174 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1175 nodeCacheManager.getOvsdbNodes();
1176 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1178 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1179 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1180 if (southbound.isTunnel(intf)) {
1181 // Delete tunnel port
1183 InetAddress src = InetAddress.getByName(
1184 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1185 InetAddress dst = InetAddress.getByName(
1186 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1187 deleteTunnelPort(srcNode,
1188 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1190 } catch (Exception e) {
1191 LOG.error(e.getMessage(), e);
1193 } else if (phyIfName.contains(intf.getName())) {
1194 deletePhysicalPort(srcNode, intf.getName());
1196 // delete all other interfaces
1197 removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1200 if (isVlan(network.getProviderNetworkType())) {
1201 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1202 } else if (isTunnel(network.getProviderNetworkType())) {
1204 for (Node dstNode : nodes.values()) {
1205 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1206 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1207 if ((src != null) && (dst != null)) {
1208 LOG.info("Remove tunnel rules for interface "
1209 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1210 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1211 dst, srcNode, intf, true, isLastInstanceOnNode);
1212 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1213 if(dstBridgeNode != null){
1214 LOG.info("Remove tunnel rules for interface "
1215 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1216 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1217 src, dstBridgeNode, intf, false, isLastInstanceOnNode);
1220 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1221 + "OpenVSwitch Table. "
1222 + "Check source {} or destination {}",
1223 src != null ? src.getHostAddress() : "null",
1224 dst != null ? dst.getHostAddress() : "null");
1233 public void initializeFlowRules(Node node) {
1234 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1235 initializeFlowRules(node, configurationService.getExternalBridgeName());
1236 triggerInterfaceUpdates(node);
1239 private void initializeFlowRules(Node node, String bridgeName) {
1240 Long dpid = southbound.getDataPathId(node);
1241 String datapathId = southbound.getDatapathId(node);
1242 LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
1243 bridgeName, dpid, datapathId);
1246 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1253 * Match: LLDP (0x88CCL)
1254 * Action: Packet_In to Controller Reserved Port
1257 writeLLDPRule(dpid);
1259 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1260 writeNormalRule(dpid);
1265 * Create an LLDP Flow Rule to encapsulate into
1266 * a packet_in that is sent to the controller
1267 * for topology handling.
1268 * Match: Ethertype 0x88CCL
1269 * Action: Punt to Controller in a Packet_In msg
1272 private void writeLLDPRule(Long dpidLong) {
1273 classifierProvider.programLLDPPuntRule(dpidLong);
1277 * Create a NORMAL Table Miss Flow Rule
1279 * Action: forward to NORMAL pipeline
1282 private void writeNormalRule(Long dpidLong) {
1284 String nodeName = Constants.OPENFLOW_NODE_PREFIX + dpidLong;
1286 MatchBuilder matchBuilder = new MatchBuilder();
1287 NodeBuilder nodeBuilder = createNodeBuilder(nodeName);
1288 FlowBuilder flowBuilder = new FlowBuilder();
1290 // Create the OF Actions and Instructions
1291 InstructionBuilder ib = new InstructionBuilder();
1292 InstructionsBuilder isb = new InstructionsBuilder();
1294 // Instructions List Stores Individual Instructions
1295 List<Instruction> instructions = Lists.newArrayList();
1297 // Call the InstructionBuilder Methods Containing Actions
1298 InstructionUtils.createNormalInstructions(nodeName, ib);
1300 ib.setKey(new InstructionKey(0));
1301 instructions.add(ib.build());
1303 // Add InstructionBuilder to the Instruction(s)Builder List
1304 isb.setInstruction(instructions);
1306 // Add InstructionsBuilder to FlowBuilder
1307 flowBuilder.setInstructions(isb.build());
1309 String flowId = "NORMAL";
1310 flowBuilder.setId(new FlowId(flowId));
1311 FlowKey key = new FlowKey(new FlowId(flowId));
1312 flowBuilder.setMatch(matchBuilder.build());
1313 flowBuilder.setPriority(0);
1314 flowBuilder.setBarrier(true);
1315 flowBuilder.setTableId((short) 0);
1316 flowBuilder.setKey(key);
1317 flowBuilder.setFlowName(flowId);
1318 flowBuilder.setHardTimeout(0);
1319 flowBuilder.setIdleTimeout(0);
1320 writeFlow(flowBuilder, nodeBuilder);
1324 * (Table:0) Ingress Tunnel Traffic
1325 * Match: OpenFlow InPort and Tunnel ID
1326 * Action: GOTO Local Table (10)
1327 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1330 private void handleTunnelIn(Long dpidLong, Short writeTable,
1331 Short goToTableId, String segmentationId,
1332 Long ofPort, boolean write) {
1333 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1337 * (Table:0) Ingress VLAN Traffic
1338 * Match: OpenFlow InPort and vlan ID
1339 * Action: GOTO Local Table (20)
1340 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1343 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1344 String segmentationId, Long ethPort, boolean write) {
1345 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1349 * (Table:0) Egress VM Traffic Towards TEP
1350 * Match: Destination Ethernet Addr and OpenFlow InPort
1351 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1352 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1353 * actions=set_field:5->tun_id,goto_table=1"
1356 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1357 String segmentationId, Long inPort, String attachedMac,
1359 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1363 * (Table:0) Egress VM Traffic Towards TEP
1364 * Match: Source Ethernet Addr and OpenFlow InPort
1365 * Instruction: Set VLANID and GOTO Table Egress (n)
1366 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1367 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1370 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1371 Short goToTableId, String segmentationId,
1372 Long inPort, String attachedMac,
1374 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1378 * (Table:0) Drop frames source from a VM that do not
1379 * match the associated MAC address of the local VM.
1380 * Match: Low priority anything not matching the VM SMAC
1382 * table=0,priority=16384,in_port=1 actions=drop"
1385 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1386 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1390 * (Table:1) Egress Tunnel Traffic
1391 * Match: Destination Ethernet Addr and Local InPort
1392 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1393 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1394 * actions=output:10,goto_table:2"
1396 private void handleTunnelOut(Long dpidLong, Short writeTable,
1397 Short goToTableId, String segmentationId,
1398 Long OFPortOut, String attachedMac,
1400 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1404 * (Table:1) Egress VLAN Traffic
1405 * Match: Destination Ethernet Addr and VLAN id
1406 * Instruction: GOTO Table Table 2
1407 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1408 * actions= goto_table:2"
1410 // TODO This method is referenced from commented code above (which needs to be checked)
1411 @SuppressWarnings("unused")
1412 private void handleVlanOut(Long dpidLong, Short writeTable,
1413 Short goToTableId, String segmentationId,
1414 Long ethPort, String attachedMac, boolean write) {
1415 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1419 * (Table:1) Egress Tunnel Traffic
1420 * Match: Destination Ethernet Addr and Local InPort
1421 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1422 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1423 * actions=output:10,output:11,goto_table:2
1426 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1427 Short localTable, String segmentationId,
1428 Long OFPortOut, boolean write) {
1429 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1433 * (Table:1) Egress VLAN Traffic
1434 * Match: Destination Ethernet Addr and VLAN id
1435 * Instruction: GOTO table 2 and Output port eth interface
1436 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1437 * actions=output:eth1,goto_table:2
1439 // TODO This method is referenced from commented code above (which needs to be checked)
1440 @SuppressWarnings("unused")
1441 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1442 Short localTable, String segmentationId,
1443 Long localPort, Long ethPort, boolean write) {
1444 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1448 * (Table:1) Table Drain w/ Catch All
1450 * Action: GOTO Local Table (10)
1451 * table=2,priority=8192,tun_id=0x5 actions=drop
1454 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1455 Short goToTableId, String segmentationId,
1457 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1462 * (Table:1) Table Drain w/ Catch All
1464 * Action: Output port eth interface
1465 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1466 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1469 private void handleVlanMiss(Long dpidLong, Short writeTable,
1470 Short goToTableId, String segmentationId,
1471 Long ethPort, boolean write) {
1472 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1476 * (Table:1) Local Broadcast Flood
1477 * Match: Tunnel ID and dMAC
1478 * Action: Output Port
1479 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1482 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1483 String segmentationId, Long localPort,
1484 String attachedMac, boolean write) {
1485 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1489 * (Table:2) Local VLAN unicast
1490 * Match: VLAN ID and dMAC
1491 * Action: Output Port
1492 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1495 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1496 String segmentationId, Long localPort,
1497 String attachedMac, boolean write) {
1498 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1502 * (Table:2) Local Broadcast Flood
1503 * Match: Tunnel ID and dMAC (::::FF:FF)
1504 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1505 * actions=output:2,3,4,5
1508 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1509 String segmentationId, Long localPort,
1511 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1515 * (Table:2) Local VLAN Broadcast Flood
1516 * Match: vlan ID and dMAC (::::FF:FF)
1517 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1518 * actions=strip_vlan, output:2,3,4,5
1519 * 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
1522 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1523 Long localPort, Long ethPort, boolean write) {
1524 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1528 * (Table:1) Local Table Miss
1529 * Match: Any Remaining Flows w/a TunID
1530 * Action: Drop w/ a low priority
1531 * table=2,priority=8192,tun_id=0x5 actions=drop
1534 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1535 String segmentationId, boolean write) {
1536 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1540 * (Table:1) Local Table Miss
1541 * Match: Any Remaining Flows w/a VLAN ID
1542 * Action: Drop w/ a low priority
1543 * table=2,priority=8192,vlan_id=0x5 actions=drop
1545 // TODO This method is referenced from commented code above (which needs to be checked)
1546 @SuppressWarnings("unused")
1547 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1548 String segmentationId, boolean write) {
1549 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1552 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1553 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1554 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1555 new GroupKey(groupBuilder.getGroupId())).build();
1556 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1558 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1559 if (data.isPresent()) {
1562 } catch (InterruptedException|ExecutionException e) {
1563 LOG.error(e.getMessage(), e);
1566 LOG.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1570 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1571 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1572 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1573 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1574 new GroupKey(groupBuilder.getGroupId())).build();
1575 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1577 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1579 commitFuture.get(); // TODO: Make it async (See bug 1362)
1580 LOG.debug("Transaction success for write of Group " + groupBuilder.getGroupName());
1581 } catch (InterruptedException|ExecutionException e) {
1582 LOG.error(e.getMessage(), e);
1586 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1587 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1588 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1589 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1590 new GroupKey(groupBuilder.getGroupId())).build();
1591 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1592 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1595 commitFuture.get(); // TODO: Make it async (See bug 1362)
1596 LOG.debug("Transaction success for deletion of Group " + groupBuilder.getGroupName());
1597 } catch (InterruptedException|ExecutionException e) {
1598 LOG.error(e.getMessage(), e);
1602 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1603 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1604 InstanceIdentifier<Flow> path1 =
1605 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1606 .rev130819.nodes.Node.class,
1607 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1608 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1610 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1611 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1612 true);//createMissingParents
1615 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1617 commitFuture.get(); // TODO: Make it async (See bug 1362)
1618 LOG.debug("Transaction success for write of Flow " + flowBuilder.getFlowName());
1619 } catch (InterruptedException|ExecutionException e) {
1620 LOG.error(e.getMessage(), e);
1625 * Create Output Port Group Instruction
1627 * @param ib Map InstructionBuilder without any instructions
1628 * @param dpidLong Long the datapath ID of a switch/node
1629 * @param port Long representing a port on a switch/node
1630 * @return ib InstructionBuilder Map with instructions
1632 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1633 @SuppressWarnings("unused")
1634 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1635 InstructionBuilder ib,
1636 Long dpidLong, Long port ,
1637 List<Instruction> instructions) {
1638 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1639 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1641 List<Action> actionList = Lists.newArrayList();
1642 ActionBuilder ab = new ActionBuilder();
1644 List<Action> existingActions;
1645 if (instructions != null) {
1646 for (Instruction in : instructions) {
1647 if (in.getInstruction() instanceof ApplyActionsCase) {
1648 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1649 actionList.addAll(existingActions);
1654 GroupBuilder groupBuilder = new GroupBuilder();
1657 /* Create output action for this port*/
1658 OutputActionBuilder oab = new OutputActionBuilder();
1659 oab.setOutputNodeConnector(ncid);
1660 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1661 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1662 boolean addNew = true;
1663 boolean groupActionAdded = false;
1665 /* Find the group action and get the group */
1666 for (Action action : actionList) {
1667 if (action.getAction() instanceof GroupActionCase) {
1668 groupActionAdded = true;
1669 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1670 Long id = groupAction.getGroupAction().getGroupId();
1671 String groupName = groupAction.getGroupAction().getGroup();
1672 GroupKey key = new GroupKey(new GroupId(id));
1674 groupBuilder.setGroupId(new GroupId(id));
1675 groupBuilder.setGroupName(groupName);
1676 groupBuilder.setGroupType(GroupTypes.GroupAll);
1677 groupBuilder.setKey(key);
1678 group = getGroup(groupBuilder, nodeBuilder);
1679 LOG.debug("createOutputGroupInstructions: group {}", group);
1684 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1685 if (groupActionAdded) {
1686 /* modify the action bucket in group */
1687 groupBuilder = new GroupBuilder(group);
1688 Buckets buckets = groupBuilder.getBuckets();
1689 for (Bucket bucket : buckets.getBucket()) {
1690 List<Action> bucketActions = bucket.getAction();
1691 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1692 for (Action action : bucketActions) {
1693 if (action.getAction() instanceof OutputActionCase) {
1694 OutputActionCase opAction = (OutputActionCase)action.getAction();
1695 /* If output port action already in the action list of one of the buckets, skip */
1696 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1703 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1704 if (addNew && !buckets.getBucket().isEmpty()) {
1705 /* the new output action is not in the bucket, add to bucket */
1706 Bucket bucket = buckets.getBucket().get(0);
1707 List<Action> bucketActionList = Lists.newArrayList();
1708 bucketActionList.addAll(bucket.getAction());
1709 /* set order for new action and add to action list */
1710 ab.setOrder(bucketActionList.size());
1711 ab.setKey(new ActionKey(bucketActionList.size()));
1712 bucketActionList.add(ab.build());
1714 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1715 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1716 List<Bucket> bucketList = Lists.newArrayList();
1717 BucketBuilder bucketBuilder = new BucketBuilder();
1718 bucketBuilder.setBucketId(new BucketId((long) 1));
1719 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1720 bucketBuilder.setAction(bucketActionList);
1721 bucketList.add(bucketBuilder.build());
1722 bucketsBuilder.setBucket(bucketList);
1723 groupBuilder.setBuckets(bucketsBuilder.build());
1724 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1728 groupBuilder = new GroupBuilder();
1729 groupBuilder.setGroupType(GroupTypes.GroupAll);
1730 groupBuilder.setGroupId(new GroupId(groupId));
1731 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1732 groupBuilder.setGroupName("Output port group " + groupId);
1733 groupBuilder.setBarrier(false);
1735 BucketsBuilder bucketBuilder = new BucketsBuilder();
1736 List<Bucket> bucketList = Lists.newArrayList();
1737 BucketBuilder bucket = new BucketBuilder();
1738 bucket.setBucketId(new BucketId((long) 1));
1739 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1741 /* put output action to the bucket */
1742 List<Action> bucketActionList = Lists.newArrayList();
1743 /* set order for new action and add to action list */
1744 ab.setOrder(bucketActionList.size());
1745 ab.setKey(new ActionKey(bucketActionList.size()));
1746 bucketActionList.add(ab.build());
1748 bucket.setAction(bucketActionList);
1749 bucketList.add(bucket.build());
1750 bucketBuilder.setBucket(bucketList);
1751 groupBuilder.setBuckets(bucketBuilder.build());
1753 /* Add new group action */
1754 GroupActionBuilder groupActionB = new GroupActionBuilder();
1755 groupActionB.setGroupId(groupId);
1756 groupActionB.setGroup("Output port group " + groupId);
1757 ab = new ActionBuilder();
1758 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1759 ab.setOrder(actionList.size());
1760 ab.setKey(new ActionKey(actionList.size()));
1761 actionList.add(ab.build());
1765 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1766 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1769 /* rewrite the group to group table */
1770 writeGroup(groupBuilder, nodeBuilder);
1773 // Create an Apply Action
1774 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1775 aab.setAction(actionList);
1776 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1782 * Remove Output Port from action list in group bucket
1784 * @param ib Map InstructionBuilder without any instructions
1785 * @param dpidLong Long the datapath ID of a switch/node
1786 * @param port Long representing a port on a switch/node
1787 * @return ib InstructionBuilder Map with instructions
1789 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1790 @SuppressWarnings("unused")
1791 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1792 Long dpidLong, Long port , List<Instruction> instructions) {
1794 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1795 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1797 List<Action> actionList = Lists.newArrayList();
1800 List<Action> existingActions;
1801 if (instructions != null) {
1802 for (Instruction in : instructions) {
1803 if (in.getInstruction() instanceof ApplyActionsCase) {
1804 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1805 actionList.addAll(existingActions);
1811 GroupBuilder groupBuilder = new GroupBuilder();
1813 boolean groupActionAdded = false;
1814 /* Find the group action and get the group */
1815 for (Action action : actionList) {
1816 if (action.getAction() instanceof GroupActionCase) {
1817 groupActionAdded = true;
1818 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1819 Long id = groupAction.getGroupAction().getGroupId();
1820 String groupName = groupAction.getGroupAction().getGroup();
1821 GroupKey key = new GroupKey(new GroupId(id));
1823 groupBuilder.setGroupId(new GroupId(id));
1824 groupBuilder.setGroupName(groupName);
1825 groupBuilder.setGroupType(GroupTypes.GroupAll);
1826 groupBuilder.setKey(key);
1827 group = getGroup(groupBuilder, nodeBuilder);
1832 if (groupActionAdded) {
1833 /* modify the action bucket in group */
1834 groupBuilder = new GroupBuilder(group);
1835 Buckets buckets = groupBuilder.getBuckets();
1836 List<Action> bucketActions = Lists.newArrayList();
1837 for (Bucket bucket : buckets.getBucket()) {
1839 boolean isPortDeleted = false;
1840 bucketActions = bucket.getAction();
1841 for (Action action : bucketActions) {
1842 if (action.getAction() instanceof OutputActionCase) {
1843 OutputActionCase opAction = (OutputActionCase)action.getAction();
1844 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1845 /* Find the output port in action list and remove */
1846 index = bucketActions.indexOf(action);
1847 bucketActions.remove(action);
1848 isPortDeleted = true;
1853 if (isPortDeleted && !bucketActions.isEmpty()) {
1854 for (int i = index; i< bucketActions.size(); i++) {
1855 Action action = bucketActions.get(i);
1856 if (action.getOrder() != i) {
1857 /* Shift the action order */
1858 ab = new ActionBuilder();
1859 ab.setAction(action.getAction());
1861 ab.setKey(new ActionKey(i));
1862 Action actionNewOrder = ab.build();
1863 bucketActions.remove(action);
1864 bucketActions.add(i, actionNewOrder);
1868 } else if (bucketActions.isEmpty()) {
1869 /* remove bucket with empty action list */
1870 buckets.getBucket().remove(bucket);
1874 if (!buckets.getBucket().isEmpty()) {
1875 /* rewrite the group to group table */
1876 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1877 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1878 List<Bucket> bucketList = Lists.newArrayList();
1879 BucketBuilder bucketBuilder = new BucketBuilder();
1880 bucketBuilder.setBucketId(new BucketId((long) 1));
1881 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1882 bucketBuilder.setAction(bucketActions);
1883 bucketList.add(bucketBuilder.build());
1884 bucketsBuilder.setBucket(bucketList);
1885 groupBuilder.setBuckets(bucketsBuilder.build());
1886 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1888 writeGroup(groupBuilder, nodeBuilder);
1889 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1890 aab.setAction(actionList);
1891 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1894 /* remove group with empty bucket. return true to delete flow */
1895 removeGroup(groupBuilder, nodeBuilder);
1899 /* no group for port list. flow can be removed */
1905 public void initializeOFFlowRules(Node openflowNode) {
1906 String bridgeName = southbound.getBridgeName(openflowNode);
1907 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1908 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1909 initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1910 triggerInterfaceUpdates(openflowNode);
1911 } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1912 initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1913 LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
1914 triggerInterfaceUpdates(openflowNode);
1915 LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
1919 public static NodeBuilder createNodeBuilder(String nodeId) {
1920 NodeBuilder builder = new NodeBuilder();
1921 builder.setId(new NodeId(nodeId));
1922 builder.setKey(new NodeKey(builder.getId()));
1927 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1928 this.bundleContext = bundleContext;
1929 configurationService =
1930 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1931 tenantNetworkManager =
1932 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1933 bridgeConfigurationManager =
1934 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1936 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1937 classifierProvider =
1938 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
1939 ingressAclProvider =
1940 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
1942 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
1943 l2ForwardingProvider =
1944 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
1945 securityServicesManager =
1946 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1948 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1952 public void setDependencies(Object impl) {
1953 if (impl instanceof NetworkingProviderManager) {
1954 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
1955 networkingProviderManager.providerAdded(
1956 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);