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);
1097 if (network == tenantNetworkManager.getTenantNetwork(port)){
1098 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1101 LOG.trace("Port {} is not part of network {}", port, network);
1105 } catch (Exception e) {
1106 LOG.error("Exception during handlingNeutron network add", e);
1110 private boolean bridgeHasVmPort(Node bridgeNode) {
1111 String intBridgeName = configurationService.getIntegrationBridgeName();
1112 String extBridgeName = configurationService.getExternalBridgeName();
1113 List<TerminationPoint> terminationPoints = bridgeNode.getTerminationPoint();
1114 if (terminationPoints == null) return false;
1116 for (TerminationPoint tp : terminationPoints) {
1117 String tpName = tp.getTpId().getValue();
1118 if (tpName != null && !tpName.equals(intBridgeName) && !tpName.equals(extBridgeName)) {
1119 OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1120 if (tpAug != null && southbound.getOFPort(tpAug) != 0) {
1130 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
1131 LOG.debug("handleInterfaceUpdate: network: {} srcNode: {}, intf: {}",
1132 network.getProviderSegmentationID(), srcNode.getNodeId(), intf.getName());
1133 Preconditions.checkNotNull(nodeCacheManager);
1135 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId srcNodeId =
1136 srcNode.getNodeId();
1137 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1138 nodeCacheManager.getOvsdbNodes();
1140 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1141 String networkType = network.getProviderNetworkType();
1142 String segmentationId = network.getProviderSegmentationID();
1143 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1145 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1147 if (isVlan(networkType)) {
1148 programVlanRules(network, srcNode, intf);
1149 } else if (isTunnel(networkType)){
1151 boolean sourceTunnelStatus = false;
1152 boolean destTunnelStatus = false;
1153 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1154 for (Node dstNode : nodes.values()) {
1155 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1156 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1157 if ((src != null) && (dst != null)) {
1158 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1160 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1161 configurationService.getIntegrationBridgeName());
1163 if (dstBridgeNode != null) {
1164 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1166 if (sourceTunnelStatus && destTunnelStatus) {
1167 LOG.debug("Created Source and destination TunnelPorts :{}, {}", src, dst);
1169 LOG.debug("Source and destination TunnelPort status :{}, {}", sourceTunnelStatus, destTunnelStatus);
1171 if (sourceTunnelStatus) {
1172 boolean isDestinNw = tenantNetworkManager.isTenantNetworkPresentInNode(dstBridgeNode, segmentationId);
1173 //Check whether the network is present in src & dst node
1174 //If only present , add vxlan ports in TunnelRules for both nodes (bug# 5614)
1175 if (isSrcinNw && isDestinNw) {
1176 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1177 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1178 } else if (configurationService.isRemoteMacLearnEnabled()) {
1179 //Even if to learn remote MAC, a network doesn't exist in a node,
1180 //a vxlan port is added in TunnelRules for both nodes.(bug# 6474)
1181 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1184 if (destTunnelStatus) {
1185 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1187 if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
1188 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1189 srcBridgeNode, dstBridgeNode, intf);
1190 intBridgesWithoutVmPorts.remove(srcNodeId);
1194 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1195 + "Check source {} or destination {}",
1196 src != null ? src.getHostAddress() : "null",
1197 dst != null ? dst.getHostAddress() : "null");
1202 if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
1203 intBridgesWithoutVmPorts.add(srcNodeId);
1209 private void triggerInterfaceUpdates(Node node) {
1210 LOG.debug("enter triggerInterfaceUpdates for : {}", node.getNodeId());
1211 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1212 if (ports != null && !ports.isEmpty()) {
1213 for (OvsdbTerminationPointAugmentation port : ports) {
1214 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1215 if (neutronNetwork != null) {
1216 LOG.warn("Trigger Interface update for {}", port);
1217 handleInterfaceUpdate(neutronNetwork, node, port);
1221 LOG.warn("triggerInterfaceUpdates: tps are null");
1223 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1227 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1228 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1229 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1230 nodeCacheManager.getOvsdbNodes();
1231 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1233 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1234 String segmentationId = network.getProviderSegmentationID();
1235 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1236 if (southbound.isTunnel(intf)) {
1237 // Delete tunnel port
1239 InetAddress src = InetAddress.getByName(
1240 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1241 InetAddress dst = InetAddress.getByName(
1242 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1243 deleteTunnelPort(srcNode,
1244 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1246 } catch (Exception e) {
1247 LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
1249 } else if (phyIfName.contains(intf.getName())) {
1250 deletePhysicalPort(srcNode, intf.getName());
1252 // delete all other interfaces
1253 removeLocalRules(network.getProviderNetworkType(), segmentationId,
1256 if (isVlan(network.getProviderNetworkType())) {
1257 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1258 } else if (isTunnel(network.getProviderNetworkType())) {
1260 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1261 for (Node dstNode : nodes.values()) {
1262 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1263 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1264 if ((src != null) && (dst != null)) {
1265 LOG.info("Remove tunnel rules for interface "
1266 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1267 removeTunnelRules(tunnelType, segmentationId,
1268 dst, srcNode, intf, true, isLastInstanceOnNode);
1269 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1270 //While removing last instance , check whether the network present in src node
1271 //If network is not present in src node AND REMOTE MAC LEARNING IS not enabled,
1272 //remove the vxlan port of src from dst node in TunnelRules(Bug# 5614)
1273 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1274 if (dstBridgeNode != null) {
1275 //To learn remote MAC, also to make the flooding the node by which a network
1276 //doesn't exist in a node, TunnelRules leaves it.
1277 if (!isSrcinNw && !configurationService.isRemoteMacLearnEnabled()) {
1278 removeTunnelRules(tunnelType, segmentationId,
1279 src, dstBridgeNode, intf, true, isLastInstanceOnNode);
1281 LOG.info("Remove tunnel rules for interface "
1282 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1283 removeTunnelRules(tunnelType, segmentationId, src,
1284 dstBridgeNode, intf, false, isLastInstanceOnNode);
1287 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1288 + "OpenVSwitch Table. "
1289 + "Check source {} or destination {}",
1290 src != null ? src.getHostAddress() : "null",
1291 dst != null ? dst.getHostAddress() : "null");
1300 public void initializeFlowRules(Node node) {
1301 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1302 initializeFlowRules(node, configurationService.getExternalBridgeName());
1303 triggerInterfaceUpdates(node);
1306 private void initializeFlowRules(Node node, String bridgeName) {
1307 Long dpid = southbound.getDataPathId(node);
1308 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1309 resubmitAclLearnProvider.programResubmit(dpid);
1311 String datapathId = southbound.getDatapathId(node);
1312 LOG.trace("initializeFlowRules: bridgeName: {}, datapathId: {} ",
1313 bridgeName, datapathId);
1314 String brExt = null;
1317 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1324 * Match: LLDP (0x88CCL)
1325 * Action: Packet_In to Controller Reserved Port
1328 writeLLDPRule(dpid);
1331 * Table(105) Rule #1
1332 * -------------------
1334 * Action: learn and goto next table
1337 writeL2ForwardingLearnRule(dpid);
1339 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
1340 NetvirtProvidersProvider.getTableOffset() != 0) {
1341 classifierProvider.programGotoTable(dpid,true);
1344 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1345 brExt = bridgeConfigurationManager.getMultipleExternalBridge(node);
1347 if (bridgeName.equals(configurationService.getExternalBridgeName()) ||
1348 (bridgeName.equals(brExt))) {
1349 writeNormalRule(dpid);
1354 * Create an LLDP Flow Rule to encapsulate into
1355 * a packet_in that is sent to the controller
1356 * for topology handling.
1357 * Match: Ethertype 0x88CCL
1358 * Action: Punt to Controller in a Packet_In msg
1361 private void writeLLDPRule(Long dpidLong) {
1362 classifierProvider.programLLDPPuntRule(dpidLong);
1366 * Create an L2Forwarding mac learn Flow Rule
1367 * Match: reg0 = ClassifierService.REG_VALUE_FROM_REMOTE
1368 * Action: learn and goto next table
1371 private void writeL2ForwardingLearnRule(Long dpidLong) {
1372 if (configurationService.isRemoteMacLearnEnabled()) {
1373 l2ForwardingLearnProvider.programL2ForwardingLearnRule(dpidLong);
1378 * Create a NORMAL Table Miss Flow Rule
1380 * Action: forward to NORMAL pipeline
1383 private void writeNormalRule(Long dpidLong) {
1384 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1385 FlowBuilder flowBuilder = new FlowBuilder();
1386 String flowName = "NORMAL";
1387 FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
1388 MatchBuilder matchBuilder = new MatchBuilder();
1389 flowBuilder.setMatch(matchBuilder.build());
1391 // Create the OF Actions and Instructions
1392 InstructionBuilder ib = new InstructionBuilder();
1393 InstructionsBuilder isb = new InstructionsBuilder();
1395 // Instructions List Stores Individual Instructions
1396 List<Instruction> instructions = new ArrayList<>();
1398 // Call the InstructionBuilder Methods Containing Actions
1399 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1401 ib.setKey(new InstructionKey(0));
1402 instructions.add(ib.build());
1404 // Add InstructionBuilder to the Instruction(s)Builder List
1405 isb.setInstruction(instructions);
1407 // Add InstructionsBuilder to FlowBuilder
1408 flowBuilder.setInstructions(isb.build());
1409 writeFlow(flowBuilder, nodeBuilder);
1413 * (Table:0) Ingress Tunnel Traffic
1414 * Match: OpenFlow InPort and Tunnel ID
1415 * Action: GOTO Local Table (10)
1416 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1419 private void handleTunnelIn(Long dpidLong, Short writeTable,
1420 Short goToTableId, String segmentationId,
1421 Long ofPort, boolean write) {
1422 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1426 * (Table:0) Ingress VLAN Traffic
1427 * Match: OpenFlow InPort and vlan ID
1428 * Action: GOTO Local Table (20)
1429 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1432 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1433 String segmentationId, Long ethPort, boolean write) {
1434 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1438 * (Table:0) Egress VM Traffic Towards TEP
1439 * Match: Destination Ethernet Addr and OpenFlow InPort
1440 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1441 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1442 * actions=set_field:5->tun_id,goto_table=1"
1445 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1446 String segmentationId, Long inPort, String attachedMac,
1448 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1452 * (Table:0) Egress VM Traffic Towards TEP
1453 * Match: Source Ethernet Addr and OpenFlow InPort
1454 * Instruction: Set VLANID and GOTO Table Egress (n)
1455 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1456 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1459 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1460 Short goToTableId, String segmentationId,
1461 Long inPort, String attachedMac,
1463 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1467 * (Table:0) Drop frames source from a VM that do not
1468 * match the associated MAC address of the local VM.
1469 * Match: Low priority anything not matching the VM SMAC
1471 * table=0,priority=16384,in_port=1 actions=drop"
1474 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1475 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1479 * (Table:1) Egress Tunnel Traffic
1480 * Match: Destination Ethernet Addr and Local InPort
1481 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1482 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1483 * actions=output:10,goto_table:2"
1485 private void handleTunnelOut(Long dpidLong, Short writeTable,
1486 Short goToTableId, String segmentationId,
1487 Long OFPortOut, String attachedMac,
1489 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1493 * (Table:1) Egress VLAN Traffic
1494 * Match: Destination Ethernet Addr and VLAN id
1495 * Instruction: GOTO Table Table 2
1496 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1497 * actions= goto_table:2"
1499 // TODO This method is referenced from commented code above (which needs to be checked)
1500 @SuppressWarnings("unused")
1501 private void handleVlanOut(Long dpidLong, Short writeTable,
1502 Short goToTableId, String segmentationId,
1503 Long ethPort, String attachedMac, boolean write) {
1504 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1508 * (Table:1) Egress Tunnel Traffic
1509 * Match: Destination Ethernet Addr and Local InPort
1510 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1511 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1512 * actions=output:10,output:11,goto_table:2
1515 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1516 Short localTable, String segmentationId,
1517 Long OFPortOut, boolean write) {
1518 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1522 * (Table:110) Flooding local unknown unicast Traffic
1523 * Match: TunnelID and Unknown unicast and Local InPort
1524 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1525 * table=110,priority=16380,tun_id=0x5,dl_dst=00:00:00:00:00:00/01:00:00:00:00:00 \
1526 * actions=output:10,output:11
1529 private void handleTunnelUnknownUcastFloodOut(Long dpidLong, Short writeTable,
1530 Short localTable, String segmentationId,
1531 Long OFPortOut, boolean write) {
1532 if (configurationService.isRemoteMacLearnEnabled()) {
1533 l2ForwardingProvider.programTunnelUnknownUcastFloodOut(dpidLong, segmentationId, OFPortOut, write);
1538 * (Table:1) Egress VLAN Traffic
1539 * Match: Destination Ethernet Addr and VLAN id
1540 * Instruction: GOTO table 2 and Output port eth interface
1541 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1542 * actions=output:eth1,goto_table:2
1544 // TODO This method is referenced from commented code above (which needs to be checked)
1545 @SuppressWarnings("unused")
1546 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1547 Short localTable, String segmentationId,
1548 Long localPort, Long ethPort, boolean write) {
1549 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1553 * (Table:1) Table Drain w/ Catch All
1555 * Action: Output port eth interface
1556 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1557 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1560 private void handleVlanMiss(Long dpidLong, Short writeTable,
1561 Short goToTableId, String segmentationId,
1562 Long ethPort, boolean write) {
1563 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1567 * (Table:1) Local Broadcast Flood
1568 * Match: Tunnel ID and dMAC
1569 * Action: Output Port
1570 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1573 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1574 String segmentationId, Long localPort,
1575 String attachedMac, boolean write) {
1576 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1580 * (Table:2) Local VLAN unicast
1581 * Match: VLAN ID and dMAC
1582 * Action: Output Port
1583 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1586 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1587 String segmentationId, Long localPort,
1588 String attachedMac, boolean write) {
1589 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1593 * (Table:2) Local Broadcast Flood
1594 * Match: Tunnel ID and dMAC (::::FF:FF)
1595 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1596 * actions=output:2,3,4,5
1599 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1600 String segmentationId, Long localPort,
1602 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1606 * (Table:2) Local VLAN Broadcast Flood
1607 * Match: vlan ID and dMAC (::::FF:FF)
1608 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1609 * actions=strip_vlan, output:2,3,4,5
1610 * 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
1613 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1614 Long localPort, Long ethPort, boolean write) {
1615 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1619 * (Table:1) Local Table Miss
1620 * Match: Any Remaining Flows w/a VLAN ID
1621 * Action: Drop w/ a low priority
1622 * table=2,priority=8192,vlan_id=0x5 actions=drop
1624 // TODO This method is referenced from commented code above (which needs to be checked)
1625 @SuppressWarnings("unused")
1626 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1627 String segmentationId, boolean write) {
1628 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1631 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1632 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1633 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1634 new GroupKey(groupBuilder.getGroupId())).build();
1635 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1637 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1638 if (data.isPresent()) {
1641 } catch (InterruptedException|ExecutionException e) {
1642 LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
1645 LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
1649 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1650 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1651 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1652 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1653 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1654 new GroupKey(groupBuilder.getGroupId())).build();
1655 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1657 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1659 commitFuture.get(); // TODO: Make it async (See bug 1362)
1660 LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
1661 } catch (InterruptedException|ExecutionException e) {
1662 LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
1667 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1668 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1669 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1670 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1671 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1672 new GroupKey(groupBuilder.getGroupId())).build();
1673 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1674 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1677 commitFuture.get(); // TODO: Make it async (See bug 1362)
1678 LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
1679 } catch (InterruptedException|ExecutionException e) {
1680 LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
1685 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1686 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1687 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1688 InstanceIdentifier<Flow> path1 =
1689 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1690 .rev130819.nodes.Node.class,
1691 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1692 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1694 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1695 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1696 true);//createMissingParents
1699 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1701 commitFuture.get(); // TODO: Make it async (See bug 1362)
1702 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
1703 } catch (InterruptedException|ExecutionException e) {
1704 LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
1710 * Create Output Port Group Instruction
1712 * @param nodeBuilder Node Builder
1713 * @param ib Map InstructionBuilder without any instructions
1714 * @param dpidLong Long the datapath ID of a switch/node
1715 * @param port Long representing a port on a switch/node
1716 * @param instructions List of instructions
1717 * @return ib InstructionBuilder Map with instructions
1719 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1720 @SuppressWarnings("unused")
1721 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1722 InstructionBuilder ib,
1723 Long dpidLong, Long port ,
1724 List<Instruction> instructions) {
1725 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1726 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1728 List<Action> actionList = new ArrayList<>();
1729 ActionBuilder ab = new ActionBuilder();
1731 List<Action> existingActions;
1732 if (instructions != null) {
1733 for (Instruction in : instructions) {
1734 if (in.getInstruction() instanceof ApplyActionsCase) {
1735 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1736 actionList.addAll(existingActions);
1741 GroupBuilder groupBuilder = new GroupBuilder();
1744 /* Create output action for this port*/
1745 OutputActionBuilder oab = new OutputActionBuilder();
1746 oab.setOutputNodeConnector(ncid);
1747 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1748 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1749 boolean addNew = true;
1750 boolean groupActionAdded = false;
1752 /* Find the group action and get the group */
1753 for (Action action : actionList) {
1754 if (action.getAction() instanceof GroupActionCase) {
1755 groupActionAdded = true;
1756 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1757 Long id = groupAction.getGroupAction().getGroupId();
1758 String groupName = groupAction.getGroupAction().getGroup();
1759 GroupKey key = new GroupKey(new GroupId(id));
1761 groupBuilder.setGroupId(new GroupId(id));
1762 groupBuilder.setGroupName(groupName);
1763 groupBuilder.setGroupType(GroupTypes.GroupAll);
1764 groupBuilder.setKey(key);
1765 group = getGroup(groupBuilder, nodeBuilder);
1766 LOG.debug("createOutputGroupInstructions: group {}", group);
1771 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1772 if (groupActionAdded) {
1773 /* modify the action bucket in group */
1774 groupBuilder = new GroupBuilder(group);
1775 Buckets buckets = groupBuilder.getBuckets();
1776 for (Bucket bucket : buckets.getBucket()) {
1777 List<Action> bucketActions = bucket.getAction();
1778 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1779 for (Action action : bucketActions) {
1780 if (action.getAction() instanceof OutputActionCase) {
1781 OutputActionCase opAction = (OutputActionCase)action.getAction();
1782 /* If output port action already in the action list of one of the buckets, skip */
1783 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1790 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1791 if (addNew && !buckets.getBucket().isEmpty()) {
1792 /* the new output action is not in the bucket, add to bucket */
1793 Bucket bucket = buckets.getBucket().get(0);
1794 List<Action> bucketActionList = new ArrayList<>();
1795 bucketActionList.addAll(bucket.getAction());
1796 /* set order for new action and add to action list */
1797 ab.setOrder(bucketActionList.size());
1798 ab.setKey(new ActionKey(bucketActionList.size()));
1799 bucketActionList.add(ab.build());
1801 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1802 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1803 List<Bucket> bucketList = new ArrayList<>();
1804 BucketBuilder bucketBuilder = new BucketBuilder();
1805 bucketBuilder.setBucketId(new BucketId((long) 1));
1806 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1807 bucketBuilder.setAction(bucketActionList);
1808 bucketList.add(bucketBuilder.build());
1809 bucketsBuilder.setBucket(bucketList);
1810 groupBuilder.setBuckets(bucketsBuilder.build());
1811 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1815 groupBuilder = new GroupBuilder();
1816 groupBuilder.setGroupType(GroupTypes.GroupAll);
1817 groupBuilder.setGroupId(new GroupId(groupId));
1818 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1819 groupBuilder.setGroupName("Output port group " + groupId);
1820 groupBuilder.setBarrier(false);
1822 BucketsBuilder bucketBuilder = new BucketsBuilder();
1823 List<Bucket> bucketList = new ArrayList<>();
1824 BucketBuilder bucket = new BucketBuilder();
1825 bucket.setBucketId(new BucketId((long) 1));
1826 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1828 /* put output action to the bucket */
1829 List<Action> bucketActionList = new ArrayList<>();
1830 /* set order for new action and add to action list */
1831 ab.setOrder(bucketActionList.size());
1832 ab.setKey(new ActionKey(bucketActionList.size()));
1833 bucketActionList.add(ab.build());
1835 bucket.setAction(bucketActionList);
1836 bucketList.add(bucket.build());
1837 bucketBuilder.setBucket(bucketList);
1838 groupBuilder.setBuckets(bucketBuilder.build());
1840 /* Add new group action */
1841 GroupActionBuilder groupActionB = new GroupActionBuilder();
1842 groupActionB.setGroupId(groupId);
1843 groupActionB.setGroup("Output port group " + groupId);
1844 ab = new ActionBuilder();
1845 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1846 ab.setOrder(actionList.size());
1847 ab.setKey(new ActionKey(actionList.size()));
1848 actionList.add(ab.build());
1852 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1853 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1856 /* rewrite the group to group table */
1857 writeGroup(groupBuilder, nodeBuilder);
1860 // Create an Apply Action
1861 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1862 aab.setAction(actionList);
1863 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1869 * Remove Output Port from action list in group bucket
1871 * @param nodeBuilder Node Builder
1872 * @param ib Map InstructionBuilder without any instructions
1873 * @param dpidLong Long the datapath ID of a switch/node
1874 * @param port Long representing a port on a switch/node
1875 * @param instructions List of instructions
1876 * @return ib InstructionBuilder Map with instructions
1878 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1879 @SuppressWarnings("unused")
1880 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1881 Long dpidLong, Long port , List<Instruction> instructions) {
1883 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1884 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1886 List<Action> actionList = new ArrayList<>();
1889 List<Action> existingActions;
1890 if (instructions != null) {
1891 for (Instruction in : instructions) {
1892 if (in.getInstruction() instanceof ApplyActionsCase) {
1893 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1894 actionList.addAll(existingActions);
1900 GroupBuilder groupBuilder = new GroupBuilder();
1902 boolean groupActionAdded = false;
1903 /* Find the group action and get the group */
1904 for (Action action : actionList) {
1905 if (action.getAction() instanceof GroupActionCase) {
1906 groupActionAdded = true;
1907 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1908 Long id = groupAction.getGroupAction().getGroupId();
1909 String groupName = groupAction.getGroupAction().getGroup();
1910 GroupKey key = new GroupKey(new GroupId(id));
1912 groupBuilder.setGroupId(new GroupId(id));
1913 groupBuilder.setGroupName(groupName);
1914 groupBuilder.setGroupType(GroupTypes.GroupAll);
1915 groupBuilder.setKey(key);
1916 group = getGroup(groupBuilder, nodeBuilder);
1921 if (groupActionAdded) {
1922 /* modify the action bucket in group */
1923 groupBuilder = new GroupBuilder(group);
1924 Buckets buckets = groupBuilder.getBuckets();
1925 List<Action> bucketActions = new ArrayList<>();
1926 for (Bucket bucket : buckets.getBucket()) {
1928 boolean isPortDeleted = false;
1929 bucketActions = bucket.getAction();
1930 for (Action action : bucketActions) {
1931 if (action.getAction() instanceof OutputActionCase) {
1932 OutputActionCase opAction = (OutputActionCase)action.getAction();
1933 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1934 /* Find the output port in action list and remove */
1935 index = bucketActions.indexOf(action);
1936 bucketActions.remove(action);
1937 isPortDeleted = true;
1942 if (isPortDeleted && !bucketActions.isEmpty()) {
1943 for (int i = index; i< bucketActions.size(); i++) {
1944 Action action = bucketActions.get(i);
1945 if (action.getOrder() != i) {
1946 /* Shift the action order */
1947 ab = new ActionBuilder();
1948 ab.setAction(action.getAction());
1950 ab.setKey(new ActionKey(i));
1951 Action actionNewOrder = ab.build();
1952 bucketActions.remove(action);
1953 bucketActions.add(i, actionNewOrder);
1957 } else if (bucketActions.isEmpty()) {
1958 /* remove bucket with empty action list */
1959 buckets.getBucket().remove(bucket);
1963 if (!buckets.getBucket().isEmpty()) {
1964 /* rewrite the group to group table */
1965 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1966 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1967 List<Bucket> bucketList = new ArrayList<>();
1968 BucketBuilder bucketBuilder = new BucketBuilder();
1969 bucketBuilder.setBucketId(new BucketId((long) 1));
1970 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1971 bucketBuilder.setAction(bucketActions);
1972 bucketList.add(bucketBuilder.build());
1973 bucketsBuilder.setBucket(bucketList);
1974 groupBuilder.setBuckets(bucketsBuilder.build());
1975 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1977 writeGroup(groupBuilder, nodeBuilder);
1978 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1979 aab.setAction(actionList);
1980 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1983 /* remove group with empty bucket. return true to delete flow */
1984 removeGroup(groupBuilder, nodeBuilder);
1988 /* no group for port list. flow can be removed */
1994 public void initializeOFFlowRules(Node openflowNode) {
1995 String bridgeName = southbound.getBridgeName(openflowNode);
1996 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1997 String brExt = null;
1998 if (configurationService.isL3MultipleExternalNetworkEnabled()) {
1999 brExt = bridgeConfigurationManager.getMultipleExternalBridge(openflowNode);
2001 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) ||
2002 bridgeName.equals(configurationService.getExternalBridgeName()) || bridgeName.equals(brExt)) {
2003 initializeFlowRules(openflowNode, bridgeName);
2004 triggerInterfaceUpdates(openflowNode);
2008 public static NodeBuilder createNodeBuilder(String nodeId) {
2009 NodeBuilder builder = new NodeBuilder();
2010 builder.setId(new NodeId(nodeId));
2011 builder.setKey(new NodeKey(builder.getId()));
2016 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
2017 this.bundleContext = bundleContext;
2018 configurationService =
2019 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
2020 tenantNetworkManager =
2021 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
2022 bridgeConfigurationManager =
2023 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
2025 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
2026 resubmitAclLearnProvider =
2027 (ResubmitAclLearnProvider) ServiceHelper.getGlobalInstance(ResubmitAclLearnProvider.class, this);
2028 classifierProvider =
2029 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
2030 ingressAclProvider =
2031 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
2033 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
2034 l2ForwardingLearnProvider =
2035 (L2ForwardingLearnProvider) ServiceHelper.getGlobalInstance(L2ForwardingLearnProvider.class, this);
2036 l2ForwardingProvider =
2037 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
2038 securityServicesManager =
2039 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
2041 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
2045 public void setDependencies(Object impl) {
2046 if (impl instanceof NetworkingProviderManager) {
2047 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
2048 networkingProviderManager.providerAdded(
2049 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);