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 java.net.InetAddress;
12 import java.util.HashSet;
13 import java.util.List;
16 import java.util.concurrent.ExecutionException;
18 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
21 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
24 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronNetwork;
25 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronPort;
26 import org.opendaylight.netvirt.openstack.netvirt.translator.NeutronSecurityGroup;
27 import org.opendaylight.netvirt.openstack.netvirt.translator.Neutron_IPs;
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.L2ForwardingProvider;
37 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProvider;
38 import org.opendaylight.netvirt.openstack.netvirt.api.NetworkingProviderManager;
39 import org.opendaylight.netvirt.openstack.netvirt.api.NodeCacheManager;
40 import org.opendaylight.netvirt.openstack.netvirt.api.SecurityServicesManager;
41 import org.opendaylight.netvirt.openstack.netvirt.api.Southbound;
42 import org.opendaylight.netvirt.openstack.netvirt.api.Status;
43 import org.opendaylight.netvirt.openstack.netvirt.api.StatusCode;
44 import org.opendaylight.netvirt.openstack.netvirt.api.TenantNetworkManager;
45 import org.opendaylight.netvirt.openstack.netvirt.providers.ConfigInterface;
46 import org.opendaylight.netvirt.openstack.netvirt.providers.NetvirtProvidersProvider;
47 import org.opendaylight.netvirt.utils.mdsal.openflow.FlowUtils;
48 import org.opendaylight.netvirt.utils.mdsal.openflow.InstructionUtils;
49 import org.opendaylight.netvirt.utils.servicehelper.ServiceHelper;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Uri;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCase;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.GroupActionCaseBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCase;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.OutputActionCaseBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.group.action._case.GroupActionBuilder;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.action.output.action._case.OutputActionBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionBuilder;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.ActionKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.InstructionsBuilder;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCaseBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.apply.actions._case.ApplyActionsBuilder;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.InstructionKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.BucketId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupTypes;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.Buckets;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.BucketsBuilder;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.Bucket;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketBuilder;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.group.buckets.BucketKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
90 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
91 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
92 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
93 import org.osgi.framework.BundleContext;
94 import org.osgi.framework.ServiceReference;
95 import org.slf4j.Logger;
96 import org.slf4j.LoggerFactory;
98 import com.google.common.base.Optional;
99 import com.google.common.base.Preconditions;
100 import com.google.common.collect.Lists;
101 import com.google.common.collect.Maps;
102 import com.google.common.util.concurrent.CheckedFuture;
106 * Open vSwitch OpenFlow 1.3 Networking Provider for OpenStack Neutron
108 * @author Madhu Venugopal
109 * @author Brent Salisbury
110 * @author Dave Tucker
113 // Methods' parameters in this class follow the same pattern to avoid confusion between same-typed parameters
114 // The patterns need to be preserved even though not all parameters are used in all methods
115 @SuppressWarnings("UnusedParameters")
116 public class OF13Provider implements ConfigInterface, NetworkingProvider {
117 private static final Logger LOG = LoggerFactory.getLogger(OF13Provider.class);
118 private static final short TABLE_0_DEFAULT_INGRESS = 0;
119 private static final short TABLE_1_ISOLATE_TENANT = 10;
120 private static final short TABLE_2_LOCAL_FORWARD = 20;
121 private static Long groupId = 1L;
122 private DataBroker dataBroker = null;
124 private volatile ConfigurationService configurationService;
125 private volatile BridgeConfigurationManager bridgeConfigurationManager;
126 private volatile TenantNetworkManager tenantNetworkManager;
127 private volatile SecurityServicesManager securityServicesManager;
128 private volatile ClassifierProvider classifierProvider;
129 private volatile IngressAclProvider ingressAclProvider;
130 private volatile EgressAclProvider egressAclProvider;
131 private volatile NodeCacheManager nodeCacheManager;
132 private volatile L2ForwardingProvider l2ForwardingProvider;
134 public static final String NAME = "OF13Provider";
135 private volatile BundleContext bundleContext;
136 private volatile Southbound southbound;
138 private Set<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId>
139 intBridgesWithoutVmPorts = new HashSet<>();
141 public OF13Provider() {
142 this.dataBroker = NetvirtProvidersProvider.getDataBroker();
146 public String getName() {
151 public boolean supportsServices() {
156 public boolean hasPerTenantTunneling() {
160 // The method is tested for in OF13ProviderTest
161 @SuppressWarnings("unused")
162 private Status getTunnelReadinessStatus (Node node, String tunnelKey) {
163 InetAddress srcTunnelEndPoint = configurationService.getTunnelEndPoint(node);
164 if (srcTunnelEndPoint == null) {
165 LOG.error("Tunnel Endpoint not configured for Node {}", node);
166 return new Status(StatusCode.NOTFOUND, "Tunnel Endpoint not configured for "+ node);
169 if (!bridgeConfigurationManager.isNodeNeutronReady(node)) {
170 LOG.error("{} is not Overlay ready", node);
171 return new Status(StatusCode.NOTACCEPTABLE, node+" is not Overlay ready");
174 if (!tenantNetworkManager.isTenantNetworkPresentInNode(node, tunnelKey)) {
175 LOG.debug("{} has no VM corresponding to segment {}", node, tunnelKey);
176 return new Status(StatusCode.NOTACCEPTABLE, node+" has no VM corresponding to segment "+ tunnelKey);
178 return new Status(StatusCode.SUCCESS);
181 private String getTunnelName(String tunnelType, InetAddress dst) {
182 return tunnelType+"-"+dst.getHostAddress();
185 private boolean addTunnelPort (Node node, String tunnelType, InetAddress src, InetAddress dst) {
186 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
187 String portName = getTunnelName(tunnelType, dst);
188 LOG.info("Added TunnelPort : portName: {}", portName);
189 if (southbound.extractTerminationPointAugmentation(node, portName) != null
190 || southbound.isTunnelTerminationPointExist(node, tunnelBridgeName, portName)) {
191 LOG.info("Tunnel {} is present in {} of {}", portName, tunnelBridgeName, node.getNodeId().getValue());
195 Map<String, String> options = Maps.newHashMap();
196 options.put("key", "flow");
197 options.put("local_ip", src.getHostAddress());
198 options.put("remote_ip", dst.getHostAddress());
200 if (!southbound.addTunnelTerminationPoint(node, tunnelBridgeName, portName, tunnelType, options)) {
201 LOG.error("Failed to insert Tunnel port {} in {}", portName, tunnelBridgeName);
205 LOG.info("addTunnelPort exit: portName: {}", portName);
209 /* delete port from ovsdb port table */
210 private boolean deletePort(Node node, String bridgeName, String portName) {
212 // might need to convert from ovsdb node to bridge node
213 return southbound.deleteTerminationPoint(node, portName);
216 private boolean deleteTunnelPort(Node node, String tunnelType, InetAddress src, InetAddress dst) {
217 String tunnelBridgeName = configurationService.getIntegrationBridgeName();
218 String portName = getTunnelName(tunnelType, dst);
219 return deletePort(node, tunnelBridgeName, portName);
222 private boolean deletePhysicalPort(Node node, String phyIntfName) {
223 String intBridgeName = configurationService.getIntegrationBridgeName();
224 return deletePort(node, intBridgeName, phyIntfName);
227 private void programLocalBridgeRules(Node node, Long dpid, String segmentationId,
228 String attachedMac, long localPort) {
232 * Match: VM sMac and Local Ingress Port
233 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
236 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT,
237 segmentationId, localPort, attachedMac, true);
242 * Match: Drop any remaining Ingress Local VM Packets
243 * Action: Drop w/ a low priority
246 handleDropSrcIface(dpid, localPort, true);
251 * Match: Match TunID and Destination DL/dMAC Addr
252 * Action: Output Port
253 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
256 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, true);
261 * Match: Tunnel ID and dMAC (::::FF:FF)
262 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
263 * actions=output:2,3,4,5
266 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
267 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, true);
270 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
275 * Match: Any remaining Ingress Local VM Packets
276 * Action: Drop w/ a low priority
277 * -------------------------------------------
278 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
281 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, true);
286 * Match: Any Remaining Flows w/a TunID
287 * Action: Drop w/ a low priority
288 * table=2,priority=8192,tun_id=0x5 actions=drop
291 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, true);
294 private void removeLocalBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
298 * Match: VM sMac and Local Ingress Port
299 * Action:Action: Set Tunnel ID and GOTO Local Table (5)
302 handleLocalInPort(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_1_ISOLATE_TENANT, segmentationId, localPort, attachedMac, false);
307 * Match: Drop any remaining Ingress Local VM Packets
308 * Action: Drop w/ a low priority
311 handleDropSrcIface(dpid, localPort, false);
316 * Match: Match TunID and Destination DL/dMAC Addr
317 * Action: Output Port
318 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
321 handleLocalUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, attachedMac, false);
326 * Match: Tunnel ID and dMAC (::::FF:FF)
327 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
328 * actions=output:2,3,4,5
331 handleLocalBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
332 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, false);
335 private void programLocalIngressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
339 * Match: Ingress Port, Tunnel ID
340 * Action: GOTO Local Table (20)
343 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
348 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
349 * Action: Flood to selected destination TEPs
350 * -------------------------------------------
351 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
352 * actions=output:10,output:11,goto_table:2
355 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, true);
359 private void programRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
363 * Match: Drop any remaining Ingress Local VM Packets
364 * Action: Drop w/ a low priority
365 * -------------------------------------------
366 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
367 * actions=output:11,goto_table:2
370 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, true);
373 private void removeRemoteEgressTunnelBridgeRules(Node node, Long dpid, String segmentationId, String attachedMac, long tunnelOFPort, long localPort) {
377 * Match: Drop any remaining Ingress Local VM Packets
378 * Action: Drop w/ a low priority
379 * -------------------------------------------
380 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
381 * actions=output:11,goto_table:2
384 handleTunnelOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, attachedMac, false);
387 /* Remove tunnel rules if last node in this tenant network */
388 private void removePerTunnelRules(Node node, Long dpid, String segmentationId, long tunnelOFPort) {
390 * TODO : Optimize the following 2 writes to be restricted only for the very first port known in a segment.
395 * Match: Any remaining Ingress Local VM Packets
396 * Action: Drop w/ a low priority
397 * -------------------------------------------
398 * table=1,priority=8192,tun_id=0x5 actions=goto_table:2
401 handleTunnelMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, false);
406 * Match: Any Remaining Flows w/a TunID
407 * Action: Drop w/ a low priority
408 * table=2,priority=8192,tun_id=0x5 actions=drop
411 handleLocalTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
416 * Match: Ingress Port, Tunnel ID
417 * Action: GOTO Local Table (10)
420 handleTunnelIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
425 * Match: Match Tunnel ID and L2 ::::FF:FF Flooding
426 * Action: Flood to selected destination TEPs
427 * -------------------------------------------
428 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
429 * actions=output:10,output:11,goto_table:2
432 handleTunnelFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, tunnelOFPort, false);
435 private void programLocalVlanRules(Node node, Long dpid, String segmentationId, String attachedMac, long localPort) {
439 * Tag traffic coming from the local port and vm srcmac
440 * Match: VM sMac and Local Ingress Port
441 * Action: Set VLAN ID and GOTO Local Table 1
444 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
445 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
451 * Drop all other traffic coming from the local port
452 * Match: Drop any remaining Ingress Local VM Packets
453 * Action: Drop w/ a low priority
456 handleDropSrcIface(dpid, localPort, true);
461 * Forward unicast traffic destined to the local port after stripping tag
462 * Match: Match VLAN ID and Destination DL/dMAC Addr
463 * Action: strip vlan, output to local port
464 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
467 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
468 localPort, attachedMac, true);
473 * Match: VLAN ID and dMAC (::::FF:FF)
474 * Action: strip vlan, output to all local ports in this vlan
475 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
476 * actions= strip_vlan, output:2,3,4,5
479 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
480 // localPort, ethPort, true);
481 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
482 // segmentationId, localPort, ethport, true);
487 * Match: Any Remaining Flows w/a VLAN ID
488 * Action: Drop w/ a low priority
489 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
492 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
496 private void removeLocalVlanRules(Node node, Long dpid,
497 String segmentationId, String attachedMac, long localPort) {
501 * Match: VM sMac and Local Ingress Port
502 * Action: Set VLAN ID and GOTO Local Table 1
505 handleLocalInPortSetVlan(dpid, TABLE_0_DEFAULT_INGRESS,
506 TABLE_1_ISOLATE_TENANT, segmentationId, localPort,
512 * Match: Drop any remaining Ingress Local VM Packets
513 * Action: Drop w/ a low priority
516 handleDropSrcIface(dpid, localPort, false);
521 * Match: Match VLAN ID and Destination DL/dMAC Addr
522 * Action: strip vlan, output to local port
523 * Example: table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions= strip vlan, output:2
526 handleLocalVlanUcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
527 localPort, attachedMac, false);
532 * Match: VLAN ID and dMAC (::::FF:FF)
533 * Action: strip vlan, output to all local ports in this vlan
534 * Example: table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
535 * actions= strip_vlan, output:2,3,4,5
538 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId,
539 // localPort, ethPort, false);
540 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
541 // segmentationId, localPort, false);
545 private void programLocalIngressVlanRules(Node node, Long dpid, String segmentationId, String attachedMac,
546 long localPort, long ethPort) {
550 * Match: Ingress port = physical interface, Vlan ID
551 * Action: GOTO Local Table 2
554 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD,
555 segmentationId, ethPort, true);
560 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
561 * Action: Flood to local and remote VLAN members
562 * -------------------------------------------
563 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
564 * actions=output:10 (eth port),goto_table:2
565 * 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
568 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, true);
573 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
574 * Action: Flood to local and remote VLAN members
575 * -------------------------------------------
576 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
577 * actions=output:10 (eth port),goto_table:2
580 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
581 // segmentationId, ethPort, true);
584 private void programRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
585 String attachedMac, long ethPort) {
589 * Match: Destination MAC is local VM MAC and vlan id
590 * Action: go to table 2
591 * -------------------------------------------
592 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
593 * actions=goto_table:2
596 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
597 // segmentationId, ethPort, attachedMac, true);
603 * Action: Go to table 2
604 * -------------------------------------------
605 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
606 * table=110,priority=8192,dl_vlan=2001 actions=output:2
609 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, true);
612 private void removeRemoteEgressVlanRules(Node node, Long dpid, String segmentationId,
613 String attachedMac, long localPort, long ethPort) {
617 * Match: Destination MAC is local VM MAC and vlan id
618 * Action: go to table 2
619 * -------------------------------------------
620 * Example: table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
621 * actions=goto_table:2
624 //handleVlanOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
625 // segmentationId, ethPort, attachedMac, false);
630 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
631 * Action: Flood to local and remote VLAN members
632 * -------------------------------------------
633 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
634 * actions=output:10 (eth port),goto_table:2
635 * 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
638 handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
641 private void removePerVlanRules(Node node, Long dpid, String segmentationId, long localPort, long ethPort) {
645 * Match: Any Remaining Flows w/a VLAN ID
646 * Action: Drop w/ a low priority
647 * Example: table=2,priority=8192,vlan_id=0x5 actions=drop
650 //handleLocalVlanTableMiss(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, false);
655 * Match: Ingress port = physical interface, Vlan ID
656 * Action: GOTO Local Table 2
659 handleVlanIn(dpid, TABLE_0_DEFAULT_INGRESS, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
664 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
665 * Action: Flood to local and remote VLAN members
666 * -------------------------------------------
667 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
668 * actions=output:10 (eth port),goto_table:2
669 * 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
672 //handleLocalVlanBcastOut(dpid, TABLE_2_LOCAL_FORWARD, segmentationId, localPort, ethPort, false);
677 * Match: Match VLAN ID and L2 ::::FF:FF Flooding
678 * Action: Flood to local and remote VLAN members
679 * -------------------------------------------
680 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
681 * actions=output:10 (eth port),goto_table:2
684 //handleVlanFloodOut(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD,
685 // segmentationId, ethPort, false);
691 * Action: Go to table 2
692 * -------------------------------------------
693 * Example: table=1,priority=8192,vlan_id=0x5 actions=output:1,goto_table:2
694 * table=110,priority=8192,dl_vlan=2001 actions=output:2
697 handleVlanMiss(dpid, TABLE_1_ISOLATE_TENANT, TABLE_2_LOCAL_FORWARD, segmentationId, ethPort, false);
700 private long getDpid(Node node) {
701 long dpid = southbound.getDataPathId(node);
703 LOG.warn("getDpid: dpid not found: {}", node);
708 private long getIntegrationBridgeOFDPID(Node node) {
710 if (southbound.getBridgeName(node).equals(configurationService.getIntegrationBridgeName())) {
711 dpid = getDpid(node);
717 * Returns true is the network if of type GRE or VXLAN
719 * @param networkType The type of the network
720 * @return returns true if the network is a tunnel
722 private boolean isTunnel(String networkType)
724 return (networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE) || networkType.equalsIgnoreCase
725 (NetworkHandler.NETWORK_TYPE_VXLAN));
729 * Returns true if the network is of type vlan.
731 * @param networkType The type of the network
732 * @return returns true if the network is a vlan
734 private boolean isVlan(String networkType)
736 return networkType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VLAN);
739 private void programLocalRules(String networkType, String segmentationId, Node node,
740 OvsdbTerminationPointAugmentation intf) {
741 LOG.debug("programLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
742 node.getNodeId(), intf.getName(), networkType, segmentationId);
744 long dpid = getIntegrationBridgeOFDPID(node);
746 LOG.debug("programLocalRules: Openflow Datapath-ID not set for the integration bridge in {}",
751 long localPort = southbound.getOFPort(intf);
752 if (localPort == 0) {
753 LOG.info("programLocalRules: could not find ofPort for Port {} on Node {}",
754 intf.getName(), node.getNodeId());
758 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
759 if (attachedMac == null) {
760 LOG.warn("No AttachedMac seen in {}", intf);
764 /* Program local rules based on network type */
765 if (isVlan(networkType)) {
766 LOG.debug("Program local vlan rules for interface {}", intf.getName());
767 programLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
769 if ((isTunnel(networkType) || isVlan(networkType))) {
770 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, true);
772 if (isTunnel(networkType)) {
773 LOG.debug("Program local bridge rules for interface {}, "
774 + "dpid: {}, segmentationId: {}, attachedMac: {}, localPort: {}",
775 intf.getName(), dpid, segmentationId, attachedMac, localPort);
776 programLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
778 } catch (Exception e) {
779 LOG.error("Exception in programming Local Rules for {} on {}", intf, node, e);
783 private void removeLocalRules(String networkType, String segmentationId, Node node,
784 OvsdbTerminationPointAugmentation intf) {
785 LOG.debug("removeLocalRules: node: {}, intf: {}, networkType: {}, segmentationId: {}",
786 node.getNodeId(), intf.getName(), networkType, segmentationId);
788 long dpid = getIntegrationBridgeOFDPID(node);
790 LOG.debug("removeLocalRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
794 long localPort = southbound.getOFPort(intf);
795 if (localPort == 0) {
796 LOG.info("removeLocalRules: could not find ofPort");
800 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
801 if (attachedMac == null) {
802 LOG.warn("No AttachedMac seen in {}", intf);
806 /* Program local rules based on network type */
807 if (isVlan(networkType)) {
808 LOG.debug("Remove local vlan rules for interface {}", intf.getName());
809 removeLocalVlanRules(node, dpid, segmentationId, attachedMac, localPort);
810 } else if (isTunnel(networkType)) {
811 LOG.debug("Remove local bridge rules for interface {}", intf.getName());
812 removeLocalBridgeRules(node, dpid, segmentationId, attachedMac, localPort);
814 if (isTunnel(networkType) || isVlan(networkType)) {
815 programLocalSecurityGroupRules(attachedMac, node, intf, dpid, localPort, segmentationId, false);
817 } catch (Exception e) {
818 LOG.error("Exception in removing Local Rules for {} on {}", intf, node, e);
822 private void programTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
823 OvsdbTerminationPointAugmentation intf, boolean local) {
824 LOG.debug("programTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
825 + "segmentationId: {}, dstAddr: {}",
826 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst.getHostAddress());
828 long dpid = getIntegrationBridgeOFDPID(node);
830 LOG.debug("programTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
834 long localPort = southbound.getOFPort(intf);
835 if (localPort == 0) {
836 LOG.info("programTunnelRules: could not find ofPort for Port {} on Node{}", intf.getName(), node.getNodeId());
840 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
841 if (attachedMac == null) {
842 LOG.warn("programTunnelRules: No AttachedMac seen in {}", intf);
846 OvsdbTerminationPointAugmentation tunnelPort= southbound.getTerminationPointOfBridge(node, getTunnelName(tunnelType, dst));
847 if (tunnelPort != null){
848 long tunnelOFPort = southbound.getOFPort(tunnelPort);
849 if (tunnelOFPort == 0) {
850 LOG.error("programTunnelRules: Could not Identify Tunnel port {} -> OF ({}) on {}",
851 tunnelPort.getName(), tunnelOFPort, node);
854 LOG.debug("programTunnelRules: Identified Tunnel port {} -> OF ({}) on {}",
855 tunnelPort.getName(), tunnelOFPort, node);
858 LOG.trace("programTunnelRules: program remote egress tunnel rules: node {}, intf {}",
859 node.getNodeId().getValue(), intf.getName());
860 programRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
861 tunnelOFPort, localPort);
863 LOG.trace("programTunnelRules: program local ingress tunnel rules: node {}, intf {}",
864 node.getNodeId().getValue(), intf.getName());
865 programLocalIngressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
866 tunnelOFPort, localPort);
869 } catch (Exception e) {
870 LOG.warn("Failed to program tunnel rules, node {}, intf {}", node, intf, e);
874 private void removeTunnelRules (String tunnelType, String segmentationId, InetAddress dst, Node node,
875 OvsdbTerminationPointAugmentation intf,
876 boolean local, boolean isLastInstanceOnNode) {
877 LOG.debug("removeTunnelRules: node: {}, intf: {}, local: {}, tunnelType: {}, "
878 + "segmentationId: {}, dstAddr: {}, isLastinstanceOnNode: {}",
879 node.getNodeId(), intf.getName(), local, tunnelType, segmentationId, dst, isLastInstanceOnNode);
881 long dpid = getIntegrationBridgeOFDPID(node);
883 LOG.debug("removeTunnelRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
887 long localPort = southbound.getOFPort(intf);
888 if (localPort == 0) {
889 LOG.info("removeTunnelRules: could not find ofPort");
893 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
894 if (attachedMac == null) {
895 LOG.error("removeTunnelRules: No AttachedMac seen in {}", intf);
899 List<OvsdbTerminationPointAugmentation> intfs = southbound.getTerminationPointsOfBridge(node);
900 for (OvsdbTerminationPointAugmentation tunIntf : intfs) {
901 if (tunIntf.getName().equals(getTunnelName(tunnelType, dst))) {
902 long tunnelOFPort = southbound.getOFPort(tunIntf);
903 if (tunnelOFPort == 0) {
904 LOG.error("Could not Identify Tunnel port {} -> OF ({}) on {}",
905 tunIntf.getName(), tunnelOFPort, node);
908 LOG.debug("Identified Tunnel port {} -> OF ({}) on {}",
909 tunIntf.getName(), tunnelOFPort, node);
912 removeRemoteEgressTunnelBridgeRules(node, dpid, segmentationId, attachedMac,
913 tunnelOFPort, localPort);
915 if (local && isLastInstanceOnNode) {
916 removePerTunnelRules(node, dpid, segmentationId, tunnelOFPort);
921 } catch (Exception e) {
922 LOG.error("Failed to remove tunnel rules, node {}, intf {}", node, intf, e);
926 private void programVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf) {
927 LOG.debug("programVlanRules: node: {}, network: {}, intf: {}",
928 node.getNodeId(), network.getNetworkUUID(), intf.getName());
929 long dpid = getIntegrationBridgeOFDPID(node);
931 LOG.debug("programVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
935 long localPort = southbound.getOFPort(intf);
936 if (localPort == 0) {
937 LOG.debug("programVlanRules: could not find ofPort for {}", intf.getName());
941 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
942 if (attachedMac == null) {
943 LOG.debug("programVlanRules: No AttachedMac seen in {}", intf);
948 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
949 long ethOFPort = southbound.getOFPort(node, phyIfName);
950 if (ethOFPort == 0) {
951 LOG.warn("programVlanRules: could not find ofPort for physical port {}", phyIfName);
954 LOG.debug("programVlanRules: Identified eth port {} -> ofPort ({}) on {}",
955 phyIfName, ethOFPort, node);
956 // TODO: add logic to only add rule on remote nodes
957 programRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
958 attachedMac, ethOFPort);
959 programLocalIngressVlanRules(node, dpid, network.getProviderSegmentationID(),
960 attachedMac, localPort, ethOFPort);
963 private void removeVlanRules (NeutronNetwork network, Node node, OvsdbTerminationPointAugmentation intf,
964 boolean isLastInstanceOnNode) {
965 LOG.debug("removeVlanRules: node: {}, network: {}, intf: {}, isLastInstanceOnNode",
966 node.getNodeId(), network.getNetworkUUID(), intf.getName(), isLastInstanceOnNode);
967 long dpid = getIntegrationBridgeOFDPID(node);
969 LOG.debug("removeVlanRules: Openflow Datapath-ID not set for the integration bridge in {}", node);
973 long localPort = southbound.getOFPort(intf);
974 if (localPort == 0) {
975 LOG.debug("removeVlanRules: programVlanRules: could not find ofPort for {}", intf.getName());
979 String attachedMac = southbound.getInterfaceExternalIdsValue(intf, Constants.EXTERNAL_ID_VM_MAC);
980 if (attachedMac == null) {
981 LOG.debug("removeVlanRules: No AttachedMac seen in {}", intf);
986 bridgeConfigurationManager.getPhysicalInterfaceName(node, network.getProviderPhysicalNetwork());
987 long ethOFPort = southbound.getOFPort(node, phyIfName);
988 if (ethOFPort == 0) {
989 LOG.warn("removeVlanRules: could not find ofPort for physical port {}", phyIfName);
992 LOG.debug("removeVlanRules: Identified eth port {} -> ofPort ({}) on {}",
993 phyIfName, ethOFPort, node);
995 removeRemoteEgressVlanRules(node, dpid, network.getProviderSegmentationID(),
996 attachedMac, localPort, ethOFPort);
997 if (isLastInstanceOnNode) {
998 removePerVlanRules(node, dpid, network.getProviderSegmentationID(), localPort, ethOFPort);
1002 private void programLocalSecurityGroupRules(String attachedMac, Node node, OvsdbTerminationPointAugmentation intf,
1003 Long dpid,long localPort, String segmentationId,
1006 LOG.debug("programLocalRules: Program fixed security group rules for interface {}", intf.getName());
1007 boolean isPortSecurityEnabled = securityServicesManager.isPortSecurityEnabled(intf);
1008 if (!isPortSecurityEnabled) {
1009 LOG.info("Port security is not enabled" + intf);
1012 NeutronPort dhcpPort = securityServicesManager.getDhcpServerPort(intf);
1013 List<Neutron_IPs> srcAddressList = null;
1014 if (null != dhcpPort) {
1015 srcAddressList = securityServicesManager.getIpAddressList(intf);
1016 if (null == srcAddressList) {
1017 LOG.warn("programLocalRules: No Ip address assigned {}", intf);
1020 ingressAclProvider.programFixedSecurityGroup(dpid, segmentationId, dhcpPort.getMacAddress(), localPort,
1021 attachedMac, write);
1022 egressAclProvider.programFixedSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1023 srcAddressList, write);
1024 /* If the network type is tunnel based (VXLAN/GRRE/etc) with Neutron Port Security ACLs */
1025 /* TODO SB_MIGRATION */
1027 LOG.debug("Neutron port has a Port Security Group");
1028 // Retrieve the security group from the Neutron Port and apply the rules
1029 List<NeutronSecurityGroup> securityGroupListInPort = securityServicesManager
1030 .getSecurityGroupInPortList(intf);
1031 String neutronPortId = southbound.getInterfaceExternalIdsValue(intf,
1032 Constants.EXTERNAL_ID_INTERFACE_ID);
1033 for (NeutronSecurityGroup securityGroupInPort:securityGroupListInPort) {
1034 ingressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1035 securityGroupInPort, neutronPortId, write);
1036 egressAclProvider.programPortSecurityGroup(dpid, segmentationId, attachedMac, localPort,
1037 securityGroupInPort, neutronPortId, write);
1041 LOG.warn("programLocalRules: No DCHP port seen in network of {}", intf);
1046 * The function is for the new compute node joining the existing network.
1047 * When a new VM is instantiated in the new compute node, neutron port add
1048 * event is generated. This event is processed only for that node. So,
1049 * loop through all the ports of the same network and install unicast mac
1050 * flow for the VM's created on the TEP of the destination node in src node.
1051 * This function will be executed even for any new VM creation in an existing
1052 * network. If a cache is maintained to optimize the below flow addition, it will
1053 * work only for one unstack and restack. For the next unstack and restack,
1054 * it will not work since the cache would have been already deleted.
1056 private void programTunnelRulesInNewNode(NeutronNetwork network,
1057 String networkType, String segmentationId,
1058 InetAddress src, InetAddress dst,
1059 Node srcBridgeNode, Node dstBridgeNode,
1060 OvsdbTerminationPointAugmentation intf){
1061 LOG.debug("programTunnelRulesInNewNode: network {} networkType {} segId {} src {} dst {} srcBridgeNode {} dstBridgeNode {} intf {}",
1062 network.getNetworkName(), networkType, segmentationId, src.getHostAddress(),
1063 dst.getHostAddress(), srcBridgeNode, dstBridgeNode, intf);
1065 long localPort = southbound.getOFPort(intf);
1068 LOG.debug("Interface update details {}", intf);
1071 * When a network is added and the TEP destination is not present in a
1072 * node C1, tunnelin and broadcast rules will not be programmed, since
1073 * OF port is not created. So, when a new node C2 joins and create a new
1074 * VM, the tunnelin and broadcast rule will not be present in C1.
1075 * So, handling it in the case below to make ping work.
1077 if (securityServicesManager.getNeutronPortFromDhcpIntf(intf) == null){
1078 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1082 * FIX for 4208 - loop through all the ports and add the VM's
1083 * unicast mac rule of the destination node in the source node.
1084 * When a new node is added, it needs to configure the VM unicast mac
1085 * flow rules which were created before it was joined to an existing
1088 List<OvsdbTerminationPointAugmentation> ports = southbound.getTerminationPointsOfBridge(dstBridgeNode);
1089 for (OvsdbTerminationPointAugmentation port : ports) {
1091 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1092 if (neutronNetwork != null) {
1093 String netType = neutronNetwork.getProviderNetworkType();
1094 String segId = neutronNetwork.getProviderSegmentationID();
1095 InetAddress dstAddr = configurationService.getTunnelEndPoint(dstBridgeNode);
1097 if (segId != null && netType != null && dstAddr != null) {
1098 programTunnelRules(netType, segId, dstAddr, srcBridgeNode, port, false);
1102 if (network == tenantNetworkManager.getTenantNetwork(port)){
1103 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, port, false);
1106 LOG.trace("Port {} is not part of network {}", port, network);
1110 } catch (Exception e) {
1111 LOG.error("Exception during handlingNeutron network add", e);
1115 private boolean bridgeHasVmPort(Node bridgeNode) {
1116 String intBridgeName = configurationService.getIntegrationBridgeName();
1117 String extBridgeName = configurationService.getExternalBridgeName();
1118 List<TerminationPoint> terminationPoints = bridgeNode.getTerminationPoint();
1119 if (terminationPoints == null) return false;
1121 for (TerminationPoint tp : terminationPoints) {
1122 String tpName = tp.getTpId().getValue();
1123 if (tpName != null && !tpName.equals(intBridgeName) && !tpName.equals(extBridgeName)) {
1124 OvsdbTerminationPointAugmentation tpAug = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
1125 if (tpAug != null && southbound.getOFPort(tpAug) != 0) {
1135 public boolean handleInterfaceUpdate(NeutronNetwork network, Node srcNode, OvsdbTerminationPointAugmentation intf) {
1136 LOG.debug("handleInterfaceUpdate: network: {} srcNode: {}, intf: {}",
1137 network.getProviderSegmentationID(), srcNode.getNodeId(), intf.getName());
1138 Preconditions.checkNotNull(nodeCacheManager);
1140 org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId srcNodeId =
1141 srcNode.getNodeId();
1142 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1143 nodeCacheManager.getOvsdbNodes();
1145 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1146 String networkType = network.getProviderNetworkType();
1147 String segmentationId = network.getProviderSegmentationID();
1148 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1150 programLocalRules(networkType, network.getProviderSegmentationID(), srcBridgeNode, intf);
1152 if (isVlan(networkType)) {
1153 programVlanRules(network, srcNode, intf);
1154 } else if (isTunnel(networkType)){
1156 boolean sourceTunnelStatus = false;
1157 boolean destTunnelStatus = false;
1158 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1159 for (Node dstNode : nodes.values()) {
1160 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1161 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1162 if ((src != null) && (dst != null)) {
1163 sourceTunnelStatus = addTunnelPort(srcBridgeNode, networkType, src, dst);
1165 Node dstBridgeNode = southbound.getBridgeNode(dstNode,
1166 configurationService.getIntegrationBridgeName());
1168 if (dstBridgeNode != null) {
1169 destTunnelStatus = addTunnelPort(dstBridgeNode, networkType, dst, src);
1171 if (sourceTunnelStatus && destTunnelStatus) {
1172 LOG.debug("Created Source and destination TunnelPorts :{}, {}", src, dst);
1174 LOG.debug("Source and destination TunnelPort status :{}, {}", sourceTunnelStatus, destTunnelStatus);
1176 if (sourceTunnelStatus) {
1177 boolean isDestinNw = tenantNetworkManager.isTenantNetworkPresentInNode(dstBridgeNode, segmentationId);
1178 //Check whether the network is present in src & dst node
1179 //If only present , add vxlan ports in TunnelRules for both nodes (bug# 5614)
1180 if (isSrcinNw && isDestinNw) {
1181 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1182 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1185 if (destTunnelStatus) {
1186 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1188 if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
1189 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1190 srcBridgeNode, dstBridgeNode, intf);
1191 intBridgesWithoutVmPorts.remove(srcNodeId);
1195 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1196 + "Check source {} or destination {}",
1197 src != null ? src.getHostAddress() : "null",
1198 dst != null ? dst.getHostAddress() : "null");
1203 if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
1204 intBridgesWithoutVmPorts.add(srcNodeId);
1210 private void triggerInterfaceUpdates(Node node) {
1211 LOG.debug("enter triggerInterfaceUpdates for : {}", node.getNodeId());
1212 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1213 if (ports != null && !ports.isEmpty()) {
1214 for (OvsdbTerminationPointAugmentation port : ports) {
1215 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1216 if (neutronNetwork != null) {
1217 LOG.warn("Trigger Interface update for {}", port);
1218 handleInterfaceUpdate(neutronNetwork, node, port);
1222 LOG.warn("triggerInterfaceUpdates: tps are null");
1224 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1228 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1229 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1230 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1231 nodeCacheManager.getOvsdbNodes();
1232 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1234 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1235 String segmentationId = network.getProviderSegmentationID();
1236 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1237 if (southbound.isTunnel(intf)) {
1238 // Delete tunnel port
1240 InetAddress src = InetAddress.getByName(
1241 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1242 InetAddress dst = InetAddress.getByName(
1243 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1244 deleteTunnelPort(srcNode,
1245 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1247 } catch (Exception e) {
1248 LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
1250 } else if (phyIfName.contains(intf.getName())) {
1251 deletePhysicalPort(srcNode, intf.getName());
1253 // delete all other interfaces
1254 removeLocalRules(network.getProviderNetworkType(), segmentationId,
1257 if (isVlan(network.getProviderNetworkType())) {
1258 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1259 } else if (isTunnel(network.getProviderNetworkType())) {
1261 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1262 for (Node dstNode : nodes.values()) {
1263 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1264 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1265 if ((src != null) && (dst != null)) {
1266 LOG.info("Remove tunnel rules for interface "
1267 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1268 removeTunnelRules(tunnelType, segmentationId,
1269 dst, srcNode, intf, true, isLastInstanceOnNode);
1270 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1271 //While removing last instance , check whether the network present in src node
1272 //If network is not present in src node , remove the vxlan port of src from dst node in TunnelRules(Bug# 5614)
1273 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1274 if (dstBridgeNode != null) {
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 String datapathId = southbound.getDatapathId(node);
1307 LOG.trace("initializeFlowRules: bridgeName: {}, datapathId: {} ",
1308 bridgeName, datapathId);
1311 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1318 * Match: LLDP (0x88CCL)
1319 * Action: Packet_In to Controller Reserved Port
1322 writeLLDPRule(dpid);
1324 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
1325 NetvirtProvidersProvider.getTableOffset() != 0) {
1326 classifierProvider.programGotoTable(dpid,true);
1329 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1330 writeNormalRule(dpid);
1335 * Create an LLDP Flow Rule to encapsulate into
1336 * a packet_in that is sent to the controller
1337 * for topology handling.
1338 * Match: Ethertype 0x88CCL
1339 * Action: Punt to Controller in a Packet_In msg
1342 private void writeLLDPRule(Long dpidLong) {
1343 classifierProvider.programLLDPPuntRule(dpidLong);
1347 * Create a NORMAL Table Miss Flow Rule
1349 * Action: forward to NORMAL pipeline
1352 private void writeNormalRule(Long dpidLong) {
1353 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1354 FlowBuilder flowBuilder = new FlowBuilder();
1355 String flowName = "NORMAL";
1356 FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
1357 MatchBuilder matchBuilder = new MatchBuilder();
1358 flowBuilder.setMatch(matchBuilder.build());
1360 // Create the OF Actions and Instructions
1361 InstructionBuilder ib = new InstructionBuilder();
1362 InstructionsBuilder isb = new InstructionsBuilder();
1364 // Instructions List Stores Individual Instructions
1365 List<Instruction> instructions = Lists.newArrayList();
1367 // Call the InstructionBuilder Methods Containing Actions
1368 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1370 ib.setKey(new InstructionKey(0));
1371 instructions.add(ib.build());
1373 // Add InstructionBuilder to the Instruction(s)Builder List
1374 isb.setInstruction(instructions);
1376 // Add InstructionsBuilder to FlowBuilder
1377 flowBuilder.setInstructions(isb.build());
1378 writeFlow(flowBuilder, nodeBuilder);
1382 * (Table:0) Ingress Tunnel Traffic
1383 * Match: OpenFlow InPort and Tunnel ID
1384 * Action: GOTO Local Table (10)
1385 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1388 private void handleTunnelIn(Long dpidLong, Short writeTable,
1389 Short goToTableId, String segmentationId,
1390 Long ofPort, boolean write) {
1391 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1395 * (Table:0) Ingress VLAN Traffic
1396 * Match: OpenFlow InPort and vlan ID
1397 * Action: GOTO Local Table (20)
1398 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1401 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1402 String segmentationId, Long ethPort, boolean write) {
1403 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1407 * (Table:0) Egress VM Traffic Towards TEP
1408 * Match: Destination Ethernet Addr and OpenFlow InPort
1409 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1410 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1411 * actions=set_field:5->tun_id,goto_table=1"
1414 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1415 String segmentationId, Long inPort, String attachedMac,
1417 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1421 * (Table:0) Egress VM Traffic Towards TEP
1422 * Match: Source Ethernet Addr and OpenFlow InPort
1423 * Instruction: Set VLANID and GOTO Table Egress (n)
1424 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1425 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1428 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1429 Short goToTableId, String segmentationId,
1430 Long inPort, String attachedMac,
1432 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1436 * (Table:0) Drop frames source from a VM that do not
1437 * match the associated MAC address of the local VM.
1438 * Match: Low priority anything not matching the VM SMAC
1440 * table=0,priority=16384,in_port=1 actions=drop"
1443 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1444 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1448 * (Table:1) Egress Tunnel Traffic
1449 * Match: Destination Ethernet Addr and Local InPort
1450 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1451 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1452 * actions=output:10,goto_table:2"
1454 private void handleTunnelOut(Long dpidLong, Short writeTable,
1455 Short goToTableId, String segmentationId,
1456 Long OFPortOut, String attachedMac,
1458 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1462 * (Table:1) Egress VLAN Traffic
1463 * Match: Destination Ethernet Addr and VLAN id
1464 * Instruction: GOTO Table Table 2
1465 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1466 * actions= goto_table:2"
1468 // TODO This method is referenced from commented code above (which needs to be checked)
1469 @SuppressWarnings("unused")
1470 private void handleVlanOut(Long dpidLong, Short writeTable,
1471 Short goToTableId, String segmentationId,
1472 Long ethPort, String attachedMac, boolean write) {
1473 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, 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,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1481 * actions=output:10,output:11,goto_table:2
1484 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1485 Short localTable, String segmentationId,
1486 Long OFPortOut, boolean write) {
1487 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1491 * (Table:1) Egress VLAN Traffic
1492 * Match: Destination Ethernet Addr and VLAN id
1493 * Instruction: GOTO table 2 and Output port eth interface
1494 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1495 * actions=output:eth1,goto_table:2
1497 // TODO This method is referenced from commented code above (which needs to be checked)
1498 @SuppressWarnings("unused")
1499 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1500 Short localTable, String segmentationId,
1501 Long localPort, Long ethPort, boolean write) {
1502 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1506 * (Table:1) Table Drain w/ Catch All
1508 * Action: GOTO Local Table (10)
1509 * table=2,priority=8192,tun_id=0x5 actions=drop
1512 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1513 Short goToTableId, String segmentationId,
1515 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1520 * (Table:1) Table Drain w/ Catch All
1522 * Action: Output port eth interface
1523 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1524 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1527 private void handleVlanMiss(Long dpidLong, Short writeTable,
1528 Short goToTableId, String segmentationId,
1529 Long ethPort, boolean write) {
1530 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1534 * (Table:1) Local Broadcast Flood
1535 * Match: Tunnel ID and dMAC
1536 * Action: Output Port
1537 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1540 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1541 String segmentationId, Long localPort,
1542 String attachedMac, boolean write) {
1543 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1547 * (Table:2) Local VLAN unicast
1548 * Match: VLAN ID and dMAC
1549 * Action: Output Port
1550 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1553 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1554 String segmentationId, Long localPort,
1555 String attachedMac, boolean write) {
1556 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1560 * (Table:2) Local Broadcast Flood
1561 * Match: Tunnel ID and dMAC (::::FF:FF)
1562 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1563 * actions=output:2,3,4,5
1566 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1567 String segmentationId, Long localPort,
1569 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1573 * (Table:2) Local VLAN Broadcast Flood
1574 * Match: vlan ID and dMAC (::::FF:FF)
1575 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1576 * actions=strip_vlan, output:2,3,4,5
1577 * 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
1580 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1581 Long localPort, Long ethPort, boolean write) {
1582 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1586 * (Table:1) Local Table Miss
1587 * Match: Any Remaining Flows w/a TunID
1588 * Action: Drop w/ a low priority
1589 * table=2,priority=8192,tun_id=0x5 actions=drop
1592 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1593 String segmentationId, boolean write) {
1594 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1598 * (Table:1) Local Table Miss
1599 * Match: Any Remaining Flows w/a VLAN ID
1600 * Action: Drop w/ a low priority
1601 * table=2,priority=8192,vlan_id=0x5 actions=drop
1603 // TODO This method is referenced from commented code above (which needs to be checked)
1604 @SuppressWarnings("unused")
1605 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1606 String segmentationId, boolean write) {
1607 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1610 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1611 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1612 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1613 new GroupKey(groupBuilder.getGroupId())).build();
1614 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1616 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1617 if (data.isPresent()) {
1620 } catch (InterruptedException|ExecutionException e) {
1621 LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
1624 LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
1628 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1629 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1630 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1631 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1632 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1633 new GroupKey(groupBuilder.getGroupId())).build();
1634 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1636 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1638 commitFuture.get(); // TODO: Make it async (See bug 1362)
1639 LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
1640 } catch (InterruptedException|ExecutionException e) {
1641 LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
1646 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1647 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1648 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1649 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1650 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1651 new GroupKey(groupBuilder.getGroupId())).build();
1652 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1653 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1656 commitFuture.get(); // TODO: Make it async (See bug 1362)
1657 LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
1658 } catch (InterruptedException|ExecutionException e) {
1659 LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
1664 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1665 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1666 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1667 InstanceIdentifier<Flow> path1 =
1668 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1669 .rev130819.nodes.Node.class,
1670 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1671 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1673 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1674 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1675 true);//createMissingParents
1678 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1680 commitFuture.get(); // TODO: Make it async (See bug 1362)
1681 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
1682 } catch (InterruptedException|ExecutionException e) {
1683 LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
1689 * Create Output Port Group Instruction
1691 * @param ib Map InstructionBuilder without any instructions
1692 * @param dpidLong Long the datapath ID of a switch/node
1693 * @param port Long representing a port on a switch/node
1694 * @return ib InstructionBuilder Map with instructions
1696 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1697 @SuppressWarnings("unused")
1698 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1699 InstructionBuilder ib,
1700 Long dpidLong, Long port ,
1701 List<Instruction> instructions) {
1702 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1703 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1705 List<Action> actionList = Lists.newArrayList();
1706 ActionBuilder ab = new ActionBuilder();
1708 List<Action> existingActions;
1709 if (instructions != null) {
1710 for (Instruction in : instructions) {
1711 if (in.getInstruction() instanceof ApplyActionsCase) {
1712 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1713 actionList.addAll(existingActions);
1718 GroupBuilder groupBuilder = new GroupBuilder();
1721 /* Create output action for this port*/
1722 OutputActionBuilder oab = new OutputActionBuilder();
1723 oab.setOutputNodeConnector(ncid);
1724 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1725 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1726 boolean addNew = true;
1727 boolean groupActionAdded = false;
1729 /* Find the group action and get the group */
1730 for (Action action : actionList) {
1731 if (action.getAction() instanceof GroupActionCase) {
1732 groupActionAdded = true;
1733 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1734 Long id = groupAction.getGroupAction().getGroupId();
1735 String groupName = groupAction.getGroupAction().getGroup();
1736 GroupKey key = new GroupKey(new GroupId(id));
1738 groupBuilder.setGroupId(new GroupId(id));
1739 groupBuilder.setGroupName(groupName);
1740 groupBuilder.setGroupType(GroupTypes.GroupAll);
1741 groupBuilder.setKey(key);
1742 group = getGroup(groupBuilder, nodeBuilder);
1743 LOG.debug("createOutputGroupInstructions: group {}", group);
1748 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1749 if (groupActionAdded) {
1750 /* modify the action bucket in group */
1751 groupBuilder = new GroupBuilder(group);
1752 Buckets buckets = groupBuilder.getBuckets();
1753 for (Bucket bucket : buckets.getBucket()) {
1754 List<Action> bucketActions = bucket.getAction();
1755 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1756 for (Action action : bucketActions) {
1757 if (action.getAction() instanceof OutputActionCase) {
1758 OutputActionCase opAction = (OutputActionCase)action.getAction();
1759 /* If output port action already in the action list of one of the buckets, skip */
1760 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1767 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1768 if (addNew && !buckets.getBucket().isEmpty()) {
1769 /* the new output action is not in the bucket, add to bucket */
1770 Bucket bucket = buckets.getBucket().get(0);
1771 List<Action> bucketActionList = Lists.newArrayList();
1772 bucketActionList.addAll(bucket.getAction());
1773 /* set order for new action and add to action list */
1774 ab.setOrder(bucketActionList.size());
1775 ab.setKey(new ActionKey(bucketActionList.size()));
1776 bucketActionList.add(ab.build());
1778 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1779 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1780 List<Bucket> bucketList = Lists.newArrayList();
1781 BucketBuilder bucketBuilder = new BucketBuilder();
1782 bucketBuilder.setBucketId(new BucketId((long) 1));
1783 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1784 bucketBuilder.setAction(bucketActionList);
1785 bucketList.add(bucketBuilder.build());
1786 bucketsBuilder.setBucket(bucketList);
1787 groupBuilder.setBuckets(bucketsBuilder.build());
1788 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1792 groupBuilder = new GroupBuilder();
1793 groupBuilder.setGroupType(GroupTypes.GroupAll);
1794 groupBuilder.setGroupId(new GroupId(groupId));
1795 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1796 groupBuilder.setGroupName("Output port group " + groupId);
1797 groupBuilder.setBarrier(false);
1799 BucketsBuilder bucketBuilder = new BucketsBuilder();
1800 List<Bucket> bucketList = Lists.newArrayList();
1801 BucketBuilder bucket = new BucketBuilder();
1802 bucket.setBucketId(new BucketId((long) 1));
1803 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1805 /* put output action to the bucket */
1806 List<Action> bucketActionList = Lists.newArrayList();
1807 /* set order for new action and add to action list */
1808 ab.setOrder(bucketActionList.size());
1809 ab.setKey(new ActionKey(bucketActionList.size()));
1810 bucketActionList.add(ab.build());
1812 bucket.setAction(bucketActionList);
1813 bucketList.add(bucket.build());
1814 bucketBuilder.setBucket(bucketList);
1815 groupBuilder.setBuckets(bucketBuilder.build());
1817 /* Add new group action */
1818 GroupActionBuilder groupActionB = new GroupActionBuilder();
1819 groupActionB.setGroupId(groupId);
1820 groupActionB.setGroup("Output port group " + groupId);
1821 ab = new ActionBuilder();
1822 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1823 ab.setOrder(actionList.size());
1824 ab.setKey(new ActionKey(actionList.size()));
1825 actionList.add(ab.build());
1829 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1830 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1833 /* rewrite the group to group table */
1834 writeGroup(groupBuilder, nodeBuilder);
1837 // Create an Apply Action
1838 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1839 aab.setAction(actionList);
1840 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1846 * Remove Output Port from action list in group bucket
1848 * @param ib Map InstructionBuilder without any instructions
1849 * @param dpidLong Long the datapath ID of a switch/node
1850 * @param port Long representing a port on a switch/node
1851 * @return ib InstructionBuilder Map with instructions
1853 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1854 @SuppressWarnings("unused")
1855 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1856 Long dpidLong, Long port , List<Instruction> instructions) {
1858 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1859 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1861 List<Action> actionList = Lists.newArrayList();
1864 List<Action> existingActions;
1865 if (instructions != null) {
1866 for (Instruction in : instructions) {
1867 if (in.getInstruction() instanceof ApplyActionsCase) {
1868 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1869 actionList.addAll(existingActions);
1875 GroupBuilder groupBuilder = new GroupBuilder();
1877 boolean groupActionAdded = false;
1878 /* Find the group action and get the group */
1879 for (Action action : actionList) {
1880 if (action.getAction() instanceof GroupActionCase) {
1881 groupActionAdded = true;
1882 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1883 Long id = groupAction.getGroupAction().getGroupId();
1884 String groupName = groupAction.getGroupAction().getGroup();
1885 GroupKey key = new GroupKey(new GroupId(id));
1887 groupBuilder.setGroupId(new GroupId(id));
1888 groupBuilder.setGroupName(groupName);
1889 groupBuilder.setGroupType(GroupTypes.GroupAll);
1890 groupBuilder.setKey(key);
1891 group = getGroup(groupBuilder, nodeBuilder);
1896 if (groupActionAdded) {
1897 /* modify the action bucket in group */
1898 groupBuilder = new GroupBuilder(group);
1899 Buckets buckets = groupBuilder.getBuckets();
1900 List<Action> bucketActions = Lists.newArrayList();
1901 for (Bucket bucket : buckets.getBucket()) {
1903 boolean isPortDeleted = false;
1904 bucketActions = bucket.getAction();
1905 for (Action action : bucketActions) {
1906 if (action.getAction() instanceof OutputActionCase) {
1907 OutputActionCase opAction = (OutputActionCase)action.getAction();
1908 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1909 /* Find the output port in action list and remove */
1910 index = bucketActions.indexOf(action);
1911 bucketActions.remove(action);
1912 isPortDeleted = true;
1917 if (isPortDeleted && !bucketActions.isEmpty()) {
1918 for (int i = index; i< bucketActions.size(); i++) {
1919 Action action = bucketActions.get(i);
1920 if (action.getOrder() != i) {
1921 /* Shift the action order */
1922 ab = new ActionBuilder();
1923 ab.setAction(action.getAction());
1925 ab.setKey(new ActionKey(i));
1926 Action actionNewOrder = ab.build();
1927 bucketActions.remove(action);
1928 bucketActions.add(i, actionNewOrder);
1932 } else if (bucketActions.isEmpty()) {
1933 /* remove bucket with empty action list */
1934 buckets.getBucket().remove(bucket);
1938 if (!buckets.getBucket().isEmpty()) {
1939 /* rewrite the group to group table */
1940 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1941 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1942 List<Bucket> bucketList = Lists.newArrayList();
1943 BucketBuilder bucketBuilder = new BucketBuilder();
1944 bucketBuilder.setBucketId(new BucketId((long) 1));
1945 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1946 bucketBuilder.setAction(bucketActions);
1947 bucketList.add(bucketBuilder.build());
1948 bucketsBuilder.setBucket(bucketList);
1949 groupBuilder.setBuckets(bucketsBuilder.build());
1950 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1952 writeGroup(groupBuilder, nodeBuilder);
1953 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1954 aab.setAction(actionList);
1955 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1958 /* remove group with empty bucket. return true to delete flow */
1959 removeGroup(groupBuilder, nodeBuilder);
1963 /* no group for port list. flow can be removed */
1969 public void initializeOFFlowRules(Node openflowNode) {
1970 String bridgeName = southbound.getBridgeName(openflowNode);
1971 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1972 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1973 initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1974 triggerInterfaceUpdates(openflowNode);
1975 } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1976 initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1977 triggerInterfaceUpdates(openflowNode);
1981 public static NodeBuilder createNodeBuilder(String nodeId) {
1982 NodeBuilder builder = new NodeBuilder();
1983 builder.setId(new NodeId(nodeId));
1984 builder.setKey(new NodeKey(builder.getId()));
1989 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1990 this.bundleContext = bundleContext;
1991 configurationService =
1992 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1993 tenantNetworkManager =
1994 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1995 bridgeConfigurationManager =
1996 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1998 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1999 classifierProvider =
2000 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
2001 ingressAclProvider =
2002 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
2004 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
2005 l2ForwardingProvider =
2006 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
2007 securityServicesManager =
2008 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
2010 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
2014 public void setDependencies(Object impl) {
2015 if (impl instanceof NetworkingProviderManager) {
2016 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
2017 networkingProviderManager.providerAdded(
2018 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);