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 com.google.common.base.Optional;
14 import java.math.BigInteger;
15 import java.util.ArrayList;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.List;
20 import java.util.concurrent.ConcurrentHashMap;
21 import java.util.concurrent.ConcurrentMap;
22 import java.util.concurrent.CopyOnWriteArraySet;
23 import java.util.concurrent.ExecutionException;
24 import java.util.concurrent.Future;
25 import javax.annotation.Nonnull;
26 import javax.annotation.Nullable;
27 import javax.inject.Inject;
28 import javax.inject.Singleton;
29 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
30 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
31 import org.opendaylight.genius.infra.Datastore;
32 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
33 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
34 import org.opendaylight.genius.infra.TypedWriteTransaction;
35 import org.opendaylight.genius.mdsalutil.ActionInfo;
36 import org.opendaylight.genius.mdsalutil.FlowEntity;
37 import org.opendaylight.genius.mdsalutil.InstructionInfo;
38 import org.opendaylight.genius.mdsalutil.MDSALUtil;
39 import org.opendaylight.genius.mdsalutil.MatchInfo;
40 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
41 import org.opendaylight.genius.mdsalutil.NwConstants;
42 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
43 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldDscp;
44 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
45 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
46 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
47 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
48 import org.opendaylight.genius.utils.ServiceIndex;
49 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
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.slf4j.Logger;
106 import org.slf4j.LoggerFactory;
109 public class QosNeutronUtils {
110 private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
112 private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
113 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
114 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
115 private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
116 private final ConcurrentHashMap<Uuid, Port> neutronPortMap = new ConcurrentHashMap<>();
117 private final ConcurrentHashMap<Uuid, Network> neutronNetworkMap = new ConcurrentHashMap<>();
119 private final QosEosHandler qosEosHandler;
120 private final INeutronVpnManager neutronVpnManager;
121 private final OdlInterfaceRpcService odlInterfaceRpcService;
122 private final DataBroker dataBroker;
123 private final ManagedNewTransactionRunner txRunner;
124 private final IMdsalApiManager mdsalUtils;
125 private final JobCoordinator jobCoordinator;
128 public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
129 final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
130 final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
131 this.qosEosHandler = qosEosHandler;
132 this.neutronVpnManager = neutronVpnManager;
133 this.odlInterfaceRpcService = odlInterfaceRpcService;
134 this.dataBroker = dataBroker;
135 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
136 this.mdsalUtils = mdsalUtils;
137 this.jobCoordinator = jobCoordinator;
140 public void addToQosPolicyCache(QosPolicy qosPolicy) {
141 qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
144 public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
145 qosPolicyMap.remove(qosPolicy.getUuid());
148 public Map<Uuid, QosPolicy> getQosPolicyMap() {
152 public Collection<Port> getQosPorts(Uuid qosUuid) {
153 final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
154 return portMap != null ? portMap.values() : emptyList();
157 public void addToQosPortsCache(Uuid qosUuid, Port port) {
158 qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
161 public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
162 if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
163 qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
167 public void addToQosNetworksCache(Uuid qosUuid, Network network) {
168 qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
172 public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
173 if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
174 qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
179 public Collection<Network> getQosNetworks(Uuid qosUuid) {
180 final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
181 return networkMap != null ? networkMap.values() : emptyList();
185 public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
186 InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
187 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
188 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
189 networkMapId, dataBroker);
190 return optionalNetworkMap.isPresent() ? nullToEmpty(optionalNetworkMap.get().getSubnetIdList()) : emptyList();
194 protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
195 InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
196 .builder(Subnetmaps.class)
197 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
198 Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
199 subnetMapId,dataBroker);
200 return optionalSubnetmap.isPresent() ? nullToEmpty(optionalSubnetmap.get().getPortList()) : emptyList();
203 public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
204 LOG.debug("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid().getValue(),
207 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
209 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
210 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
211 // handle Bandwidth Limit Rules update
212 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
213 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
214 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
216 // handle DSCP Mark Rules update
217 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
218 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
219 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
224 public void handleQosInterfaceAdd(Port port, Uuid qosUuid) {
225 LOG.debug("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid().getValue(),
228 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
230 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
231 // handle DSCP Mark Rules update
232 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
233 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
234 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
240 public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
241 LOG.debug("Handling Port QoS update: port: {} qosservice: {}", port.getUuid().getValue(),
242 qosUuidNew.getValue());
244 QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
245 QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
247 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
248 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
249 // handle Bandwidth Limit Rules update
250 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
251 && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
252 setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), tx);
254 if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
255 && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
256 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
257 setPortBandwidthLimits(port, bwLimitBuilder
258 .setMaxBurstKbps(BigInteger.ZERO)
259 .setMaxKbps(BigInteger.ZERO).build(), tx);
262 //handle DSCP Mark Rules update
263 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
264 && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
265 setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
267 if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
268 && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
269 unsetPortDscpMark(port);
275 public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
276 LOG.debug("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid().getValue(), qosUuid.getValue());
278 // check for network qosservice to apply
279 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
280 if (network != null && network.augmentation(QosNetworkExtension.class) != null) {
281 Uuid networkQosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
282 if (networkQosUuid != null) {
283 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
286 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
288 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
289 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
290 // handle Bandwidth Limit Rules removal
291 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
292 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
293 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
294 setPortBandwidthLimits(port, bwLimitBuilder
295 .setMaxBurstKbps(BigInteger.ZERO)
296 .setMaxKbps(BigInteger.ZERO).build(), tx);
298 // handle DSCP MArk Rules removal
299 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
300 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
301 unsetPortDscpMark(port);
307 public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
308 LOG.debug("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid().getValue(),
310 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
312 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
313 //check if any DSCP rule in the policy
314 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
315 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
316 unsetPortDscpMark(port);
322 public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
323 LOG.debug("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid().getValue(),
325 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
327 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
328 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
329 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
330 unsetPortDscpMark(port, intrf);
337 public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
338 LOG.debug("Handling Network QoS update: net: {} qosservice: {}", network.getUuid().getValue(), qosUuid);
339 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
340 if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
341 || qosPolicy.getBandwidthLimitRules().isEmpty())
342 && (qosPolicy.getDscpmarkingRules() == null
343 || qosPolicy.getDscpmarkingRules().isEmpty())) {
346 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
347 for (Uuid subnetId : subnetIds) {
348 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
349 for (Uuid portId : portIds) {
350 Port port = getNeutronPort(portId);
351 if (port != null && (port.augmentation(QosPortExtension.class) == null
352 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
353 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
354 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
355 CONFIGURATION, tx -> {
356 if (qosPolicy.getBandwidthLimitRules() != null
357 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
358 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
360 if (qosPolicy.getDscpmarkingRules() != null
361 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
362 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
370 public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
371 LOG.debug("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid().getValue(),
373 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
375 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
376 for (Uuid subnetId : subnetIds) {
377 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
378 for (Uuid portId : portIds) {
379 Port port = getNeutronPort(portId);
380 if (port != null && (port.augmentation(QosPortExtension.class) == null
381 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
382 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
383 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(
384 CONFIGURATION, tx -> {
385 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
386 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
387 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
388 setPortBandwidthLimits(port, bwLimitBuilder
389 .setMaxBurstKbps(BigInteger.ZERO)
390 .setMaxKbps(BigInteger.ZERO).build(), tx);
392 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
393 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
394 unsetPortDscpMark(port);
402 public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
403 LOG.debug("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid().getValue());
405 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
407 for (Uuid subnetId: subnetIds) {
408 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
409 for (Uuid portId : portIds) {
410 Port port = getNeutronPort(portId);
411 if (port != null && (port.augmentation(QosPortExtension.class) == null
412 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
413 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> Collections.singletonList(
414 txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION,
415 tx -> setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
421 public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
422 LOG.debug("Handling Qos Dscp Rule Remove, net: {}", network.getUuid().getValue());
424 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
426 for (Uuid subnetId: subnetIds) {
427 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
428 for (Uuid portId : portIds) {
429 Port port = getNeutronPort(portId);
430 if (port != null && (port.augmentation(QosPortExtension.class) == null
431 || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
432 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
433 unsetPortDscpMark(port);
441 // TODO Clean up the exception handling
442 @SuppressWarnings("checkstyle:IllegalCatch")
443 public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit,
444 TypedWriteTransaction<Datastore.Configuration> writeConfigTxn) {
445 if (!qosEosHandler.isQosClusterOwner()) {
446 LOG.debug("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
449 BigInteger dpId = getDpnForInterface(port.getUuid().getValue());
450 if (dpId.equals(BigInteger.ZERO)) {
451 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
455 LOG.trace("Setting bandwidth limits {} on Port {}", port.getUuid().getValue(), bwLimit);
456 OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
457 Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
458 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
459 if (!bridgeNode.isPresent()) {
460 LOG.error("bridge not found for dpn {} port {} in operational datastore", dpId, port.getUuid().getValue());
463 LOG.debug("bridgeNode {}", bridgeNode.get().getNodeId().getValue());
465 TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
466 port.getUuid().getValue());
468 LOG.debug("Skipping setting of bandwidth limit rules for subport {}",
469 port.getUuid().getValue());
472 LOG.debug("tp: {}", tp.getTpId().getValue());
473 OvsdbTerminationPointAugmentation ovsdbTp = tp.augmentation(OvsdbTerminationPointAugmentation.class);
475 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
476 tpAugmentationBuilder.setName(ovsdbTp.getName());
477 tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
478 tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
480 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
481 tpBuilder.withKey(tp.key());
482 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
484 if (writeConfigTxn != null) {
485 writeConfigTxn.merge(InstanceIdentifier
486 .create(NetworkTopology.class)
487 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
488 .child(Node.class, bridgeNode.get().key())
489 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build(), true);
491 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
492 .create(NetworkTopology.class)
493 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
494 .child(Node.class, bridgeNode.get().key())
495 .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build());
497 } catch (Exception e) {
498 if (LOG.isDebugEnabled()) {
499 LOG.debug("Failure while setting BwLimitRule {} to port {} exception ", bwLimit,
500 port.getUuid().getValue(), e);
502 LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port.getUuid().getValue());
508 public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
509 if (!qosEosHandler.isQosClusterOwner()) {
510 LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
514 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
515 String ifName = port.getUuid().getValue();
516 Interface ifState = getInterfaceStateFromOperDS(ifName);
517 Short dscpValue = dscpMark.getDscpMark();
519 if (dpnId.equals(BigInteger.ZERO)) {
520 LOG.info("DPN ID for interface {} not found. Cannot set dscp value {} on port {}",
521 port.getUuid().getValue(), dscpMark, port.getUuid().getValue());
524 int ipVersions = getIpVersions(port);
526 if (hasIpv4Addr(ipVersions)) {
527 LOG.trace("setting ipv4 flow for port: {}, dscp: {}", ifName, dscpValue);
528 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV4, ifState);
530 if (hasIpv6Addr(ipVersions)) {
531 LOG.trace("setting ipv6 flow for port: {}, dscp: {}", ifName, dscpValue);
532 addFlow(dpnId, dscpValue, ifName, NwConstants.ETHTYPE_IPV6, ifState);
535 if (qosServiceConfiguredPorts.add(port.getUuid())) {
536 // bind qos service to interface
541 public void unsetPortDscpMark(Port port) {
542 if (!qosEosHandler.isQosClusterOwner()) {
543 LOG.debug("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
547 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
548 String ifName = port.getUuid().getValue();
550 if (dpnId.equals(BigInteger.ZERO)) {
551 LOG.debug("DPN ID for port {} not found. Cannot unset dscp value", port.getUuid().getValue());
554 LOG.trace("Removing dscp marking rule from Port {}", port.getUuid().getValue());
555 Interface intf = getInterfaceStateFromOperDS(ifName);
556 //unbind service from interface
557 unbindservice(ifName);
559 int ipVersions = getIpVersions(port);
560 if (hasIpv4Addr(ipVersions)) {
561 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intf);
563 if (hasIpv6Addr(ipVersions)) {
564 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intf);
566 qosServiceConfiguredPorts.remove(port.getUuid());
569 public void unsetPortDscpMark(Port port, Interface intrf) {
570 if (!qosEosHandler.isQosClusterOwner()) {
573 BigInteger dpnId = getDpIdFromInterface(intrf);
574 String ifName = port.getUuid().getValue();
576 if (dpnId.equals(BigInteger.ZERO)) {
577 LOG.error("Unable to retrieve DPN Id for interface {}. Cannot unset dscp value on port", ifName);
580 LOG.trace("Removing dscp marking rule from Port {}", port.getUuid().getValue());
581 unbindservice(ifName);
582 int ipVersions = getIpVersions(port);
583 if (hasIpv4Addr(ipVersions)) {
584 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV4, intrf);
586 if (hasIpv6Addr(ipVersions)) {
587 removeFlow(dpnId, ifName, NwConstants.ETHTYPE_IPV6, intrf);
589 qosServiceConfiguredPorts.remove(port.getUuid());
592 private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
593 .interfaces.rev140508.interfaces.state.Interface ifState) {
594 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
595 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
596 return BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
599 public BigInteger getDpnForInterface(String ifName) {
600 BigInteger nodeId = BigInteger.ZERO;
602 GetDpidFromInterfaceInput
603 dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
604 Future<RpcResult<GetDpidFromInterfaceOutput>>
605 dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
606 RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
607 if (dpIdResult.isSuccessful()) {
608 nodeId = dpIdResult.getResult().getDpid();
610 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
612 } catch (NullPointerException | InterruptedException | ExecutionException e) {
613 if (LOG.isDebugEnabled()) {
614 LOG.debug("Exception when getting DPN for interface {} exception ", ifName, e);
616 LOG.error("Could not retrieve DPN for interface {}", ifName);
623 private BridgeEntry getBridgeEntryFromConfigDS(BigInteger dpnId) {
624 BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
625 InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
626 LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
627 return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
631 private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
632 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker).orNull();
636 private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
637 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orNull();
641 private OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId) {
642 BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
643 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
644 BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
645 if (bridgeRefEntry == null) {
646 // bridge ref entry will be null if the bridge is disconnected from controller.
647 // In that case, fetch bridge reference from bridge interface entry config DS
648 BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
649 if (bridgeEntry == null) {
652 return bridgeEntry.getBridgeReference();
654 return bridgeRefEntry.getBridgeReference();
658 private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
659 return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
663 private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
664 return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
667 public void removeStaleFlowEntry(Interface intrf, int ethType) {
668 List<MatchInfo> matches = new ArrayList<>();
670 BigInteger dpnId = getDpIdFromInterface(intrf);
672 Integer ifIndex = intrf.getIfIndex();
673 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
674 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
675 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
676 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
678 mdsalUtils.removeFlow(flowEntity);
681 public void addFlow(BigInteger dpnId, Short dscpValue, String ifName, int ethType, Interface ifState) {
682 if (ifState == null) {
683 LOG.debug("Could not find the ifState for interface {}", ifName);
686 Integer ifIndex = ifState.getIfIndex();
688 List<MatchInfo> matches = new ArrayList<>();
689 matches.add(new MatchEthernetType(ethType));
690 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
692 List<ActionInfo> actionsInfos = new ArrayList<>();
693 actionsInfos.add(new ActionSetFieldDscp(dscpValue));
694 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
696 List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
697 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
698 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType),
699 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
700 matches, instructions);
701 mdsalUtils.installFlow(flowEntity);
704 public void removeFlow(BigInteger dpnId, String ifName, int ethType, Interface ifState) {
705 if (ifState == null) {
706 LOG.debug("Could not find the ifState for interface {}", ifName);
709 Integer ifIndex = ifState.getIfIndex();
711 mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
712 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex, ethType)));
716 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
717 .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
718 String interfaceName) {
719 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
720 createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
724 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
725 .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
726 String interfaceName) {
727 return InstanceIdentifier
728 .builder(InterfacesState.class)
729 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
730 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
731 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
732 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
737 public void bindservice(String ifName) {
738 int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
739 int instructionKey = 0;
740 List<Instruction> instructions = new ArrayList<>();
741 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
742 short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
744 BoundServices serviceInfo = getBoundServices(
745 String.format("%s.%s", "qos", ifName), qosServiceIndex,
746 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
747 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
748 buildServiceId(ifName, qosServiceIndex),
752 public void unbindservice(String ifName) {
753 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
754 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
757 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
758 return InstanceIdentifier.builder(ServiceBindings.class)
759 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
760 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
763 private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
764 BigInteger cookieQosTable, List<Instruction> instructions) {
765 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
766 .setFlowPriority(priority).setInstruction(instructions);
767 return new BoundServicesBuilder().withKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
768 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
769 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
773 public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag, int ethType) {
774 return new StringBuilder().append(tableId).append(NwConstants.FLOWID_SEPARATOR).append(dpId)
775 .append(NwConstants.FLOWID_SEPARATOR).append(lportTag)
776 .append(NwConstants.FLOWID_SEPARATOR).append(ethType).toString();
779 public boolean portHasQosPolicy(Port port) {
780 LOG.trace("checking qos policy for port: {}", port.getUuid().getValue());
782 boolean isQosPolicy = port.augmentation(QosPortExtension.class) != null
783 && port.augmentation(QosPortExtension.class).getQosPolicyId() != null;
785 LOG.trace("portHasQosPolicy for port: {} return value {}", port.getUuid().getValue(), isQosPolicy);
790 public QosPolicy getQosPolicy(Port port) {
792 QosPolicy qosPolicy = null;
794 if (port.augmentation(QosPortExtension.class) != null) {
795 qosUuid = port.augmentation(QosPortExtension.class).getQosPolicyId();
797 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
799 if (network.augmentation(QosNetworkExtension.class) != null) {
800 qosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
804 if (qosUuid != null) {
805 qosPolicy = qosPolicyMap.get(qosUuid);
811 public boolean hasDscpMarkingRule(QosPolicy qosPolicy) {
812 if (qosPolicy != null) {
813 return qosPolicy.getDscpmarkingRules() != null && !qosPolicy.getDscpmarkingRules().isEmpty();
818 public void addToPortCache(Port port) {
819 neutronPortMap.put(port.getUuid(), port);
822 public void removeFromPortCache(Port port) {
823 neutronPortMap.remove(port.getUuid());
826 public Port getNeutronPort(Uuid portUuid) {
827 return neutronPortMap.get(portUuid);
830 public Port getNeutronPort(String portName) {
831 return getNeutronPort(new Uuid(portName));
834 public void addToNetworkCache(Network network) {
835 neutronNetworkMap.put(network.getUuid(), network);
838 public void removeFromNetworkCache(Network network) {
839 neutronNetworkMap.remove(network.getUuid());
842 public Network getNeutronNetwork(Uuid networkUuid) {
843 return neutronNetworkMap.get(networkUuid);
847 public static BigInteger getDpnIdFromLowerLayerIf(String lowerLayerIf) {
849 return new BigInteger(lowerLayerIf.substring(lowerLayerIf.indexOf(":") + 1, lowerLayerIf.lastIndexOf(":")));
850 } catch (NullPointerException e) {
856 public static String getPortNumberFromLowerLayerIf(String lowerLayerIf) {
858 return (lowerLayerIf.substring(lowerLayerIf.lastIndexOf(":") + 1));
859 } catch (NullPointerException e) {
864 public int getIpVersions(Port port) {
866 for (FixedIps fixedIp: port.getFixedIps()) {
867 if (fixedIp.getIpAddress().getIpv4Address() != null) {
868 versions |= (1 << QosConstants.IPV4_ADDR_MASK_BIT);
869 } else if (fixedIp.getIpAddress().getIpv6Address() != null) {
870 versions |= (1 << QosConstants.IPV6_ADDR_MASK_BIT);
876 public boolean hasIpv4Addr(int versions) {
877 return (versions & (1 << QosConstants.IPV4_ADDR_MASK_BIT)) != 0;
880 public boolean hasIpv6Addr(int versions) {
881 return (versions & (1 << QosConstants.IPV6_ADDR_MASK_BIT)) != 0;
884 // TODO Replace this with mdsal's DataObjectUtils.nullToEmpty when upgrading to mdsal 3
886 public static <T> List<T> nullToEmpty(final @Nullable List<T> input) {
887 return input != null ? input : emptyList();