Fixup Augmentable and Identifiable methods changing
[netvirt.git] / qosservice / impl / src / main / java / org / opendaylight / netvirt / qosservice / QosNeutronUtils.java
1 /*
2  * Copyright (c) 2017 Intel Corporation and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.netvirt.qosservice;
9
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;
16 import java.util.Map;
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.OdlInterfaceRpcService;
64 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceBindings;
65 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceModeIngress;
66 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.ServiceTypeFlowBased;
67 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflow;
68 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.StypeOpenflowBuilder;
69 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfo;
70 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.ServicesInfoKey;
71 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServices;
72 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesBuilder;
73 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.servicebinding.rev160406.service.bindings.services.info.BoundServicesKey;
74 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
75 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.NetworkMaps;
76 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.Subnetmaps;
77 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMap;
78 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.networkmaps.NetworkMapKey;
79 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.Subnetmap;
80 import org.opendaylight.yang.gen.v1.urn.opendaylight.netvirt.neutronvpn.rev150602.subnetmaps.SubnetmapKey;
81 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
82 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
83 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosNetworkExtension;
84 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.ext.rev160613.QosPortExtension;
85 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
86 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
87 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
88 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
89 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
90 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
91 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
92 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
93 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
94 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
95 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
96 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
97 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
98 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
99 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
100 import org.opendaylight.yangtools.yang.common.RpcResult;
101 import org.slf4j.Logger;
102 import org.slf4j.LoggerFactory;
103
104 @Singleton
105 public class QosNeutronUtils {
106     private static final Logger LOG = LoggerFactory.getLogger(QosNeutronUtils.class);
107
108     private final ConcurrentMap<Uuid, QosPolicy> qosPolicyMap = new ConcurrentHashMap<>();
109     private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Port>> qosPortsMap = new ConcurrentHashMap<>();
110     private final ConcurrentMap<Uuid, ConcurrentMap<Uuid, Network>> qosNetworksMap = new ConcurrentHashMap<>();
111     private final CopyOnWriteArraySet<Uuid> qosServiceConfiguredPorts = new CopyOnWriteArraySet<>();
112     private final ConcurrentHashMap<Uuid, Port> neutronPortMap = new ConcurrentHashMap<>();
113     private final ConcurrentHashMap<Uuid, Network> neutronNetworkMap = new ConcurrentHashMap<>();
114
115     private final QosEosHandler qosEosHandler;
116     private final INeutronVpnManager neutronVpnManager;
117     private final OdlInterfaceRpcService odlInterfaceRpcService;
118     private final DataBroker dataBroker;
119     private final ManagedNewTransactionRunner txRunner;
120     private final IMdsalApiManager mdsalUtils;
121     private final JobCoordinator jobCoordinator;
122
123     @Inject
124     public QosNeutronUtils(final QosEosHandler qosEosHandler, final INeutronVpnManager neutronVpnManager,
125             final OdlInterfaceRpcService odlInterfaceRpcService, final DataBroker dataBroker,
126             final IMdsalApiManager mdsalUtils, final JobCoordinator jobCoordinator) {
127         this.qosEosHandler = qosEosHandler;
128         this.neutronVpnManager = neutronVpnManager;
129         this.odlInterfaceRpcService = odlInterfaceRpcService;
130         this.dataBroker = dataBroker;
131         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
132         this.mdsalUtils = mdsalUtils;
133         this.jobCoordinator = jobCoordinator;
134     }
135
136     public void addToQosPolicyCache(QosPolicy qosPolicy) {
137         qosPolicyMap.put(qosPolicy.getUuid(),qosPolicy);
138     }
139
140     public void removeFromQosPolicyCache(QosPolicy qosPolicy) {
141         qosPolicyMap.remove(qosPolicy.getUuid());
142     }
143
144     public Map<Uuid, QosPolicy> getQosPolicyMap() {
145         return qosPolicyMap;
146     }
147
148     public Collection<Port> getQosPorts(Uuid qosUuid) {
149         final ConcurrentMap<Uuid, Port> portMap = qosPortsMap.get(qosUuid);
150         return portMap != null ? portMap.values() : Collections.emptyList();
151     }
152
153     public void addToQosPortsCache(Uuid qosUuid, Port port) {
154         qosPortsMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(port.getUuid(), port);
155     }
156
157     public void removeFromQosPortsCache(Uuid qosUuid, Port port) {
158         if (qosPortsMap.containsKey(qosUuid) && qosPortsMap.get(qosUuid).containsKey(port.getUuid())) {
159             qosPortsMap.get(qosUuid).remove(port.getUuid(), port);
160         }
161     }
162
163     public void addToQosNetworksCache(Uuid qosUuid, Network network) {
164         qosNetworksMap.computeIfAbsent(qosUuid, key -> new ConcurrentHashMap<>()).putIfAbsent(network.getUuid(),
165                 network);
166     }
167
168     public void removeFromQosNetworksCache(Uuid qosUuid, Network network) {
169         if (qosNetworksMap.containsKey(qosUuid) && qosNetworksMap.get(qosUuid).containsKey(network.getUuid())) {
170             qosNetworksMap.get(qosUuid).remove(network.getUuid(), network);
171         }
172     }
173
174     @Nonnull
175     public Collection<Network> getQosNetworks(Uuid qosUuid) {
176         final ConcurrentMap<Uuid, Network> networkMap = qosNetworksMap.get(qosUuid);
177         return networkMap != null ? networkMap.values() : Collections.emptyList();
178     }
179
180     @Nonnull
181     public List<Uuid> getSubnetIdsFromNetworkId(Uuid networkId) {
182         InstanceIdentifier<NetworkMap> networkMapId = InstanceIdentifier.builder(NetworkMaps.class)
183                 .child(NetworkMap.class, new NetworkMapKey(networkId)).build();
184         Optional<NetworkMap> optionalNetworkMap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
185                 networkMapId, dataBroker);
186         return optionalNetworkMap.isPresent() ? optionalNetworkMap.get().getSubnetIdList() : Collections.emptyList();
187     }
188
189     @Nonnull
190     protected List<Uuid> getPortIdsFromSubnetId(Uuid subnetId) {
191         InstanceIdentifier<Subnetmap> subnetMapId = InstanceIdentifier
192                 .builder(Subnetmaps.class)
193                 .child(Subnetmap.class, new SubnetmapKey(subnetId)).build();
194         Optional<Subnetmap> optionalSubnetmap = MDSALUtil.read(LogicalDatastoreType.CONFIGURATION,
195                 subnetMapId,dataBroker);
196         return optionalSubnetmap.isPresent() ? optionalSubnetmap.get().getPortList() : Collections.emptyList();
197     }
198
199     public void handleNeutronPortQosAdd(Port port, Uuid qosUuid) {
200         LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
201
202         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
203
204         jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
205             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
206                 // handle Bandwidth Limit Rules update
207                 if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
208                         && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
209                     setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
210                 }
211                 // handle DSCP Mark Rules update
212                 if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
213                         && !qosPolicy.getDscpmarkingRules().isEmpty()) {
214                     setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
215                 }
216             })));
217     }
218
219     public void handleQosInterfaceAdd(Port port, Uuid qosUuid) {
220         LOG.trace("Handling Port add and QoS associated: port: {} qos: {}", port.getUuid(), qosUuid);
221
222         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
223
224         jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () ->
225                 Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
226                     // handle DSCP Mark Rules update
227                     if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
228                             && !qosPolicy.getDscpmarkingRules().isEmpty()) {
229                         setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
230                     }
231                 })));
232     }
233
234     public void handleNeutronPortQosUpdate(Port port, Uuid qosUuidNew, Uuid qosUuidOld) {
235         LOG.trace("Handling Port QoS update: port: {} qosservice: {}", port.getUuid(), qosUuidNew);
236
237         QosPolicy qosPolicyNew = qosPolicyMap.get(qosUuidNew);
238         QosPolicy qosPolicyOld = qosPolicyMap.get(qosUuidOld);
239
240         jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
241             () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
242                 // handle Bandwidth Limit Rules update
243                 if (qosPolicyNew != null && qosPolicyNew.getBandwidthLimitRules() != null
244                         && !qosPolicyNew.getBandwidthLimitRules().isEmpty()) {
245                     setPortBandwidthLimits(port, qosPolicyNew.getBandwidthLimitRules().get(0), tx);
246                 } else {
247                     if (qosPolicyOld != null && qosPolicyOld.getBandwidthLimitRules() != null
248                             && !qosPolicyOld.getBandwidthLimitRules().isEmpty()) {
249                         BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
250                         setPortBandwidthLimits(port, bwLimitBuilder
251                                 .setMaxBurstKbps(BigInteger.ZERO)
252                                 .setMaxKbps(BigInteger.ZERO).build(), tx);
253                     }
254                 }
255                 //handle DSCP Mark Rules update
256                 if (qosPolicyNew != null && qosPolicyNew.getDscpmarkingRules() != null
257                         && !qosPolicyNew.getDscpmarkingRules().isEmpty()) {
258                     setPortDscpMarking(port, qosPolicyNew.getDscpmarkingRules().get(0));
259                 } else {
260                     if (qosPolicyOld != null && qosPolicyOld.getDscpmarkingRules() != null
261                             && !qosPolicyOld.getDscpmarkingRules().isEmpty()) {
262                         unsetPortDscpMark(port);
263                     }
264                 }
265             })));
266     }
267
268     public void handleNeutronPortQosRemove(Port port, Uuid qosUuid) {
269         LOG.trace("Handling Port QoS removal: port: {} qosservice: {}", port.getUuid(), qosUuid);
270
271         // check for network qosservice to apply
272         Network network =  neutronVpnManager.getNeutronNetwork(port.getNetworkId());
273         if (network != null && network.augmentation(QosNetworkExtension.class) != null) {
274             Uuid networkQosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
275             if (networkQosUuid != null) {
276                 handleNeutronPortQosUpdate(port, networkQosUuid, qosUuid);
277             }
278         } else {
279             QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
280
281             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(),
282                 () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
283                     // handle Bandwidth Limit Rules removal
284                     if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
285                             && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
286                         BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
287                         setPortBandwidthLimits(port, bwLimitBuilder
288                                 .setMaxBurstKbps(BigInteger.ZERO)
289                                 .setMaxKbps(BigInteger.ZERO).build(), tx);
290                     }
291                     // handle DSCP MArk Rules removal
292                     if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
293                             && !qosPolicy.getDscpmarkingRules().isEmpty()) {
294                         unsetPortDscpMark(port);
295                     }
296                 })));
297         }
298     }
299
300     public void handleNeutronPortRemove(Port port, Uuid qosUuid) {
301         LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
302         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
303
304         jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
305             //check if any DSCP rule in the policy
306             if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
307                     && !qosPolicy.getDscpmarkingRules().isEmpty()) {
308                 unsetPortDscpMark(port);
309             }
310             return Collections.emptyList();
311         });
312     }
313
314     public void handleNeutronPortRemove(Port port, Uuid qosUuid, Interface intrf) {
315         LOG.trace("Handling Port removal and Qos associated: port: {} qos: {}", port.getUuid(), qosUuid);
316         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
317
318         jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
319             if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
320                     && !qosPolicy.getDscpmarkingRules().isEmpty()) {
321                 unsetPortDscpMark(port, intrf);
322             }
323             return Collections.emptyList();
324         });
325     }
326
327
328     public void handleNeutronNetworkQosUpdate(Network network, Uuid qosUuid) {
329         LOG.trace("Handling Network QoS update: net: {} qosservice: {}", network.getUuid(), qosUuid);
330         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
331         if (qosPolicy == null || (qosPolicy.getBandwidthLimitRules() == null
332                 || qosPolicy.getBandwidthLimitRules().isEmpty())
333                 && (qosPolicy.getDscpmarkingRules() == null
334                 || qosPolicy.getDscpmarkingRules().isEmpty())) {
335             return;
336         }
337         List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
338         for (Uuid subnetId : subnetIds) {
339             List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
340             for (Uuid portId : portIds) {
341                 Port port = getNeutronPort(portId);
342                 if (port != null && (port.augmentation(QosPortExtension.class) == null
343                         || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
344                     jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
345                         () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
346                             if (qosPolicy.getBandwidthLimitRules() != null
347                                     && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
348                                 setPortBandwidthLimits(port, qosPolicy.getBandwidthLimitRules().get(0), tx);
349                             }
350                             if (qosPolicy.getDscpmarkingRules() != null
351                                     && !qosPolicy.getDscpmarkingRules().isEmpty()) {
352                                 setPortDscpMarking(port, qosPolicy.getDscpmarkingRules().get(0));
353                             }
354                         })));
355                 }
356             }
357         }
358     }
359
360     public void handleNeutronNetworkQosRemove(Network network, Uuid qosUuid) {
361         LOG.trace("Handling Network QoS removal: net: {} qosservice: {}", network.getUuid(), qosUuid);
362         QosPolicy qosPolicy = qosPolicyMap.get(qosUuid);
363
364         List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
365         for (Uuid subnetId : subnetIds) {
366             List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
367             for (Uuid portId : portIds) {
368                 Port port = getNeutronPort(portId);
369                 if (port != null && (port.augmentation(QosPortExtension.class) == null
370                         || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
371                     jobCoordinator.enqueueJob("QosPort-" + portId.getValue(),
372                         () -> Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
373                             if (qosPolicy != null && qosPolicy.getBandwidthLimitRules() != null
374                                     && !qosPolicy.getBandwidthLimitRules().isEmpty()) {
375                                 BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
376                                 setPortBandwidthLimits(port, bwLimitBuilder
377                                         .setMaxBurstKbps(BigInteger.ZERO)
378                                         .setMaxKbps(BigInteger.ZERO).build(), tx);
379                             }
380                             if (qosPolicy != null && qosPolicy.getDscpmarkingRules() != null
381                                     && !qosPolicy.getDscpmarkingRules().isEmpty()) {
382                                 unsetPortDscpMark(port);
383                             }
384                         })));
385                 }
386             }
387         }
388     }
389
390     public void handleNeutronNetworkQosBwRuleRemove(Network network, BandwidthLimitRules zeroBwLimitRule) {
391         LOG.trace("Handling Qos Bandwidth Rule Remove, net: {}", network.getUuid());
392
393         List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
394
395         for (Uuid subnetId: subnetIds) {
396             List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
397             for (Uuid portId : portIds) {
398                 Port port = getNeutronPort(portId);
399                 if (port != null && (port.augmentation(QosPortExtension.class) == null
400                         || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
401                     jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> Collections.singletonList(
402                             txRunner.callWithNewWriteOnlyTransactionAndSubmit(
403                                 tx -> setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
404                 }
405             }
406         }
407     }
408
409     public void handleNeutronNetworkQosDscpRuleRemove(Network network) {
410         LOG.trace("Handling Qos Dscp Rule Remove, net: {}", network.getUuid());
411
412         List<Uuid> subnetIds = getSubnetIdsFromNetworkId(network.getUuid());
413
414         for (Uuid subnetId: subnetIds) {
415             List<Uuid> portIds = getPortIdsFromSubnetId(subnetId);
416             for (Uuid portId : portIds) {
417                 Port port = getNeutronPort(portId);
418                 if (port != null && (port.augmentation(QosPortExtension.class) == null
419                         || port.augmentation(QosPortExtension.class).getQosPolicyId() == null)) {
420                     jobCoordinator.enqueueJob("QosPort-" + portId.getValue(), () -> {
421                         unsetPortDscpMark(port);
422                         return Collections.emptyList();
423                     });
424                 }
425             }
426         }
427     }
428
429     // TODO Clean up the exception handling
430     @SuppressWarnings("checkstyle:IllegalCatch")
431     public void setPortBandwidthLimits(Port port, BandwidthLimitRules bwLimit, WriteTransaction writeConfigTxn) {
432         if (!qosEosHandler.isQosClusterOwner()) {
433             LOG.trace("Not Qos Cluster Owner. Ignoring setting bandwidth limits");
434             return;
435         }
436         LOG.trace("Setting bandwidth limits {} on Port {}", port, bwLimit);
437
438         BigInteger dpId = getDpnForInterface(port.getUuid().getValue());
439         if (dpId.equals(BigInteger.ZERO)) {
440             LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
441             return;
442         }
443
444         OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId);
445         Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
446                 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
447
448
449         TerminationPoint tp = SouthboundUtils.getTerminationPointByExternalId(bridgeNode.get(),
450                 port.getUuid().getValue());
451         OvsdbTerminationPointAugmentation ovsdbTp = tp.augmentation(OvsdbTerminationPointAugmentation.class);
452
453         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
454         tpAugmentationBuilder.setName(ovsdbTp.getName());
455         tpAugmentationBuilder.setIngressPolicingRate(bwLimit.getMaxKbps().longValue());
456         tpAugmentationBuilder.setIngressPolicingBurst(bwLimit.getMaxBurstKbps().longValue());
457
458         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
459         tpBuilder.withKey(tp.key());
460         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
461         try {
462             if (writeConfigTxn != null) {
463                 writeConfigTxn.merge(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
464                         .create(NetworkTopology.class)
465                         .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
466                         .child(Node.class, bridgeNode.get().key())
467                         .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build(), true);
468             } else {
469                 MDSALUtil.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION, InstanceIdentifier
470                         .create(NetworkTopology.class)
471                         .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
472                         .child(Node.class, bridgeNode.get().key())
473                         .child(TerminationPoint.class, new TerminationPointKey(tp.key())), tpBuilder.build());
474             }
475         } catch (Exception e) {
476             LOG.error("Failure while setting BwLimitRule {} to port {}", bwLimit, port, e);
477         }
478
479     }
480
481     public void setPortDscpMarking(Port port, DscpmarkingRules dscpMark) {
482         if (!qosEosHandler.isQosClusterOwner()) {
483             LOG.trace("Not Qos Cluster Owner. Ignoring setting DSCP marking");
484             return;
485         }
486         LOG.trace("Setting DSCP value {} on Port {}", port, dscpMark);
487
488         BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
489         String ifName = port.getUuid().getValue();
490         IpAddress ipAddress = port.getFixedIps().get(0).getIpAddress();
491         Short dscpValue = dscpMark.getDscpMark();
492
493         if (dpnId.equals(BigInteger.ZERO)) {
494             LOG.info("DPN ID for interface {} not found", port.getUuid().getValue());
495             return;
496         }
497
498         //1. OF rules
499         addFlow(dpnId, dscpValue, ifName, ipAddress, getInterfaceStateFromOperDS(ifName));
500         if (qosServiceConfiguredPorts.add(port.getUuid())) {
501             // bind qos service to interface
502             bindservice(ifName);
503         }
504     }
505
506     public void unsetPortDscpMark(Port port) {
507         if (!qosEosHandler.isQosClusterOwner()) {
508             LOG.trace("Not Qos Cluster Owner. Ignoring unsetting DSCP marking");
509             return;
510         }
511         LOG.trace("Removing dscp marking rule from Port {}", port);
512
513         BigInteger dpnId = getDpnForInterface(port.getUuid().getValue());
514         String ifName = port.getUuid().getValue();
515
516         if (dpnId.equals(BigInteger.ZERO)) {
517             LOG.info("DPN ID for port {} not found", port);
518             return;
519         }
520
521         //unbind service from interface
522         unbindservice(ifName);
523         // 1. OF
524         removeFlow(dpnId, ifName, getInterfaceStateFromOperDS(ifName));
525         qosServiceConfiguredPorts.remove(port.getUuid());
526     }
527
528     public void unsetPortDscpMark(Port port, Interface intrf) {
529         LOG.trace("Removing dscp marking rule from Port {}", port);
530
531         BigInteger dpnId = getDpIdFromInterface(intrf);
532         String ifName = port.getUuid().getValue();
533
534         if (dpnId.equals(BigInteger.ZERO)) {
535             LOG.error("Unable to retrieve DPN Id for interface {}", ifName);
536             return;
537         }
538         unbindservice(ifName);
539         removeFlow(dpnId, ifName, intrf);
540     }
541
542     private static BigInteger getDpIdFromInterface(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf
543                                                            .interfaces.rev140508.interfaces.state.Interface ifState) {
544         String lowerLayerIf = ifState.getLowerLayerIf().get(0);
545         NodeConnectorId nodeConnectorId = new NodeConnectorId(lowerLayerIf);
546         return BigInteger.valueOf(MDSALUtil.getDpnIdFromPortName(nodeConnectorId));
547     }
548
549     public BigInteger getDpnForInterface(String ifName) {
550         BigInteger nodeId = BigInteger.ZERO;
551         try {
552             GetDpidFromInterfaceInput
553                     dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
554             Future<RpcResult<GetDpidFromInterfaceOutput>>
555                     dpIdOutput = odlInterfaceRpcService.getDpidFromInterface(dpIdInput);
556             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
557             if (dpIdResult.isSuccessful()) {
558                 nodeId = dpIdResult.getResult().getDpid();
559             } else {
560                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
561             }
562         } catch (NullPointerException | InterruptedException | ExecutionException e) {
563             LOG.error("Exception when getting dpn for interface {}", ifName,  e);
564         }
565         return nodeId;
566     }
567
568     @Nullable
569     private BridgeEntry getBridgeEntryFromConfigDS(BigInteger dpnId) {
570         BridgeEntryKey bridgeEntryKey = new BridgeEntryKey(dpnId);
571         InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier = getBridgeEntryIdentifier(bridgeEntryKey);
572         LOG.debug("Trying to retrieve bridge entry from config for Id: {}", bridgeEntryInstanceIdentifier);
573         return getBridgeEntryFromConfigDS(bridgeEntryInstanceIdentifier);
574     }
575
576     @Nullable
577     private BridgeEntry getBridgeEntryFromConfigDS(InstanceIdentifier<BridgeEntry> bridgeEntryInstanceIdentifier) {
578         return MDSALUtil.read(LogicalDatastoreType.CONFIGURATION, bridgeEntryInstanceIdentifier, dataBroker).orNull();
579     }
580
581     @Nullable
582     private BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid) {
583         return MDSALUtil.read(LogicalDatastoreType.OPERATIONAL, dpnBridgeEntryIid, dataBroker).orNull();
584     }
585
586     @Nullable
587     private OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId) {
588         BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
589         InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
590         BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid);
591         if (bridgeRefEntry == null) {
592             // bridge ref entry will be null if the bridge is disconnected from controller.
593             // In that case, fetch bridge reference from bridge interface entry config DS
594             BridgeEntry bridgeEntry = getBridgeEntryFromConfigDS(dpId);
595             if (bridgeEntry == null) {
596                 return null;
597             }
598             return  bridgeEntry.getBridgeReference();
599         }
600         return bridgeRefEntry.getBridgeReference();
601     }
602
603     @Nonnull
604     private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
605         return InstanceIdentifier.builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey).build();
606     }
607
608     @Nonnull
609     private static InstanceIdentifier<BridgeEntry> getBridgeEntryIdentifier(BridgeEntryKey bridgeEntryKey) {
610         return InstanceIdentifier.builder(BridgeInterfaceInfo.class).child(BridgeEntry.class, bridgeEntryKey).build();
611     }
612
613     public void removeStaleFlowEntry(Interface intrf) {
614         List<MatchInfo> matches = new ArrayList<>();
615
616         BigInteger dpnId = getDpIdFromInterface(intrf);
617
618         Integer ifIndex = intrf.getIfIndex();
619         matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
620         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
621                 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
622                 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSRemoveFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
623                 matches, null);
624         mdsalUtils.removeFlow(flowEntity);
625     }
626
627     private void addFlow(BigInteger dpnId, Short dscpValue, String ifName, IpAddress ipAddress, Interface ifState) {
628         if (ifState == null) {
629             LOG.trace("Could not find the ifState for interface {}", ifName);
630             return;
631         }
632         Integer ifIndex = ifState.getIfIndex();
633
634         List<MatchInfo> matches = new ArrayList<>();
635         if (ipAddress.getIpv4Address() != null) {
636             matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV4));
637         } else {
638             matches.add(new MatchEthernetType(NwConstants.ETHTYPE_IPV6));
639         }
640         matches.add(new MatchMetadata(MetaDataUtil.getLportTagMetaData(ifIndex), MetaDataUtil.METADATA_MASK_LPORT_TAG));
641
642         List<ActionInfo> actionsInfos = new ArrayList<>();
643         actionsInfos.add(new ActionSetFieldDscp(dscpValue));
644         actionsInfos.add(new ActionNxResubmit(NwConstants.LPORT_DISPATCHER_TABLE));
645
646         List<InstructionInfo> instructions = Collections.singletonList(new InstructionApplyActions(actionsInfos));
647         FlowEntity flowEntity = MDSALUtil.buildFlowEntity(dpnId, NwConstants.QOS_DSCP_TABLE,
648                 getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex),
649                 QosConstants.QOS_DEFAULT_FLOW_PRIORITY, "QoSConfigFlow", 0, 0, NwConstants.COOKIE_QOS_TABLE,
650                 matches, instructions);
651         mdsalUtils.installFlow(flowEntity);
652     }
653
654     private void removeFlow(BigInteger dpnId, String ifName, Interface ifState) {
655         if (ifState == null) {
656             LOG.trace("Could not find the ifState for interface {}", ifName);
657             return;
658         }
659         Integer ifIndex = ifState.getIfIndex();
660
661         mdsalUtils.removeFlow(dpnId, NwConstants.QOS_DSCP_TABLE,
662                 new FlowId(getQosFlowId(NwConstants.QOS_DSCP_TABLE, dpnId, ifIndex)));
663     }
664
665     @Nullable
666     public org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
667             .ietf.interfaces.rev140508.interfaces.state.Interface getInterfaceStateFromOperDS(
668             String interfaceName) {
669         return MDSALUtil.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
670                 createInterfaceStateInstanceIdentifier(interfaceName)).orNull();
671     }
672
673     @Nonnull
674     public static InstanceIdentifier<org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
675             .ietf.interfaces.rev140508.interfaces.state.Interface> createInterfaceStateInstanceIdentifier(
676             String interfaceName) {
677         return InstanceIdentifier
678                 .builder(InterfacesState.class)
679                 .child(org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
680                                 .ietf.interfaces.rev140508.interfaces.state.Interface.class,
681                         new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang
682                                 .ietf.interfaces.rev140508.interfaces.state.InterfaceKey(
683                                 interfaceName))
684                 .build();
685     }
686
687     public void bindservice(String ifName) {
688         int priority = QosConstants.QOS_DEFAULT_FLOW_PRIORITY;
689         int instructionKey = 0;
690         List<Instruction> instructions = new ArrayList<>();
691         instructions.add(MDSALUtil.buildAndGetGotoTableInstruction(NwConstants.QOS_DSCP_TABLE, ++instructionKey));
692         short qosServiceIndex = ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX);
693
694         BoundServices serviceInfo = getBoundServices(
695                 String.format("%s.%s", "qos", ifName), qosServiceIndex,
696                 priority, NwConstants.COOKIE_QOS_TABLE, instructions);
697         MDSALUtil.syncWrite(dataBroker, LogicalDatastoreType.CONFIGURATION,
698                 buildServiceId(ifName, qosServiceIndex),
699                 serviceInfo);
700     }
701
702     public void unbindservice(String ifName) {
703         MDSALUtil.syncDelete(dataBroker, LogicalDatastoreType.CONFIGURATION, buildServiceId(ifName,
704                 ServiceIndex.getIndex(NwConstants.QOS_SERVICE_NAME, NwConstants.QOS_SERVICE_INDEX)));
705     }
706
707     private static InstanceIdentifier<BoundServices> buildServiceId(String interfaceName, short qosServiceIndex) {
708         return InstanceIdentifier.builder(ServiceBindings.class)
709                 .child(ServicesInfo.class, new ServicesInfoKey(interfaceName, ServiceModeIngress.class))
710                 .child(BoundServices.class, new BoundServicesKey(qosServiceIndex)).build();
711     }
712
713     private static BoundServices getBoundServices(String serviceName, short qosServiceIndex, int priority,
714                                                   BigInteger cookieQosTable, List<Instruction> instructions) {
715         StypeOpenflowBuilder augBuilder = new StypeOpenflowBuilder().setFlowCookie(cookieQosTable)
716                 .setFlowPriority(priority).setInstruction(instructions);
717         return new BoundServicesBuilder().withKey(new BoundServicesKey(qosServiceIndex)).setServiceName(serviceName)
718                 .setServicePriority(qosServiceIndex).setServiceType(ServiceTypeFlowBased.class)
719                 .addAugmentation(StypeOpenflow.class, augBuilder.build()).build();
720     }
721
722     @Nonnull
723     public static String getQosFlowId(short tableId, BigInteger dpId, int lportTag) {
724         return String.valueOf(tableId) + dpId + lportTag;
725     }
726
727     public boolean portHasQosPolicy(Port port) {
728         LOG.trace("checking qos policy for port: {}", port.getUuid());
729
730         boolean isQosPolicy = port.augmentation(QosPortExtension.class) != null
731                 && port.augmentation(QosPortExtension.class).getQosPolicyId() != null;
732
733         LOG.trace("portHasQosPolicy for  port: {} return value {}", port.getUuid(), isQosPolicy);
734         return isQosPolicy;
735     }
736
737     @Nullable
738     public QosPolicy getQosPolicy(Port port) {
739         Uuid qosUuid = null;
740         QosPolicy qosPolicy = null;
741
742         if (port.augmentation(QosPortExtension.class) != null) {
743             qosUuid = port.augmentation(QosPortExtension.class).getQosPolicyId();
744         } else {
745             Network network = neutronVpnManager.getNeutronNetwork(port.getNetworkId());
746
747             if (network.augmentation(QosNetworkExtension.class) != null) {
748                 qosUuid = network.augmentation(QosNetworkExtension.class).getQosPolicyId();
749             }
750         }
751
752         if (qosUuid != null) {
753             qosPolicy = qosPolicyMap.get(qosUuid);
754         }
755
756         return qosPolicy;
757     }
758
759     public void addToPortCache(Port port) {
760         neutronPortMap.put(port.getUuid(), port);
761     }
762
763     public void removeFromPortCache(Port port) {
764         neutronPortMap.remove(port.getUuid());
765     }
766
767     public Port getNeutronPort(Uuid portUuid) {
768         return neutronPortMap.get(portUuid);
769     }
770
771     public Port getNeutronPort(String portName) {
772         return getNeutronPort(new Uuid(portName));
773     }
774
775     public void addToNetworkCache(Network network) {
776         neutronNetworkMap.put(network.getUuid(), network);
777     }
778
779     public void removeFromNetworkCache(Network network) {
780         neutronNetworkMap.remove(network.getUuid());
781     }
782
783     public Network getNeutronNetwork(Uuid networkUuid) {
784         return neutronNetworkMap.get(networkUuid);
785     }
786
787     public static BigInteger getDpnIdFromLowerLayerIf(String lowerLayerIf) {
788         try {
789             return new BigInteger(lowerLayerIf.substring(lowerLayerIf.indexOf(":") + 1, lowerLayerIf.lastIndexOf(":")));
790         } catch (NullPointerException e) {
791             return null;
792         }
793     }
794
795     public static String getPortNumberFromLowerLayerIf(String lowerLayerIf) {
796         try {
797             return (lowerLayerIf.substring(lowerLayerIf.lastIndexOf(":") + 1));
798         } catch (NullPointerException e) {
799             return null;
800         }
801     }
802
803 }