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 static java.util.Collections.emptyList;
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
18 import java.util.Optional;
19 import java.util.concurrent.ConcurrentHashMap;
20 import java.util.concurrent.ConcurrentMap;
21 import java.util.concurrent.CopyOnWriteArraySet;
22 import java.util.concurrent.ExecutionException;
23 import java.util.concurrent.Future;
24 import javax.inject.Inject;
25 import javax.inject.Singleton;
26 import org.eclipse.jdt.annotation.NonNull;
27 import org.eclipse.jdt.annotation.Nullable;
28 import org.opendaylight.genius.datastoreutils.SingleTransactionDataBroker;
29 import org.opendaylight.genius.infra.Datastore;
30 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
31 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
32 import org.opendaylight.genius.infra.TypedWriteTransaction;
33 import org.opendaylight.genius.mdsalutil.ActionInfo;
34 import org.opendaylight.genius.mdsalutil.FlowEntity;
35 import org.opendaylight.genius.mdsalutil.InstructionInfo;
36 import org.opendaylight.genius.mdsalutil.MDSALUtil;
37 import org.opendaylight.genius.mdsalutil.MatchInfo;
38 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
39 import org.opendaylight.genius.mdsalutil.NwConstants;
40 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
41 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldDscp;
42 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
43 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
44 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
45 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
46 import org.opendaylight.genius.utils.ServiceIndex;
47 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
48 import org.opendaylight.mdsal.binding.api.DataBroker;
49 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
50 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
51 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeInterfaceInfo;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntryKey;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.port.attributes.FixedIps;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
95 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
101 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
102 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
103 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
104 import org.opendaylight.yangtools.yang.common.RpcResult;
105 import org.opendaylight.yangtools.yang.common.Uint64;
106 import org.slf4j.Logger;
107 import org.slf4j.LoggerFactory;
110 public class QosNeutronUtils {
111 private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
113 private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
114 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
115 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
116 private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
117 private final ConcurrentHashMap<Uuid, Port> neutronPortMap = new ConcurrentHashMap<>();
118 private final ConcurrentHashMap<Uuid, Network> neutronNetworkMap = new ConcurrentHashMap<>();
120 private final QosEosHandler qosEosHandler;
121 private final INeutronVpnManager neutronVpnManager;
122 private final OdlInterfaceRpcService odlInterfaceRpcService;
123 private final DataBroker dataBroker;
124 private final ManagedNewTransactionRunner txRunner;
125 private final IMdsalApiManager mdsalUtils;
126 private final JobCoordinator jobCoordinator;
129 public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
130 final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
131 final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
132 this.qosEosHandler = qosEosHandler;
133 this.neutronVpnManager = neutronVpnManager;
134 this.odlInterfaceRpcService = odlInterfaceRpcService;
135 this.dataBroker = dataBroker;
136 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
137 this.mdsalUtils = mdsalUtils;
138 this.jobCoordinator = jobCoordinator;
141 public void addToQosPolicyCache(QosPolicy qosPolicy) {
142 qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
145 public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
146 qosPolicyMap.remove(qosPolicy.getUuid());
149 public Map<Uuid, QosPolicy> getQosPolicyMap() {
153 public Collection<Port> getQosPorts(Uuid qosUuid) {
154 final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
155 return portMap != null ? portMap.values() : emptyList();
158 public void addToQosPortsCache(Uuid qosUuid, Port port) {
159 qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
162 public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
163 if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
164 qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
168 public void addToQosNetworksCache(Uuid qosUuid, Network network) {
169 qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
173 public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
174 if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
175 qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
180 public Collection<Network> getQosNetworks(Uuid qosUuid) {
181 final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
182 return networkMap != null ? networkMap.values() : emptyList();
186 public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
187 InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
188 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
189 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
190 networkMapId, dataBroker);
191 return (optionalNetworkMap.isPresent() && optionalNetworkMap.get().getSubnetIdList() != null)
192 ? optionalNetworkMap.get().getSubnetIdList() : emptyList();
196 protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
197 InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
198 .builder(Subnetmaps.class)
199 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
200 Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
201 subnetMapId,dataBroker);
202 return (optionalSubnetmap.isPresent() && optionalSubnetmap.get().getPortList() != null)
203 ? optionalSubnetmap.get().getPortList() : emptyList();
206 public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
207 LOG.debug("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid().getValue(),
210 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
212 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
213 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
214 // handle Bandwidth Limit Rules update
215 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
216 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
217 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
219 // handle DSCP Mark Rules update
220 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
221 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
222 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
227 public void handleQosInterfaceAdd(Port port, Uuid qosUuid) {
228 LOG.debug("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid().getValue(),
231 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
233 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
234 // handle DSCP Mark Rules update
235 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
236 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
237 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
243 public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
244 LOG.debug("Handling Port QoS update: port: {} qosservice: {}", port.getUuid().getValue(),
245 qosUuidNew.getValue());
247 QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
248 QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
250 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
251 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
252 // handle Bandwidth Limit Rules update
253 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
254 && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
255 setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), tx);
257 if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
258 && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
259 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
260 setPortBandwidthLimits(port, bwLimitBuilder
261 .setMaxBurstKbps(Uint64.ZERO)
262 .setMaxKbps(Uint64.ZERO).build(), tx);
265 //handle DSCP Mark Rules update
266 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
267 && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
268 setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
270 if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
271 && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
272 unsetPortDscpMark(port);
278 public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
279 LOG.debug("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid().getValue(), qosUuid.getValue());
281 // check for network qosservice to apply
282 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
283 if (network != null && network.augmentation(QosNetworkExtension.class) != null) {
284 Uuid networkQosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
285 if (networkQosUuid != null) {
286 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
289 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
291 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
292 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
293 // handle Bandwidth Limit Rules removal
294 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
295 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
296 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
297 setPortBandwidthLimits(port, bwLimitBuilder
298 .setMaxBurstKbps(Uint64.ZERO)
299 .setMaxKbps(Uint64.ZERO).build(), tx);
301 // handle DSCP MArk Rules removal
302 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
303 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
304 unsetPortDscpMark(port);
310 public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
311 LOG.debug("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid().getValue(),
313 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
315 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
316 //check if any DSCP rule in the policy
317 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
318 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
319 unsetPortDscpMark(port);
325 public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
326 LOG.debug("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid().getValue(),
328 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
330 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
331 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
332 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
333 unsetPortDscpMark(port, intrf);
340 public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
341 LOG.debug("Handling Network QoS update: net: {} qosservice: {}", network.getUuid().getValue(), qosUuid);
342 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
343 if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
344 || qosPolicy.getBandwidthLimitRules().isEmpty())
345 && (qosPolicy.getDscpmarkingRules() == null
346 || qosPolicy.getDscpmarkingRules().isEmpty())) {
349 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
350 for (Uuid subnetId : subnetIds) {
351 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
352 for (Uuid portId : portIds) {
353 Port port = getNeutronPort(portId);
354 if (port != null && (port.augmentation(QosPortExtension.class) == null
355 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
356 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
357 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
358 CONFIGURATION, tx -> {
359 if (qosPolicy.getBandwidthLimitRules() != null
360 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
361 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
363 if (qosPolicy.getDscpmarkingRules() != null
364 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
365 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
373 public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
374 LOG.debug("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid().getValue(),
376 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
378 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
379 for (Uuid subnetId : subnetIds) {
380 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
381 for (Uuid portId : portIds) {
382 Port port = getNeutronPort(portId);
383 if (port != null && (port.augmentation(QosPortExtension.class) == null
384 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
385 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
386 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
387 CONFIGURATION, tx -> {
388 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
389 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
390 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
391 setPortBandwidthLimits(port, bwLimitBuilder
392 .setMaxBurstKbps(Uint64.ZERO)
393 .setMaxKbps(Uint64.ZERO).build(), tx);
395 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
396 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
397 unsetPortDscpMark(port);
405 public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
406 LOG.debug("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid().getValue());
408 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
410 for (Uuid subnetId: subnetIds) {
411 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
412 for (Uuid portId : portIds) {
413 Port port = getNeutronPort(portId);
414 if (port != null && (port.augmentation(QosPortExtension.class) == null
415 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
416 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> Collections.singletonList(
417 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
418 tx -> setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
424 public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
425 LOG.debug("Handling Qos Dscp Rule Remove, net: {}", network.getUuid().getValue());
427 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
429 for (Uuid subnetId: subnetIds) {
430 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
431 for (Uuid portId : portIds) {
432 Port port = getNeutronPort(portId);
433 if (port != null && (port.augmentation(QosPortExtension.class) == null
434 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
435 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
436 unsetPortDscpMark(port);
444 // TODO Clean up the exception handling
445 @SuppressWarnings("checkstyle:IllegalCatch")
446 public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit,
447 TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
448 if (!qosEosHandler.isQosClusterOwner()) {
449 LOG.debug("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
452 Uint64 dpId = getDpnForInterface(port.getUuid().getValue());
453 if (dpId.equals(Uint64.ZERO)) {
454 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
458 LOG.trace("Setting bandwidth limits {} on Port {}", port.getUuid().getValue(), bwLimit);
459 OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
460 Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
461 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
462 if (!bridgeNode.isPresent()) {
463 LOG.error("bridge not found for dpn {} port {} in operational datastore", dpId, port.getUuid().getValue());
466 LOG.debug("bridgeNode {}", bridgeNode.get().getNodeId().getValue());
468 TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
469 port.getUuid().getValue());
471 LOG.debug("Skipping setting of bandwidth limit rules for subport {}",
472 port.getUuid().getValue());
475 LOG.debug("tp: {}", tp.getTpId().getValue());
476 OvsdbTerminationPointAugmentation ovsdbTp = tp.augmentation(OvsdbTerminationPointAugmentation.class);
478 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
479 tpAugmentationBuilder.setName(ovsdbTp.getName());
480 tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
481 tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
483 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
484 tpBuilder.withKey(tp.key());
485 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
487 if (writeConfigTxn != null) {
488 writeConfigTxn.merge(InstanceIdentifier
489 .create(NetworkTopology.class)
490 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
491 .child(Node.class, bridgeNode.get().key())
492 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build(), true);
494 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
495 .create(NetworkTopology.class)
496 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
497 .child(Node.class, bridgeNode.get().key())
498 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build());
500 } catch (Exception e) {
501 if (LOG.isDebugEnabled()) {
502 LOG.debug("Failure while setting BwLimitRule {} to port {} exception ", bwLimit,
503 port.getUuid().getValue(), e);
505 LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port.getUuid().getValue());
511 public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
513 Uint64 dpnId = getDpnForInterface(port.getUuid().getValue());
514 String ifName = port.getUuid().getValue();
516 if (dpnId.equals(Uint64.ZERO)) {
517 LOG.info("DPN ID for interface {} not found. Cannot set dscp value {} on port {}",
518 port.getUuid().getValue(), dscpMark, port.getUuid().getValue());
522 if (!qosEosHandler.isQosClusterOwner()) {
523 qosServiceConfiguredPorts.add(port.getUuid());
524 LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
527 Interface ifState = getInterfaceStateFromOperDS(ifName);
528 Short dscpValue = dscpMark.getDscpMark().toJava();
529 int ipVersions = getIpVersions(port);
531 if (hasIpv4Addr(ipVersions)) {
532 LOG.trace("setting ipv4 flow for port: {}, dscp: {}", ifName, dscpValue);
533 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV4, ifState);
535 if (hasIpv6Addr(ipVersions)) {
536 LOG.trace("setting ipv6 flow for port: {}, dscp: {}", ifName, dscpValue);
537 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV6, ifState);
540 if (qosServiceConfiguredPorts.add(port.getUuid())) {
541 // bind qos service to interface
548 public void unsetPortDscpMark(Port port) {
550 Uint64 dpnId = getDpnForInterface(port.getUuid().getValue());
551 String ifName = port.getUuid().getValue();
553 if (dpnId.equals(Uint64.ZERO)) {
554 LOG.debug("DPN ID for port {} not found. Cannot unset dscp value", port.getUuid().getValue());
558 if (!qosEosHandler.isQosClusterOwner()) {
559 qosServiceConfiguredPorts.remove(port.getUuid());
560 LOG.debug("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
563 LOG.trace("Removing dscp marking rule from Port {}", port.getUuid().getValue());
564 Interface intf = getInterfaceStateFromOperDS(ifName);
565 //unbind service from interface
566 unbindservice(ifName);
568 int ipVersions = getIpVersions(port);
569 if (hasIpv4Addr(ipVersions)) {
570 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intf);
572 if (hasIpv6Addr(ipVersions)) {
573 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intf);
575 qosServiceConfiguredPorts.remove(port.getUuid());
579 public void unsetPortDscpMark(Port port, Interface intrf) {
581 Uint64 dpnId = getDpIdFromInterface(intrf);
582 String ifName = port.getUuid().getValue();
584 if (dpnId.equals(Uint64.ZERO)) {
585 LOG.error("Unable to retrieve DPN Id for interface {}. Cannot unset dscp value on port", ifName);
588 if (!qosEosHandler.isQosClusterOwner()) {
589 qosServiceConfiguredPorts.remove(port.getUuid());
592 LOG.trace("Removing dscp marking rule from Port {}", port.getUuid().getValue());
593 unbindservice(ifName);
594 int ipVersions = getIpVersions(port);
595 if (hasIpv4Addr(ipVersions)) {
596 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intrf);
598 if (hasIpv6Addr(ipVersions)) {
599 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intrf);
601 qosServiceConfiguredPorts.remove(port.getUuid());
605 private static Uint64 getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
606 .interfaces.rev140508.interfaces.state.Interface ifState) {
607 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
608 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
609 Long dpIdLong = MDSALUtil.getDpnIdFromPortName(nodeConnectorId);
610 Uint64 dpnId = dpIdLong < 0 ? Uint64.ZERO : Uint64.valueOf(dpIdLong);
614 public Uint64 getDpnForInterface(String ifName) {
615 Uint64 nodeId = Uint64.ZERO;
617 GetDpidFromInterfaceInput
618 dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
619 Future<RpcResult<GetDpidFromInterfaceOutput>>
620 dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
621 RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
622 if (dpIdResult.isSuccessful()) {
623 nodeId = dpIdResult.getResult().getDpid();
625 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
627 } catch (NullPointerException | InterruptedException | ExecutionException e) {
628 if (LOG.isDebugEnabled()) {
629 LOG.debug("Exception when getting DPN for interface {} exception ", ifName, e);
631 LOG.error("Could not retrieve DPN for interface {}", ifName);
638 private BridgeEntry getBridgeEntryFromConfigDS(Uint64 dpnId) {
639 BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
640 InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
641 LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
642 return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
646 private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
647 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker)
652 private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
653 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orElse(null);
657 private OvsdbBridgeRef getBridgeRefEntryFromOperDS(Uint64 dpId) {
658 BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
659 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
660 BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
661 if (bridgeRefEntry == null) {
662 // bridge ref entry will be null if the bridge is disconnected from controller.
663 // In that case, fetch bridge reference from bridge interface entry config DS
664 BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
665 if (bridgeEntry == null) {
668 return bridgeEntry.getBridgeReference();
670 return bridgeRefEntry.getBridgeReference();
674 private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
675 return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
679 private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
680 return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
683 public void removeStaleFlowEntry(Interface intrf, int ethType) {
684 List<MatchInfo> matches = new ArrayList<>();
686 Uint64 dpnId = getDpIdFromInterface(intrf);
688 Integer ifIndex = intrf.getIfIndex();
689 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
690 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
691 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
692 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
694 mdsalUtils.removeFlow(flowEntity);
697 public void addFlow(Uint64 dpnId, Short dscpValue, String ifName, int ethType, Interface ifState) {
698 if (ifState == null) {
699 LOG.debug("Could not find the ifState for interface {}", ifName);
702 Integer ifIndex = ifState.getIfIndex();
704 List<MatchInfo> matches = new ArrayList<>();
705 matches.add(new MatchEthernetType(ethType));
706 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
708 List<ActionInfo> actionsInfos = new ArrayList<>();
709 actionsInfos.add(new ActionSetFieldDscp(dscpValue));
710 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
712 List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
713 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
714 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
715 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
716 matches, instructions);
717 mdsalUtils.installFlow(flowEntity);
720 public void removeFlow(Uint64 dpnId, String ifName, int ethType, Interface ifState) {
721 if (ifState == null) {
722 LOG.debug("Could not find the ifState for interface {}", ifName);
725 Integer ifIndex = ifState.getIfIndex();
727 mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
728 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType)));
731 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state
732 .@Nullable Interface getInterfaceStateFromOperDS(String interfaceName) {
734 return SingleTransactionDataBroker.syncReadOptional(dataBroker, LogicalDatastoreType.OPERATIONAL,
735 createInterfaceStateInstanceIdentifier(interfaceName)).orElse(null);
736 } catch (ExecutionException | InterruptedException e) {
737 LOG.error("getInterfaceStateFromOperDS: Exception while reading interface DS for the interface {}",
744 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
745 .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
746 String interfaceName) {
747 return InstanceIdentifier
748 .builder(InterfacesState.class)
749 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
750 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
751 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
752 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
757 public void bindservice(String ifName) {
758 int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
759 int instructionKey = 0;
760 List<Instruction> instructions = new ArrayList<>();
761 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
762 short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
764 BoundServices serviceInfo = getBoundServices(
765 String.format("%s.%s", "qos", ifName), qosServiceIndex,
766 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
767 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
768 buildServiceId(ifName, qosServiceIndex),
772 public void unbindservice(String ifName) {
773 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
774 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
777 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
778 return InstanceIdentifier.builder(ServiceBindings.class)
779 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
780 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
783 private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
784 Uint64 cookieQosTable, List<Instruction> instructions) {
785 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
786 .setFlowPriority(priority).setInstruction(instructions);
787 return new BoundServicesBuilder().withKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
788 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
789 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
793 public static String getQosFlowId(short tableId, Uint64 dpId, int lportTag, int ethType) {
794 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(dpId)
795 .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
796 .append(NwConstants.FLOWID_SEPARATOR).append(ethType).toString();
799 public boolean portHasQosPolicy(Port port) {
800 LOG.trace("checking qos policy for port: {}", port.getUuid().getValue());
802 boolean isQosPolicy = port.augmentation(QosPortExtension.class) != null
803 && port.augmentation(QosPortExtension.class).getQosPolicyId() != null;
805 LOG.trace("portHasQosPolicy for port: {} return value {}", port.getUuid().getValue(), isQosPolicy);
810 public QosPolicy getQosPolicy(Port port) {
812 QosPolicy qosPolicy = null;
814 if (port.augmentation(QosPortExtension.class) != null) {
815 qosUuid = port.augmentation(QosPortExtension.class).getQosPolicyId();
817 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
819 if (network != null && network.augmentation(QosNetworkExtension.class) != null) {
820 qosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
824 if (qosUuid != null) {
825 qosPolicy = qosPolicyMap.get(qosUuid);
831 public boolean hasDscpMarkingRule(QosPolicy qosPolicy) {
832 if (qosPolicy != null) {
833 return qosPolicy.getDscpmarkingRules() != null && !qosPolicy.getDscpmarkingRules().isEmpty();
838 public void addToPortCache(Port port) {
839 neutronPortMap.put(port.getUuid(), port);
842 public void removeFromPortCache(Port port) {
843 neutronPortMap.remove(port.getUuid());
846 public Port getNeutronPort(Uuid portUuid) {
847 return neutronPortMap.get(portUuid);
850 public Port getNeutronPort(String portName) {
851 return getNeutronPort(new Uuid(portName));
854 public void addToNetworkCache(Network network) {
855 neutronNetworkMap.put(network.getUuid(), network);
858 public void removeFromNetworkCache(Network network) {
859 neutronNetworkMap.remove(network.getUuid());
862 public Network getNeutronNetwork(Uuid networkUuid) {
863 return neutronNetworkMap.get(networkUuid);
867 public static Uint64 getDpnIdFromLowerLayerIf(String lowerLayerIf) {
869 return Uint64.valueOf(lowerLayerIf.substring(lowerLayerIf.indexOf(":") + 1, lowerLayerIf.lastIndexOf(":")));
870 } catch (NullPointerException e) {
876 public static String getPortNumberFromLowerLayerIf(String lowerLayerIf) {
878 return (lowerLayerIf.substring(lowerLayerIf.lastIndexOf(":") + 1));
879 } catch (NullPointerException e) {
884 public int getIpVersions(Port port) {
886 for (FixedIps fixedIp: port.getFixedIps()) {
887 if (fixedIp.getIpAddress().getIpv4Address() != null) {
888 versions |= (1 << QosConstants.IPV4_ADDR_MASK_BIT);
889 } else if (fixedIp.getIpAddress().getIpv6Address() != null) {
890 versions |= (1 << QosConstants.IPV6_ADDR_MASK_BIT);
896 public boolean hasIpv4Addr(int versions) {
897 return (versions & (1 << QosConstants.IPV4_ADDR_MASK_BIT)) != 0;
900 public boolean hasIpv6Addr(int versions) {
901 return (versions & (1 << QosConstants.IPV6_ADDR_MASK_BIT)) != 0;
904 public boolean isBindServiceDone(Optional<Uuid> uuid) {
906 return qosServiceConfiguredPorts.contains(uuid.get());
911 public void removeInterfaceInQosConfiguredPorts(Optional<Uuid> uuid) {
913 qosServiceConfiguredPorts.remove(uuid.get());