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.rev100924.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("addTunnelPort enter: 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);
1172 if (sourceTunnelStatus) {
1173 boolean isDestinNw = tenantNetworkManager.isTenantNetworkPresentInNode(dstBridgeNode, segmentationId);
1174 //Check whether the network is present in src & dst node
1175 //If only present , add vxlan ports in TunnelRules for both nodes (bug# 5614)
1176 if (isSrcinNw && isDestinNw) {
1177 programTunnelRules(networkType, segmentationId, dst, srcBridgeNode, intf, true);
1178 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, true);
1181 if (destTunnelStatus) {
1182 programTunnelRules(networkType, segmentationId, src, dstBridgeNode, intf, false);
1184 if (srcNodeId != null && intBridgesWithoutVmPorts.contains(srcNodeId)) {
1185 programTunnelRulesInNewNode(network, networkType, segmentationId, src, dst,
1186 srcBridgeNode, dstBridgeNode, intf);
1187 intBridgesWithoutVmPorts.remove(srcNodeId);
1191 LOG.warn("Tunnel end-point configuration missing. Please configure it in OpenVSwitch Table. "
1192 + "Check source {} or destination {}",
1193 src != null ? src.getHostAddress() : "null",
1194 dst != null ? dst.getHostAddress() : "null");
1199 if (srcNodeId != null && !bridgeHasVmPort(srcNode)) {
1200 intBridgesWithoutVmPorts.add(srcNodeId);
1206 private void triggerInterfaceUpdates(Node node) {
1207 LOG.debug("enter triggerInterfaceUpdates for {}", node.getNodeId());
1208 List<OvsdbTerminationPointAugmentation> ports = southbound.extractTerminationPointAugmentations(node);
1209 if (ports != null && !ports.isEmpty()) {
1210 for (OvsdbTerminationPointAugmentation port : ports) {
1211 NeutronNetwork neutronNetwork = tenantNetworkManager.getTenantNetwork(port);
1212 if (neutronNetwork != null) {
1213 LOG.warn("Trigger Interface update for {}", port);
1214 handleInterfaceUpdate(neutronNetwork, node, port);
1218 LOG.warn("triggerInterfaceUpdates: tps are null");
1220 LOG.debug("exit triggerInterfaceUpdates for {}", node.getNodeId());
1224 public boolean handleInterfaceDelete(String tunnelType, NeutronNetwork network, Node srcNode,
1225 OvsdbTerminationPointAugmentation intf, boolean isLastInstanceOnNode) {
1226 Map<org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId,Node> nodes =
1227 nodeCacheManager.getOvsdbNodes();
1228 nodes.remove(southbound.extractBridgeOvsdbNodeId(srcNode));
1230 LOG.info("Delete intf " + intf.getName() + " isLastInstanceOnNode " + isLastInstanceOnNode);
1231 String segmentationId = network.getProviderSegmentationID();
1232 List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(srcNode);
1233 if (southbound.isTunnel(intf)) {
1234 // Delete tunnel port
1236 InetAddress src = InetAddress.getByName(
1237 southbound.getOptionsValue(intf.getOptions(), "local_ip"));
1238 InetAddress dst = InetAddress.getByName(
1239 southbound.getOptionsValue(intf.getOptions(), "remote_ip"));
1240 deleteTunnelPort(srcNode,
1241 MdsalHelper.createOvsdbInterfaceType(intf.getInterfaceType()),
1243 } catch (Exception e) {
1244 LOG.error("handleInterfaceDelete: failed to delete tunnel port", e);
1246 } else if (phyIfName.contains(intf.getName())) {
1247 deletePhysicalPort(srcNode, intf.getName());
1249 // delete all other interfaces
1250 removeLocalRules(network.getProviderNetworkType(), segmentationId,
1253 if (isVlan(network.getProviderNetworkType())) {
1254 removeVlanRules(network, srcNode, intf, isLastInstanceOnNode);
1255 } else if (isTunnel(network.getProviderNetworkType())) {
1257 Node srcBridgeNode = southbound.getBridgeNode(srcNode, configurationService.getIntegrationBridgeName());
1258 for (Node dstNode : nodes.values()) {
1259 InetAddress src = configurationService.getTunnelEndPoint(srcNode);
1260 InetAddress dst = configurationService.getTunnelEndPoint(dstNode);
1261 if ((src != null) && (dst != null)) {
1262 LOG.info("Remove tunnel rules for interface "
1263 + intf.getName() + " on srcNode " + srcNode.getNodeId().getValue());
1264 removeTunnelRules(tunnelType, segmentationId,
1265 dst, srcNode, intf, true, isLastInstanceOnNode);
1266 Node dstBridgeNode = southbound.getBridgeNode(dstNode, Constants.INTEGRATION_BRIDGE);
1267 //While removing last instance , check whether the network present in src node
1268 //If network is not present in src node , remove the vxlan port of src from dst node in TunnelRules(Bug# 5614)
1269 boolean isSrcinNw = tenantNetworkManager.isTenantNetworkPresentInNode(srcBridgeNode, segmentationId);
1270 if (dstBridgeNode != null) {
1272 removeTunnelRules(tunnelType, segmentationId,
1273 src, dstBridgeNode, intf, true, isLastInstanceOnNode);
1275 LOG.info("Remove tunnel rules for interface "
1276 + intf.getName() + " on dstNode " + dstNode.getNodeId().getValue());
1277 removeTunnelRules(tunnelType, segmentationId, src,
1278 dstBridgeNode, intf, false, isLastInstanceOnNode);
1281 LOG.warn("Tunnel end-point configuration missing. Please configure it in "
1282 + "OpenVSwitch Table. "
1283 + "Check source {} or destination {}",
1284 src != null ? src.getHostAddress() : "null",
1285 dst != null ? dst.getHostAddress() : "null");
1294 public void initializeFlowRules(Node node) {
1295 initializeFlowRules(node, configurationService.getIntegrationBridgeName());
1296 initializeFlowRules(node, configurationService.getExternalBridgeName());
1297 triggerInterfaceUpdates(node);
1300 private void initializeFlowRules(Node node, String bridgeName) {
1301 Long dpid = southbound.getDataPathId(node);
1302 String datapathId = southbound.getDatapathId(node);
1303 LOG.info("initializeFlowRules: bridgeName: {}, dpid: {} - {}",
1304 bridgeName, dpid, datapathId);
1307 LOG.debug("Openflow Datapath-ID not set for the integration bridge in {}", node);
1314 * Match: LLDP (0x88CCL)
1315 * Action: Packet_In to Controller Reserved Port
1318 writeLLDPRule(dpid);
1320 if (bridgeName.equals(configurationService.getIntegrationBridgeName()) &&
1321 NetvirtProvidersProvider.getTableOffset() != 0) {
1322 classifierProvider.programGotoTable(dpid,true);
1325 if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1326 writeNormalRule(dpid);
1331 * Create an LLDP Flow Rule to encapsulate into
1332 * a packet_in that is sent to the controller
1333 * for topology handling.
1334 * Match: Ethertype 0x88CCL
1335 * Action: Punt to Controller in a Packet_In msg
1338 private void writeLLDPRule(Long dpidLong) {
1339 classifierProvider.programLLDPPuntRule(dpidLong);
1343 * Create a NORMAL Table Miss Flow Rule
1345 * Action: forward to NORMAL pipeline
1348 private void writeNormalRule(Long dpidLong) {
1349 NodeBuilder nodeBuilder = FlowUtils.createNodeBuilder(dpidLong);
1350 FlowBuilder flowBuilder = new FlowBuilder();
1351 String flowName = "NORMAL";
1352 FlowUtils.initFlowBuilder(flowBuilder, flowName, Service.CLASSIFIER.getTable()).setPriority(0);
1353 MatchBuilder matchBuilder = new MatchBuilder();
1354 flowBuilder.setMatch(matchBuilder.build());
1356 // Create the OF Actions and Instructions
1357 InstructionBuilder ib = new InstructionBuilder();
1358 InstructionsBuilder isb = new InstructionsBuilder();
1360 // Instructions List Stores Individual Instructions
1361 List<Instruction> instructions = Lists.newArrayList();
1363 // Call the InstructionBuilder Methods Containing Actions
1364 InstructionUtils.createNormalInstructions(FlowUtils.getNodeName(dpidLong), ib);
1366 ib.setKey(new InstructionKey(0));
1367 instructions.add(ib.build());
1369 // Add InstructionBuilder to the Instruction(s)Builder List
1370 isb.setInstruction(instructions);
1372 // Add InstructionsBuilder to FlowBuilder
1373 flowBuilder.setInstructions(isb.build());
1374 writeFlow(flowBuilder, nodeBuilder);
1378 * (Table:0) Ingress Tunnel Traffic
1379 * Match: OpenFlow InPort and Tunnel ID
1380 * Action: GOTO Local Table (10)
1381 * table=0,tun_id=0x5,in_port=10, actions=goto_table:2
1384 private void handleTunnelIn(Long dpidLong, Short writeTable,
1385 Short goToTableId, String segmentationId,
1386 Long ofPort, boolean write) {
1387 classifierProvider.programTunnelIn(dpidLong, segmentationId, ofPort, write);
1391 * (Table:0) Ingress VLAN Traffic
1392 * Match: OpenFlow InPort and vlan ID
1393 * Action: GOTO Local Table (20)
1394 * table=0,vlan_id=0x5,in_port=10, actions=goto_table:2
1397 private void handleVlanIn(Long dpidLong, Short writeTable, Short goToTableId,
1398 String segmentationId, Long ethPort, boolean write) {
1399 classifierProvider.programVlanIn(dpidLong, segmentationId, ethPort, write);
1403 * (Table:0) Egress VM Traffic Towards TEP
1404 * Match: Destination Ethernet Addr and OpenFlow InPort
1405 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1406 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1407 * actions=set_field:5->tun_id,goto_table=1"
1410 private void handleLocalInPort(Long dpidLong, Short writeTable, Short goToTableId,
1411 String segmentationId, Long inPort, String attachedMac,
1413 classifierProvider.programLocalInPort(dpidLong, segmentationId, inPort, attachedMac, write);
1417 * (Table:0) Egress VM Traffic Towards TEP
1418 * Match: Source Ethernet Addr and OpenFlow InPort
1419 * Instruction: Set VLANID and GOTO Table Egress (n)
1420 * table=0,in_port=2,dl_src=00:00:00:00:00:01 \
1421 * actions=push_vlan, set_field:5->vlan_id,goto_table=1"
1424 private void handleLocalInPortSetVlan(Long dpidLong, Short writeTable,
1425 Short goToTableId, String segmentationId,
1426 Long inPort, String attachedMac,
1428 classifierProvider.programLocalInPortSetVlan(dpidLong, segmentationId, inPort, attachedMac, write);
1432 * (Table:0) Drop frames source from a VM that do not
1433 * match the associated MAC address of the local VM.
1434 * Match: Low priority anything not matching the VM SMAC
1436 * table=0,priority=16384,in_port=1 actions=drop"
1439 private void handleDropSrcIface(Long dpidLong, Long inPort, boolean write) {
1440 classifierProvider.programDropSrcIface(dpidLong, inPort, write);
1444 * (Table:1) Egress Tunnel Traffic
1445 * Match: Destination Ethernet Addr and Local InPort
1446 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1447 * table=1,tun_id=0x5,dl_dst=00:00:00:00:00:08 \
1448 * actions=output:10,goto_table:2"
1450 private void handleTunnelOut(Long dpidLong, Short writeTable,
1451 Short goToTableId, String segmentationId,
1452 Long OFPortOut, String attachedMac,
1454 l2ForwardingProvider.programTunnelOut(dpidLong, segmentationId, OFPortOut, attachedMac, write);
1458 * (Table:1) Egress VLAN Traffic
1459 * Match: Destination Ethernet Addr and VLAN id
1460 * Instruction: GOTO Table Table 2
1461 * table=1,vlan_id=0x5,dl_dst=00:00:00:00:00:08 \
1462 * actions= goto_table:2"
1464 // TODO This method is referenced from commented code above (which needs to be checked)
1465 @SuppressWarnings("unused")
1466 private void handleVlanOut(Long dpidLong, Short writeTable,
1467 Short goToTableId, String segmentationId,
1468 Long ethPort, String attachedMac, boolean write) {
1469 l2ForwardingProvider.programVlanOut(dpidLong, segmentationId, ethPort, attachedMac, write);
1473 * (Table:1) Egress Tunnel Traffic
1474 * Match: Destination Ethernet Addr and Local InPort
1475 * Instruction: Set TunnelID and GOTO Table Tunnel Table (n)
1476 * table=1,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1477 * actions=output:10,output:11,goto_table:2
1480 private void handleTunnelFloodOut(Long dpidLong, Short writeTable,
1481 Short localTable, String segmentationId,
1482 Long OFPortOut, boolean write) {
1483 l2ForwardingProvider.programTunnelFloodOut(dpidLong, segmentationId, OFPortOut, write);
1487 * (Table:1) Egress VLAN Traffic
1488 * Match: Destination Ethernet Addr and VLAN id
1489 * Instruction: GOTO table 2 and Output port eth interface
1490 * Example: table=1,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1491 * actions=output:eth1,goto_table:2
1493 // TODO This method is referenced from commented code above (which needs to be checked)
1494 @SuppressWarnings("unused")
1495 private void handleVlanFloodOut(Long dpidLong, Short writeTable,
1496 Short localTable, String segmentationId,
1497 Long localPort, Long ethPort, boolean write) {
1498 //l2ForwardingProvider.programVlanFloodOut(dpidLong, segmentationId, localPort, ethPort, write);
1502 * (Table:1) Table Drain w/ Catch All
1504 * Action: GOTO Local Table (10)
1505 * table=2,priority=8192,tun_id=0x5 actions=drop
1508 private void handleTunnelMiss(Long dpidLong, Short writeTable,
1509 Short goToTableId, String segmentationId,
1511 l2ForwardingProvider.programTunnelMiss(dpidLong, segmentationId, write);
1516 * (Table:1) Table Drain w/ Catch All
1518 * Action: Output port eth interface
1519 * table=1,priority=8192,vlan_id=0x5 actions= output port:eth1
1520 * table=110,priority=8192,dl_vlan=2001 actions=output:2
1523 private void handleVlanMiss(Long dpidLong, Short writeTable,
1524 Short goToTableId, String segmentationId,
1525 Long ethPort, boolean write) {
1526 l2ForwardingProvider.programVlanMiss(dpidLong, segmentationId, ethPort, write);
1530 * (Table:1) Local Broadcast Flood
1531 * Match: Tunnel ID and dMAC
1532 * Action: Output Port
1533 * table=2,tun_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1536 private void handleLocalUcastOut(Long dpidLong, Short writeTable,
1537 String segmentationId, Long localPort,
1538 String attachedMac, boolean write) {
1539 l2ForwardingProvider.programLocalUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1543 * (Table:2) Local VLAN unicast
1544 * Match: VLAN ID and dMAC
1545 * Action: Output Port
1546 * table=2,vlan_id=0x5,dl_dst=00:00:00:00:00:01 actions=output:2
1549 private void handleLocalVlanUcastOut(Long dpidLong, Short writeTable,
1550 String segmentationId, Long localPort,
1551 String attachedMac, boolean write) {
1552 l2ForwardingProvider.programLocalVlanUcastOut(dpidLong, segmentationId, localPort, attachedMac, write);
1556 * (Table:2) Local Broadcast Flood
1557 * Match: Tunnel ID and dMAC (::::FF:FF)
1558 * table=2,priority=16384,tun_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1559 * actions=output:2,3,4,5
1562 private void handleLocalBcastOut(Long dpidLong, Short writeTable,
1563 String segmentationId, Long localPort,
1565 l2ForwardingProvider.programLocalBcastOut(dpidLong, segmentationId, localPort, write);
1569 * (Table:2) Local VLAN Broadcast Flood
1570 * Match: vlan ID and dMAC (::::FF:FF)
1571 * table=2,priority=16384,vlan_id=0x5,dl_dst=ff:ff:ff:ff:ff:ff \
1572 * actions=strip_vlan, output:2,3,4,5
1573 * 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
1576 private void handleLocalVlanBcastOut(Long dpidLong, Short writeTable, String segmentationId,
1577 Long localPort, Long ethPort, boolean write) {
1578 l2ForwardingProvider.programLocalVlanBcastOut(dpidLong, segmentationId, localPort, ethPort, write);
1582 * (Table:1) Local Table Miss
1583 * Match: Any Remaining Flows w/a TunID
1584 * Action: Drop w/ a low priority
1585 * table=2,priority=8192,tun_id=0x5 actions=drop
1588 private void handleLocalTableMiss(Long dpidLong, Short writeTable,
1589 String segmentationId, boolean write) {
1590 l2ForwardingProvider.programLocalTableMiss(dpidLong, segmentationId, write);
1594 * (Table:1) Local Table Miss
1595 * Match: Any Remaining Flows w/a VLAN ID
1596 * Action: Drop w/ a low priority
1597 * table=2,priority=8192,vlan_id=0x5 actions=drop
1599 // TODO This method is referenced from commented code above (which needs to be checked)
1600 @SuppressWarnings("unused")
1601 private void handleLocalVlanTableMiss(Long dpidLong, Short writeTable,
1602 String segmentationId, boolean write) {
1603 l2ForwardingProvider.programLocalVlanTableMiss(dpidLong, segmentationId, write);
1606 private Group getGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1607 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1608 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1609 new GroupKey(groupBuilder.getGroupId())).build();
1610 ReadOnlyTransaction readTx = dataBroker.newReadOnlyTransaction();
1612 Optional<Group> data = readTx.read(LogicalDatastoreType.CONFIGURATION, path1).get();
1613 if (data.isPresent()) {
1616 } catch (InterruptedException|ExecutionException e) {
1617 LOG.error("Failed to get group {}", groupBuilder.getGroupName(), e);
1620 LOG.debug("Cannot find data for Group {}", groupBuilder.getGroupName());
1624 private void writeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1625 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1626 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1627 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1628 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1629 new GroupKey(groupBuilder.getGroupId())).build();
1630 modification.put(LogicalDatastoreType.CONFIGURATION, path1, groupBuilder.build(), true /*createMissingParents*/);
1632 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1634 commitFuture.get(); // TODO: Make it async (See bug 1362)
1635 LOG.debug("Transaction success for write of Group {}", groupBuilder.getGroupName());
1636 } catch (InterruptedException|ExecutionException e) {
1637 LOG.error("Failed to write group {}", groupBuilder.getGroupName(), e);
1642 private void removeGroup(GroupBuilder groupBuilder, NodeBuilder nodeBuilder) {
1643 if (NetvirtProvidersProvider.isMasterProviderInstance()) {
1644 WriteTransaction modification = dataBroker.newWriteOnlyTransaction();
1645 InstanceIdentifier<Group> path1 = InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1646 .rev130819.nodes.Node.class, nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Group.class,
1647 new GroupKey(groupBuilder.getGroupId())).build();
1648 modification.delete(LogicalDatastoreType.CONFIGURATION, path1);
1649 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1652 commitFuture.get(); // TODO: Make it async (See bug 1362)
1653 LOG.debug("Transaction success for deletion of Group {}", groupBuilder.getGroupName());
1654 } catch (InterruptedException|ExecutionException e) {
1655 LOG.error("Failed to remove group {}", groupBuilder.getGroupName(), e);
1660 private void writeFlow(FlowBuilder flowBuilder, NodeBuilder nodeBuilder) {
1661 if (NetvirtProvidersProvider.isMasterProviderInstance()){
1662 ReadWriteTransaction modification = dataBroker.newReadWriteTransaction();
1663 InstanceIdentifier<Flow> path1 =
1664 InstanceIdentifier.builder(Nodes.class).child(org.opendaylight.yang.gen.v1.urn.opendaylight.inventory
1665 .rev130819.nodes.Node.class,
1666 nodeBuilder.getKey()).augmentation(FlowCapableNode.class).child(Table.class,
1667 new TableKey(flowBuilder.getTableId())).child(Flow.class, flowBuilder.getKey()).build();
1669 //modification.put(LogicalDatastoreType.OPERATIONAL, path1, flowBuilder.build());
1670 modification.put(LogicalDatastoreType.CONFIGURATION, path1, flowBuilder.build(),
1671 true);//createMissingParents
1674 CheckedFuture<Void, TransactionCommitFailedException> commitFuture = modification.submit();
1676 commitFuture.get(); // TODO: Make it async (See bug 1362)
1677 LOG.debug("Transaction success for write of Flow {}", flowBuilder.getFlowName());
1678 } catch (InterruptedException|ExecutionException e) {
1679 LOG.error("Failed to write flows {}", flowBuilder.getFlowName(), e);
1685 * Create Output Port Group Instruction
1687 * @param ib Map InstructionBuilder without any instructions
1688 * @param dpidLong Long the datapath ID of a switch/node
1689 * @param port Long representing a port on a switch/node
1690 * @return ib InstructionBuilder Map with instructions
1692 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1693 @SuppressWarnings("unused")
1694 protected InstructionBuilder createOutputGroupInstructions(NodeBuilder nodeBuilder,
1695 InstructionBuilder ib,
1696 Long dpidLong, Long port ,
1697 List<Instruction> instructions) {
1698 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1699 LOG.debug("createOutputGroupInstructions() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1701 List<Action> actionList = Lists.newArrayList();
1702 ActionBuilder ab = new ActionBuilder();
1704 List<Action> existingActions;
1705 if (instructions != null) {
1706 for (Instruction in : instructions) {
1707 if (in.getInstruction() instanceof ApplyActionsCase) {
1708 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1709 actionList.addAll(existingActions);
1714 GroupBuilder groupBuilder = new GroupBuilder();
1717 /* Create output action for this port*/
1718 OutputActionBuilder oab = new OutputActionBuilder();
1719 oab.setOutputNodeConnector(ncid);
1720 ab.setAction(new OutputActionCaseBuilder().setOutputAction(oab.build()).build());
1721 LOG.debug("createOutputGroupInstructions(): output action {}", ab.build());
1722 boolean addNew = true;
1723 boolean groupActionAdded = false;
1725 /* Find the group action and get the group */
1726 for (Action action : actionList) {
1727 if (action.getAction() instanceof GroupActionCase) {
1728 groupActionAdded = true;
1729 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1730 Long id = groupAction.getGroupAction().getGroupId();
1731 String groupName = groupAction.getGroupAction().getGroup();
1732 GroupKey key = new GroupKey(new GroupId(id));
1734 groupBuilder.setGroupId(new GroupId(id));
1735 groupBuilder.setGroupName(groupName);
1736 groupBuilder.setGroupType(GroupTypes.GroupAll);
1737 groupBuilder.setKey(key);
1738 group = getGroup(groupBuilder, nodeBuilder);
1739 LOG.debug("createOutputGroupInstructions: group {}", group);
1744 LOG.debug("createOutputGroupInstructions: groupActionAdded {}", groupActionAdded);
1745 if (groupActionAdded) {
1746 /* modify the action bucket in group */
1747 groupBuilder = new GroupBuilder(group);
1748 Buckets buckets = groupBuilder.getBuckets();
1749 for (Bucket bucket : buckets.getBucket()) {
1750 List<Action> bucketActions = bucket.getAction();
1751 LOG.debug("createOutputGroupInstructions: bucketActions {}", bucketActions);
1752 for (Action action : bucketActions) {
1753 if (action.getAction() instanceof OutputActionCase) {
1754 OutputActionCase opAction = (OutputActionCase)action.getAction();
1755 /* If output port action already in the action list of one of the buckets, skip */
1756 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1763 LOG.debug("createOutputGroupInstructions: addNew {}", addNew);
1764 if (addNew && !buckets.getBucket().isEmpty()) {
1765 /* the new output action is not in the bucket, add to bucket */
1766 Bucket bucket = buckets.getBucket().get(0);
1767 List<Action> bucketActionList = Lists.newArrayList();
1768 bucketActionList.addAll(bucket.getAction());
1769 /* set order for new action and add to action list */
1770 ab.setOrder(bucketActionList.size());
1771 ab.setKey(new ActionKey(bucketActionList.size()));
1772 bucketActionList.add(ab.build());
1774 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1775 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1776 List<Bucket> bucketList = Lists.newArrayList();
1777 BucketBuilder bucketBuilder = new BucketBuilder();
1778 bucketBuilder.setBucketId(new BucketId((long) 1));
1779 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1780 bucketBuilder.setAction(bucketActionList);
1781 bucketList.add(bucketBuilder.build());
1782 bucketsBuilder.setBucket(bucketList);
1783 groupBuilder.setBuckets(bucketsBuilder.build());
1784 LOG.debug("createOutputGroupInstructions: bucketList {}", bucketList);
1788 groupBuilder = new GroupBuilder();
1789 groupBuilder.setGroupType(GroupTypes.GroupAll);
1790 groupBuilder.setGroupId(new GroupId(groupId));
1791 groupBuilder.setKey(new GroupKey(new GroupId(groupId)));
1792 groupBuilder.setGroupName("Output port group " + groupId);
1793 groupBuilder.setBarrier(false);
1795 BucketsBuilder bucketBuilder = new BucketsBuilder();
1796 List<Bucket> bucketList = Lists.newArrayList();
1797 BucketBuilder bucket = new BucketBuilder();
1798 bucket.setBucketId(new BucketId((long) 1));
1799 bucket.setKey(new BucketKey(new BucketId((long) 1)));
1801 /* put output action to the bucket */
1802 List<Action> bucketActionList = Lists.newArrayList();
1803 /* set order for new action and add to action list */
1804 ab.setOrder(bucketActionList.size());
1805 ab.setKey(new ActionKey(bucketActionList.size()));
1806 bucketActionList.add(ab.build());
1808 bucket.setAction(bucketActionList);
1809 bucketList.add(bucket.build());
1810 bucketBuilder.setBucket(bucketList);
1811 groupBuilder.setBuckets(bucketBuilder.build());
1813 /* Add new group action */
1814 GroupActionBuilder groupActionB = new GroupActionBuilder();
1815 groupActionB.setGroupId(groupId);
1816 groupActionB.setGroup("Output port group " + groupId);
1817 ab = new ActionBuilder();
1818 ab.setAction(new GroupActionCaseBuilder().setGroupAction(groupActionB.build()).build());
1819 ab.setOrder(actionList.size());
1820 ab.setKey(new ActionKey(actionList.size()));
1821 actionList.add(ab.build());
1825 LOG.debug("createOutputGroupInstructions: group {}", groupBuilder.build());
1826 LOG.debug("createOutputGroupInstructions: actionList {}", actionList);
1829 /* rewrite the group to group table */
1830 writeGroup(groupBuilder, nodeBuilder);
1833 // Create an Apply Action
1834 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1835 aab.setAction(actionList);
1836 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1842 * Remove Output Port from action list in group bucket
1844 * @param ib Map InstructionBuilder without any instructions
1845 * @param dpidLong Long the datapath ID of a switch/node
1846 * @param port Long representing a port on a switch/node
1847 * @return ib InstructionBuilder Map with instructions
1849 // TODO This method is referenced from commented code in L2ForwardingService (which needs to be checked)
1850 @SuppressWarnings("unused")
1851 protected boolean removeOutputPortFromGroup(NodeBuilder nodeBuilder, InstructionBuilder ib,
1852 Long dpidLong, Long port , List<Instruction> instructions) {
1854 NodeConnectorId ncid = new NodeConnectorId(Constants.OPENFLOW_NODE_PREFIX + dpidLong + ":" + port);
1855 LOG.debug("removeOutputPortFromGroup() Node Connector ID is - Type=openflow: DPID={} port={} existingInstructions={}", dpidLong, port, instructions);
1857 List<Action> actionList = Lists.newArrayList();
1860 List<Action> existingActions;
1861 if (instructions != null) {
1862 for (Instruction in : instructions) {
1863 if (in.getInstruction() instanceof ApplyActionsCase) {
1864 existingActions = (((ApplyActionsCase) in.getInstruction()).getApplyActions().getAction());
1865 actionList.addAll(existingActions);
1871 GroupBuilder groupBuilder = new GroupBuilder();
1873 boolean groupActionAdded = false;
1874 /* Find the group action and get the group */
1875 for (Action action : actionList) {
1876 if (action.getAction() instanceof GroupActionCase) {
1877 groupActionAdded = true;
1878 GroupActionCase groupAction = (GroupActionCase) action.getAction();
1879 Long id = groupAction.getGroupAction().getGroupId();
1880 String groupName = groupAction.getGroupAction().getGroup();
1881 GroupKey key = new GroupKey(new GroupId(id));
1883 groupBuilder.setGroupId(new GroupId(id));
1884 groupBuilder.setGroupName(groupName);
1885 groupBuilder.setGroupType(GroupTypes.GroupAll);
1886 groupBuilder.setKey(key);
1887 group = getGroup(groupBuilder, nodeBuilder);
1892 if (groupActionAdded) {
1893 /* modify the action bucket in group */
1894 groupBuilder = new GroupBuilder(group);
1895 Buckets buckets = groupBuilder.getBuckets();
1896 List<Action> bucketActions = Lists.newArrayList();
1897 for (Bucket bucket : buckets.getBucket()) {
1899 boolean isPortDeleted = false;
1900 bucketActions = bucket.getAction();
1901 for (Action action : bucketActions) {
1902 if (action.getAction() instanceof OutputActionCase) {
1903 OutputActionCase opAction = (OutputActionCase)action.getAction();
1904 if (opAction.getOutputAction().getOutputNodeConnector().equals(new Uri(ncid))) {
1905 /* Find the output port in action list and remove */
1906 index = bucketActions.indexOf(action);
1907 bucketActions.remove(action);
1908 isPortDeleted = true;
1913 if (isPortDeleted && !bucketActions.isEmpty()) {
1914 for (int i = index; i< bucketActions.size(); i++) {
1915 Action action = bucketActions.get(i);
1916 if (action.getOrder() != i) {
1917 /* Shift the action order */
1918 ab = new ActionBuilder();
1919 ab.setAction(action.getAction());
1921 ab.setKey(new ActionKey(i));
1922 Action actionNewOrder = ab.build();
1923 bucketActions.remove(action);
1924 bucketActions.add(i, actionNewOrder);
1928 } else if (bucketActions.isEmpty()) {
1929 /* remove bucket with empty action list */
1930 buckets.getBucket().remove(bucket);
1934 if (!buckets.getBucket().isEmpty()) {
1935 /* rewrite the group to group table */
1936 /* set bucket and buckets list. Reset groupBuilder with new buckets.*/
1937 BucketsBuilder bucketsBuilder = new BucketsBuilder();
1938 List<Bucket> bucketList = Lists.newArrayList();
1939 BucketBuilder bucketBuilder = new BucketBuilder();
1940 bucketBuilder.setBucketId(new BucketId((long) 1));
1941 bucketBuilder.setKey(new BucketKey(new BucketId((long) 1)));
1942 bucketBuilder.setAction(bucketActions);
1943 bucketList.add(bucketBuilder.build());
1944 bucketsBuilder.setBucket(bucketList);
1945 groupBuilder.setBuckets(bucketsBuilder.build());
1946 LOG.debug("removeOutputPortFromGroup: bucketList {}", bucketList);
1948 writeGroup(groupBuilder, nodeBuilder);
1949 ApplyActionsBuilder aab = new ApplyActionsBuilder();
1950 aab.setAction(actionList);
1951 ib.setInstruction(new ApplyActionsCaseBuilder().setApplyActions(aab.build()).build());
1954 /* remove group with empty bucket. return true to delete flow */
1955 removeGroup(groupBuilder, nodeBuilder);
1959 /* no group for port list. flow can be removed */
1965 public void initializeOFFlowRules(Node openflowNode) {
1966 String bridgeName = southbound.getBridgeName(openflowNode);
1967 LOG.info("initializeOFFlowRules: bridgeName: {}", bridgeName);
1968 if (bridgeName.equals(configurationService.getIntegrationBridgeName())) {
1969 initializeFlowRules(openflowNode, configurationService.getIntegrationBridgeName());
1970 triggerInterfaceUpdates(openflowNode);
1971 } else if (bridgeName.equals(configurationService.getExternalBridgeName())) {
1972 initializeFlowRules(openflowNode, configurationService.getExternalBridgeName());
1973 LOG.info("initializeOFFlowRules after writeFlow: bridgeName: {}", bridgeName);
1974 triggerInterfaceUpdates(openflowNode);
1975 LOG.info("initializeOFFlowRules after triggerUpdates: bridgeName: {}", bridgeName);
1979 public static NodeBuilder createNodeBuilder(String nodeId) {
1980 NodeBuilder builder = new NodeBuilder();
1981 builder.setId(new NodeId(nodeId));
1982 builder.setKey(new NodeKey(builder.getId()));
1987 public void setDependencies(BundleContext bundleContext, ServiceReference serviceReference) {
1988 this.bundleContext = bundleContext;
1989 configurationService =
1990 (ConfigurationService) ServiceHelper.getGlobalInstance(ConfigurationService.class, this);
1991 tenantNetworkManager =
1992 (TenantNetworkManager) ServiceHelper.getGlobalInstance(TenantNetworkManager.class, this);
1993 bridgeConfigurationManager =
1994 (BridgeConfigurationManager) ServiceHelper.getGlobalInstance(BridgeConfigurationManager.class, this);
1996 (NodeCacheManager) ServiceHelper.getGlobalInstance(NodeCacheManager.class, this);
1997 classifierProvider =
1998 (ClassifierProvider) ServiceHelper.getGlobalInstance(ClassifierProvider.class, this);
1999 ingressAclProvider =
2000 (IngressAclProvider) ServiceHelper.getGlobalInstance(IngressAclProvider.class, this);
2002 (EgressAclProvider) ServiceHelper.getGlobalInstance(EgressAclProvider.class, this);
2003 l2ForwardingProvider =
2004 (L2ForwardingProvider) ServiceHelper.getGlobalInstance(L2ForwardingProvider.class, this);
2005 securityServicesManager =
2006 (SecurityServicesManager) ServiceHelper.getGlobalInstance(SecurityServicesManager.class, this);
2008 (Southbound) ServiceHelper.getGlobalInstance(Southbound.class, this);
2012 public void setDependencies(Object impl) {
2013 if (impl instanceof NetworkingProviderManager) {
2014 NetworkingProviderManager networkingProviderManager = (NetworkingProviderManager) impl;
2015 networkingProviderManager.providerAdded(
2016 bundleContext.getServiceReference(NetworkingProvider.class.getName()), this);