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.netvirt.openstack.netvirt.providers.openflow13;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import java.net.InetAddress;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.HashSet;
18 import java.util.List;
21 import java.util.concurrent.ExecutionException;
22 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
23 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
24 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
25 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
27 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
28 import org.opendaylight.netvirt.openstack.netvirt.MdsalHelper;
29 import org.opendaylight.netvirt.openstack.netvirt.NetworkHandler;
30 import org.opendaylight.netvirt.openstack.netvirt.api.BridgeConfigurationManager;
31 import org.opendaylight.netvirt.openstack.netvirt.api.ClassifierProvider;
32 import org.opendaylight.netvirt.openstack.netvirt.api.ConfigurationService;
33 import org.opendaylight.netvirt.openstack.netvirt.api.Constants;
34 import org.opendaylight.netvirt.openstack.netvirt.api.EgressAclProvider;
35 import org.opendaylight.netvirt.openstack.netvirt.api.IngressAclProvider;
36 import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingLearnProvider;
37 import org.opendaylight.netvirt.openstack.netvirt.api.L2ForwardingProvider;
38 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
39 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
40 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
41 import org.opendaylight.netvirt.openstack.netvirt.api.ResubmitAclLearnProvider;
42 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
43 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
44 import org.opendaylight.netvirt.openstack.netvirt.api.Status;
45 import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
46 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
47 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
48 import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
49 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
50 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
51 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
52 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
53 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
54 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
55 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
56 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
98 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
99 import org.osgi.framework.BundleContext;
100 import org.osgi.framework.ServiceReference;
101 import org.slf4j.Logger;
102 import org.slf4j.LoggerFactory;
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 ResubmitAclLearnProvider resubmitAclLearnProvider;
132 private volatile L2ForwardingLearnProvider l2ForwardingLearnProvider;
133 private volatile L2ForwardingProvider l2ForwardingProvider;
135 public static final String NAME = "OF13Provider";
136 private volatile BundleContext bundleContext;
137 private volatile Southbound southbound;
139 private Set<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId>
140 intBridgesWithoutVmPorts = new HashSet<>();
142 public OF13Provider() {
143 this.dataBroker = NetvirtProvidersProvider.getDataBroker();
147 public String getName() {
152 public boolean supportsServices() {
157 public boolean hasPerTenantTunneling() {
161 // The method is tested for in OF13ProviderTest
162 @SuppressWarnings("unused")
163 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
164 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
165 if (srcTunnelEndPoint == null) {
166 LOG.error("Tunnel Endpoint not configured for Node {}", node);
167 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
170 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
171 LOG.error("{} is not Overlay ready", node);
172 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
175 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
176 LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
177 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
179 return new Status(StatusCode.SUCCESS);
182 private String getTunnelName(String tunnelType, InetAddress dst) {
183 return tunnelType+"-"+dst.getHostAddress();
186 private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
187 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
188 String portName = getTunnelName(tunnelType, dst);
189 LOG.trace("Added TunnelPort : portName: {}", portName);
190 if (southbound.extractTerminationPointAugmentation(node, portName) != null
191 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
192 if (LOG.isTraceEnabled()) {
193 LOG.trace("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
198 Map<String, String> options = new HashMap<>();
199 options.put("key", "flow");
200 options.put("local_ip", src.getHostAddress());
201 options.put("remote_ip", dst.getHostAddress());
203 if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
204 LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
208 LOG.info("addTunnelPort exit: portName: {}", portName);
212 /* delete port from ovsdb port table */
213 private boolean deletePort(Node node, String bridgeName, String portName) {
215 // might need to convert from ovsdb node to bridge node
216 return southbound.deleteTerminationPoint(node, portName);
219 private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
220 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
221 String portName = getTunnelName(tunnelType, dst);
222 return deletePort(node, tunnelBridgeName, portName);
225 private boolean deletePhysicalPort(Node node, String phyIntfName) {
226 String intBridgeName = configurationService.getIntegrationBridgeName();
227 return deletePort(node, intBridgeName, phyIntfName);
230 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
231 String attachedMac, long localPort) {
235 * Match: VM sMac and Local Ingress Port
236 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
239 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
240 segmentationId, localPort, attachedMac, true);
245 * Match: Drop any remaining Ingress Local VM Packets
246 * Action: Drop w/ a low priority
249 handleDropSrcIface(dpid, localPort, true);
254 * Match: Match TunID and Destination DL/dMAC Addr
255 * Action: Output Port
256 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
259 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
264 * Match: Tunnel ID and dMAC (::::FF:FF)
265 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
266 * actions=output:2,3,4,5
269 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
270 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
275 * Match: Tunnel ID and unknown unicast
276 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
277 * actions=output:2,3,4,5
280 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
283 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
287 * Match: VM sMac and Local Ingress Port
288 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
291 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
296 * Match: Drop any remaining Ingress Local VM Packets
297 * Action: Drop w/ a low priority
300 handleDropSrcIface(dpid, localPort, false);
305 * Match: Match TunID and Destination DL/dMAC Addr
306 * Action: Output Port
307 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
310 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
315 * Match: Tunnel ID and dMAC (::::FF:FF)
316 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
317 * actions=output:2,3,4,5
320 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
321 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
326 * Match: Tunnel ID and unknown unicast
327 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
328 * actions=output:2,3,4,5
331 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
334 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
338 * Match: Ingress Port, Tunnel ID
339 * Action: GOTO Local Table (20)
342 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
347 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
348 * Action: Flood to selected destination TEPs
349 * -------------------------------------------
350 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
351 * actions=output:10,output:11,goto_table:2
354 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
359 * Match: Tunnel ID and unknown unicast
360 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
361 * actions=output:2,3,4,5
363 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
367 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
371 * Match: Drop any remaining Ingress Local VM Packets
372 * Action: Drop w/ a low priority
373 * -------------------------------------------
374 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
375 * actions=output:11,goto_table:2
378 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
381 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
385 * Match: Drop any remaining Ingress Local VM Packets
386 * Action: Drop w/ a low priority
387 * -------------------------------------------
388 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
389 * actions=output:11,goto_table:2
392 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
395 /* Remove tunnel rules if last node in this tenant network */
396 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
400 * Match: Ingress Port, Tunnel ID
401 * Action: GOTO Local Table (10)
404 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
409 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
410 * Action: Flood to selected destination TEPs
411 * -------------------------------------------
412 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
413 * actions=output:10,output:11,goto_table:2
416 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
421 * Match: Tunnel ID and unknown unicast
422 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
423 * actions=output:2,3,4,5
426 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
429 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
433 * Tag traffic coming from the local port and vm srcmac
434 * Match: VM sMac and Local Ingress Port
435 * Action: Set VLAN ID and GOTO Local Table 1
438 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
439 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
445 * Drop all other traffic coming from the local port
446 * Match: Drop any remaining Ingress Local VM Packets
447 * Action: Drop w/ a low priority
450 handleDropSrcIface(dpid, localPort, true);
455 * Forward unicast traffic destined to the local port after stripping tag
456 * Match: Match VLAN ID and Destination DL/dMAC Addr
457 * Action: strip vlan, output to local port
458 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
461 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
462 localPort, attachedMac, true);
467 * Match: VLAN ID and dMAC (::::FF:FF)
468 * Action: strip vlan, output to all local ports in this vlan
469 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
470 * actions= strip_vlan, output:2,3,4,5
473 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
474 // localPort, ethPort, true);
475 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
476 // segmentationId, localPort, ethport, true);
481 * Match: Any Remaining Flows w/a VLAN ID
482 * Action: Drop w/ a low priority
483 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
486 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
490 private void removeLocalVlanRules(Node node, Long dpid,
491 String segmentationId, String attachedMac, long localPort) {
495 * Match: VM sMac and Local Ingress Port
496 * Action: Set VLAN ID and GOTO Local Table 1
499 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
500 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
506 * Match: Drop any remaining Ingress Local VM Packets
507 * Action: Drop w/ a low priority
510 handleDropSrcIface(dpid, localPort, false);
515 * Match: Match VLAN ID and Destination DL/dMAC Addr
516 * Action: strip vlan, output to local port
517 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
520 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
521 localPort, attachedMac, false);
526 * Match: VLAN ID and dMAC (::::FF:FF)
527 * Action: strip vlan, output to all local ports in this vlan
528 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
529 * actions= strip_vlan, output:2,3,4,5
532 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
533 // localPort, ethPort, false);
534 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
535 // segmentationId, localPort, false);
539 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
540 long localPort, long ethPort) {
544 * Match: Ingress port = physical interface, Vlan ID
545 * Action: GOTO Local Table 2
548 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
549 segmentationId, ethPort, true);
554 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
555 * Action: Flood to local and remote VLAN members
556 * -------------------------------------------
557 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
558 * actions=output:10 (eth port),goto_table:2
559 * 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
562 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
567 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
568 * Action: Flood to local and remote VLAN members
569 * -------------------------------------------
570 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
571 * actions=output:10 (eth port),goto_table:2
574 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
575 // segmentationId, ethPort, true);
578 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
579 String attachedMac, long ethPort) {
583 * Match: Destination MAC is local VM MAC and vlan id
584 * Action: go to table 2
585 * -------------------------------------------
586 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
587 * actions=goto_table:2
590 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
591 // segmentationId, ethPort, attachedMac, true);
597 * Action: Go to table 2
598 * -------------------------------------------
599 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
600 * table=110,priority=8192,dl_vlan=2001 actions=output:2
603 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
606 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
607 String attachedMac, long localPort, long ethPort) {
611 * Match: Destination MAC is local VM MAC and vlan id
612 * Action: go to table 2
613 * -------------------------------------------
614 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
615 * actions=goto_table:2
618 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
619 // segmentationId, ethPort, attachedMac, false);
624 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
625 * Action: Flood to local and remote VLAN members
626 * -------------------------------------------
627 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
628 * actions=output:10 (eth port),goto_table:2
629 * 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
632 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
635 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
639 * Match: Any Remaining Flows w/a VLAN ID
640 * Action: Drop w/ a low priority
641 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
644 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
649 * Match: Ingress port = physical interface, Vlan ID
650 * Action: GOTO Local Table 2
653 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
658 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
659 * Action: Flood to local and remote VLAN members
660 * -------------------------------------------
661 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
662 * actions=output:10 (eth port),goto_table:2
663 * 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
666 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
671 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
672 * Action: Flood to local and remote VLAN members
673 * -------------------------------------------
674 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
675 * actions=output:10 (eth port),goto_table:2
678 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
679 // segmentationId, ethPort, false);
685 * Action: Go to table 2
686 * -------------------------------------------
687 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
688 * table=110,priority=8192,dl_vlan=2001 actions=output:2
691 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
694 private long getDpid(Node node) {
695 long dpid = southbound.getDataPathId(node);
697 LOG.warn("getDpid: dpid not found: {}", node);
702 private long getIntegrationBridgeOFDPID(Node node) {
704 if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
705 dpid = getDpid(node);
711 * Returns true is the network if of type GRE or VXLAN
713 * @param networkType The type of the network
714 * @return returns true if the network is a tunnel
716 private boolean isTunnel(String networkType)
718 return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
719 (NetworkHandler.NETWORK_TYPE_VXLAN));
723 * Returns true if the network is of type vlan.
725 * @param networkType The type of the network
726 * @return returns true if the network is a vlan
728 private boolean isVlan(String networkType)
730 return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
733 private void programLocalRules(String networkType, String segmentationId, Node node,
734 OvsdbTerminationPointAugmentation intf) {
735 LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
736 node.getNodeId(), intf.getName(), networkType, segmentationId);
738 long dpid = getIntegrationBridgeOFDPID(node);
740 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
745 long localPort = southbound.getOFPort(intf);
746 if (localPort == 0) {
747 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
748 intf.getName(), node.getNodeId());
752 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
753 if (attachedMac == null) {
754 LOG.warn("No AttachedMac seen in {}", intf);
758 /* Program local rules based on network type */
759 if (isVlan(networkType)) {
760 LOG.debug("Program local vlan rules for interface {}", intf.getName());
761 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
763 if ((isTunnel(networkType) || isVlan(networkType))) {
764 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
766 if (isTunnel(networkType)) {
767 LOG.debug("Program local bridge rules for interface {}, "
768 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
769 intf.getName(), dpid, segmentationId, attachedMac, localPort);
770 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
772 } catch (Exception e) {
773 LOG.error("Exception in programming Local Rules for {} on {}", intf, node, e);
777 private void removeLocalRules(String networkType, String segmentationId, Node node,
778 OvsdbTerminationPointAugmentation intf) {
779 LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
780 node.getNodeId(), intf.getName(), networkType, segmentationId);
782 long dpid = getIntegrationBridgeOFDPID(node);
784 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
788 long localPort = southbound.getOFPort(intf);
789 if (localPort == 0) {
790 LOG.info("removeLocalRules: could not find ofPort");
794 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
795 if (attachedMac == null) {
796 LOG.warn("No AttachedMac seen in {}", intf);
800 /* Program local rules based on network type */
801 if (isVlan(networkType)) {
802 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
803 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
804 } else if (isTunnel(networkType)) {
805 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
806 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
808 if (isTunnel(networkType) || isVlan(networkType)) {
809 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
811 } catch (Exception e) {
812 LOG.error("Exception in removing Local Rules for {} on {}", intf, node, e);
816 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
817 OvsdbTerminationPointAugmentation intf, boolean local) {
818 LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
819 + "segmentationId: {}, dstAddr: {}",
820 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
822 long dpid = getIntegrationBridgeOFDPID(node);
824 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
828 long localPort = southbound.getOFPort(intf);
829 if (localPort == 0) {
830 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
834 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
835 if (attachedMac == null) {
836 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
840 OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
841 if (tunnelPort != null){
842 long tunnelOFPort = southbound.getOFPort(tunnelPort);
843 if (tunnelOFPort == 0) {
844 LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
845 tunnelPort.getName(), tunnelOFPort, node);
848 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
849 tunnelPort.getName(), tunnelOFPort, node);
852 LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
853 node.getNodeId().getValue(), intf.getName());
854 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
855 tunnelOFPort, localPort);
857 LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
858 node.getNodeId().getValue(), intf.getName());
859 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
860 tunnelOFPort, localPort);
863 } catch (Exception e) {
864 LOG.warn("Failed to program tunnel rules, node {}, intf {}", node, intf, e);
868 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
869 OvsdbTerminationPointAugmentation intf,
870 boolean local, boolean isLastInstanceOnNode) {
871 LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
872 + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
873 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
875 long dpid = getIntegrationBridgeOFDPID(node);
877 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
881 long localPort = southbound.getOFPort(intf);
882 if (localPort == 0) {
883 LOG.info("removeTunnelRules: could not find ofPort");
887 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
888 if (attachedMac == null) {
889 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
893 List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
894 for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
895 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
896 long tunnelOFPort = southbound.getOFPort(tunIntf);
897 if (tunnelOFPort == 0) {
898 LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
899 tunIntf.getName(), tunnelOFPort, node);
902 LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
903 tunIntf.getName(), tunnelOFPort, node);
906 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
907 tunnelOFPort, localPort);
909 if (local && isLastInstanceOnNode) {
910 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
915 } catch (Exception e) {
916 LOG.error("Failed to remove tunnel rules, node {}, intf {}", node, intf, e);
920 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
921 LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
922 node.getNodeId(), network.getNetworkUUID(), intf.getName());
923 long dpid = getIntegrationBridgeOFDPID(node);
925 LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
929 long localPort = southbound.getOFPort(intf);
930 if (localPort == 0) {
931 LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
935 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
936 if (attachedMac == null) {
937 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
942 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
943 long ethOFPort = southbound.getOFPort(node, phyIfName);
944 if (ethOFPort == 0) {
945 LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
948 LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
949 phyIfName, ethOFPort, node);
950 // TODO: add logic to only add rule on remote nodes
951 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
952 attachedMac, ethOFPort);
953 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
954 attachedMac, localPort, ethOFPort);
957 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
958 boolean isLastInstanceOnNode) {
959 LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
960 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
961 long dpid = getIntegrationBridgeOFDPID(node);
963 LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
967 long localPort = southbound.getOFPort(intf);
968 if (localPort == 0) {
969 LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
973 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
974 if (attachedMac == null) {
975 LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
980 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
981 long ethOFPort = southbound.getOFPort(node, phyIfName);
982 if (ethOFPort == 0) {
983 LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
986 LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
987 phyIfName, ethOFPort, node);
989 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
990 attachedMac, localPort, ethOFPort);
991 if (isLastInstanceOnNode) {
992 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
996 private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
997 Long dpid,long localPort, String segmentationId,
1000 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
1001 boolean isPortSecurityEnabled = securityServicesManager.isPortSecurityEnabled(intf);
1002 if (!isPortSecurityEnabled) {
1003 LOG.info("Port security is not enabled" + intf);
1006 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId nodeId = node.getNodeId();
1007 NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
1008 List<Neutron_IPs> srcAddressList = null;
1009 if (null != dhcpPort) {
1010 srcAddressList = securityServicesManager.getIpAddressList(intf);
1011 if (null == srcAddressList) {
1012 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1015 ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1016 attachedMac, write);
1017 egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1018 srcAddressList, write);
1019 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
1020 /* TODO SB_MIGRATION */
1022 LOG.debug("Neutron port has a Port Security Group");
1023 // Retrieve the security group from the Neutron Port and apply the rules
1024 List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
1025 .getSecurityGroupInPortList(intf);
1026 String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
1027 Constants.EXTERNAL_ID_INTERFACE_ID);
1028 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1029 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1030 securityGroupInPort, neutronPortId, nodeId, write);
1031 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1032 securityGroupInPort, neutronPortId, nodeId, write);
1036 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1041 * The function is for the new compute node joining the existing network.
1042 * When a new VM is instantiated in the new compute node, neutron port add
1043 * event is generated. This event is processed only for that node. So,
1044 * loop through all the ports of the same network and install unicast mac
1045 * flow for the VM's created on the TEP of the destination node in src node.
1046 * This function will be executed even for any new VM creation in an existing
1047 * network. If a cache is maintained to optimize the below flow addition, it will
1048 * work only for one unstack and restack. For the next unstack and restack,
1049 * it will not work since the cache would have been already deleted.
1051 private void programTunnelRulesInNewNode(NeutronNetwork network,
1052 String networkType, String segmentationId,
1053 InetAddress src, InetAddress dst,
1054 Node srcBridgeNode, Node dstBridgeNode,
1055 OvsdbTerminationPointAugmentation intf){
1056 LOG.debug("programTunnelRulesInNewNode: network {} networkType {} segId {} src {} dst {} srcBridgeNode {} dstBridgeNode {} intf {}",
1057 network.getNetworkName(), networkType, segmentationId, src.getHostAddress(),
1058 dst.getHostAddress(), srcBridgeNode, dstBridgeNode, intf);
1060 long localPort = southbound.getOFPort(intf);
1063 LOG.debug("Interface update details {}", intf);
1066 * When a network is added and the TEP destination is not present in a
1067 * node C1, tunnelin and broadcast rules will not be programmed, since
1068 * OF port is not created. So, when a new node C2 joins and create a new
1069 * VM, the tunnelin and broadcast rule will not be present in C1.
1070 * So, handling it in the case below to make ping work.
1072 if (securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1073 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1077 * FIX for 4208 - loop through all the ports and add the VM's
1078 * unicast mac rule of the destination node in the source node.
1079 * When a new node is added, it needs to configure the VM unicast mac
1080 * flow rules which were created before it was joined to an existing
1083 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1084 for (OvsdbTerminationPointAugmentation port : ports) {
1086 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1087 if (neutronNetwork != null) {
1088 String netType = neutronNetwork.getProviderNetworkType();
1089 String segId = neutronNetwork.getProviderSegmentationID();
1090 InetAddress dstAddr = configurationService.getTunnelEndPoint(dstBridgeNode);
1092 if (segId != null && netType != null && dstAddr != null) {
1093 programTunnelRules(netType, segId, dstAddr, srcBridgeNode, port, false);
1098 } catch (Exception e) {
1099 LOG.error("Exception during handlingNeutron network add", e);
1103 private boolean bridgeHasVmPort(Node bridgeNode) {
1104 String intBridgeName = configurationService.getIntegrationBridgeName();
1105 String extBridgeName = configurationService.getExternalBridgeName();
1106 List<TerminationPoint> terminationPoints = bridgeNode.getTerminationPoint();
1107 if (terminationPoints == null) return false;
1109 for (TerminationPoint tp : terminationPoints) {
1110 String tpName = tp.getTpId().getValue();
1111 if (tpName != null && !tpName.equals(intBridgeName) && !tpName.equals(extBridgeName)) {
1112 OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1113 if (tpAug != null && southbound.getOFPort(tpAug) != 0) {
1123 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
1124 LOG.debug("handleInterfaceUpdate: network: {} srcNode: {}, intf: {}",
1125 network.getProviderSegmentationID(), srcNode.getNodeId(), intf.getName());
1126 Preconditions.checkNotNull(nodeCacheManager);
1128 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId srcNodeId =
1129 srcNode.getNodeId();
1130 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1131 nodeCacheManager.getOvsdbNodes();
1133 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1134 String networkType = network.getProviderNetworkType();
1135 String segmentationId = network.getProviderSegmentationID();
1136 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1138 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1140 if (isVlan(networkType)) {
1141 programVlanRules(network, srcNode, intf);
1142 } else if (isTunnel(networkType)){
1144 boolean sourceTunnelStatus = false;
1145 boolean destTunnelStatus = false;
1146 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1147 for (Node dstNode : nodes.values()) {
1148 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1149 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1150 if ((src != null) && (dst != null)) {
1151 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1153 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1154 configurationService.getIntegrationBridgeName());
1156 if (dstBridgeNode != null) {
1157 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1159 if (sourceTunnelStatus && destTunnelStatus) {
1160 LOG.debug("Created Source and destination TunnelPorts :{}, {}", src, dst);
1162 LOG.debug("Source and destination TunnelPort status :{}, {}", sourceTunnelStatus, destTunnelStatus);
1164 if (sourceTunnelStatus) {
1165 boolean isDestinNw = tenantNetworkManager.isTenantNetworkPresentInNode(dstBridgeNode, segmentationId);
1166 //Check whether the network is present in src & dst node
1167 //If only present , add vxlan ports in TunnelRules for both nodes (bug# 5614)
1168 if (isSrcinNw && isDestinNw) {
1169 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1170 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1171 } else if (configurationService.isRemoteMacLearnEnabled()) {
1172 //Even if to learn remote MAC, a network doesn't exist in a node,
1173 //a vxlan port is added in TunnelRules for both nodes.(bug# 6474)
1174 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1177 if (destTunnelStatus) {
1178 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1180 if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
1181 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1182 srcBridgeNode, dstBridgeNode, intf);
1183 intBridgesWithoutVmPorts.remove(srcNodeId);
1187 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1188 + "Check source {} or destination {}",
1189 src != null ? src.getHostAddress() : "null",
1190 dst != null ? dst.getHostAddress() : "null");
1195 if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
1196 intBridgesWithoutVmPorts.add(srcNodeId);
1202 private void triggerInterfaceUpdates(Node node) {
1203 LOG.debug("enter triggerInterfaceUpdates for : {}", node.getNodeId());
1204 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1205 if (ports != null && !ports.isEmpty()) {
1206 for (OvsdbTerminationPointAugmentation port : ports) {
1207 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1208 if (neutronNetwork != null) {
1209 LOG.warn("Trigger Interface update for {}", port);
1210 handleInterfaceUpdate(neutronNetwork, node, port);
1214 LOG.warn("triggerInterfaceUpdates: tps are null");
1216 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1220 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1221 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1222 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1223 nodeCacheManager.getOvsdbNodes();
1224 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1226 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1227 String segmentationId = network.getProviderSegmentationID();
1228 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1229 if (southbound.isTunnel(intf)) {
1230 // Delete tunnel port
1232 InetAddress src = InetAddress.getByName(
1233 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1234 InetAddress dst = InetAddress.getByName(
1235 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1236 deleteTunnelPort(srcNode,
1237 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1239 } catch (Exception e) {
1240 LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
1242 } else if (phyIfName.contains(intf.getName())) {
1243 deletePhysicalPort(srcNode, intf.getName());
1245 // delete all other interfaces
1246 removeLocalRules(network.getProviderNetworkType(), segmentationId,
1249 if (isVlan(network.getProviderNetworkType())) {
1250 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1251 } else if (isTunnel(network.getProviderNetworkType())) {
1253 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1254 for (Node dstNode : nodes.values()) {
1255 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1256 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1257 if ((src != null) && (dst != null)) {
1258 LOG.info("Remove tunnel rules for interface "
1259 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1260 removeTunnelRules(tunnelType, segmentationId,
1261 dst, srcNode, intf, true, isLastInstanceOnNode);
1262 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1263 //While removing last instance , check whether the network present in src node
1264 //If network is not present in src node AND REMOTE MAC LEARNING IS not enabled,
1265 //remove the vxlan port of src from dst node in TunnelRules(Bug# 5614)
1266 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1267 if (dstBridgeNode != null) {
1268 //To learn remote MAC, also to make the flooding the node by which a network
1269 //doesn't exist in a node, TunnelRules leaves it.
1270 if (!isSrcinNw && !configurationService.isRemoteMacLearnEnabled()) {
1271 removeTunnelRules(tunnelType, segmentationId,
1272 src, dstBridgeNode, intf, true, isLastInstanceOnNode);
1274 LOG.info("Remove tunnel rules for interface "
1275 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1276 removeTunnelRules(tunnelType, segmentationId, src,
1277 dstBridgeNode, intf, false, isLastInstanceOnNode);
1280 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1281 + "OpenVSwitch Table. "
1282 + "Check source {} or destination {}",
1283 src != null ? src.getHostAddress() : "null",
1284 dst != null ? dst.getHostAddress() : "null");
1293 public void initializeFlowRules(Node node) {
1294 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1295 initializeFlowRules(node, configurationService.getExternalBridgeName());
1296 triggerInterfaceUpdates(node);
1299 private void initializeFlowRules(Node node, String bridgeName) {
1300 Long dpid = southbound.getDataPathId(node);
1301 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1302 resubmitAclLearnProvider.programResubmit(dpid);
1304 String datapathId = southbound.getDatapathId(node);
1305 LOG.trace("initializeFlowRules: bridgeName: {}, datapathId: {} ",
1306 bridgeName, datapathId);
1307 String brExt = null;
1310 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1317 * Match: LLDP (0x88CCL)
1318 * Action: Packet_In to Controller Reserved Port
1321 writeLLDPRule(dpid);
1324 * Table(105) Rule #1
1325 * -------------------
1327 * Action: learn and goto next table
1330 writeL2ForwardingLearnRule(dpid);
1332 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
1333 NetvirtProvidersProvider.getTableOffset() != 0) {
1334 classifierProvider.programGotoTable(dpid,true);
1337 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1338 brExt = bridgeConfigurationManager.getMultipleExternalBridge(node);
1340 if (bridgeName.equals(configurationService.getExternalBridgeName()) ||
1341 (bridgeName.equals(brExt))) {
1342 writeNormalRule(dpid);
1347 * Create an LLDP Flow Rule to encapsulate into
1348 * a packet_in that is sent to the controller
1349 * for topology handling.
1350 * Match: Ethertype 0x88CCL
1351 * Action: Punt to Controller in a Packet_In msg
1354 private void writeLLDPRule(Long dpidLong) {
1355 classifierProvider.programLLDPPuntRule(dpidLong);
1359 * Create an L2Forwarding mac learn Flow Rule
1360 * Match: reg0 = ClassifierService.REG_VALUE_FROM_REMOTE
1361 * Action: learn and goto next table
1364 private void writeL2ForwardingLearnRule(Long dpidLong) {
1365 if (configurationService.isRemoteMacLearnEnabled()) {
1366 l2ForwardingLearnProvider.programL2ForwardingLearnRule(dpidLong);
1371 * Create a NORMAL Table Miss Flow Rule
1373 * Action: forward to NORMAL pipeline
1376 private void writeNormalRule(Long dpidLong) {
1377 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1378 FlowBuilder flowBuilder = new FlowBuilder();
1379 String flowName = "NORMAL";
1380 FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
1381 MatchBuilder matchBuilder = new MatchBuilder();
1382 flowBuilder.setMatch(matchBuilder.build());
1384 // Create the OF Actions and Instructions
1385 InstructionBuilder ib = new InstructionBuilder();
1386 InstructionsBuilder isb = new InstructionsBuilder();
1388 // Instructions List Stores Individual Instructions
1389 List<Instruction> instructions = new ArrayList<>();
1391 // Call the InstructionBuilder Methods Containing Actions
1392 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1394 ib.setKey(new InstructionKey(0));
1395 instructions.add(ib.build());
1397 // Add InstructionBuilder to the Instruction(s)Builder List
1398 isb.setInstruction(instructions);
1400 // Add InstructionsBuilder to FlowBuilder
1401 flowBuilder.setInstructions(isb.build());
1402 writeFlow(flowBuilder, nodeBuilder);
1406 * (Table:0) Ingress Tunnel Traffic
1407 * Match: OpenFlow InPort and Tunnel ID
1408 * Action: GOTO Local Table (10)
1409 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1412 private void handleTunnelIn(Long dpidLong, Short writeTable,
1413 Short goToTableId, String segmentationId,
1414 Long ofPort, boolean write) {
1415 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1419 * (Table:0) Ingress VLAN Traffic
1420 * Match: OpenFlow InPort and vlan ID
1421 * Action: GOTO Local Table (20)
1422 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1425 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1426 String segmentationId, Long ethPort, boolean write) {
1427 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1431 * (Table:0) Egress VM Traffic Towards TEP
1432 * Match: Destination Ethernet Addr and OpenFlow InPort
1433 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1434 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1435 * actions=set_field:5->tun_id,goto_table=1"
1438 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1439 String segmentationId, Long inPort, String attachedMac,
1441 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1445 * (Table:0) Egress VM Traffic Towards TEP
1446 * Match: Source Ethernet Addr and OpenFlow InPort
1447 * Instruction: Set VLANID and GOTO Table Egress (n)
1448 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1449 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1452 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1453 Short goToTableId, String segmentationId,
1454 Long inPort, String attachedMac,
1456 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1460 * (Table:0) Drop frames source from a VM that do not
1461 * match the associated MAC address of the local VM.
1462 * Match: Low priority anything not matching the VM SMAC
1464 * table=0,priority=16384,in_port=1 actions=drop"
1467 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1468 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1472 * (Table:1) Egress Tunnel Traffic
1473 * Match: Destination Ethernet Addr and Local InPort
1474 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1475 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1476 * actions=output:10,goto_table:2"
1478 private void handleTunnelOut(Long dpidLong, Short writeTable,
1479 Short goToTableId, String segmentationId,
1480 Long OFPortOut, String attachedMac,
1482 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1486 * (Table:1) Egress VLAN Traffic
1487 * Match: Destination Ethernet Addr and VLAN id
1488 * Instruction: GOTO Table Table 2
1489 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1490 * actions= goto_table:2"
1492 // TODO This method is referenced from commented code above (which needs to be checked)
1493 @SuppressWarnings("unused")
1494 private void handleVlanOut(Long dpidLong, Short writeTable,
1495 Short goToTableId, String segmentationId,
1496 Long ethPort, String attachedMac, boolean write) {
1497 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1501 * (Table:1) Egress Tunnel Traffic
1502 * Match: Destination Ethernet Addr and Local InPort
1503 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1504 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1505 * actions=output:10,output:11,goto_table:2
1508 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1509 Short localTable, String segmentationId,
1510 Long OFPortOut, boolean write) {
1511 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1515 * (Table:110) Flooding local unknown unicast Traffic
1516 * Match: TunnelID and Unknown unicast and Local InPort
1517 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1518 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
1519 * actions=output:10,output:11
1522 private void handleTunnelUnknownUcastFloodOut(Long dpidLong, Short writeTable,
1523 Short localTable, String segmentationId,
1524 Long OFPortOut, boolean write) {
1525 if (configurationService.isRemoteMacLearnEnabled()) {
1526 l2ForwardingProvider.programTunnelUnknownUcastFloodOut(dpidLong, segmentationId, OFPortOut, write);
1531 * (Table:1) Egress VLAN Traffic
1532 * Match: Destination Ethernet Addr and VLAN id
1533 * Instruction: GOTO table 2 and Output port eth interface
1534 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1535 * actions=output:eth1,goto_table:2
1537 // TODO This method is referenced from commented code above (which needs to be checked)
1538 @SuppressWarnings("unused")
1539 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1540 Short localTable, String segmentationId,
1541 Long localPort, Long ethPort, boolean write) {
1542 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1546 * (Table:1) Table Drain w/ Catch All
1548 * Action: Output port eth interface
1549 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1550 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1553 private void handleVlanMiss(Long dpidLong, Short writeTable,
1554 Short goToTableId, String segmentationId,
1555 Long ethPort, boolean write) {
1556 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1560 * (Table:1) Local Broadcast Flood
1561 * Match: Tunnel ID and dMAC
1562 * Action: Output Port
1563 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1566 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1567 String segmentationId, Long localPort,
1568 String attachedMac, boolean write) {
1569 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1573 * (Table:2) Local VLAN unicast
1574 * Match: VLAN ID and dMAC
1575 * Action: Output Port
1576 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1579 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1580 String segmentationId, Long localPort,
1581 String attachedMac, boolean write) {
1582 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1586 * (Table:2) Local Broadcast Flood
1587 * Match: Tunnel ID and dMAC (::::FF:FF)
1588 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1589 * actions=output:2,3,4,5
1592 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1593 String segmentationId, Long localPort,
1595 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1599 * (Table:2) Local VLAN Broadcast Flood
1600 * Match: vlan ID and dMAC (::::FF:FF)
1601 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1602 * actions=strip_vlan, output:2,3,4,5
1603 * 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
1606 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1607 Long localPort, Long ethPort, boolean write) {
1608 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1612 * (Table:1) Local Table Miss
1613 * Match: Any Remaining Flows w/a VLAN ID
1614 * Action: Drop w/ a low priority
1615 * table=2,priority=8192,vlan_id=0x5 actions=drop
1617 // TODO This method is referenced from commented code above (which needs to be checked)
1618 @SuppressWarnings("unused")
1619 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1620 String segmentationId, boolean write) {
1621 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1624 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1625 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1626 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1627 new GroupKey(groupBuilder.getGroupId())).build();
1628 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1630 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1631 if (data.isPresent()) {
1634 } catch (InterruptedException|ExecutionException e) {
1635 LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
1638 LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
1642 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1643 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1644 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1645 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1646 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1647 new GroupKey(groupBuilder.getGroupId())).build();
1648 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1650 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1652 commitFuture.get(); // TODO: Make it async (See bug 1362)
1653 LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
1654 } catch (InterruptedException|ExecutionException e) {
1655 LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
1660 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1661 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1662 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1663 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1664 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1665 new GroupKey(groupBuilder.getGroupId())).build();
1666 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1667 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1670 commitFuture.get(); // TODO: Make it async (See bug 1362)
1671 LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
1672 } catch (InterruptedException|ExecutionException e) {
1673 LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
1678 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1679 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1680 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1681 InstanceIdentifier<Flow> path1 =
1682 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1683 .rev130819.nodes.Node.class,
1684 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1685 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1687 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1688 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1689 true);//createMissingParents
1692 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1694 commitFuture.get(); // TODO: Make it async (See bug 1362)
1695 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
1696 } catch (InterruptedException|ExecutionException e) {
1697 LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
1703 * Create Output Port Group Instruction
1705 * @param nodeBuilder Node Builder
1706 * @param ib Map InstructionBuilder without any instructions
1707 * @param dpidLong Long the datapath ID of a switch/node
1708 * @param port Long representing a port on a switch/node
1709 * @param instructions List of instructions
1710 * @return ib InstructionBuilder Map with instructions
1712 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1713 @SuppressWarnings("unused")
1714 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1715 InstructionBuilder ib,
1716 Long dpidLong, Long port ,
1717 List<Instruction> instructions) {
1718 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1719 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1721 List<Action> actionList = new ArrayList<>();
1722 ActionBuilder ab = new ActionBuilder();
1724 List<Action> existingActions;
1725 if (instructions != null) {
1726 for (Instruction in : instructions) {
1727 if (in.getInstruction() instanceof ApplyActionsCase) {
1728 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1729 actionList.addAll(existingActions);
1734 GroupBuilder groupBuilder = new GroupBuilder();
1737 /* Create output action for this port*/
1738 OutputActionBuilder oab = new OutputActionBuilder();
1739 oab.setOutputNodeConnector(ncid);
1740 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1741 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1742 boolean addNew = true;
1743 boolean groupActionAdded = false;
1745 /* Find the group action and get the group */
1746 for (Action action : actionList) {
1747 if (action.getAction() instanceof GroupActionCase) {
1748 groupActionAdded = true;
1749 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1750 Long id = groupAction.getGroupAction().getGroupId();
1751 String groupName = groupAction.getGroupAction().getGroup();
1752 GroupKey key = new GroupKey(new GroupId(id));
1754 groupBuilder.setGroupId(new GroupId(id));
1755 groupBuilder.setGroupName(groupName);
1756 groupBuilder.setGroupType(GroupTypes.GroupAll);
1757 groupBuilder.setKey(key);
1758 group = getGroup(groupBuilder, nodeBuilder);
1759 LOG.debug("createOutputGroupInstructions: group {}", group);
1764 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1765 if (groupActionAdded) {
1766 /* modify the action bucket in group */
1767 groupBuilder = new GroupBuilder(group);
1768 Buckets buckets = groupBuilder.getBuckets();
1769 for (Bucket bucket : buckets.getBucket()) {
1770 List<Action> bucketActions = bucket.getAction();
1771 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1772 for (Action action : bucketActions) {
1773 if (action.getAction() instanceof OutputActionCase) {
1774 OutputActionCase opAction = (OutputActionCase)action.getAction();
1775 /* If output port action already in the action list of one of the buckets, skip */
1776 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1783 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1784 if (addNew && !buckets.getBucket().isEmpty()) {
1785 /* the new output action is not in the bucket, add to bucket */
1786 Bucket bucket = buckets.getBucket().get(0);
1787 List<Action> bucketActionList = new ArrayList<>();
1788 bucketActionList.addAll(bucket.getAction());
1789 /* set order for new action and add to action list */
1790 ab.setOrder(bucketActionList.size());
1791 ab.setKey(new ActionKey(bucketActionList.size()));
1792 bucketActionList.add(ab.build());
1794 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1795 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1796 List<Bucket> bucketList = new ArrayList<>();
1797 BucketBuilder bucketBuilder = new BucketBuilder();
1798 bucketBuilder.setBucketId(new BucketId((long) 1));
1799 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1800 bucketBuilder.setAction(bucketActionList);
1801 bucketList.add(bucketBuilder.build());
1802 bucketsBuilder.setBucket(bucketList);
1803 groupBuilder.setBuckets(bucketsBuilder.build());
1804 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1808 groupBuilder = new GroupBuilder();
1809 groupBuilder.setGroupType(GroupTypes.GroupAll);
1810 groupBuilder.setGroupId(new GroupId(groupId));
1811 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1812 groupBuilder.setGroupName("Output port group " + groupId);
1813 groupBuilder.setBarrier(false);
1815 BucketsBuilder bucketBuilder = new BucketsBuilder();
1816 List<Bucket> bucketList = new ArrayList<>();
1817 BucketBuilder bucket = new BucketBuilder();
1818 bucket.setBucketId(new BucketId((long) 1));
1819 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1821 /* put output action to the bucket */
1822 List<Action> bucketActionList = new ArrayList<>();
1823 /* set order for new action and add to action list */
1824 ab.setOrder(bucketActionList.size());
1825 ab.setKey(new ActionKey(bucketActionList.size()));
1826 bucketActionList.add(ab.build());
1828 bucket.setAction(bucketActionList);
1829 bucketList.add(bucket.build());
1830 bucketBuilder.setBucket(bucketList);
1831 groupBuilder.setBuckets(bucketBuilder.build());
1833 /* Add new group action */
1834 GroupActionBuilder groupActionB = new GroupActionBuilder();
1835 groupActionB.setGroupId(groupId);
1836 groupActionB.setGroup("Output port group " + groupId);
1837 ab = new ActionBuilder();
1838 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1839 ab.setOrder(actionList.size());
1840 ab.setKey(new ActionKey(actionList.size()));
1841 actionList.add(ab.build());
1845 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1846 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1849 /* rewrite the group to group table */
1850 writeGroup(groupBuilder, nodeBuilder);
1853 // Create an Apply Action
1854 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1855 aab.setAction(actionList);
1856 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1862 * Remove Output Port from action list in group bucket
1864 * @param nodeBuilder Node Builder
1865 * @param ib Map InstructionBuilder without any instructions
1866 * @param dpidLong Long the datapath ID of a switch/node
1867 * @param port Long representing a port on a switch/node
1868 * @param instructions List of instructions
1869 * @return ib InstructionBuilder Map with instructions
1871 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1872 @SuppressWarnings("unused")
1873 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1874 Long dpidLong, Long port , List<Instruction> instructions) {
1876 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1877 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1879 List<Action> actionList = new ArrayList<>();
1882 List<Action> existingActions;
1883 if (instructions != null) {
1884 for (Instruction in : instructions) {
1885 if (in.getInstruction() instanceof ApplyActionsCase) {
1886 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1887 actionList.addAll(existingActions);
1893 GroupBuilder groupBuilder = new GroupBuilder();
1895 boolean groupActionAdded = false;
1896 /* Find the group action and get the group */
1897 for (Action action : actionList) {
1898 if (action.getAction() instanceof GroupActionCase) {
1899 groupActionAdded = true;
1900 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1901 Long id = groupAction.getGroupAction().getGroupId();
1902 String groupName = groupAction.getGroupAction().getGroup();
1903 GroupKey key = new GroupKey(new GroupId(id));
1905 groupBuilder.setGroupId(new GroupId(id));
1906 groupBuilder.setGroupName(groupName);
1907 groupBuilder.setGroupType(GroupTypes.GroupAll);
1908 groupBuilder.setKey(key);
1909 group = getGroup(groupBuilder, nodeBuilder);
1914 if (groupActionAdded) {
1915 /* modify the action bucket in group */
1916 groupBuilder = new GroupBuilder(group);
1917 Buckets buckets = groupBuilder.getBuckets();
1918 List<Action> bucketActions = new ArrayList<>();
1919 for (Bucket bucket : buckets.getBucket()) {
1921 boolean isPortDeleted = false;
1922 bucketActions = bucket.getAction();
1923 for (Action action : bucketActions) {
1924 if (action.getAction() instanceof OutputActionCase) {
1925 OutputActionCase opAction = (OutputActionCase)action.getAction();
1926 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1927 /* Find the output port in action list and remove */
1928 index = bucketActions.indexOf(action);
1929 bucketActions.remove(action);
1930 isPortDeleted = true;
1935 if (isPortDeleted && !bucketActions.isEmpty()) {
1936 for (int i = index; i< bucketActions.size(); i++) {
1937 Action action = bucketActions.get(i);
1938 if (action.getOrder() != i) {
1939 /* Shift the action order */
1940 ab = new ActionBuilder();
1941 ab.setAction(action.getAction());
1943 ab.setKey(new ActionKey(i));
1944 Action actionNewOrder = ab.build();
1945 bucketActions.remove(action);
1946 bucketActions.add(i, actionNewOrder);
1950 } else if (bucketActions.isEmpty()) {
1951 /* remove bucket with empty action list */
1952 buckets.getBucket().remove(bucket);
1956 if (!buckets.getBucket().isEmpty()) {
1957 /* rewrite the group to group table */
1958 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1959 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1960 List<Bucket> bucketList = new ArrayList<>();
1961 BucketBuilder bucketBuilder = new BucketBuilder();
1962 bucketBuilder.setBucketId(new BucketId((long) 1));
1963 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1964 bucketBuilder.setAction(bucketActions);
1965 bucketList.add(bucketBuilder.build());
1966 bucketsBuilder.setBucket(bucketList);
1967 groupBuilder.setBuckets(bucketsBuilder.build());
1968 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1970 writeGroup(groupBuilder, nodeBuilder);
1971 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1972 aab.setAction(actionList);
1973 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1976 /* remove group with empty bucket. return true to delete flow */
1977 removeGroup(groupBuilder, nodeBuilder);
1981 /* no group for port list. flow can be removed */
1987 public void initializeOFFlowRules(Node openflowNode) {
1988 String bridgeName = southbound.getBridgeName(openflowNode);
1989 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1990 String brExt = null;
1991 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1992 brExt = bridgeConfigurationManager.getMultipleExternalBridge(openflowNode);
1994 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) ||
1995 bridgeName.equals(configurationService.getExternalBridgeName()) || bridgeName.equals(brExt)) {
1996 initializeFlowRules(openflowNode, bridgeName);
1997 triggerInterfaceUpdates(openflowNode);
2001 public static NodeBuilder createNodeBuilder(String nodeId) {
2002 NodeBuilder builder = new NodeBuilder();
2003 builder.setId(new NodeId(nodeId));
2004 builder.setKey(new NodeKey(builder.getId()));
2009 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
2010 this.bundleContext = bundleContext;
2011 configurationService =
2012 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
2013 tenantNetworkManager =
2014 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
2015 bridgeConfigurationManager =
2016 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
2018 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
2019 resubmitAclLearnProvider =
2020 (ResubmitAclLearnProvider) ServiceHelper.getGlobalInstance(ResubmitAclLearnProvider.class, this);
2021 classifierProvider =
2022 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
2023 ingressAclProvider =
2024 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
2026 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
2027 l2ForwardingLearnProvider =
2028 (L2ForwardingLearnProvider) ServiceHelper.getGlobalInstance(L2ForwardingLearnProvider.class, this);
2029 l2ForwardingProvider =
2030 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
2031 securityServicesManager =
2032 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
2034 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
2038 public void setDependencies(Object impl) {
2039 if (impl instanceof NetworkingProviderManager) {
2040 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
2041 networkingProviderManager.providerAdded(
2042 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);