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 com.google.common.util.concurrent.ListenableFuture;
12 import java.math.BigInteger;
13 import java.util.ArrayList;
14 import java.util.Collection;
15 import java.util.Collections;
16 import java.util.List;
18 import java.util.concurrent.ConcurrentHashMap;
19 import java.util.concurrent.ConcurrentMap;
20 import java.util.concurrent.CopyOnWriteArraySet;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import javax.annotation.Nonnull;
24 import javax.annotation.Nullable;
25 import javax.inject.Inject;
26 import javax.inject.Singleton;
27 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
28 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
29 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
30 import org.opendaylight.genius.mdsalutil.ActionInfo;
31 import org.opendaylight.genius.mdsalutil.FlowEntity;
32 import org.opendaylight.genius.mdsalutil.InstructionInfo;
33 import org.opendaylight.genius.mdsalutil.MDSALUtil;
34 import org.opendaylight.genius.mdsalutil.MatchInfo;
35 import org.opendaylight.genius.mdsalutil.MetaDataUtil;
36 import org.opendaylight.genius.mdsalutil.NwConstants;
37 import org.opendaylight.genius.mdsalutil.actions.ActionNxResubmit;
38 import org.opendaylight.genius.mdsalutil.actions.ActionSetFieldDscp;
39 import org.opendaylight.genius.mdsalutil.instructions.InstructionApplyActions;
40 import org.opendaylight.genius.mdsalutil.interfaces.IMdsalApiManager;
41 import org.opendaylight.genius.mdsalutil.matches.MatchEthernetType;
42 import org.opendaylight.genius.mdsalutil.matches.MatchMetadata;
43 import org.opendaylight.genius.utils.ServiceIndex;
44 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
45 import org.opendaylight.netvirt.neutronvpn.interfaces.INeutronVpnManager;
46 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
47 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
48 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.InterfacesState;
49 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.interfaces.rev140508.interfaces.state.Interface;
50 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeInterfaceInfo;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntry;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge._interface.info.BridgeEntryKey;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
62 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInput;
63 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceInputBuilder;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetPortFromInterfaceOutput;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
92 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
93 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
99 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
100 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
101 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
102 import org.opendaylight.yangtools.yang.common.RpcResult;
103 import org.slf4j.Logger;
104 import org.slf4j.LoggerFactory;
107 public class QosNeutronUtils {
108 private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
110 private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
111 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
112 private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
113 private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
115 private final QosEosHandler qosEosHandler;
116 private final INeutronVpnManager neutronVpnManager;
117 private final OdlInterfaceRpcService odlInterfaceRpcService;
118 private final DataBroker dataBroker;
119 private final IMdsalApiManager mdsalUtils;
120 private final JobCoordinator jobCoordinator;
123 public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
124 final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
125 final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
126 this.qosEosHandler = qosEosHandler;
127 this.neutronVpnManager = neutronVpnManager;
128 this.odlInterfaceRpcService = odlInterfaceRpcService;
129 this.dataBroker = dataBroker;
130 this.mdsalUtils = mdsalUtils;
131 this.jobCoordinator = jobCoordinator;
134 public void addToQosPolicyCache(QosPolicy qosPolicy) {
135 qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
138 public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
139 qosPolicyMap.remove(qosPolicy.getUuid());
142 public Map<Uuid, QosPolicy> getQosPolicyMap() {
146 public Collection<Port> getQosPorts(Uuid qosUuid) {
147 final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
148 return portMap != null ? portMap.values() : Collections.emptyList();
151 public void addToQosPortsCache(Uuid qosUuid, Port port) {
152 qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
155 public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
156 if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
157 qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
161 public void addToQosNetworksCache(Uuid qosUuid, Network network) {
162 qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
166 public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
167 if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
168 qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
173 public Collection<Network> getQosNetworks(Uuid qosUuid) {
174 final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
175 return networkMap != null ? networkMap.values() : Collections.emptyList();
179 public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
180 InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
181 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
182 Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
183 networkMapId, dataBroker);
184 return optionalNetworkMap.isPresent() ? optionalNetworkMap.get().getSubnetIdList() : Collections.emptyList();
188 protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
189 InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
190 .builder(Subnetmaps.class)
191 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
192 Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
193 subnetMapId,dataBroker);
194 return optionalSubnetmap.isPresent() ? optionalSubnetmap.get().getPortList() : Collections.emptyList();
197 public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
198 LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
200 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
202 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
203 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
204 List<ListenableFuture<Void>> futures = new ArrayList<>();
205 // handle Bandwidth Limit Rules update
206 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
207 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
208 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), wrtConfigTxn);
210 // handle DSCP Mark Rules update
211 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
212 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
213 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
215 futures.add(wrtConfigTxn.submit());
220 public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
221 LOG.trace("Handling Port QoS update: port: {} qosservice: {}", port.getUuid(), qosUuidNew);
223 QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
224 QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
226 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
227 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
228 List<ListenableFuture<Void>> futures = new ArrayList<>();
229 // handle Bandwidth Limit Rules update
230 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
231 && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
232 setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), wrtConfigTxn);
234 if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
235 && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
236 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
237 setPortBandwidthLimits(port, bwLimitBuilder
238 .setMaxBurstKbps(BigInteger.ZERO)
239 .setMaxKbps(BigInteger.ZERO).build(), wrtConfigTxn);
242 //handle DSCP Mark Rules update
243 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
244 && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
245 setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
247 if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
248 && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
249 unsetPortDscpMark(port);
252 futures.add(wrtConfigTxn.submit());
257 public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
258 LOG.trace("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid(), qosUuid);
260 // check for network qosservice to apply
261 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
262 if (network != null && network.getAugmentation(QosNetworkExtension.class) != null) {
263 Uuid networkQosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
264 if (networkQosUuid != null) {
265 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
268 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
270 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
271 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
272 List<ListenableFuture<Void>> futures = new ArrayList<>();
273 // handle Bandwidth Limit Rules removal
274 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
275 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
276 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
277 setPortBandwidthLimits(port, bwLimitBuilder
278 .setMaxBurstKbps(BigInteger.ZERO)
279 .setMaxKbps(BigInteger.ZERO).build(), wrtConfigTxn);
281 // handle DSCP MArk Rules removal
282 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
283 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
284 unsetPortDscpMark(port);
286 futures.add(wrtConfigTxn.submit());
292 public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
293 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
294 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
296 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
297 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
298 List<ListenableFuture<Void>> futures = new ArrayList<>();
299 //check if any DSCP rule in the policy
300 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
301 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
302 unsetPortDscpMark(port);
304 futures.add(wrtConfigTxn.submit());
309 public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
310 LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
311 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
313 jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
314 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
315 List<ListenableFuture<Void>> futures = new ArrayList<>();
316 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
317 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
318 unsetPortDscpMark(port, intrf);
320 futures.add(wrtConfigTxn.submit());
326 public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
327 LOG.trace("Handling Network QoS update: net: {} qosservice: {}", network.getUuid(), qosUuid);
328 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
329 if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
330 || qosPolicy.getBandwidthLimitRules().isEmpty())
331 && (qosPolicy.getDscpmarkingRules() == null
332 || qosPolicy.getDscpmarkingRules().isEmpty())) {
335 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
336 for (Uuid subnetId : subnetIds) {
337 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
338 for (Uuid portId : portIds) {
339 Port port = neutronVpnManager.getNeutronPort(portId);
340 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
341 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
342 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
343 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
344 List<ListenableFuture<Void>> futures = new ArrayList<>();
345 if (qosPolicy.getBandwidthLimitRules() != null
346 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
347 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0),
350 if (qosPolicy.getDscpmarkingRules() != null && !qosPolicy.getDscpmarkingRules().isEmpty()) {
351 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
353 futures.add(wrtConfigTxn.submit());
361 public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
362 LOG.trace("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid(), qosUuid);
363 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
365 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
366 for (Uuid subnetId : subnetIds) {
367 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
368 for (Uuid portId : portIds) {
369 Port port = neutronVpnManager.getNeutronPort(portId);
370 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
371 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
372 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
373 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
374 List<ListenableFuture<Void>> futures = new ArrayList<>();
375 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
376 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
377 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
378 setPortBandwidthLimits(port, bwLimitBuilder
379 .setMaxBurstKbps(BigInteger.ZERO)
380 .setMaxKbps(BigInteger.ZERO).build(), null);
382 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
383 && !qosPolicy.getDscpmarkingRules().isEmpty()) {
384 unsetPortDscpMark(port);
386 futures.add(wrtConfigTxn.submit());
394 public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
395 LOG.trace("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid());
397 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
399 for (Uuid subnetId: subnetIds) {
400 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
401 for (Uuid portId : portIds) {
402 Port port = neutronVpnManager.getNeutronPort(portId);
403 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
404 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
405 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
406 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
407 List<ListenableFuture<Void>> futures = new ArrayList<>();
408 setPortBandwidthLimits(port, zeroBwLimitRule, wrtConfigTxn);
409 futures.add(wrtConfigTxn.submit());
417 public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
418 LOG.trace("Handling Qos Dscp Rule Remove, net: {}", network.getUuid());
420 List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
422 for (Uuid subnetId: subnetIds) {
423 List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
424 for (Uuid portId : portIds) {
425 Port port = neutronVpnManager.getNeutronPort(portId);
426 if (port != null && (port.getAugmentation(QosPortExtension.class) == null
427 || port.getAugmentation(QosPortExtension.class).getQosPolicyId() == null)) {
428 jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
429 WriteTransaction wrtConfigTxn = dataBroker.newWriteOnlyTransaction();
430 List<ListenableFuture<Void>> futures = new ArrayList<>();
431 unsetPortDscpMark(port);
432 futures.add(wrtConfigTxn.submit());
440 // TODO Clean up the exception handling
441 @SuppressWarnings("checkstyle:IllegalCatch")
442 public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit, WriteTransaction writeConfigTxn) {
443 if (!qosEosHandler.isQosClusterOwner()) {
444 LOG.trace("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
447 LOG.trace("Setting bandwidth limits {} on Port {}", port, bwLimit);
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 OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
456 Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
457 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
460 TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
461 port.getUuid().getValue());
462 OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
464 OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
465 tpAugmentationBuilder.setName(ovsdbTp.getName());
466 tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
467 tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
469 TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
470 tpBuilder.setKey(tp.getKey());
471 tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
473 if (writeConfigTxn != null) {
474 writeConfigTxn.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
475 .create(NetworkTopology.class)
476 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
477 .child(Node.class, bridgeNode.get().getKey())
478 .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())), tpBuilder.build());
480 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
481 .create(NetworkTopology.class)
482 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
483 .child(Node.class, bridgeNode.get().getKey())
484 .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())), tpBuilder.build());
486 } catch (Exception e) {
487 LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port, e);
492 public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
493 if (!qosEosHandler.isQosClusterOwner()) {
494 LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
497 LOG.trace("Setting DSCP value {} on Port {}", port, dscpMark);
499 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
500 String ifName = port.getUuid().getValue();
501 IpAddress ipAddress = port.getFixedIps().get(0).getIpAddress();
502 Short dscpValue = dscpMark.getDscpMark();
504 if (dpnId.equals(BigInteger.ZERO)) {
505 LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
510 addFlow(dpnId, dscpValue, ifName, ipAddress, getInterfaceStateFromOperDS(ifName));
511 if (qosServiceConfiguredPorts.add(port.getUuid())) {
512 // bind qos service to interface
517 public void unsetPortDscpMark(Port port) {
518 if (!qosEosHandler.isQosClusterOwner()) {
519 LOG.trace("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
522 LOG.trace("Removing dscp marking rule from Port {}", port);
524 BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
525 String ifName = port.getUuid().getValue();
527 if (dpnId.equals(BigInteger.ZERO)) {
528 LOG.info("DPN ID for port {} not found", port);
532 //unbind service from interface
533 unbindservice(ifName);
535 removeFlow(dpnId, ifName, getInterfaceStateFromOperDS(ifName));
536 qosServiceConfiguredPorts.remove(port.getUuid());
539 public void unsetPortDscpMark(Port port, Interface intrf) {
540 LOG.trace("Removing dscp marking rule from Port {}", port);
542 BigInteger dpnId = getDpIdFromInterface(intrf);
543 String ifName = port.getUuid().getValue();
545 if (dpnId.equals(BigInteger.ZERO)) {
546 LOG.error("Unable to retrieve DPN Id for interface {}", ifName);
549 unbindservice(ifName);
550 removeFlow(dpnId, ifName, intrf);
553 private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
554 .interfaces.rev140508.interfaces.state.Interface ifState) {
555 String lowerLayerIf = ifState.getLowerLayerIf().get(0);
556 NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
557 return BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
560 public BigInteger getDpnForInterface(String ifName) {
561 BigInteger nodeId = BigInteger.ZERO;
563 GetDpidFromInterfaceInput
564 dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
565 Future<RpcResult<GetDpidFromInterfaceOutput>>
566 dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
567 RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
568 if (dpIdResult.isSuccessful()) {
569 nodeId = dpIdResult.getResult().getDpid();
571 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
573 } catch (NullPointerException | InterruptedException | ExecutionException e) {
574 LOG.error("Exception when getting dpn for interface {}", ifName, e);
580 private BridgeEntry getBridgeEntryFromConfigDS(BigInteger dpnId) {
581 BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
582 InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
583 LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
584 return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
588 private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
589 return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker).orNull();
593 private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
594 return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orNull();
598 private OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId) {
599 BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
600 InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
601 BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
602 if (bridgeRefEntry == null) {
603 // bridge ref entry will be null if the bridge is disconnected from controller.
604 // In that case, fetch bridge reference from bridge interface entry config DS
605 BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
606 if (bridgeEntry == null) {
609 return bridgeEntry.getBridgeReference();
611 return bridgeRefEntry.getBridgeReference();
615 private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
616 return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
620 private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
621 return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
624 public void removeStaleFlowEntry(Interface intrf) {
625 List<MatchInfo> matches = new ArrayList<>();
627 BigInteger dpnId = getDpIdFromInterface(intrf);
629 Integer ifIndex = intrf.getIfIndex();
630 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
631 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
632 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
633 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
635 mdsalUtils.removeFlow(flowEntity);
638 private void addFlow(BigInteger dpnId, Short dscpValue, String ifName, IpAddress ipAddress, Interface ifState) {
639 if (ifState == null) {
640 LOG.trace("Could not find the ifState for interface {}", ifName);
643 Integer ifIndex = ifState.getIfIndex();
645 List<MatchInfo> matches = new ArrayList<>();
646 if (ipAddress.getIpv4Address() != null) {
647 matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV4));
649 matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV6));
651 matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
653 List<ActionInfo> actionsInfos = new ArrayList<>();
654 actionsInfos.add(new ActionSetFieldDscp(dscpValue));
655 actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
657 List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
658 FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
659 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
660 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
661 matches, instructions);
662 mdsalUtils.installFlow(flowEntity);
665 private void removeFlow(BigInteger dpnId, String ifName, Interface ifState) {
666 if (ifState == null) {
667 LOG.trace("Could not find the ifState for interface {}", ifName);
670 Integer ifIndex = ifState.getIfIndex();
672 mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
673 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex)));
677 public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
678 .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
679 String interfaceName) {
680 return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
681 createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
685 public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
686 .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
687 String interfaceName) {
688 return InstanceIdentifier
689 .builder(InterfacesState.class)
690 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
691 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
692 new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
693 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
698 public void bindservice(String ifName) {
699 int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
700 int instructionKey = 0;
701 List<Instruction> instructions = new ArrayList<>();
702 instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
703 short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
705 BoundServices serviceInfo = getBoundServices(
706 String.format("%s.%s", "qos", ifName), qosServiceIndex,
707 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
708 MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
709 buildServiceId(ifName, qosServiceIndex),
713 public void unbindservice(String ifName) {
714 MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
715 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
718 private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
719 return InstanceIdentifier.builder(ServiceBindings.class)
720 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
721 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
724 private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
725 BigInteger cookieQosTable, List<Instruction> instructions) {
726 StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
727 .setFlowPriority(priority).setInstruction(instructions);
728 return new BoundServicesBuilder().setKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
729 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
730 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
734 public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag) {
735 return String.valueOf(tableId) + dpId + lportTag;
738 public String getPortNumberForInterface(String ifName) {
739 GetPortFromInterfaceInput portNumberInput = new GetPortFromInterfaceInputBuilder().setIntfName(ifName).build();
740 Future<RpcResult<GetPortFromInterfaceOutput>> portNumberOutput =
741 odlInterfaceRpcService.getPortFromInterface(portNumberInput);
743 RpcResult<GetPortFromInterfaceOutput> portResult = portNumberOutput.get();
744 if (portResult.isSuccessful()) {
745 return portResult.getResult().getPortno().toString();
747 } catch (NullPointerException | InterruptedException | ExecutionException e) {
748 LOG.warn("Exception when getting port for interface {}", e);
753 public boolean portHasQosPolicy(Port port) {
754 LOG.trace("checking qos policy for port: {}", port.getUuid());
756 boolean isQosPolicy = port.getAugmentation(QosPortExtension.class) != null
757 && port.getAugmentation(QosPortExtension.class).getQosPolicyId() != null;
759 LOG.trace("portHasQosPolicy for port: {} return value {}", port.getUuid(), isQosPolicy);
765 public boolean hasBandwidthLimitRule(Port port) {
767 boolean bwLimitRule = false;
769 LOG.trace("checking bandwidth limit rule for port: {}", port.getUuid());
771 if (port.getAugmentation(QosPortExtension.class) != null) {
772 qosUuid = port.getAugmentation(QosPortExtension.class).getQosPolicyId();
774 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
776 if (network.getAugmentation(QosNetworkExtension.class) != null) {
777 qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
781 if (qosUuid != null) {
782 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
783 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
784 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
789 LOG.trace("Bandwidth limit rule for port: {} return value {}", port.getUuid(), bwLimitRule);
793 public boolean hasBandwidthLimitRule(Network network) {
794 boolean bwLimitRule = false;
796 LOG.trace("checking bandwidth limit rule for network: {}", network.getUuid());
798 if (network.getAugmentation(QosNetworkExtension.class) != null) {
799 Uuid qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
801 if (qosUuid != null) {
802 QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
803 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
804 && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
810 LOG.trace("Bandwidth limit rule for network: {} return value {}", network.getUuid(), bwLimitRule);
815 public QosPolicy getQosPolicy(Port port) {
817 QosPolicy qosPolicy = null;
819 if (port.getAugmentation(QosPortExtension.class) != null) {
820 qosUuid = port.getAugmentation(QosPortExtension.class).getQosPolicyId();
822 Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
824 if (network.getAugmentation(QosNetworkExtension.class) != null) {
825 qosUuid = network.getAugmentation(QosNetworkExtension.class).getQosPolicyId();
829 if (qosUuid != null) {
830 qosPolicy = qosPolicyMap.get(qosUuid);