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.FlowUtils;
46 import org.opendaylight.ovsdb.utils.mdsal.openflow.InstructionUtils;
47 import org.opendaylight.ovsdb.utils.servicehelper.ServiceHelper;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
91 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
92 import org.osgi.framework.BundleContext;
93 import org.osgi.framework.ServiceReference;
94 import org.slf4j.Logger;
95 import org.slf4j.LoggerFactory;
97 import com.google.common.base.Optional;
98 import com.google.common.base.Preconditions;
99 import com.google.common.collect.Lists;
100 import com.google.common.collect.Maps;
101 import com.google.common.util.concurrent.CheckedFuture;
105 * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
107 * @author Madhu Venugopal
108 * @author Brent Salisbury
109 * @author Dave Tucker
112 // Methods' parameters in this class follow the same pattern to avoid confusion between same-typed parameters
113 // The patterns need to be preserved even though not all parameters are used in all methods
114 @SuppressWarnings("UnusedParameters")
115 public class OF13Provider implements ConfigInterface, NetworkingProvider {
116 private static final Logger LOG = LoggerFactory.getLogger(OF13Provider.class);
117 private static final short TABLE_0_DEFAULT_INGRESS = 0;
118 private static final short TABLE_1_ISOLATE_TENANT = 10;
119 private static final short TABLE_2_LOCAL_FORWARD = 20;
120 private static Long groupId = 1L;
121 private DataBroker dataBroker = null;
123 private volatile ConfigurationService configurationService;
124 private volatile BridgeConfigurationManager bridgeConfigurationManager;
125 private volatile TenantNetworkManager tenantNetworkManager;
126 private volatile SecurityServicesManager securityServicesManager;
127 private volatile ClassifierProvider classifierProvider;
128 private volatile IngressAclProvider ingressAclProvider;
129 private volatile EgressAclProvider egressAclProvider;
130 private volatile NodeCacheManager nodeCacheManager;
131 private volatile L2ForwardingProvider l2ForwardingProvider;
133 public static final String NAME = "OF13Provider";
134 private volatile BundleContext bundleContext;
135 private volatile Southbound southbound;
137 public OF13Provider() {
138 this.dataBroker = NetvirtProvidersProvider.getDataBroker();
142 public String getName() {
147 public boolean supportsServices() {
152 public boolean hasPerTenantTunneling() {
156 // The method is tested for in OF13ProviderTest
157 @SuppressWarnings("unused")
158 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
159 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
160 if (srcTunnelEndPoint == null) {
161 LOG.error("Tunnel Endpoint not configured for Node {}", node);
162 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
165 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
166 LOG.error("{} is not Overlay ready", node);
167 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
170 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
171 LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
172 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
174 return new Status(StatusCode.SUCCESS);
177 private String getTunnelName(String tunnelType, InetAddress dst) {
178 return tunnelType+"-"+dst.getHostAddress();
181 private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
182 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
183 String portName = getTunnelName(tunnelType, dst);
184 LOG.info("addTunnelPort enter: portName: {}", portName);
185 if (southbound.extractTerminationPointAugmentation(node, portName) != null
186 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
187 LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
191 Map<String, String> options = Maps.newHashMap();
192 options.put("key", "flow");
193 options.put("local_ip", src.getHostAddress());
194 options.put("remote_ip", dst.getHostAddress());
196 if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
197 LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
201 LOG.info("addTunnelPort exit: portName: {}", portName);
205 /* delete port from ovsdb port table */
206 private boolean deletePort(Node node, String bridgeName, String portName) {
208 // might need to convert from ovsdb node to bridge node
209 return southbound.deleteTerminationPoint(node, portName);
212 private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
213 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
214 String portName = getTunnelName(tunnelType, dst);
215 return deletePort(node, tunnelBridgeName, portName);
218 private boolean deletePhysicalPort(Node node, String phyIntfName) {
219 String intBridgeName = configurationService.getIntegrationBridgeName();
220 return deletePort(node, intBridgeName, phyIntfName);
223 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
224 String attachedMac, long localPort) {
228 * Match: VM sMac and Local Ingress Port
229 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
232 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
233 segmentationId, localPort, attachedMac, true);
238 * Match: Drop any remaining Ingress Local VM Packets
239 * Action: Drop w/ a low priority
242 handleDropSrcIface(dpid, localPort, true);
247 * Match: Match TunID and Destination DL/dMAC Addr
248 * Action: Output Port
249 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
252 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
257 * Match: Tunnel ID and dMAC (::::FF:FF)
258 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
259 * actions=output:2,3,4,5
262 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
263 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
266 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
271 * Match: Any remaining Ingress Local VM Packets
272 * Action: Drop w/ a low priority
273 * -------------------------------------------
274 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
277 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
282 * Match: Any Remaining Flows w/a TunID
283 * Action: Drop w/ a low priority
284 * table=2,priority=8192,tun_id=0x5 actions=drop
287 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
290 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
294 * Match: VM sMac and Local Ingress Port
295 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
298 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
303 * Match: Drop any remaining Ingress Local VM Packets
304 * Action: Drop w/ a low priority
307 handleDropSrcIface(dpid, localPort, false);
312 * Match: Match TunID and Destination DL/dMAC Addr
313 * Action: Output Port
314 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
317 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
322 * Match: Tunnel ID and dMAC (::::FF:FF)
323 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
324 * actions=output:2,3,4,5
327 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
328 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
331 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
335 * Match: Ingress Port, Tunnel ID
336 * Action: GOTO Local Table (20)
339 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
344 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
345 * Action: Flood to selected destination TEPs
346 * -------------------------------------------
347 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
348 * actions=output:10,output:11,goto_table:2
351 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
355 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
359 * Match: Drop any remaining Ingress Local VM Packets
360 * Action: Drop w/ a low priority
361 * -------------------------------------------
362 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
363 * actions=output:11,goto_table:2
366 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
369 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
373 * Match: Drop any remaining Ingress Local VM Packets
374 * Action: Drop w/ a low priority
375 * -------------------------------------------
376 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
377 * actions=output:11,goto_table:2
380 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
383 /* Remove tunnel rules if last node in this tenant network */
384 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
386 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
391 * Match: Any remaining Ingress Local VM Packets
392 * Action: Drop w/ a low priority
393 * -------------------------------------------
394 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
397 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
402 * Match: Any Remaining Flows w/a TunID
403 * Action: Drop w/ a low priority
404 * table=2,priority=8192,tun_id=0x5 actions=drop
407 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
412 * Match: Ingress Port, Tunnel ID
413 * Action: GOTO Local Table (10)
416 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
421 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
422 * Action: Flood to selected destination TEPs
423 * -------------------------------------------
424 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
425 * actions=output:10,output:11,goto_table:2
428 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
431 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
435 * Tag traffic coming from the local port and vm srcmac
436 * Match: VM sMac and Local Ingress Port
437 * Action: Set VLAN ID and GOTO Local Table 1
440 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
441 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
447 * Drop all other traffic coming from the local port
448 * Match: Drop any remaining Ingress Local VM Packets
449 * Action: Drop w/ a low priority
452 handleDropSrcIface(dpid, localPort, true);
457 * Forward unicast traffic destined to the local port after stripping tag
458 * Match: Match VLAN ID and Destination DL/dMAC Addr
459 * Action: strip vlan, output to local port
460 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
463 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
464 localPort, attachedMac, true);
469 * Match: VLAN ID and dMAC (::::FF:FF)
470 * Action: strip vlan, output to all local ports in this vlan
471 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
472 * actions= strip_vlan, output:2,3,4,5
475 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
476 // localPort, ethPort, true);
477 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
478 // segmentationId, localPort, ethport, true);
483 * Match: Any Remaining Flows w/a VLAN ID
484 * Action: Drop w/ a low priority
485 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
488 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
492 private void removeLocalVlanRules(Node node, Long dpid,
493 String segmentationId, String attachedMac, long localPort) {
497 * Match: VM sMac and Local Ingress Port
498 * Action: Set VLAN ID and GOTO Local Table 1
501 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
502 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
508 * Match: Drop any remaining Ingress Local VM Packets
509 * Action: Drop w/ a low priority
512 handleDropSrcIface(dpid, localPort, false);
517 * Match: Match VLAN ID and Destination DL/dMAC Addr
518 * Action: strip vlan, output to local port
519 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
522 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
523 localPort, attachedMac, false);
528 * Match: VLAN ID and dMAC (::::FF:FF)
529 * Action: strip vlan, output to all local ports in this vlan
530 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
531 * actions= strip_vlan, output:2,3,4,5
534 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
535 // localPort, ethPort, false);
536 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
537 // segmentationId, localPort, false);
541 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
542 long localPort, long ethPort) {
546 * Match: Ingress port = physical interface, Vlan ID
547 * Action: GOTO Local Table 2
550 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
551 segmentationId, ethPort, true);
556 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
557 * Action: Flood to local and remote VLAN members
558 * -------------------------------------------
559 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
560 * actions=output:10 (eth port),goto_table:2
561 * 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
564 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
569 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
570 * Action: Flood to local and remote VLAN members
571 * -------------------------------------------
572 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
573 * actions=output:10 (eth port),goto_table:2
576 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
577 // segmentationId, ethPort, true);
580 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
581 String attachedMac, long ethPort) {
585 * Match: Destination MAC is local VM MAC and vlan id
586 * Action: go to table 2
587 * -------------------------------------------
588 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
589 * actions=goto_table:2
592 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
593 // segmentationId, ethPort, attachedMac, true);
599 * Action: Go to table 2
600 * -------------------------------------------
601 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
602 * table=110,priority=8192,dl_vlan=2001 actions=output:2
605 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
608 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
609 String attachedMac, long localPort, long ethPort) {
613 * Match: Destination MAC is local VM MAC and vlan id
614 * Action: go to table 2
615 * -------------------------------------------
616 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
617 * actions=goto_table:2
620 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
621 // segmentationId, ethPort, attachedMac, false);
626 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
627 * Action: Flood to local and remote VLAN members
628 * -------------------------------------------
629 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
630 * actions=output:10 (eth port),goto_table:2
631 * 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
634 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
637 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
641 * Match: Any Remaining Flows w/a VLAN ID
642 * Action: Drop w/ a low priority
643 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
646 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
651 * Match: Ingress port = physical interface, Vlan ID
652 * Action: GOTO Local Table 2
655 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
660 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
661 * Action: Flood to local and remote VLAN members
662 * -------------------------------------------
663 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
664 * actions=output:10 (eth port),goto_table:2
665 * table=110, priority=16384,dl_vlan=2001,dl_dst=01:00:00:00:00:00/01:00:00:00:00:00 actions=output:2,pop_vlan,output:1,output:3,output:4
668 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
673 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
674 * Action: Flood to local and remote VLAN members
675 * -------------------------------------------
676 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
677 * actions=output:10 (eth port),goto_table:2
680 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
681 // segmentationId, ethPort, false);
687 * Action: Go to table 2
688 * -------------------------------------------
689 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
690 * table=110,priority=8192,dl_vlan=2001 actions=output:2
693 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
696 private long getDpid(Node node) {
697 long dpid = southbound.getDataPathId(node);
699 LOG.warn("getDpid: dpid not found: {}", node);
704 private long getIntegrationBridgeOFDPID(Node node) {
706 if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
707 dpid = getDpid(node);
713 * Returns true is the network if of type GRE or VXLAN
715 * @param networkType The type of the network
716 * @return returns true if the network is a tunnel
718 private boolean isTunnel(String networkType)
720 return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
721 (NetworkHandler.NETWORK_TYPE_VXLAN));
725 * Returns true if the network is of type vlan.
727 * @param networkType The type of the network
728 * @return returns true if the network is a vlan
730 private boolean isVlan(String networkType)
732 return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
735 private void programLocalRules(String networkType, String segmentationId, Node node,
736 OvsdbTerminationPointAugmentation intf) {
737 LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
738 node.getNodeId(), intf.getName(), networkType, segmentationId);
740 long dpid = getIntegrationBridgeOFDPID(node);
742 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
747 long localPort = southbound.getOFPort(intf);
748 if (localPort == 0) {
749 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
750 intf.getName(), node.getNodeId());
754 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
755 if (attachedMac == null) {
756 LOG.warn("No AttachedMac seen in {}", intf);
760 /* Program local rules based on network type */
761 if (isVlan(networkType)) {
762 LOG.debug("Program local vlan rules for interface {}", intf.getName());
763 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
765 if ((isTunnel(networkType) || isVlan(networkType))) {
766 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
768 if (isTunnel(networkType)) {
769 LOG.debug("Program local bridge rules for interface {}, "
770 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
771 intf.getName(), dpid, segmentationId, attachedMac, localPort);
772 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
774 } catch (Exception e) {
775 LOG.error("Exception in programming Local Rules for " + intf + " on " + node, e);
779 private void removeLocalRules(String networkType, String segmentationId, Node node,
780 OvsdbTerminationPointAugmentation intf) {
781 LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
782 node.getNodeId(), intf.getName(), networkType, segmentationId);
784 long dpid = getIntegrationBridgeOFDPID(node);
786 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
790 long localPort = southbound.getOFPort(intf);
791 if (localPort == 0) {
792 LOG.info("removeLocalRules: could not find ofPort");
796 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
797 if (attachedMac == null) {
798 LOG.warn("No AttachedMac seen in {}", intf);
802 /* Program local rules based on network type */
803 if (isVlan(networkType)) {
804 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
805 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
806 } else if (isTunnel(networkType)) {
807 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
808 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
810 if (isTunnel(networkType) || isVlan(networkType)) {
811 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
813 } catch (Exception e) {
814 LOG.error("Exception in removing Local Rules for " + intf + " on " + node, e);
819 // Need to handle case where a node comes online after a network and tunnels have
820 // already been created. The interface update is what triggers creating the l2 forwarding flows
821 // so we don't see those updates in this case - we only see the new nodes interface updates.
822 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
823 OvsdbTerminationPointAugmentation intf, boolean local) {
824 LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
825 + "segmentationId: {}, dstAddr: {}",
826 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
828 long dpid = getIntegrationBridgeOFDPID(node);
830 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
834 long localPort = southbound.getOFPort(intf);
835 if (localPort == 0) {
836 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
840 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
841 if (attachedMac == null) {
842 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
846 OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
847 if(tunnelPort != null){
848 long tunnelOFPort = southbound.getOFPort(tunnelPort);
849 if (tunnelOFPort == 0) {
850 LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
851 tunnelPort.getName(), tunnelOFPort, node);
854 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
855 tunnelPort.getName(), tunnelOFPort, node);
858 LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
859 node.getNodeId().getValue(), intf.getName());
860 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
861 tunnelOFPort, localPort);
863 LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
864 node.getNodeId().getValue(), intf.getName());
865 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
866 tunnelOFPort, localPort);
869 } catch (Exception e) {
874 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
875 OvsdbTerminationPointAugmentation intf,
876 boolean local, boolean isLastInstanceOnNode) {
877 LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
878 + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
879 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
881 long dpid = getIntegrationBridgeOFDPID(node);
883 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
887 long localPort = southbound.getOFPort(intf);
888 if (localPort == 0) {
889 LOG.info("removeTunnelRules: could not find ofPort");
893 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
894 if (attachedMac == null) {
895 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
899 List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
900 for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
901 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
902 long tunnelOFPort = southbound.getOFPort(tunIntf);
903 if (tunnelOFPort == 0) {
904 LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
905 tunIntf.getName(), tunnelOFPort, node);
908 LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
909 tunIntf.getName(), tunnelOFPort, node);
912 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
913 tunnelOFPort, localPort);
915 if (local && isLastInstanceOnNode) {
916 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
921 } catch (Exception e) {
926 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
927 LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
928 node.getNodeId(), network.getNetworkUUID(), intf.getName());
929 long dpid = getIntegrationBridgeOFDPID(node);
931 LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
935 long localPort = southbound.getOFPort(intf);
936 if (localPort == 0) {
937 LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
941 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
942 if (attachedMac == null) {
943 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
948 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
949 long ethOFPort = southbound.getOFPort(node, phyIfName);
950 if (ethOFPort == 0) {
951 LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
954 LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
955 phyIfName, ethOFPort, node);
956 // TODO: add logic to only add rule on remote nodes
957 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
958 attachedMac, ethOFPort);
959 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
960 attachedMac, localPort, ethOFPort);
963 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
964 boolean isLastInstanceOnNode) {
965 LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
966 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
967 long dpid = getIntegrationBridgeOFDPID(node);
969 LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
973 long localPort = southbound.getOFPort(intf);
974 if (localPort == 0) {
975 LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
979 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
980 if (attachedMac == null) {
981 LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
986 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
987 long ethOFPort = southbound.getOFPort(node, phyIfName);
988 if (ethOFPort == 0) {
989 LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
992 LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
993 phyIfName, ethOFPort, node);
995 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
996 attachedMac, localPort, ethOFPort);
997 if (isLastInstanceOnNode) {
998 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1002 private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
1003 Long dpid,long localPort, String segmentationId,
1006 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
1007 NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
1008 boolean isComputePort = false;
1009 boolean isLastPortinBridge = false;
1010 boolean isLastPortinSubnet = false;
1011 List<Neutron_IPs> srcAddressList = null;
1012 if (null != dhcpPort) {
1013 isComputePort = securityServicesManager.isComputePort(intf);
1014 isLastPortinBridge = securityServicesManager.isLastPortinBridge(node, intf);
1015 isLastPortinSubnet = false;
1016 if (isComputePort) {
1017 isLastPortinSubnet = securityServicesManager.isLastPortinSubnet(node, intf);
1018 srcAddressList = securityServicesManager.getIpAddressList(intf);
1019 if (null == srcAddressList) {
1020 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1024 ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1025 isLastPortinSubnet, isComputePort, write);
1026 egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1027 srcAddressList, isLastPortinBridge, isComputePort,write);
1028 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
1029 /* TODO SB_MIGRATION */
1031 LOG.debug("Neutron port has a Port Security Group");
1032 // Retrieve the security group from the Neutron Port and apply the rules
1033 if (securityServicesManager.isPortSecurityReady(intf)) {
1034 //Associate the security group flows.
1035 List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
1036 .getSecurityGroupInPortList(intf);
1037 String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
1038 Constants.EXTERNAL_ID_INTERFACE_ID);
1039 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1040 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1041 securityGroupInPort, neutronPortId, write);
1042 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1043 securityGroupInPort, neutronPortId, write);
1047 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1052 * The function is for the new compute node joining the existing network.
1053 * When a new VM is instantiated in the new compute node, neutron port add
1054 * event is generated. This event is processed only for that node. So,
1055 * loop through all the ports of the same network and install unicast mac
1056 * flow for the VM's created on the TEP of the destination node in src node.
1057 * This function will be executed even for any new VM creation in an existing
1058 * network. If a cache is maintained to optimize the below flow addition, it will
1059 * work only for one unstack and restack. For the next unstack and restack,
1060 * it will not work since the cache would have been already deleted.
1062 private void programTunnelRulesInNewNode(NeutronNetwork network,
1063 String networkType, String segmentationId,
1064 InetAddress src, InetAddress dst,
1065 Node srcBridgeNode, Node dstBridgeNode,
1066 OvsdbTerminationPointAugmentation intf){
1068 long localPort = southbound.getOFPort(intf);
1071 LOG.debug("Interface update details {}", intf);
1074 * When a network is added and the TEP destination is not present in a
1075 * node C1, tunnelin and broadcast rules will not be programmed, since
1076 * OF port is not created. So, when a new node C2 joins and create a new
1077 * VM, the tunnelin and broadcast rule will not be present in C1.
1078 * So, handling it in the case below to make ping work.
1080 if(securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1081 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1085 * FIX for 4208 - loop through all the ports and add the VM's
1086 * unicast mac rule of the destination node in the source node.
1087 * When a new node is added, it needs to configure the VM unicast mac
1088 * flow rules which were created before it was joined to an existing
1091 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1092 for (OvsdbTerminationPointAugmentation port : ports) {
1093 if(network == tenantNetworkManager.getTenantNetwork(port)){
1094 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1097 LOG.trace("Port {} is not part of network {}", port, network);
1101 } catch (Exception e) {
1102 LOG.error("Exception during handlingNeutron network add", e);
1107 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode,
1108 OvsdbTerminationPointAugmentation intf) {
1109 Preconditions.checkNotNull(nodeCacheManager);
1110 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1111 nodeCacheManager.getOvsdbNodes();
1112 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1113 String networkType = network.getProviderNetworkType();
1114 String segmentationId = network.getProviderSegmentationID();
1115 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1116 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1118 if (isVlan(networkType)) {
1119 programVlanRules(network, srcNode, intf);
1120 } else if (isTunnel(networkType)){
1122 boolean sourceTunnelStatus = false;
1123 boolean destTunnelStatus = false;
1124 for (Node dstNode : nodes.values()) {
1125 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1126 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1127 if ((src != null) && (dst != null)) {
1128 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1130 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1131 configurationService.getIntegrationBridgeName());
1133 if(dstBridgeNode != null){
1134 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1137 if (sourceTunnelStatus) {
1138 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1140 if (destTunnelStatus) {
1141 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1142 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1143 srcBridgeNode, dstBridgeNode, intf);
1146 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1147 + "Check source {} or destination {}",
1148 src != null ? src.getHostAddress() : "null",
1149 dst != null ? dst.getHostAddress() : "null");
1157 private void triggerInterfaceUpdates(Node node) {
1158 LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
1159 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1160 if (ports != null && !ports.isEmpty()) {
1161 for (OvsdbTerminationPointAugmentation port : ports) {
1162 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1163 if (neutronNetwork != null) {
1164 LOG.warn("Trigger Interface update for {}", port);
1165 handleInterfaceUpdate(neutronNetwork, node, port);
1169 LOG.warn("triggerInterfaceUpdates: tps are null");
1171 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1175 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1176 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1177 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1178 nodeCacheManager.getOvsdbNodes();
1179 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1181 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1182 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1183 if (southbound.isTunnel(intf)) {
1184 // Delete tunnel port
1186 InetAddress src = InetAddress.getByName(
1187 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1188 InetAddress dst = InetAddress.getByName(
1189 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1190 deleteTunnelPort(srcNode,
1191 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1193 } catch (Exception e) {
1194 LOG.error(e.getMessage(), e);
1196 } else if (phyIfName.contains(intf.getName())) {
1197 deletePhysicalPort(srcNode, intf.getName());
1199 // delete all other interfaces
1200 removeLocalRules(network.getProviderNetworkType(), network.getProviderSegmentationID(),
1203 if (isVlan(network.getProviderNetworkType())) {
1204 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1205 } else if (isTunnel(network.getProviderNetworkType())) {
1207 for (Node dstNode : nodes.values()) {
1208 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1209 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1210 if ((src != null) && (dst != null)) {
1211 LOG.info("Remove tunnel rules for interface "
1212 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1213 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1214 dst, srcNode, intf, true, isLastInstanceOnNode);
1215 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1216 if(dstBridgeNode != null){
1217 LOG.info("Remove tunnel rules for interface "
1218 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1219 removeTunnelRules(tunnelType, network.getProviderSegmentationID(),
1220 src, dstBridgeNode, intf, false, isLastInstanceOnNode);
1223 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1224 + "OpenVSwitch Table. "
1225 + "Check source {} or destination {}",
1226 src != null ? src.getHostAddress() : "null",
1227 dst != null ? dst.getHostAddress() : "null");
1236 public void initializeFlowRules(Node node) {
1237 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1238 initializeFlowRules(node, configurationService.getExternalBridgeName());
1239 triggerInterfaceUpdates(node);
1242 private void initializeFlowRules(Node node, String bridgeName) {
1243 Long dpid = southbound.getDataPathId(node);
1244 String datapathId = southbound.getDatapathId(node);
1245 LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
1246 bridgeName, dpid, datapathId);
1249 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1256 * Match: LLDP (0x88CCL)
1257 * Action: Packet_In to Controller Reserved Port
1260 writeLLDPRule(dpid);
1262 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1263 writeNormalRule(dpid);
1268 * Create an LLDP Flow Rule to encapsulate into
1269 * a packet_in that is sent to the controller
1270 * for topology handling.
1271 * Match: Ethertype 0x88CCL
1272 * Action: Punt to Controller in a Packet_In msg
1275 private void writeLLDPRule(Long dpidLong) {
1276 classifierProvider.programLLDPPuntRule(dpidLong);
1280 * Create a NORMAL Table Miss Flow Rule
1282 * Action: forward to NORMAL pipeline
1285 private void writeNormalRule(Long dpidLong) {
1286 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1287 FlowBuilder flowBuilder = new FlowBuilder();
1288 String flowName = "NORMAL";
1289 FlowUtils.initFlowBuilder(flowBuilder, flowName, (short)0).setPriority(0);
1290 MatchBuilder matchBuilder = new MatchBuilder();
1291 flowBuilder.setMatch(matchBuilder.build());
1293 // Create the OF Actions and Instructions
1294 InstructionBuilder ib = new InstructionBuilder();
1295 InstructionsBuilder isb = new InstructionsBuilder();
1297 // Instructions List Stores Individual Instructions
1298 List<Instruction> instructions = Lists.newArrayList();
1300 // Call the InstructionBuilder Methods Containing Actions
1301 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1303 ib.setKey(new InstructionKey(0));
1304 instructions.add(ib.build());
1306 // Add InstructionBuilder to the Instruction(s)Builder List
1307 isb.setInstruction(instructions);
1309 // Add InstructionsBuilder to FlowBuilder
1310 flowBuilder.setInstructions(isb.build());
1311 writeFlow(flowBuilder, nodeBuilder);
1315 * (Table:0) Ingress Tunnel Traffic
1316 * Match: OpenFlow InPort and Tunnel ID
1317 * Action: GOTO Local Table (10)
1318 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1321 private void handleTunnelIn(Long dpidLong, Short writeTable,
1322 Short goToTableId, String segmentationId,
1323 Long ofPort, boolean write) {
1324 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1328 * (Table:0) Ingress VLAN Traffic
1329 * Match: OpenFlow InPort and vlan ID
1330 * Action: GOTO Local Table (20)
1331 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1334 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1335 String segmentationId, Long ethPort, boolean write) {
1336 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1340 * (Table:0) Egress VM Traffic Towards TEP
1341 * Match: Destination Ethernet Addr and OpenFlow InPort
1342 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1343 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1344 * actions=set_field:5->tun_id,goto_table=1"
1347 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1348 String segmentationId, Long inPort, String attachedMac,
1350 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1354 * (Table:0) Egress VM Traffic Towards TEP
1355 * Match: Source Ethernet Addr and OpenFlow InPort
1356 * Instruction: Set VLANID and GOTO Table Egress (n)
1357 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1358 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1361 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1362 Short goToTableId, String segmentationId,
1363 Long inPort, String attachedMac,
1365 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1369 * (Table:0) Drop frames source from a VM that do not
1370 * match the associated MAC address of the local VM.
1371 * Match: Low priority anything not matching the VM SMAC
1373 * table=0,priority=16384,in_port=1 actions=drop"
1376 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1377 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1381 * (Table:1) Egress Tunnel Traffic
1382 * Match: Destination Ethernet Addr and Local InPort
1383 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1384 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1385 * actions=output:10,goto_table:2"
1387 private void handleTunnelOut(Long dpidLong, Short writeTable,
1388 Short goToTableId, String segmentationId,
1389 Long OFPortOut, String attachedMac,
1391 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1395 * (Table:1) Egress VLAN Traffic
1396 * Match: Destination Ethernet Addr and VLAN id
1397 * Instruction: GOTO Table Table 2
1398 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1399 * actions= goto_table:2"
1401 // TODO This method is referenced from commented code above (which needs to be checked)
1402 @SuppressWarnings("unused")
1403 private void handleVlanOut(Long dpidLong, Short writeTable,
1404 Short goToTableId, String segmentationId,
1405 Long ethPort, String attachedMac, boolean write) {
1406 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1410 * (Table:1) Egress Tunnel Traffic
1411 * Match: Destination Ethernet Addr and Local InPort
1412 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1413 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1414 * actions=output:10,output:11,goto_table:2
1417 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1418 Short localTable, String segmentationId,
1419 Long OFPortOut, boolean write) {
1420 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1424 * (Table:1) Egress VLAN Traffic
1425 * Match: Destination Ethernet Addr and VLAN id
1426 * Instruction: GOTO table 2 and Output port eth interface
1427 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1428 * actions=output:eth1,goto_table:2
1430 // TODO This method is referenced from commented code above (which needs to be checked)
1431 @SuppressWarnings("unused")
1432 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1433 Short localTable, String segmentationId,
1434 Long localPort, Long ethPort, boolean write) {
1435 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1439 * (Table:1) Table Drain w/ Catch All
1441 * Action: GOTO Local Table (10)
1442 * table=2,priority=8192,tun_id=0x5 actions=drop
1445 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1446 Short goToTableId, String segmentationId,
1448 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1453 * (Table:1) Table Drain w/ Catch All
1455 * Action: Output port eth interface
1456 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1457 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1460 private void handleVlanMiss(Long dpidLong, Short writeTable,
1461 Short goToTableId, String segmentationId,
1462 Long ethPort, boolean write) {
1463 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1467 * (Table:1) Local Broadcast Flood
1468 * Match: Tunnel ID and dMAC
1469 * Action: Output Port
1470 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1473 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1474 String segmentationId, Long localPort,
1475 String attachedMac, boolean write) {
1476 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1480 * (Table:2) Local VLAN unicast
1481 * Match: VLAN ID and dMAC
1482 * Action: Output Port
1483 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1486 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1487 String segmentationId, Long localPort,
1488 String attachedMac, boolean write) {
1489 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1493 * (Table:2) Local Broadcast Flood
1494 * Match: Tunnel ID and dMAC (::::FF:FF)
1495 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1496 * actions=output:2,3,4,5
1499 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1500 String segmentationId, Long localPort,
1502 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1506 * (Table:2) Local VLAN Broadcast Flood
1507 * Match: vlan ID and dMAC (::::FF:FF)
1508 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1509 * actions=strip_vlan, output:2,3,4,5
1510 * 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
1513 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1514 Long localPort, Long ethPort, boolean write) {
1515 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1519 * (Table:1) Local Table Miss
1520 * Match: Any Remaining Flows w/a TunID
1521 * Action: Drop w/ a low priority
1522 * table=2,priority=8192,tun_id=0x5 actions=drop
1525 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1526 String segmentationId, boolean write) {
1527 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1531 * (Table:1) Local Table Miss
1532 * Match: Any Remaining Flows w/a VLAN ID
1533 * Action: Drop w/ a low priority
1534 * table=2,priority=8192,vlan_id=0x5 actions=drop
1536 // TODO This method is referenced from commented code above (which needs to be checked)
1537 @SuppressWarnings("unused")
1538 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1539 String segmentationId, boolean write) {
1540 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1543 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1544 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1545 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1546 new GroupKey(groupBuilder.getGroupId())).build();
1547 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1549 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1550 if (data.isPresent()) {
1553 } catch (InterruptedException|ExecutionException e) {
1554 LOG.error(e.getMessage(), e);
1557 LOG.debug("Cannot find data for Group " + groupBuilder.getGroupName());
1561 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1562 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1563 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1564 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1565 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1566 new GroupKey(groupBuilder.getGroupId())).build();
1567 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1569 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1571 commitFuture.get(); // TODO: Make it async (See bug 1362)
1572 LOG.debug("Transaction success for write of Group " + groupBuilder.getGroupName());
1573 } catch (InterruptedException|ExecutionException e) {
1574 LOG.error(e.getMessage(), e);
1579 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1580 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1581 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1582 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1583 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1584 new GroupKey(groupBuilder.getGroupId())).build();
1585 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1586 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1589 commitFuture.get(); // TODO: Make it async (See bug 1362)
1590 LOG.debug("Transaction success for deletion of Group " + groupBuilder.getGroupName());
1591 } catch (InterruptedException|ExecutionException e) {
1592 LOG.error(e.getMessage(), e);
1597 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1598 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1599 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1600 InstanceIdentifier<Flow> path1 =
1601 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1602 .rev130819.nodes.Node.class,
1603 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1604 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1606 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1607 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1608 true);//createMissingParents
1611 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1613 commitFuture.get(); // TODO: Make it async (See bug 1362)
1614 LOG.debug("Transaction success for write of Flow " + flowBuilder.getFlowName());
1615 } catch (InterruptedException|ExecutionException e) {
1616 LOG.error(e.getMessage(), e);
1622 * Create Output Port Group Instruction
1624 * @param ib Map InstructionBuilder without any instructions
1625 * @param dpidLong Long the datapath ID of a switch/node
1626 * @param port Long representing a port on a switch/node
1627 * @return ib InstructionBuilder Map with instructions
1629 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1630 @SuppressWarnings("unused")
1631 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1632 InstructionBuilder ib,
1633 Long dpidLong, Long port ,
1634 List<Instruction> instructions) {
1635 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1636 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1638 List<Action> actionList = Lists.newArrayList();
1639 ActionBuilder ab = new ActionBuilder();
1641 List<Action> existingActions;
1642 if (instructions != null) {
1643 for (Instruction in : instructions) {
1644 if (in.getInstruction() instanceof ApplyActionsCase) {
1645 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1646 actionList.addAll(existingActions);
1651 GroupBuilder groupBuilder = new GroupBuilder();
1654 /* Create output action for this port*/
1655 OutputActionBuilder oab = new OutputActionBuilder();
1656 oab.setOutputNodeConnector(ncid);
1657 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1658 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1659 boolean addNew = true;
1660 boolean groupActionAdded = false;
1662 /* Find the group action and get the group */
1663 for (Action action : actionList) {
1664 if (action.getAction() instanceof GroupActionCase) {
1665 groupActionAdded = true;
1666 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1667 Long id = groupAction.getGroupAction().getGroupId();
1668 String groupName = groupAction.getGroupAction().getGroup();
1669 GroupKey key = new GroupKey(new GroupId(id));
1671 groupBuilder.setGroupId(new GroupId(id));
1672 groupBuilder.setGroupName(groupName);
1673 groupBuilder.setGroupType(GroupTypes.GroupAll);
1674 groupBuilder.setKey(key);
1675 group = getGroup(groupBuilder, nodeBuilder);
1676 LOG.debug("createOutputGroupInstructions: group {}", group);
1681 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1682 if (groupActionAdded) {
1683 /* modify the action bucket in group */
1684 groupBuilder = new GroupBuilder(group);
1685 Buckets buckets = groupBuilder.getBuckets();
1686 for (Bucket bucket : buckets.getBucket()) {
1687 List<Action> bucketActions = bucket.getAction();
1688 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1689 for (Action action : bucketActions) {
1690 if (action.getAction() instanceof OutputActionCase) {
1691 OutputActionCase opAction = (OutputActionCase)action.getAction();
1692 /* If output port action already in the action list of one of the buckets, skip */
1693 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1700 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1701 if (addNew && !buckets.getBucket().isEmpty()) {
1702 /* the new output action is not in the bucket, add to bucket */
1703 Bucket bucket = buckets.getBucket().get(0);
1704 List<Action> bucketActionList = Lists.newArrayList();
1705 bucketActionList.addAll(bucket.getAction());
1706 /* set order for new action and add to action list */
1707 ab.setOrder(bucketActionList.size());
1708 ab.setKey(new ActionKey(bucketActionList.size()));
1709 bucketActionList.add(ab.build());
1711 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1712 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1713 List<Bucket> bucketList = Lists.newArrayList();
1714 BucketBuilder bucketBuilder = new BucketBuilder();
1715 bucketBuilder.setBucketId(new BucketId((long) 1));
1716 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1717 bucketBuilder.setAction(bucketActionList);
1718 bucketList.add(bucketBuilder.build());
1719 bucketsBuilder.setBucket(bucketList);
1720 groupBuilder.setBuckets(bucketsBuilder.build());
1721 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1725 groupBuilder = new GroupBuilder();
1726 groupBuilder.setGroupType(GroupTypes.GroupAll);
1727 groupBuilder.setGroupId(new GroupId(groupId));
1728 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1729 groupBuilder.setGroupName("Output port group " + groupId);
1730 groupBuilder.setBarrier(false);
1732 BucketsBuilder bucketBuilder = new BucketsBuilder();
1733 List<Bucket> bucketList = Lists.newArrayList();
1734 BucketBuilder bucket = new BucketBuilder();
1735 bucket.setBucketId(new BucketId((long) 1));
1736 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1738 /* put output action to the bucket */
1739 List<Action> bucketActionList = Lists.newArrayList();
1740 /* set order for new action and add to action list */
1741 ab.setOrder(bucketActionList.size());
1742 ab.setKey(new ActionKey(bucketActionList.size()));
1743 bucketActionList.add(ab.build());
1745 bucket.setAction(bucketActionList);
1746 bucketList.add(bucket.build());
1747 bucketBuilder.setBucket(bucketList);
1748 groupBuilder.setBuckets(bucketBuilder.build());
1750 /* Add new group action */
1751 GroupActionBuilder groupActionB = new GroupActionBuilder();
1752 groupActionB.setGroupId(groupId);
1753 groupActionB.setGroup("Output port group " + groupId);
1754 ab = new ActionBuilder();
1755 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1756 ab.setOrder(actionList.size());
1757 ab.setKey(new ActionKey(actionList.size()));
1758 actionList.add(ab.build());
1762 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1763 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1766 /* rewrite the group to group table */
1767 writeGroup(groupBuilder, nodeBuilder);
1770 // Create an Apply Action
1771 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1772 aab.setAction(actionList);
1773 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1779 * Remove Output Port from action list in group bucket
1781 * @param ib Map InstructionBuilder without any instructions
1782 * @param dpidLong Long the datapath ID of a switch/node
1783 * @param port Long representing a port on a switch/node
1784 * @return ib InstructionBuilder Map with instructions
1786 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1787 @SuppressWarnings("unused")
1788 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1789 Long dpidLong, Long port , List<Instruction> instructions) {
1791 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1792 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1794 List<Action> actionList = Lists.newArrayList();
1797 List<Action> existingActions;
1798 if (instructions != null) {
1799 for (Instruction in : instructions) {
1800 if (in.getInstruction() instanceof ApplyActionsCase) {
1801 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1802 actionList.addAll(existingActions);
1808 GroupBuilder groupBuilder = new GroupBuilder();
1810 boolean groupActionAdded = false;
1811 /* Find the group action and get the group */
1812 for (Action action : actionList) {
1813 if (action.getAction() instanceof GroupActionCase) {
1814 groupActionAdded = true;
1815 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1816 Long id = groupAction.getGroupAction().getGroupId();
1817 String groupName = groupAction.getGroupAction().getGroup();
1818 GroupKey key = new GroupKey(new GroupId(id));
1820 groupBuilder.setGroupId(new GroupId(id));
1821 groupBuilder.setGroupName(groupName);
1822 groupBuilder.setGroupType(GroupTypes.GroupAll);
1823 groupBuilder.setKey(key);
1824 group = getGroup(groupBuilder, nodeBuilder);
1829 if (groupActionAdded) {
1830 /* modify the action bucket in group */
1831 groupBuilder = new GroupBuilder(group);
1832 Buckets buckets = groupBuilder.getBuckets();
1833 List<Action> bucketActions = Lists.newArrayList();
1834 for (Bucket bucket : buckets.getBucket()) {
1836 boolean isPortDeleted = false;
1837 bucketActions = bucket.getAction();
1838 for (Action action : bucketActions) {
1839 if (action.getAction() instanceof OutputActionCase) {
1840 OutputActionCase opAction = (OutputActionCase)action.getAction();
1841 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1842 /* Find the output port in action list and remove */
1843 index = bucketActions.indexOf(action);
1844 bucketActions.remove(action);
1845 isPortDeleted = true;
1850 if (isPortDeleted && !bucketActions.isEmpty()) {
1851 for (int i = index; i< bucketActions.size(); i++) {
1852 Action action = bucketActions.get(i);
1853 if (action.getOrder() != i) {
1854 /* Shift the action order */
1855 ab = new ActionBuilder();
1856 ab.setAction(action.getAction());
1858 ab.setKey(new ActionKey(i));
1859 Action actionNewOrder = ab.build();
1860 bucketActions.remove(action);
1861 bucketActions.add(i, actionNewOrder);
1865 } else if (bucketActions.isEmpty()) {
1866 /* remove bucket with empty action list */
1867 buckets.getBucket().remove(bucket);
1871 if (!buckets.getBucket().isEmpty()) {
1872 /* rewrite the group to group table */
1873 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1874 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1875 List<Bucket> bucketList = Lists.newArrayList();
1876 BucketBuilder bucketBuilder = new BucketBuilder();
1877 bucketBuilder.setBucketId(new BucketId((long) 1));
1878 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1879 bucketBuilder.setAction(bucketActions);
1880 bucketList.add(bucketBuilder.build());
1881 bucketsBuilder.setBucket(bucketList);
1882 groupBuilder.setBuckets(bucketsBuilder.build());
1883 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1885 writeGroup(groupBuilder, nodeBuilder);
1886 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1887 aab.setAction(actionList);
1888 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1891 /* remove group with empty bucket. return true to delete flow */
1892 removeGroup(groupBuilder, nodeBuilder);
1896 /* no group for port list. flow can be removed */
1902 public void initializeOFFlowRules(Node openflowNode) {
1903 String bridgeName = southbound.getBridgeName(openflowNode);
1904 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1905 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1906 initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1907 triggerInterfaceUpdates(openflowNode);
1908 } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1909 initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1910 LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
1911 triggerInterfaceUpdates(openflowNode);
1912 LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
1916 public static NodeBuilder createNodeBuilder(String nodeId) {
1917 NodeBuilder builder = new NodeBuilder();
1918 builder.setId(new NodeId(nodeId));
1919 builder.setKey(new NodeKey(builder.getId()));
1924 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1925 this.bundleContext = bundleContext;
1926 configurationService =
1927 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1928 tenantNetworkManager =
1929 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1930 bridgeConfigurationManager =
1931 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1933 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1934 classifierProvider =
1935 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
1936 ingressAclProvider =
1937 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
1939 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
1940 l2ForwardingProvider =
1941 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
1942 securityServicesManager =
1943 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
1945 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
1949 public void setDependencies(Object impl) {
1950 if (impl instanceof NetworkingProviderManager) {
1951 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
1952 networkingProviderManager.providerAdded(
1953 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);