2 * Copyright (c) 2017 Intel Corporation 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
8 package org.opendaylight.netvirt.qosservice;
10 import com.google.common.base.Optional;
11 import java.math.BigInteger;
12 import java.util.ArrayList;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.List;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ConcurrentMap;
19 import java.util.concurrent.CopyOnWriteArraySet;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Future;
22 import javax.annotation.Nonnull;
23 import javax.annotation.Nullable;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
27 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
31 import org.opendaylight.genius.mdsalutil.ActionInfo;
32 import org.opendaylight.genius.mdsalutil.FlowEntity;
33 import org.opendaylight.genius.mdsalutil.InstructionInfo;
34 import org.opendaylight.genius.mdsalutil.MDSALUtil;
35 import org.opendaylight.genius.mdsalutil.MatchInfo;
36 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
37 import org.opendaylight.genius.mdsalutil.NwConstants;
38 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
39 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldDscp;
40 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
41 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
42 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
43 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
44 import org.opendaylight.genius.utils.ServiceIndex;
45 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
46 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
47 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeInterfaceInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
99 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
100 import org.opendaylight.yangtools.yang.common.RpcResult;
101 import org.slf4j.Logger;
102 import org.slf4j.LoggerFactory;
105 public class QosNeutronUtils {
106 private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
108 private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
109 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
110 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
111 private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
112 private final ConcurrentHashMap<Uuid, Port> neutronPortMap = new ConcurrentHashMap<>();
113 private final ConcurrentHashMap<Uuid, Network> neutronNetworkMap = new ConcurrentHashMap<>();
115 private final QosEosHandler qosEosHandler;
116 private final INeutronVpnManager neutronVpnManager;
117 private final OdlInterfaceRpcService odlInterfaceRpcService;
118 private final DataBroker dataBroker;
119 private final ManagedNewTransactionRunner txRunner;
120 private final IMdsalApiManager mdsalUtils;
121 private final JobCoordinator jobCoordinator;
124 public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
125 final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
126 final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
127 this.qosEosHandler = qosEosHandler;
128 this.neutronVpnManager = neutronVpnManager;
129 this.odlInterfaceRpcService = odlInterfaceRpcService;
130 this.dataBroker = dataBroker;
131 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
132 this.mdsalUtils = mdsalUtils;
133 this.jobCoordinator = jobCoordinator;
136 public void addToQosPolicyCache(QosPolicy qosPolicy) {
137 qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
140 public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
141 qosPolicyMap.remove(qosPolicy.getUuid());
144 public Map<Uuid, QosPolicy> getQosPolicyMap() {
148 public Collection<Port> getQosPorts(Uuid qosUuid) {
149 final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
150 return portMap != null ? portMap.values() : Collections.emptyList();
153 public void addToQosPortsCache(Uuid qosUuid, Port port) {
154 qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
157 public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
158 if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
159 qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
163 public void addToQosNetworksCache(Uuid qosUuid, Network network) {
164 qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
168 public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
169 if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
170 qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
175 public Collection<Network> getQosNetworks(Uuid qosUuid) {
176 final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
177 return networkMap != null ? networkMap.values() : Collections.emptyList();
181 public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
182 InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
183 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
184 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
185 networkMapId, dataBroker);
186 return optionalNetworkMap.isPresent() ? optionalNetworkMap.get().getSubnetIdList() : Collections.emptyList();
190 protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
191 InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
192 .builder(Subnetmaps.class)
193 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
194 Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
195 subnetMapId,dataBroker);
196 return optionalSubnetmap.isPresent() ? optionalSubnetmap.get().getPortList() : Collections.emptyList();
199 public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
200 LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
202 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
204 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
205 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
206 // handle Bandwidth Limit Rules update
207 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
208 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
209 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
211 // handle DSCP Mark Rules update
212 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
213 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
214 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
219 public void handleQosInterfaceAdd(Port port, Uuid qosUuid) {
220 LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
222 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
224 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
225 // handle DSCP Mark Rules update
226 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
227 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
228 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
230 return Collections.emptyList();
234 public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
235 LOG.trace("Handling Port QoS update: port: {} qosservice: {}", port.getUuid(), qosUuidNew);
237 QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
238 QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
240 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
241 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
242 // handle Bandwidth Limit Rules update
243 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
244 && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
245 setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), tx);
247 if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
248 && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
249 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
250 setPortBandwidthLimits(port, bwLimitBuilder
251 .setMaxBurstKbps(BigInteger.ZERO)
252 .setMaxKbps(BigInteger.ZERO).build(), tx);
255 //handle DSCP Mark Rules update
256 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
257 && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
258 setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
260 if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
261 && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
262 unsetPortDscpMark(port);
268 public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
269 LOG.trace("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid(), qosUuid);
271 // check for network qosservice to apply
272 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
273 if (network != null && network.augmentation(QosNetworkExtension.class) != null) {
274 Uuid networkQosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
275 if (networkQosUuid != null) {
276 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
279 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
281 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
282 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
283 // handle Bandwidth Limit Rules removal
284 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
285 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
286 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
287 setPortBandwidthLimits(port, bwLimitBuilder
288 .setMaxBurstKbps(BigInteger.ZERO)
289 .setMaxKbps(BigInteger.ZERO).build(), tx);
291 // handle DSCP MArk Rules removal
292 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
293 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
294 unsetPortDscpMark(port);
300 public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
301 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
302 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
304 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
305 //check if any DSCP rule in the policy
306 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
307 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
308 unsetPortDscpMark(port);
310 return Collections.emptyList();
314 public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
315 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
316 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
318 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
319 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
320 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
321 unsetPortDscpMark(port, intrf);
323 return Collections.emptyList();
328 public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
329 LOG.trace("Handling Network QoS update: net: {} qosservice: {}", network.getUuid(), qosUuid);
330 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
331 if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
332 || qosPolicy.getBandwidthLimitRules().isEmpty())
333 && (qosPolicy.getDscpmarkingRules() == null
334 || qosPolicy.getDscpmarkingRules().isEmpty())) {
337 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
338 for (Uuid subnetId : subnetIds) {
339 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
340 for (Uuid portId : portIds) {
341 Port port = getNeutronPort(portId);
342 if (port != null && (port.augmentation(QosPortExtension.class) == null
343 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
344 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
345 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
346 if (qosPolicy.getBandwidthLimitRules() != null
347 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
348 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
350 if (qosPolicy.getDscpmarkingRules() != null
351 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
352 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
360 public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
361 LOG.trace("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid(), qosUuid);
362 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
364 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
365 for (Uuid subnetId : subnetIds) {
366 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
367 for (Uuid portId : portIds) {
368 Port port = getNeutronPort(portId);
369 if (port != null && (port.augmentation(QosPortExtension.class) == null
370 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
371 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
372 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
373 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
374 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
375 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
376 setPortBandwidthLimits(port, bwLimitBuilder
377 .setMaxBurstKbps(BigInteger.ZERO)
378 .setMaxKbps(BigInteger.ZERO).build(), tx);
380 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
381 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
382 unsetPortDscpMark(port);
390 public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
391 LOG.trace("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid());
393 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
395 for (Uuid subnetId: subnetIds) {
396 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
397 for (Uuid portId : portIds) {
398 Port port = getNeutronPort(portId);
399 if (port != null && (port.augmentation(QosPortExtension.class) == null
400 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
401 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> Collections.singletonList(
402 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
403 tx -> setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
409 public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
410 LOG.trace("Handling Qos Dscp Rule Remove, net: {}", network.getUuid());
412 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
414 for (Uuid subnetId: subnetIds) {
415 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
416 for (Uuid portId : portIds) {
417 Port port = getNeutronPort(portId);
418 if (port != null && (port.augmentation(QosPortExtension.class) == null
419 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
420 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
421 unsetPortDscpMark(port);
422 return Collections.emptyList();
429 // TODO Clean up the exception handling
430 @SuppressWarnings("checkstyle:IllegalCatch")
431 public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit, WriteTransaction writeConfigTxn) {
432 if (!qosEosHandler.isQosClusterOwner()) {
433 LOG.trace("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
436 LOG.trace("Setting bandwidth limits {} on Port {}", port, bwLimit);
438 BigInteger dpId = getDpnForInterface(port.getUuid().getValue());
439 if (dpId.equals(BigInteger.ZERO)) {
440 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
444 OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
445 Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
446 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
449 TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
450 port.getUuid().getValue());
451 OvsdbTerminationPointAugmentation ovsdbTp = tp.augmentation(OvsdbTerminationPointAugmentation.class);
453 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
454 tpAugmentationBuilder.setName(ovsdbTp.getName());
455 tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
456 tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
458 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
459 tpBuilder.withKey(tp.key());
460 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
462 if (writeConfigTxn != null) {
463 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
464 .create(NetworkTopology.class)
465 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
466 .child(Node.class, bridgeNode.get().key())
467 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build(), true);
469 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
470 .create(NetworkTopology.class)
471 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
472 .child(Node.class, bridgeNode.get().key())
473 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build());
475 } catch (Exception e) {
476 LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port, e);
481 public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
482 if (!qosEosHandler.isQosClusterOwner()) {
483 LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
486 LOG.trace("Setting DSCP value {} on Port {}", port, dscpMark);
488 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
489 String ifName = port.getUuid().getValue();
490 Interface ifState = getInterfaceStateFromOperDS(ifName);
491 Short dscpValue = dscpMark.getDscpMark();
493 if (dpnId.equals(BigInteger.ZERO)) {
494 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
498 int ipVersions = getIpVersions(port);
501 if (hasIpv4Addr(ipVersions)) {
502 LOG.trace("setting ipv4 flow for port: {}, dscp: {}", ifName, dscpValue);
503 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV4, ifState);
505 if (hasIpv6Addr(ipVersions)) {
506 LOG.trace("setting ipv6 flow for port: {}, dscp: {}", ifName, dscpValue);
507 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV6, ifState);
510 if (qosServiceConfiguredPorts.add(port.getUuid())) {
511 // bind qos service to interface
516 public void unsetPortDscpMark(Port port) {
517 if (!qosEosHandler.isQosClusterOwner()) {
518 LOG.trace("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
521 LOG.trace("Removing dscp marking rule from Port {}", port);
523 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
524 String ifName = port.getUuid().getValue();
526 if (dpnId.equals(BigInteger.ZERO)) {
527 LOG.info("DPN ID for port {} not found", port);
530 Interface intf = getInterfaceStateFromOperDS(ifName);
532 //unbind service from interface
533 unbindservice(ifName);
535 int ipVersions = getIpVersions(port);
536 if (hasIpv4Addr(ipVersions)) {
537 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intf);
539 if (hasIpv6Addr(ipVersions)) {
540 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intf);
542 qosServiceConfiguredPorts.remove(port.getUuid());
545 public void unsetPortDscpMark(Port port, Interface intrf) {
546 if (!qosEosHandler.isQosClusterOwner()) {
549 LOG.trace("Removing dscp marking rule from Port {}", port);
551 BigInteger dpnId = getDpIdFromInterface(intrf);
552 String ifName = port.getUuid().getValue();
554 if (dpnId.equals(BigInteger.ZERO)) {
555 LOG.error("Unable to retrieve DPN Id for interface {}", ifName);
558 unbindservice(ifName);
559 int ipVersions = getIpVersions(port);
560 if (hasIpv4Addr(ipVersions)) {
561 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intrf);
563 if (hasIpv6Addr(ipVersions)) {
564 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intrf);
566 qosServiceConfiguredPorts.remove(port.getUuid());
569 private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
570 .interfaces.rev140508.interfaces.state.Interface ifState) {
571 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
572 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
573 return BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
576 public BigInteger getDpnForInterface(String ifName) {
577 BigInteger nodeId = BigInteger.ZERO;
579 GetDpidFromInterfaceInput
580 dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
581 Future<RpcResult<GetDpidFromInterfaceOutput>>
582 dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
583 RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
584 if (dpIdResult.isSuccessful()) {
585 nodeId = dpIdResult.getResult().getDpid();
587 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
589 } catch (NullPointerException | InterruptedException | ExecutionException e) {
590 LOG.error("Exception when getting dpn for interface {}", ifName, e);
596 private BridgeEntry getBridgeEntryFromConfigDS(BigInteger dpnId) {
597 BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
598 InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
599 LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
600 return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
604 private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
605 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker).orNull();
609 private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
610 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orNull();
614 private OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId) {
615 BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
616 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
617 BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
618 if (bridgeRefEntry == null) {
619 // bridge ref entry will be null if the bridge is disconnected from controller.
620 // In that case, fetch bridge reference from bridge interface entry config DS
621 BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
622 if (bridgeEntry == null) {
625 return bridgeEntry.getBridgeReference();
627 return bridgeRefEntry.getBridgeReference();
631 private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
632 return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
636 private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
637 return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
640 public void removeStaleFlowEntry(Interface intrf, int ethType) {
641 List<MatchInfo> matches = new ArrayList<>();
643 BigInteger dpnId = getDpIdFromInterface(intrf);
645 Integer ifIndex = intrf.getIfIndex();
646 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
647 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
648 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
649 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
651 mdsalUtils.removeFlow(flowEntity);
654 public void addFlow(BigInteger dpnId, Short dscpValue, String ifName, int ethType, Interface ifState) {
655 if (ifState == null) {
656 LOG.trace("Could not find the ifState for interface {}", ifName);
659 Integer ifIndex = ifState.getIfIndex();
661 List<MatchInfo> matches = new ArrayList<>();
662 matches.add(new MatchEthernetType(ethType));
663 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
665 List<ActionInfo> actionsInfos = new ArrayList<>();
666 actionsInfos.add(new ActionSetFieldDscp(dscpValue));
667 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
669 List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
670 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
671 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
672 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
673 matches, instructions);
674 mdsalUtils.installFlow(flowEntity);
677 public void removeFlow(BigInteger dpnId, String ifName, int ethType, Interface ifState) {
678 if (ifState == null) {
679 LOG.trace("Could not find the ifState for interface {}", ifName);
682 Integer ifIndex = ifState.getIfIndex();
684 mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
685 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType)));
689 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
690 .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
691 String interfaceName) {
692 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
693 createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
697 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
698 .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
699 String interfaceName) {
700 return InstanceIdentifier
701 .builder(InterfacesState.class)
702 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
703 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
704 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
705 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
710 public void bindservice(String ifName) {
711 int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
712 int instructionKey = 0;
713 List<Instruction> instructions = new ArrayList<>();
714 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
715 short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
717 BoundServices serviceInfo = getBoundServices(
718 String.format("%s.%s", "qos", ifName), qosServiceIndex,
719 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
720 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
721 buildServiceId(ifName, qosServiceIndex),
725 public void unbindservice(String ifName) {
726 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
727 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
730 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
731 return InstanceIdentifier.builder(ServiceBindings.class)
732 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
733 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
736 private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
737 BigInteger cookieQosTable, List<Instruction> instructions) {
738 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
739 .setFlowPriority(priority).setInstruction(instructions);
740 return new BoundServicesBuilder().withKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
741 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
742 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
746 public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag, int ethType) {
747 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(dpId)
748 .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
749 .append(NwConstants.FLOWID_SEPARATOR).append(ethType).toString();
752 public boolean portHasQosPolicy(Port port) {
753 LOG.trace("checking qos policy for port: {}", port.getUuid());
755 boolean isQosPolicy = port.augmentation(QosPortExtension.class) != null
756 && port.augmentation(QosPortExtension.class).getQosPolicyId() != null;
758 LOG.trace("portHasQosPolicy for port: {} return value {}", port.getUuid(), isQosPolicy);
763 public QosPolicy getQosPolicy(Port port) {
765 QosPolicy qosPolicy = null;
767 if (port.augmentation(QosPortExtension.class) != null) {
768 qosUuid = port.augmentation(QosPortExtension.class).getQosPolicyId();
770 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
772 if (network.augmentation(QosNetworkExtension.class) != null) {
773 qosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
777 if (qosUuid != null) {
778 qosPolicy = qosPolicyMap.get(qosUuid);
784 public boolean hasDscpMarkingRule(QosPolicy qosPolicy) {
785 if (qosPolicy != null) {
786 return qosPolicy.getDscpmarkingRules() != null && !qosPolicy.getDscpmarkingRules().isEmpty();
791 public void addToPortCache(Port port) {
792 neutronPortMap.put(port.getUuid(), port);
795 public void removeFromPortCache(Port port) {
796 neutronPortMap.remove(port.getUuid());
799 public Port getNeutronPort(Uuid portUuid) {
800 return neutronPortMap.get(portUuid);
803 public Port getNeutronPort(String portName) {
804 return getNeutronPort(new Uuid(portName));
807 public void addToNetworkCache(Network network) {
808 neutronNetworkMap.put(network.getUuid(), network);
811 public void removeFromNetworkCache(Network network) {
812 neutronNetworkMap.remove(network.getUuid());
815 public Network getNeutronNetwork(Uuid networkUuid) {
816 return neutronNetworkMap.get(networkUuid);
819 public static BigInteger getDpnIdFromLowerLayerIf(String lowerLayerIf) {
821 return new BigInteger(lowerLayerIf.substring(lowerLayerIf.indexOf(":") + 1, lowerLayerIf.lastIndexOf(":")));
822 } catch (NullPointerException e) {
827 public static String getPortNumberFromLowerLayerIf(String lowerLayerIf) {
829 return (lowerLayerIf.substring(lowerLayerIf.lastIndexOf(":") + 1));
830 } catch (NullPointerException e) {
835 public int getIpVersions(Port port) {
837 for (FixedIps fixedIp: port.getFixedIps()) {
838 if (fixedIp.getIpAddress().getIpv4Address() != null) {
839 versions |= (1 << QosConstants.IPV4_ADDR_MASK_BIT);
840 } else if (fixedIp.getIpAddress().getIpv6Address() != null) {
841 versions |= (1 << QosConstants.IPV6_ADDR_MASK_BIT);
847 public boolean hasIpv4Addr(int versions) {
848 if ((versions & (1 << QosConstants.IPV4_ADDR_MASK_BIT)) != 0) {
854 public boolean hasIpv6Addr(int versions) {
855 if ((versions & (1 << QosConstants.IPV6_ADDR_MASK_BIT)) != 0) {