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.inet.types.rev130715.IpAddress;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
51 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeInterfaceInfo;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntryKey;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInput;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
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.ports.attributes.ports.Port;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
94 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
101 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
102 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
103 import org.opendaylight.yangtools.yang.common.RpcResult;
104 import org.slf4j.Logger;
105 import org.slf4j.LoggerFactory;
108 public class QosNeutronUtils {
109 private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
111 private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
112 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
113 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
114 private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
115 private final ConcurrentHashMap<Uuid, Port> neutronPortMap = new ConcurrentHashMap<>();
116 private final ConcurrentHashMap<Uuid, Network> neutronNetworkMap = new ConcurrentHashMap<>();
118 private final QosEosHandler qosEosHandler;
119 private final INeutronVpnManager neutronVpnManager;
120 private final OdlInterfaceRpcService odlInterfaceRpcService;
121 private final DataBroker dataBroker;
122 private final ManagedNewTransactionRunner txRunner;
123 private final IMdsalApiManager mdsalUtils;
124 private final JobCoordinator jobCoordinator;
127 public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
128 final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
129 final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
130 this.qosEosHandler = qosEosHandler;
131 this.neutronVpnManager = neutronVpnManager;
132 this.odlInterfaceRpcService = odlInterfaceRpcService;
133 this.dataBroker = dataBroker;
134 this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
135 this.mdsalUtils = mdsalUtils;
136 this.jobCoordinator = jobCoordinator;
139 public void addToQosPolicyCache(QosPolicy qosPolicy) {
140 qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
143 public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
144 qosPolicyMap.remove(qosPolicy.getUuid());
147 public Map<Uuid, QosPolicy> getQosPolicyMap() {
151 public Collection<Port> getQosPorts(Uuid qosUuid) {
152 final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
153 return portMap != null ? portMap.values() : Collections.emptyList();
156 public void addToQosPortsCache(Uuid qosUuid, Port port) {
157 qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
160 public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
161 if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
162 qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
166 public void addToQosNetworksCache(Uuid qosUuid, Network network) {
167 qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
171 public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
172 if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
173 qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
178 public Collection<Network> getQosNetworks(Uuid qosUuid) {
179 final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
180 return networkMap != null ? networkMap.values() : Collections.emptyList();
184 public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
185 InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
186 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
187 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
188 networkMapId, dataBroker);
189 return optionalNetworkMap.isPresent() ? optionalNetworkMap.get().getSubnetIdList() : Collections.emptyList();
193 protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
194 InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
195 .builder(Subnetmaps.class)
196 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
197 Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
198 subnetMapId,dataBroker);
199 return optionalSubnetmap.isPresent() ? optionalSubnetmap.get().getPortList() : Collections.emptyList();
202 public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
203 LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
205 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
207 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
208 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
209 // handle Bandwidth Limit Rules update
210 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
211 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
212 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
214 // handle DSCP Mark Rules update
215 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
216 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
217 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
222 public void handleQosInterfaceAdd(Port port, Uuid qosUuid) {
223 LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
225 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
227 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () ->
228 Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
229 // handle DSCP Mark Rules update
230 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
231 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
232 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
237 public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
238 LOG.trace("Handling Port QoS update: port: {} qosservice: {}", port.getUuid(), qosUuidNew);
240 QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
241 QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
243 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
244 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
245 // handle Bandwidth Limit Rules update
246 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
247 && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
248 setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), tx);
250 if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
251 && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
252 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
253 setPortBandwidthLimits(port, bwLimitBuilder
254 .setMaxBurstKbps(BigInteger.ZERO)
255 .setMaxKbps(BigInteger.ZERO).build(), tx);
258 //handle DSCP Mark Rules update
259 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
260 && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
261 setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
263 if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
264 && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
265 unsetPortDscpMark(port);
271 public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
272 LOG.trace("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid(), qosUuid);
274 // check for network qosservice to apply
275 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
276 if (network != null && network.getAugmentation(QosNetworkExtension.class) != null) {
277 Uuid networkQosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
278 if (networkQosUuid != null) {
279 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
282 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
284 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
285 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
286 // handle Bandwidth Limit Rules removal
287 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
288 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
289 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
290 setPortBandwidthLimits(port, bwLimitBuilder
291 .setMaxBurstKbps(BigInteger.ZERO)
292 .setMaxKbps(BigInteger.ZERO).build(), tx);
294 // handle DSCP MArk Rules removal
295 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
296 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
297 unsetPortDscpMark(port);
303 public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
304 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
305 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
307 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
308 //check if any DSCP rule in the policy
309 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
310 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
311 unsetPortDscpMark(port);
313 return Collections.emptyList();
317 public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
318 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
319 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
321 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
322 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
323 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
324 unsetPortDscpMark(port, intrf);
326 return Collections.emptyList();
331 public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
332 LOG.trace("Handling Network QoS update: net: {} qosservice: {}", network.getUuid(), qosUuid);
333 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
334 if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
335 || qosPolicy.getBandwidthLimitRules().isEmpty())
336 && (qosPolicy.getDscpmarkingRules() == null
337 || qosPolicy.getDscpmarkingRules().isEmpty())) {
340 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
341 for (Uuid subnetId : subnetIds) {
342 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
343 for (Uuid portId : portIds) {
344 Port port = getNeutronPort(portId);
345 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
346 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
347 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
348 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
349 if (qosPolicy.getBandwidthLimitRules() != null
350 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
351 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
353 if (qosPolicy.getDscpmarkingRules() != null
354 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
355 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
363 public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
364 LOG.trace("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid(), qosUuid);
365 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
367 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
368 for (Uuid subnetId : subnetIds) {
369 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
370 for (Uuid portId : portIds) {
371 Port port = getNeutronPort(portId);
372 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
373 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
374 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
375 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
376 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
377 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
378 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
379 setPortBandwidthLimits(port, bwLimitBuilder
380 .setMaxBurstKbps(BigInteger.ZERO)
381 .setMaxKbps(BigInteger.ZERO).build(), tx);
383 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
384 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
385 unsetPortDscpMark(port);
393 public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
394 LOG.trace("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid());
396 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
398 for (Uuid subnetId: subnetIds) {
399 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
400 for (Uuid portId : portIds) {
401 Port port = getNeutronPort(portId);
402 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
403 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
404 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> Collections.singletonList(
405 txRunner.callWithNewWriteOnlyTransactionAndSubmit(
406 tx -> setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
412 public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
413 LOG.trace("Handling Qos Dscp Rule Remove, net: {}", network.getUuid());
415 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
417 for (Uuid subnetId: subnetIds) {
418 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
419 for (Uuid portId : portIds) {
420 Port port = getNeutronPort(portId);
421 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
422 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
423 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
424 unsetPortDscpMark(port);
425 return Collections.emptyList();
432 // TODO Clean up the exception handling
433 @SuppressWarnings("checkstyle:IllegalCatch")
434 public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit, WriteTransaction writeConfigTxn) {
435 if (!qosEosHandler.isQosClusterOwner()) {
436 LOG.trace("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
439 LOG.trace("Setting bandwidth limits {} on Port {}", port, bwLimit);
441 BigInteger dpId = getDpnForInterface(port.getUuid().getValue());
442 if (dpId.equals(BigInteger.ZERO)) {
443 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
447 OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
448 Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
449 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
452 TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
453 port.getUuid().getValue());
454 OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
456 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
457 tpAugmentationBuilder.setName(ovsdbTp.getName());
458 tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
459 tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
461 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
462 tpBuilder.setKey(tp.getKey());
463 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
465 if (writeConfigTxn != null) {
466 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
467 .create(NetworkTopology.class)
468 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
469 .child(Node.class, bridgeNode.get().getKey())
470 .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())), tpBuilder.build(), true);
472 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
473 .create(NetworkTopology.class)
474 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
475 .child(Node.class, bridgeNode.get().getKey())
476 .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())), tpBuilder.build());
478 } catch (Exception e) {
479 LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port, e);
484 public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
485 if (!qosEosHandler.isQosClusterOwner()) {
486 LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
489 LOG.trace("Setting DSCP value {} on Port {}", port, dscpMark);
491 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
492 String ifName = port.getUuid().getValue();
493 IpAddress ipAddress = port.getFixedIps().get(0).getIpAddress();
494 Short dscpValue = dscpMark.getDscpMark();
496 if (dpnId.equals(BigInteger.ZERO)) {
497 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
502 addFlow(dpnId, dscpValue, ifName, ipAddress, getInterfaceStateFromOperDS(ifName));
503 if (qosServiceConfiguredPorts.add(port.getUuid())) {
504 // bind qos service to interface
509 public void unsetPortDscpMark(Port port) {
510 if (!qosEosHandler.isQosClusterOwner()) {
511 LOG.trace("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
514 LOG.trace("Removing dscp marking rule from Port {}", port);
516 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
517 String ifName = port.getUuid().getValue();
519 if (dpnId.equals(BigInteger.ZERO)) {
520 LOG.info("DPN ID for port {} not found", port);
524 //unbind service from interface
525 unbindservice(ifName);
527 removeFlow(dpnId, ifName, getInterfaceStateFromOperDS(ifName));
528 qosServiceConfiguredPorts.remove(port.getUuid());
531 public void unsetPortDscpMark(Port port, Interface intrf) {
532 LOG.trace("Removing dscp marking rule from Port {}", port);
534 BigInteger dpnId = getDpIdFromInterface(intrf);
535 String ifName = port.getUuid().getValue();
537 if (dpnId.equals(BigInteger.ZERO)) {
538 LOG.error("Unable to retrieve DPN Id for interface {}", ifName);
541 unbindservice(ifName);
542 removeFlow(dpnId, ifName, intrf);
545 private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
546 .interfaces.rev140508.interfaces.state.Interface ifState) {
547 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
548 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
549 return BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
552 public BigInteger getDpnForInterface(String ifName) {
553 BigInteger nodeId = BigInteger.ZERO;
555 GetDpidFromInterfaceInput
556 dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
557 Future<RpcResult<GetDpidFromInterfaceOutput>>
558 dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
559 RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
560 if (dpIdResult.isSuccessful()) {
561 nodeId = dpIdResult.getResult().getDpid();
563 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
565 } catch (NullPointerException | InterruptedException | ExecutionException e) {
566 LOG.error("Exception when getting dpn for interface {}", ifName, e);
572 private BridgeEntry getBridgeEntryFromConfigDS(BigInteger dpnId) {
573 BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
574 InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
575 LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
576 return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
580 private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
581 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker).orNull();
585 private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
586 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orNull();
590 private OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId) {
591 BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
592 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
593 BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
594 if (bridgeRefEntry == null) {
595 // bridge ref entry will be null if the bridge is disconnected from controller.
596 // In that case, fetch bridge reference from bridge interface entry config DS
597 BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
598 if (bridgeEntry == null) {
601 return bridgeEntry.getBridgeReference();
603 return bridgeRefEntry.getBridgeReference();
607 private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
608 return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
612 private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
613 return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
616 public void removeStaleFlowEntry(Interface intrf) {
617 List<MatchInfo> matches = new ArrayList<>();
619 BigInteger dpnId = getDpIdFromInterface(intrf);
621 Integer ifIndex = intrf.getIfIndex();
622 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
623 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
624 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
625 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
627 mdsalUtils.removeFlow(flowEntity);
630 private void addFlow(BigInteger dpnId, Short dscpValue, String ifName, IpAddress ipAddress, Interface ifState) {
631 if (ifState == null) {
632 LOG.trace("Could not find the ifState for interface {}", ifName);
635 Integer ifIndex = ifState.getIfIndex();
637 List<MatchInfo> matches = new ArrayList<>();
638 if (ipAddress.getIpv4Address() != null) {
639 matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV4));
641 matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV6));
643 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
645 List<ActionInfo> actionsInfos = new ArrayList<>();
646 actionsInfos.add(new ActionSetFieldDscp(dscpValue));
647 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
649 List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
650 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
651 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
652 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
653 matches, instructions);
654 mdsalUtils.installFlow(flowEntity);
657 private void removeFlow(BigInteger dpnId, String ifName, Interface ifState) {
658 if (ifState == null) {
659 LOG.trace("Could not find the ifState for interface {}", ifName);
662 Integer ifIndex = ifState.getIfIndex();
664 mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
665 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex)));
669 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
670 .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
671 String interfaceName) {
672 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
673 createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
677 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
678 .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
679 String interfaceName) {
680 return InstanceIdentifier
681 .builder(InterfacesState.class)
682 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
683 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
684 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
685 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
690 public void bindservice(String ifName) {
691 int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
692 int instructionKey = 0;
693 List<Instruction> instructions = new ArrayList<>();
694 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
695 short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
697 BoundServices serviceInfo = getBoundServices(
698 String.format("%s.%s", "qos", ifName), qosServiceIndex,
699 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
700 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
701 buildServiceId(ifName, qosServiceIndex),
705 public void unbindservice(String ifName) {
706 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
707 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
710 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
711 return InstanceIdentifier.builder(ServiceBindings.class)
712 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
713 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
716 private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
717 BigInteger cookieQosTable, List<Instruction> instructions) {
718 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
719 .setFlowPriority(priority).setInstruction(instructions);
720 return new BoundServicesBuilder().setKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
721 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
722 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
726 public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag) {
727 return String.valueOf(tableId) + dpId + lportTag;
730 public String getPortNumberForInterface(String ifName) {
731 GetPortFromInterfaceInput portNumberInput = new GetPortFromInterfaceInputBuilder().setIntfName(ifName).build();
732 Future<RpcResult<GetPortFromInterfaceOutput>> portNumberOutput =
733 odlInterfaceRpcService.getPortFromInterface(portNumberInput);
735 RpcResult<GetPortFromInterfaceOutput> portResult = portNumberOutput.get();
736 if (portResult.isSuccessful()) {
737 return portResult.getResult().getPortno().toString();
739 } catch (NullPointerException | InterruptedException | ExecutionException e) {
740 LOG.warn("Exception when getting port for interface {}", e);
745 public boolean portHasQosPolicy(Port port) {
746 LOG.trace("checking qos policy for port: {}", port.getUuid());
748 boolean isQosPolicy = port.getAugmentation(QosPortExtension.class) != null
749 && port.getAugmentation(QosPortExtension.class).getQosPolicyId() != null;
751 LOG.trace("portHasQosPolicy for port: {} return value {}", port.getUuid(), isQosPolicy);
757 public boolean hasBandwidthLimitRule(Port port) {
759 boolean bwLimitRule = false;
761 LOG.trace("checking bandwidth limit rule for port: {}", port.getUuid());
763 if (port.getAugmentation(QosPortExtension.class) != null) {
764 qosUuid = port.getAugmentation(QosPortExtension.class).getQosPolicyId();
766 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
768 if (network.getAugmentation(QosNetworkExtension.class) != null) {
769 qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
773 if (qosUuid != null) {
774 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
775 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
776 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
781 LOG.trace("Bandwidth limit rule for port: {} return value {}", port.getUuid(), bwLimitRule);
785 public boolean hasBandwidthLimitRule(Network network) {
786 boolean bwLimitRule = false;
788 LOG.trace("checking bandwidth limit rule for network: {}", network.getUuid());
790 if (network.getAugmentation(QosNetworkExtension.class) != null) {
791 Uuid qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
793 if (qosUuid != null) {
794 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
795 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
796 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
802 LOG.trace("Bandwidth limit rule for network: {} return value {}", network.getUuid(), bwLimitRule);
807 public QosPolicy getQosPolicy(Port port) {
809 QosPolicy qosPolicy = null;
811 if (port.getAugmentation(QosPortExtension.class) != null) {
812 qosUuid = port.getAugmentation(QosPortExtension.class).getQosPolicyId();
814 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
816 if (network.getAugmentation(QosNetworkExtension.class) != null) {
817 qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
821 if (qosUuid != null) {
822 qosPolicy = qosPolicyMap.get(qosUuid);
828 public void addToPortCache(Port port) {
829 neutronPortMap.put(port.getUuid(), port);
832 public void removeFromPortCache(Port port) {
833 neutronPortMap.remove(port.getUuid());
836 public Port getNeutronPort(Uuid portUuid) {
837 return neutronPortMap.get(portUuid);
840 public Port getNeutronPort(String portName) {
841 return getNeutronPort(new Uuid(portName));
844 public void addToNetworkCache(Network network) {
845 neutronNetworkMap.put(network.getUuid(), network);
848 public void removeFromNetworkCache(Network network) {
849 neutronNetworkMap.remove(network.getUuid());
852 public Network getNeutronNetwork(Uuid networkUuid) {
853 return neutronNetworkMap.get(networkUuid);