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.info("Added TunnelPort : portName: {}", portName);
190 if (southbound.extractTerminationPointAugmentation(node, portName) != null
191 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
192 LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
196 Map<String, String> options = new HashMap<>();
197 options.put("key", "flow");
198 options.put("local_ip", src.getHostAddress());
199 options.put("remote_ip", dst.getHostAddress());
201 if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
202 LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
206 LOG.info("addTunnelPort exit: portName: {}", portName);
210 /* delete port from ovsdb port table */
211 private boolean deletePort(Node node, String bridgeName, String portName) {
213 // might need to convert from ovsdb node to bridge node
214 return southbound.deleteTerminationPoint(node, portName);
217 private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
218 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
219 String portName = getTunnelName(tunnelType, dst);
220 return deletePort(node, tunnelBridgeName, portName);
223 private boolean deletePhysicalPort(Node node, String phyIntfName) {
224 String intBridgeName = configurationService.getIntegrationBridgeName();
225 return deletePort(node, intBridgeName, phyIntfName);
228 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
229 String attachedMac, long localPort) {
233 * Match: VM sMac and Local Ingress Port
234 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
237 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
238 segmentationId, localPort, attachedMac, true);
243 * Match: Drop any remaining Ingress Local VM Packets
244 * Action: Drop w/ a low priority
247 handleDropSrcIface(dpid, localPort, true);
252 * Match: Match TunID and Destination DL/dMAC Addr
253 * Action: Output Port
254 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
257 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
262 * Match: Tunnel ID and dMAC (::::FF:FF)
263 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
264 * actions=output:2,3,4,5
267 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
268 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
273 * Match: Tunnel ID and unknown unicast
274 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
275 * actions=output:2,3,4,5
278 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
281 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
285 * Match: VM sMac and Local Ingress Port
286 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
289 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
294 * Match: Drop any remaining Ingress Local VM Packets
295 * Action: Drop w/ a low priority
298 handleDropSrcIface(dpid, localPort, false);
303 * Match: Match TunID and Destination DL/dMAC Addr
304 * Action: Output Port
305 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
308 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
313 * Match: Tunnel ID and dMAC (::::FF:FF)
314 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
315 * actions=output:2,3,4,5
318 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
319 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
324 * Match: Tunnel ID and unknown unicast
325 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
326 * actions=output:2,3,4,5
329 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
332 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
336 * Match: Ingress Port, Tunnel ID
337 * Action: GOTO Local Table (20)
340 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
345 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
346 * Action: Flood to selected destination TEPs
347 * -------------------------------------------
348 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
349 * actions=output:10,output:11,goto_table:2
352 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
357 * Match: Tunnel ID and unknown unicast
358 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
359 * actions=output:2,3,4,5
361 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
365 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
369 * Match: Drop any remaining Ingress Local VM Packets
370 * Action: Drop w/ a low priority
371 * -------------------------------------------
372 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
373 * actions=output:11,goto_table:2
376 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
379 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
383 * Match: Drop any remaining Ingress Local VM Packets
384 * Action: Drop w/ a low priority
385 * -------------------------------------------
386 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
387 * actions=output:11,goto_table:2
390 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
393 /* Remove tunnel rules if last node in this tenant network */
394 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
398 * Match: Ingress Port, Tunnel ID
399 * Action: GOTO Local Table (10)
402 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
407 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
408 * Action: Flood to selected destination TEPs
409 * -------------------------------------------
410 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
411 * actions=output:10,output:11,goto_table:2
414 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
419 * Match: Tunnel ID and unknown unicast
420 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
421 * actions=output:2,3,4,5
424 handleTunnelUnknownUcastFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
427 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
431 * Tag traffic coming from the local port and vm srcmac
432 * Match: VM sMac and Local Ingress Port
433 * Action: Set VLAN ID and GOTO Local Table 1
436 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
437 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
443 * Drop all other traffic coming from the local port
444 * Match: Drop any remaining Ingress Local VM Packets
445 * Action: Drop w/ a low priority
448 handleDropSrcIface(dpid, localPort, true);
453 * Forward unicast traffic destined to the local port after stripping tag
454 * Match: Match VLAN ID and Destination DL/dMAC Addr
455 * Action: strip vlan, output to local port
456 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
459 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
460 localPort, attachedMac, true);
465 * Match: VLAN ID and dMAC (::::FF:FF)
466 * Action: strip vlan, output to all local ports in this vlan
467 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
468 * actions= strip_vlan, output:2,3,4,5
471 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
472 // localPort, ethPort, true);
473 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
474 // segmentationId, localPort, ethport, true);
479 * Match: Any Remaining Flows w/a VLAN ID
480 * Action: Drop w/ a low priority
481 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
484 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
488 private void removeLocalVlanRules(Node node, Long dpid,
489 String segmentationId, String attachedMac, long localPort) {
493 * Match: VM sMac and Local Ingress Port
494 * Action: Set VLAN ID and GOTO Local Table 1
497 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
498 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
504 * Match: Drop any remaining Ingress Local VM Packets
505 * Action: Drop w/ a low priority
508 handleDropSrcIface(dpid, localPort, false);
513 * Match: Match VLAN ID and Destination DL/dMAC Addr
514 * Action: strip vlan, output to local port
515 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
518 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
519 localPort, attachedMac, false);
524 * Match: VLAN ID and dMAC (::::FF:FF)
525 * Action: strip vlan, output to all local ports in this vlan
526 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
527 * actions= strip_vlan, output:2,3,4,5
530 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
531 // localPort, ethPort, false);
532 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
533 // segmentationId, localPort, false);
537 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
538 long localPort, long ethPort) {
542 * Match: Ingress port = physical interface, Vlan ID
543 * Action: GOTO Local Table 2
546 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
547 segmentationId, ethPort, true);
552 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
553 * Action: Flood to local and remote VLAN members
554 * -------------------------------------------
555 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
556 * actions=output:10 (eth port),goto_table:2
557 * 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
560 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
565 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
566 * Action: Flood to local and remote VLAN members
567 * -------------------------------------------
568 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
569 * actions=output:10 (eth port),goto_table:2
572 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
573 // segmentationId, ethPort, true);
576 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
577 String attachedMac, long ethPort) {
581 * Match: Destination MAC is local VM MAC and vlan id
582 * Action: go to table 2
583 * -------------------------------------------
584 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
585 * actions=goto_table:2
588 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
589 // segmentationId, ethPort, attachedMac, true);
595 * Action: Go to table 2
596 * -------------------------------------------
597 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
598 * table=110,priority=8192,dl_vlan=2001 actions=output:2
601 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
604 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
605 String attachedMac, long localPort, long ethPort) {
609 * Match: Destination MAC is local VM MAC and vlan id
610 * Action: go to table 2
611 * -------------------------------------------
612 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
613 * actions=goto_table:2
616 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
617 // segmentationId, ethPort, attachedMac, false);
622 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
623 * Action: Flood to local and remote VLAN members
624 * -------------------------------------------
625 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
626 * actions=output:10 (eth port),goto_table:2
627 * 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
630 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
633 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
637 * Match: Any Remaining Flows w/a VLAN ID
638 * Action: Drop w/ a low priority
639 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
642 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
647 * Match: Ingress port = physical interface, Vlan ID
648 * Action: GOTO Local Table 2
651 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
656 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
657 * Action: Flood to local and remote VLAN members
658 * -------------------------------------------
659 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
660 * actions=output:10 (eth port),goto_table:2
661 * 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
664 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
669 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
670 * Action: Flood to local and remote VLAN members
671 * -------------------------------------------
672 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
673 * actions=output:10 (eth port),goto_table:2
676 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
677 // segmentationId, ethPort, false);
683 * Action: Go to table 2
684 * -------------------------------------------
685 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
686 * table=110,priority=8192,dl_vlan=2001 actions=output:2
689 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
692 private long getDpid(Node node) {
693 long dpid = southbound.getDataPathId(node);
695 LOG.warn("getDpid: dpid not found: {}", node);
700 private long getIntegrationBridgeOFDPID(Node node) {
702 if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
703 dpid = getDpid(node);
709 * Returns true is the network if of type GRE or VXLAN
711 * @param networkType The type of the network
712 * @return returns true if the network is a tunnel
714 private boolean isTunnel(String networkType)
716 return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
717 (NetworkHandler.NETWORK_TYPE_VXLAN));
721 * Returns true if the network is of type vlan.
723 * @param networkType The type of the network
724 * @return returns true if the network is a vlan
726 private boolean isVlan(String networkType)
728 return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
731 private void programLocalRules(String networkType, String segmentationId, Node node,
732 OvsdbTerminationPointAugmentation intf) {
733 LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
734 node.getNodeId(), intf.getName(), networkType, segmentationId);
736 long dpid = getIntegrationBridgeOFDPID(node);
738 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
743 long localPort = southbound.getOFPort(intf);
744 if (localPort == 0) {
745 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
746 intf.getName(), node.getNodeId());
750 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
751 if (attachedMac == null) {
752 LOG.warn("No AttachedMac seen in {}", intf);
756 /* Program local rules based on network type */
757 if (isVlan(networkType)) {
758 LOG.debug("Program local vlan rules for interface {}", intf.getName());
759 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
761 if ((isTunnel(networkType) || isVlan(networkType))) {
762 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
764 if (isTunnel(networkType)) {
765 LOG.debug("Program local bridge rules for interface {}, "
766 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
767 intf.getName(), dpid, segmentationId, attachedMac, localPort);
768 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
770 } catch (Exception e) {
771 LOG.error("Exception in programming Local Rules for {} on {}", intf, node, e);
775 private void removeLocalRules(String networkType, String segmentationId, Node node,
776 OvsdbTerminationPointAugmentation intf) {
777 LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
778 node.getNodeId(), intf.getName(), networkType, segmentationId);
780 long dpid = getIntegrationBridgeOFDPID(node);
782 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
786 long localPort = southbound.getOFPort(intf);
787 if (localPort == 0) {
788 LOG.info("removeLocalRules: could not find ofPort");
792 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
793 if (attachedMac == null) {
794 LOG.warn("No AttachedMac seen in {}", intf);
798 /* Program local rules based on network type */
799 if (isVlan(networkType)) {
800 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
801 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
802 } else if (isTunnel(networkType)) {
803 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
804 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
806 if (isTunnel(networkType) || isVlan(networkType)) {
807 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
809 } catch (Exception e) {
810 LOG.error("Exception in removing Local Rules for {} on {}", intf, node, e);
814 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
815 OvsdbTerminationPointAugmentation intf, boolean local) {
816 LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
817 + "segmentationId: {}, dstAddr: {}",
818 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
820 long dpid = getIntegrationBridgeOFDPID(node);
822 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
826 long localPort = southbound.getOFPort(intf);
827 if (localPort == 0) {
828 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
832 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
833 if (attachedMac == null) {
834 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
838 OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
839 if (tunnelPort != null){
840 long tunnelOFPort = southbound.getOFPort(tunnelPort);
841 if (tunnelOFPort == 0) {
842 LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
843 tunnelPort.getName(), tunnelOFPort, node);
846 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
847 tunnelPort.getName(), tunnelOFPort, node);
850 LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
851 node.getNodeId().getValue(), intf.getName());
852 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
853 tunnelOFPort, localPort);
855 LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
856 node.getNodeId().getValue(), intf.getName());
857 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
858 tunnelOFPort, localPort);
861 } catch (Exception e) {
862 LOG.warn("Failed to program tunnel rules, node {}, intf {}", node, intf, e);
866 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
867 OvsdbTerminationPointAugmentation intf,
868 boolean local, boolean isLastInstanceOnNode) {
869 LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
870 + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
871 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
873 long dpid = getIntegrationBridgeOFDPID(node);
875 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
879 long localPort = southbound.getOFPort(intf);
880 if (localPort == 0) {
881 LOG.info("removeTunnelRules: could not find ofPort");
885 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
886 if (attachedMac == null) {
887 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
891 List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
892 for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
893 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
894 long tunnelOFPort = southbound.getOFPort(tunIntf);
895 if (tunnelOFPort == 0) {
896 LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
897 tunIntf.getName(), tunnelOFPort, node);
900 LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
901 tunIntf.getName(), tunnelOFPort, node);
904 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
905 tunnelOFPort, localPort);
907 if (local && isLastInstanceOnNode) {
908 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
913 } catch (Exception e) {
914 LOG.error("Failed to remove tunnel rules, node {}, intf {}", node, intf, e);
918 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
919 LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
920 node.getNodeId(), network.getNetworkUUID(), intf.getName());
921 long dpid = getIntegrationBridgeOFDPID(node);
923 LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
927 long localPort = southbound.getOFPort(intf);
928 if (localPort == 0) {
929 LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
933 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
934 if (attachedMac == null) {
935 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
940 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
941 long ethOFPort = southbound.getOFPort(node, phyIfName);
942 if (ethOFPort == 0) {
943 LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
946 LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
947 phyIfName, ethOFPort, node);
948 // TODO: add logic to only add rule on remote nodes
949 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
950 attachedMac, ethOFPort);
951 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
952 attachedMac, localPort, ethOFPort);
955 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
956 boolean isLastInstanceOnNode) {
957 LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
958 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
959 long dpid = getIntegrationBridgeOFDPID(node);
961 LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
965 long localPort = southbound.getOFPort(intf);
966 if (localPort == 0) {
967 LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
971 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
972 if (attachedMac == null) {
973 LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
978 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
979 long ethOFPort = southbound.getOFPort(node, phyIfName);
980 if (ethOFPort == 0) {
981 LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
984 LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
985 phyIfName, ethOFPort, node);
987 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
988 attachedMac, localPort, ethOFPort);
989 if (isLastInstanceOnNode) {
990 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
994 private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
995 Long dpid,long localPort, String segmentationId,
998 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
999 boolean isPortSecurityEnabled = securityServicesManager.isPortSecurityEnabled(intf);
1000 if (!isPortSecurityEnabled) {
1001 LOG.info("Port security is not enabled" + intf);
1004 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId nodeId = node.getNodeId();
1005 NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
1006 List<Neutron_IPs> srcAddressList = null;
1007 if (null != dhcpPort) {
1008 srcAddressList = securityServicesManager.getIpAddressList(intf);
1009 if (null == srcAddressList) {
1010 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1013 ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1014 attachedMac, write);
1015 egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1016 srcAddressList, write);
1017 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
1018 /* TODO SB_MIGRATION */
1020 LOG.debug("Neutron port has a Port Security Group");
1021 // Retrieve the security group from the Neutron Port and apply the rules
1022 List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
1023 .getSecurityGroupInPortList(intf);
1024 String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
1025 Constants.EXTERNAL_ID_INTERFACE_ID);
1026 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1027 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1028 securityGroupInPort, neutronPortId, nodeId, write);
1029 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1030 securityGroupInPort, neutronPortId, nodeId, write);
1034 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1039 * The function is for the new compute node joining the existing network.
1040 * When a new VM is instantiated in the new compute node, neutron port add
1041 * event is generated. This event is processed only for that node. So,
1042 * loop through all the ports of the same network and install unicast mac
1043 * flow for the VM's created on the TEP of the destination node in src node.
1044 * This function will be executed even for any new VM creation in an existing
1045 * network. If a cache is maintained to optimize the below flow addition, it will
1046 * work only for one unstack and restack. For the next unstack and restack,
1047 * it will not work since the cache would have been already deleted.
1049 private void programTunnelRulesInNewNode(NeutronNetwork network,
1050 String networkType, String segmentationId,
1051 InetAddress src, InetAddress dst,
1052 Node srcBridgeNode, Node dstBridgeNode,
1053 OvsdbTerminationPointAugmentation intf){
1054 LOG.debug("programTunnelRulesInNewNode: network {} networkType {} segId {} src {} dst {} srcBridgeNode {} dstBridgeNode {} intf {}",
1055 network.getNetworkName(), networkType, segmentationId, src.getHostAddress(),
1056 dst.getHostAddress(), srcBridgeNode, dstBridgeNode, intf);
1058 long localPort = southbound.getOFPort(intf);
1061 LOG.debug("Interface update details {}", intf);
1064 * When a network is added and the TEP destination is not present in a
1065 * node C1, tunnelin and broadcast rules will not be programmed, since
1066 * OF port is not created. So, when a new node C2 joins and create a new
1067 * VM, the tunnelin and broadcast rule will not be present in C1.
1068 * So, handling it in the case below to make ping work.
1070 if (securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1071 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1075 * FIX for 4208 - loop through all the ports and add the VM's
1076 * unicast mac rule of the destination node in the source node.
1077 * When a new node is added, it needs to configure the VM unicast mac
1078 * flow rules which were created before it was joined to an existing
1081 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1082 for (OvsdbTerminationPointAugmentation port : ports) {
1084 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1085 if (neutronNetwork != null) {
1086 String netType = neutronNetwork.getProviderNetworkType();
1087 String segId = neutronNetwork.getProviderSegmentationID();
1088 InetAddress dstAddr = configurationService.getTunnelEndPoint(dstBridgeNode);
1090 if (segId != null && netType != null && dstAddr != null) {
1091 programTunnelRules(netType, segId, dstAddr, srcBridgeNode, port, false);
1095 if (network == tenantNetworkManager.getTenantNetwork(port)){
1096 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1099 LOG.trace("Port {} is not part of network {}", port, network);
1103 } catch (Exception e) {
1104 LOG.error("Exception during handlingNeutron network add", e);
1108 private boolean bridgeHasVmPort(Node bridgeNode) {
1109 String intBridgeName = configurationService.getIntegrationBridgeName();
1110 String extBridgeName = configurationService.getExternalBridgeName();
1111 List<TerminationPoint> terminationPoints = bridgeNode.getTerminationPoint();
1112 if (terminationPoints == null) return false;
1114 for (TerminationPoint tp : terminationPoints) {
1115 String tpName = tp.getTpId().getValue();
1116 if (tpName != null && !tpName.equals(intBridgeName) && !tpName.equals(extBridgeName)) {
1117 OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1118 if (tpAug != null && southbound.getOFPort(tpAug) != 0) {
1128 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
1129 LOG.debug("handleInterfaceUpdate: network: {} srcNode: {}, intf: {}",
1130 network.getProviderSegmentationID(), srcNode.getNodeId(), intf.getName());
1131 Preconditions.checkNotNull(nodeCacheManager);
1133 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId srcNodeId =
1134 srcNode.getNodeId();
1135 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1136 nodeCacheManager.getOvsdbNodes();
1138 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1139 String networkType = network.getProviderNetworkType();
1140 String segmentationId = network.getProviderSegmentationID();
1141 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1143 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1145 if (isVlan(networkType)) {
1146 programVlanRules(network, srcNode, intf);
1147 } else if (isTunnel(networkType)){
1149 boolean sourceTunnelStatus = false;
1150 boolean destTunnelStatus = false;
1151 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1152 for (Node dstNode : nodes.values()) {
1153 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1154 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1155 if ((src != null) && (dst != null)) {
1156 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1158 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1159 configurationService.getIntegrationBridgeName());
1161 if (dstBridgeNode != null) {
1162 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1164 if (sourceTunnelStatus && destTunnelStatus) {
1165 LOG.debug("Created Source and destination TunnelPorts :{}, {}", src, dst);
1167 LOG.debug("Source and destination TunnelPort status :{}, {}", sourceTunnelStatus, destTunnelStatus);
1169 if (sourceTunnelStatus) {
1170 boolean isDestinNw = tenantNetworkManager.isTenantNetworkPresentInNode(dstBridgeNode, segmentationId);
1171 //Check whether the network is present in src & dst node
1172 //If only present , add vxlan ports in TunnelRules for both nodes (bug# 5614)
1173 if (isSrcinNw && isDestinNw) {
1174 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1175 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1176 } else if (configurationService.isRemoteMacLearnEnabled()) {
1177 //Even if to learn remote MAC, a network doesn't exist in a node,
1178 //a vxlan port is added in TunnelRules for both nodes.(bug# 6474)
1179 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1182 if (destTunnelStatus) {
1183 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1185 if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
1186 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1187 srcBridgeNode, dstBridgeNode, intf);
1188 intBridgesWithoutVmPorts.remove(srcNodeId);
1192 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1193 + "Check source {} or destination {}",
1194 src != null ? src.getHostAddress() : "null",
1195 dst != null ? dst.getHostAddress() : "null");
1200 if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
1201 intBridgesWithoutVmPorts.add(srcNodeId);
1207 private void triggerInterfaceUpdates(Node node) {
1208 LOG.debug("enter triggerInterfaceUpdates for : {}", node.getNodeId());
1209 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1210 if (ports != null && !ports.isEmpty()) {
1211 for (OvsdbTerminationPointAugmentation port : ports) {
1212 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1213 if (neutronNetwork != null) {
1214 LOG.warn("Trigger Interface update for {}", port);
1215 handleInterfaceUpdate(neutronNetwork, node, port);
1219 LOG.warn("triggerInterfaceUpdates: tps are null");
1221 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1225 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1226 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1227 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1228 nodeCacheManager.getOvsdbNodes();
1229 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1231 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1232 String segmentationId = network.getProviderSegmentationID();
1233 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1234 if (southbound.isTunnel(intf)) {
1235 // Delete tunnel port
1237 InetAddress src = InetAddress.getByName(
1238 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1239 InetAddress dst = InetAddress.getByName(
1240 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1241 deleteTunnelPort(srcNode,
1242 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1244 } catch (Exception e) {
1245 LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
1247 } else if (phyIfName.contains(intf.getName())) {
1248 deletePhysicalPort(srcNode, intf.getName());
1250 // delete all other interfaces
1251 removeLocalRules(network.getProviderNetworkType(), segmentationId,
1254 if (isVlan(network.getProviderNetworkType())) {
1255 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1256 } else if (isTunnel(network.getProviderNetworkType())) {
1258 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1259 for (Node dstNode : nodes.values()) {
1260 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1261 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1262 if ((src != null) && (dst != null)) {
1263 LOG.info("Remove tunnel rules for interface "
1264 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1265 removeTunnelRules(tunnelType, segmentationId,
1266 dst, srcNode, intf, true, isLastInstanceOnNode);
1267 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1268 //While removing last instance , check whether the network present in src node
1269 //If network is not present in src node AND REMOTE MAC LEARNING IS not enabled,
1270 //remove the vxlan port of src from dst node in TunnelRules(Bug# 5614)
1271 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1272 if (dstBridgeNode != null) {
1273 //To learn remote MAC, also to make the flooding the node by which a network
1274 //doesn't exist in a node, TunnelRules leaves it.
1275 if (!isSrcinNw && !configurationService.isRemoteMacLearnEnabled()) {
1276 removeTunnelRules(tunnelType, segmentationId,
1277 src, dstBridgeNode, intf, true, isLastInstanceOnNode);
1279 LOG.info("Remove tunnel rules for interface "
1280 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1281 removeTunnelRules(tunnelType, segmentationId, src,
1282 dstBridgeNode, intf, false, isLastInstanceOnNode);
1285 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1286 + "OpenVSwitch Table. "
1287 + "Check source {} or destination {}",
1288 src != null ? src.getHostAddress() : "null",
1289 dst != null ? dst.getHostAddress() : "null");
1298 public void initializeFlowRules(Node node) {
1299 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1300 initializeFlowRules(node, configurationService.getExternalBridgeName());
1301 triggerInterfaceUpdates(node);
1304 private void initializeFlowRules(Node node, String bridgeName) {
1305 Long dpid = southbound.getDataPathId(node);
1306 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1307 resubmitAclLearnProvider.programResubmit(dpid);
1309 String datapathId = southbound.getDatapathId(node);
1310 LOG.trace("initializeFlowRules: bridgeName: {}, datapathId: {} ",
1311 bridgeName, datapathId);
1312 String brExt = null;
1315 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1322 * Match: LLDP (0x88CCL)
1323 * Action: Packet_In to Controller Reserved Port
1326 writeLLDPRule(dpid);
1329 * Table(105) Rule #1
1330 * -------------------
1332 * Action: learn and goto next table
1335 writeL2ForwardingLearnRule(dpid);
1337 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
1338 NetvirtProvidersProvider.getTableOffset() != 0) {
1339 classifierProvider.programGotoTable(dpid,true);
1342 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1343 brExt = bridgeConfigurationManager.getMultipleExternalBridge(node);
1345 if (bridgeName.equals(configurationService.getExternalBridgeName()) ||
1346 (bridgeName.equals(brExt))) {
1347 writeNormalRule(dpid);
1352 * Create an LLDP Flow Rule to encapsulate into
1353 * a packet_in that is sent to the controller
1354 * for topology handling.
1355 * Match: Ethertype 0x88CCL
1356 * Action: Punt to Controller in a Packet_In msg
1359 private void writeLLDPRule(Long dpidLong) {
1360 classifierProvider.programLLDPPuntRule(dpidLong);
1364 * Create an L2Forwarding mac learn Flow Rule
1365 * Match: reg0 = ClassifierService.REG_VALUE_FROM_REMOTE
1366 * Action: learn and goto next table
1369 private void writeL2ForwardingLearnRule(Long dpidLong) {
1370 if (configurationService.isRemoteMacLearnEnabled()) {
1371 l2ForwardingLearnProvider.programL2ForwardingLearnRule(dpidLong);
1376 * Create a NORMAL Table Miss Flow Rule
1378 * Action: forward to NORMAL pipeline
1381 private void writeNormalRule(Long dpidLong) {
1382 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1383 FlowBuilder flowBuilder = new FlowBuilder();
1384 String flowName = "NORMAL";
1385 FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
1386 MatchBuilder matchBuilder = new MatchBuilder();
1387 flowBuilder.setMatch(matchBuilder.build());
1389 // Create the OF Actions and Instructions
1390 InstructionBuilder ib = new InstructionBuilder();
1391 InstructionsBuilder isb = new InstructionsBuilder();
1393 // Instructions List Stores Individual Instructions
1394 List<Instruction> instructions = new ArrayList<>();
1396 // Call the InstructionBuilder Methods Containing Actions
1397 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1399 ib.setKey(new InstructionKey(0));
1400 instructions.add(ib.build());
1402 // Add InstructionBuilder to the Instruction(s)Builder List
1403 isb.setInstruction(instructions);
1405 // Add InstructionsBuilder to FlowBuilder
1406 flowBuilder.setInstructions(isb.build());
1407 writeFlow(flowBuilder, nodeBuilder);
1411 * (Table:0) Ingress Tunnel Traffic
1412 * Match: OpenFlow InPort and Tunnel ID
1413 * Action: GOTO Local Table (10)
1414 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1417 private void handleTunnelIn(Long dpidLong, Short writeTable,
1418 Short goToTableId, String segmentationId,
1419 Long ofPort, boolean write) {
1420 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1424 * (Table:0) Ingress VLAN Traffic
1425 * Match: OpenFlow InPort and vlan ID
1426 * Action: GOTO Local Table (20)
1427 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1430 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1431 String segmentationId, Long ethPort, boolean write) {
1432 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1436 * (Table:0) Egress VM Traffic Towards TEP
1437 * Match: Destination Ethernet Addr and OpenFlow InPort
1438 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1439 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1440 * actions=set_field:5->tun_id,goto_table=1"
1443 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1444 String segmentationId, Long inPort, String attachedMac,
1446 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1450 * (Table:0) Egress VM Traffic Towards TEP
1451 * Match: Source Ethernet Addr and OpenFlow InPort
1452 * Instruction: Set VLANID and GOTO Table Egress (n)
1453 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1454 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1457 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1458 Short goToTableId, String segmentationId,
1459 Long inPort, String attachedMac,
1461 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1465 * (Table:0) Drop frames source from a VM that do not
1466 * match the associated MAC address of the local VM.
1467 * Match: Low priority anything not matching the VM SMAC
1469 * table=0,priority=16384,in_port=1 actions=drop"
1472 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1473 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1477 * (Table:1) Egress Tunnel Traffic
1478 * Match: Destination Ethernet Addr and Local InPort
1479 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1480 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1481 * actions=output:10,goto_table:2"
1483 private void handleTunnelOut(Long dpidLong, Short writeTable,
1484 Short goToTableId, String segmentationId,
1485 Long OFPortOut, String attachedMac,
1487 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1491 * (Table:1) Egress VLAN Traffic
1492 * Match: Destination Ethernet Addr and VLAN id
1493 * Instruction: GOTO Table Table 2
1494 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1495 * actions= goto_table:2"
1497 // TODO This method is referenced from commented code above (which needs to be checked)
1498 @SuppressWarnings("unused")
1499 private void handleVlanOut(Long dpidLong, Short writeTable,
1500 Short goToTableId, String segmentationId,
1501 Long ethPort, String attachedMac, boolean write) {
1502 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1506 * (Table:1) Egress Tunnel Traffic
1507 * Match: Destination Ethernet Addr and Local InPort
1508 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1509 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1510 * actions=output:10,output:11,goto_table:2
1513 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1514 Short localTable, String segmentationId,
1515 Long OFPortOut, boolean write) {
1516 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1520 * (Table:110) Flooding local unknown unicast Traffic
1521 * Match: TunnelID and Unknown unicast and Local InPort
1522 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1523 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
1524 * actions=output:10,output:11
1527 private void handleTunnelUnknownUcastFloodOut(Long dpidLong, Short writeTable,
1528 Short localTable, String segmentationId,
1529 Long OFPortOut, boolean write) {
1530 if (configurationService.isRemoteMacLearnEnabled()) {
1531 l2ForwardingProvider.programTunnelUnknownUcastFloodOut(dpidLong, segmentationId, OFPortOut, write);
1536 * (Table:1) Egress VLAN Traffic
1537 * Match: Destination Ethernet Addr and VLAN id
1538 * Instruction: GOTO table 2 and Output port eth interface
1539 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1540 * actions=output:eth1,goto_table:2
1542 // TODO This method is referenced from commented code above (which needs to be checked)
1543 @SuppressWarnings("unused")
1544 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1545 Short localTable, String segmentationId,
1546 Long localPort, Long ethPort, boolean write) {
1547 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1551 * (Table:1) Table Drain w/ Catch All
1553 * Action: Output port eth interface
1554 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1555 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1558 private void handleVlanMiss(Long dpidLong, Short writeTable,
1559 Short goToTableId, String segmentationId,
1560 Long ethPort, boolean write) {
1561 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1565 * (Table:1) Local Broadcast Flood
1566 * Match: Tunnel ID and dMAC
1567 * Action: Output Port
1568 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1571 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1572 String segmentationId, Long localPort,
1573 String attachedMac, boolean write) {
1574 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1578 * (Table:2) Local VLAN unicast
1579 * Match: VLAN ID and dMAC
1580 * Action: Output Port
1581 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1584 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1585 String segmentationId, Long localPort,
1586 String attachedMac, boolean write) {
1587 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1591 * (Table:2) Local Broadcast Flood
1592 * Match: Tunnel ID and dMAC (::::FF:FF)
1593 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1594 * actions=output:2,3,4,5
1597 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1598 String segmentationId, Long localPort,
1600 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1604 * (Table:2) Local VLAN Broadcast Flood
1605 * Match: vlan ID and dMAC (::::FF:FF)
1606 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1607 * actions=strip_vlan, output:2,3,4,5
1608 * 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
1611 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1612 Long localPort, Long ethPort, boolean write) {
1613 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1617 * (Table:1) Local Table Miss
1618 * Match: Any Remaining Flows w/a VLAN ID
1619 * Action: Drop w/ a low priority
1620 * table=2,priority=8192,vlan_id=0x5 actions=drop
1622 // TODO This method is referenced from commented code above (which needs to be checked)
1623 @SuppressWarnings("unused")
1624 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1625 String segmentationId, boolean write) {
1626 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1629 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1630 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1631 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1632 new GroupKey(groupBuilder.getGroupId())).build();
1633 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1635 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1636 if (data.isPresent()) {
1639 } catch (InterruptedException|ExecutionException e) {
1640 LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
1643 LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
1647 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1648 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1649 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1650 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1651 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1652 new GroupKey(groupBuilder.getGroupId())).build();
1653 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1655 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1657 commitFuture.get(); // TODO: Make it async (See bug 1362)
1658 LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
1659 } catch (InterruptedException|ExecutionException e) {
1660 LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
1665 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1666 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1667 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1668 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1669 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1670 new GroupKey(groupBuilder.getGroupId())).build();
1671 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1672 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1675 commitFuture.get(); // TODO: Make it async (See bug 1362)
1676 LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
1677 } catch (InterruptedException|ExecutionException e) {
1678 LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
1683 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1684 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1685 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1686 InstanceIdentifier<Flow> path1 =
1687 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1688 .rev130819.nodes.Node.class,
1689 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1690 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1692 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1693 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1694 true);//createMissingParents
1697 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1699 commitFuture.get(); // TODO: Make it async (See bug 1362)
1700 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
1701 } catch (InterruptedException|ExecutionException e) {
1702 LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
1708 * Create Output Port Group Instruction
1710 * @param nodeBuilder Node Builder
1711 * @param ib Map InstructionBuilder without any instructions
1712 * @param dpidLong Long the datapath ID of a switch/node
1713 * @param port Long representing a port on a switch/node
1714 * @param instructions List of instructions
1715 * @return ib InstructionBuilder Map with instructions
1717 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1718 @SuppressWarnings("unused")
1719 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1720 InstructionBuilder ib,
1721 Long dpidLong, Long port ,
1722 List<Instruction> instructions) {
1723 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1724 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1726 List<Action> actionList = new ArrayList<>();
1727 ActionBuilder ab = new ActionBuilder();
1729 List<Action> existingActions;
1730 if (instructions != null) {
1731 for (Instruction in : instructions) {
1732 if (in.getInstruction() instanceof ApplyActionsCase) {
1733 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1734 actionList.addAll(existingActions);
1739 GroupBuilder groupBuilder = new GroupBuilder();
1742 /* Create output action for this port*/
1743 OutputActionBuilder oab = new OutputActionBuilder();
1744 oab.setOutputNodeConnector(ncid);
1745 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1746 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1747 boolean addNew = true;
1748 boolean groupActionAdded = false;
1750 /* Find the group action and get the group */
1751 for (Action action : actionList) {
1752 if (action.getAction() instanceof GroupActionCase) {
1753 groupActionAdded = true;
1754 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1755 Long id = groupAction.getGroupAction().getGroupId();
1756 String groupName = groupAction.getGroupAction().getGroup();
1757 GroupKey key = new GroupKey(new GroupId(id));
1759 groupBuilder.setGroupId(new GroupId(id));
1760 groupBuilder.setGroupName(groupName);
1761 groupBuilder.setGroupType(GroupTypes.GroupAll);
1762 groupBuilder.setKey(key);
1763 group = getGroup(groupBuilder, nodeBuilder);
1764 LOG.debug("createOutputGroupInstructions: group {}", group);
1769 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1770 if (groupActionAdded) {
1771 /* modify the action bucket in group */
1772 groupBuilder = new GroupBuilder(group);
1773 Buckets buckets = groupBuilder.getBuckets();
1774 for (Bucket bucket : buckets.getBucket()) {
1775 List<Action> bucketActions = bucket.getAction();
1776 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1777 for (Action action : bucketActions) {
1778 if (action.getAction() instanceof OutputActionCase) {
1779 OutputActionCase opAction = (OutputActionCase)action.getAction();
1780 /* If output port action already in the action list of one of the buckets, skip */
1781 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1788 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1789 if (addNew && !buckets.getBucket().isEmpty()) {
1790 /* the new output action is not in the bucket, add to bucket */
1791 Bucket bucket = buckets.getBucket().get(0);
1792 List<Action> bucketActionList = new ArrayList<>();
1793 bucketActionList.addAll(bucket.getAction());
1794 /* set order for new action and add to action list */
1795 ab.setOrder(bucketActionList.size());
1796 ab.setKey(new ActionKey(bucketActionList.size()));
1797 bucketActionList.add(ab.build());
1799 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1800 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1801 List<Bucket> bucketList = new ArrayList<>();
1802 BucketBuilder bucketBuilder = new BucketBuilder();
1803 bucketBuilder.setBucketId(new BucketId((long) 1));
1804 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1805 bucketBuilder.setAction(bucketActionList);
1806 bucketList.add(bucketBuilder.build());
1807 bucketsBuilder.setBucket(bucketList);
1808 groupBuilder.setBuckets(bucketsBuilder.build());
1809 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1813 groupBuilder = new GroupBuilder();
1814 groupBuilder.setGroupType(GroupTypes.GroupAll);
1815 groupBuilder.setGroupId(new GroupId(groupId));
1816 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1817 groupBuilder.setGroupName("Output port group " + groupId);
1818 groupBuilder.setBarrier(false);
1820 BucketsBuilder bucketBuilder = new BucketsBuilder();
1821 List<Bucket> bucketList = new ArrayList<>();
1822 BucketBuilder bucket = new BucketBuilder();
1823 bucket.setBucketId(new BucketId((long) 1));
1824 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1826 /* put output action to the bucket */
1827 List<Action> bucketActionList = new ArrayList<>();
1828 /* set order for new action and add to action list */
1829 ab.setOrder(bucketActionList.size());
1830 ab.setKey(new ActionKey(bucketActionList.size()));
1831 bucketActionList.add(ab.build());
1833 bucket.setAction(bucketActionList);
1834 bucketList.add(bucket.build());
1835 bucketBuilder.setBucket(bucketList);
1836 groupBuilder.setBuckets(bucketBuilder.build());
1838 /* Add new group action */
1839 GroupActionBuilder groupActionB = new GroupActionBuilder();
1840 groupActionB.setGroupId(groupId);
1841 groupActionB.setGroup("Output port group " + groupId);
1842 ab = new ActionBuilder();
1843 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1844 ab.setOrder(actionList.size());
1845 ab.setKey(new ActionKey(actionList.size()));
1846 actionList.add(ab.build());
1850 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1851 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1854 /* rewrite the group to group table */
1855 writeGroup(groupBuilder, nodeBuilder);
1858 // Create an Apply Action
1859 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1860 aab.setAction(actionList);
1861 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1867 * Remove Output Port from action list in group bucket
1869 * @param nodeBuilder Node Builder
1870 * @param ib Map InstructionBuilder without any instructions
1871 * @param dpidLong Long the datapath ID of a switch/node
1872 * @param port Long representing a port on a switch/node
1873 * @param instructions List of instructions
1874 * @return ib InstructionBuilder Map with instructions
1876 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1877 @SuppressWarnings("unused")
1878 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1879 Long dpidLong, Long port , List<Instruction> instructions) {
1881 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1882 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1884 List<Action> actionList = new ArrayList<>();
1887 List<Action> existingActions;
1888 if (instructions != null) {
1889 for (Instruction in : instructions) {
1890 if (in.getInstruction() instanceof ApplyActionsCase) {
1891 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1892 actionList.addAll(existingActions);
1898 GroupBuilder groupBuilder = new GroupBuilder();
1900 boolean groupActionAdded = false;
1901 /* Find the group action and get the group */
1902 for (Action action : actionList) {
1903 if (action.getAction() instanceof GroupActionCase) {
1904 groupActionAdded = true;
1905 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1906 Long id = groupAction.getGroupAction().getGroupId();
1907 String groupName = groupAction.getGroupAction().getGroup();
1908 GroupKey key = new GroupKey(new GroupId(id));
1910 groupBuilder.setGroupId(new GroupId(id));
1911 groupBuilder.setGroupName(groupName);
1912 groupBuilder.setGroupType(GroupTypes.GroupAll);
1913 groupBuilder.setKey(key);
1914 group = getGroup(groupBuilder, nodeBuilder);
1919 if (groupActionAdded) {
1920 /* modify the action bucket in group */
1921 groupBuilder = new GroupBuilder(group);
1922 Buckets buckets = groupBuilder.getBuckets();
1923 List<Action> bucketActions = new ArrayList<>();
1924 for (Bucket bucket : buckets.getBucket()) {
1926 boolean isPortDeleted = false;
1927 bucketActions = bucket.getAction();
1928 for (Action action : bucketActions) {
1929 if (action.getAction() instanceof OutputActionCase) {
1930 OutputActionCase opAction = (OutputActionCase)action.getAction();
1931 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1932 /* Find the output port in action list and remove */
1933 index = bucketActions.indexOf(action);
1934 bucketActions.remove(action);
1935 isPortDeleted = true;
1940 if (isPortDeleted && !bucketActions.isEmpty()) {
1941 for (int i = index; i< bucketActions.size(); i++) {
1942 Action action = bucketActions.get(i);
1943 if (action.getOrder() != i) {
1944 /* Shift the action order */
1945 ab = new ActionBuilder();
1946 ab.setAction(action.getAction());
1948 ab.setKey(new ActionKey(i));
1949 Action actionNewOrder = ab.build();
1950 bucketActions.remove(action);
1951 bucketActions.add(i, actionNewOrder);
1955 } else if (bucketActions.isEmpty()) {
1956 /* remove bucket with empty action list */
1957 buckets.getBucket().remove(bucket);
1961 if (!buckets.getBucket().isEmpty()) {
1962 /* rewrite the group to group table */
1963 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1964 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1965 List<Bucket> bucketList = new ArrayList<>();
1966 BucketBuilder bucketBuilder = new BucketBuilder();
1967 bucketBuilder.setBucketId(new BucketId((long) 1));
1968 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1969 bucketBuilder.setAction(bucketActions);
1970 bucketList.add(bucketBuilder.build());
1971 bucketsBuilder.setBucket(bucketList);
1972 groupBuilder.setBuckets(bucketsBuilder.build());
1973 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1975 writeGroup(groupBuilder, nodeBuilder);
1976 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1977 aab.setAction(actionList);
1978 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1981 /* remove group with empty bucket. return true to delete flow */
1982 removeGroup(groupBuilder, nodeBuilder);
1986 /* no group for port list. flow can be removed */
1992 public void initializeOFFlowRules(Node openflowNode) {
1993 String bridgeName = southbound.getBridgeName(openflowNode);
1994 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1995 String brExt = null;
1996 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1997 brExt = bridgeConfigurationManager.getMultipleExternalBridge(openflowNode);
1999 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) ||
2000 bridgeName.equals(configurationService.getExternalBridgeName()) || bridgeName.equals(brExt)) {
2001 initializeFlowRules(openflowNode, bridgeName);
2002 triggerInterfaceUpdates(openflowNode);
2006 public static NodeBuilder createNodeBuilder(String nodeId) {
2007 NodeBuilder builder = new NodeBuilder();
2008 builder.setId(new NodeId(nodeId));
2009 builder.setKey(new NodeKey(builder.getId()));
2014 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
2015 this.bundleContext = bundleContext;
2016 configurationService =
2017 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
2018 tenantNetworkManager =
2019 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
2020 bridgeConfigurationManager =
2021 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
2023 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
2024 resubmitAclLearnProvider =
2025 (ResubmitAclLearnProvider) ServiceHelper.getGlobalInstance(ResubmitAclLearnProvider.class, this);
2026 classifierProvider =
2027 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
2028 ingressAclProvider =
2029 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
2031 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
2032 l2ForwardingLearnProvider =
2033 (L2ForwardingLearnProvider) ServiceHelper.getGlobalInstance(L2ForwardingLearnProvider.class, this);
2034 l2ForwardingProvider =
2035 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
2036 securityServicesManager =
2037 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
2039 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
2043 public void setDependencies(Object impl) {
2044 if (impl instanceof NetworkingProviderManager) {
2045 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
2046 networkingProviderManager.providerAdded(
2047 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);