Migrate to serviceutils/tools and serviceutils/srm
[netvirt.git] / qosservice / impl / src / main / java / org / opendaylight / netvirt / qosservice / QosPolicyChangeListener.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 java.math.BigInteger;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import javax.annotation.PostConstruct;
18 import javax.inject.Inject;
19 import javax.inject.Singleton;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.genius.datastoreutils.AsyncClusteredDataTreeChangeListenerBase;
24 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
25 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
26 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
27 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
28 import org.opendaylight.netvirt.neutronvpn.api.utils.ChangeUtils;
29 import org.opendaylight.netvirt.qosservice.recovery.QosServiceRecoveryHandler;
30 import org.opendaylight.serviceutils.srm.RecoverableListener;
31 import org.opendaylight.serviceutils.srm.ServiceRecoveryRegistry;
32 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.networks.rev150712.networks.attributes.networks.Network;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.QosPolicies;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.QosRuleTypes;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.QosRuleTypesBuilder;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRulesBuilder;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.DscpmarkingRules;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.rule.types.RuleTypes;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.rule.types.RuleTypesBuilder;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.rev150712.Neutron;
45 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 @Singleton
50 public class QosPolicyChangeListener extends AsyncClusteredDataTreeChangeListenerBase<QosPolicy,
51                                                 QosPolicyChangeListener> implements RecoverableListener {
52     private static final Logger LOG = LoggerFactory.getLogger(QosPolicyChangeListener.class);
53     private final DataBroker dataBroker;
54     private final ManagedNewTransactionRunner txRunner;
55     private final QosNeutronUtils qosNeutronUtils;
56     private final JobCoordinator jobCoordinator;
57
58     @Inject
59     public QosPolicyChangeListener(final DataBroker dataBroker,
60                                    final QosNeutronUtils qosNeutronUtils, final JobCoordinator jobCoordinator,
61                                    final ServiceRecoveryRegistry serviceRecoveryRegistry,
62                                    final QosServiceRecoveryHandler qosServiceRecoveryHandler) {
63         super(QosPolicy.class, QosPolicyChangeListener.class);
64         this.dataBroker = dataBroker;
65         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
66         this.qosNeutronUtils = qosNeutronUtils;
67         this.jobCoordinator = jobCoordinator;
68         serviceRecoveryRegistry.addRecoverableListener(qosServiceRecoveryHandler.buildServiceRegistryKey(),
69                 this);
70         LOG.trace("{} created",  getClass().getSimpleName());
71     }
72
73     @PostConstruct
74     public void init() {
75         registerListener();
76         supportedQoSRuleTypes();
77         LOG.trace("{} init and registerListener done", getClass().getSimpleName());
78     }
79
80     @Override
81     public void registerListener() {
82         registerListener(LogicalDatastoreType.CONFIGURATION, dataBroker);
83     }
84
85     @Override
86     protected InstanceIdentifier<QosPolicy> getWildCardPath() {
87         return InstanceIdentifier.create(Neutron.class).child(QosPolicies.class).child(QosPolicy.class);
88     }
89
90     @Override
91     public void onDataTreeChanged(Collection<DataTreeModification<QosPolicy>> changes) {
92         handleQosPolicyChanges(changes);
93         handleBandwidthLimitRulesChanges(changes);
94         handleDscpMarkingRulesChanges(changes);
95     }
96
97     @Override
98     protected QosPolicyChangeListener getDataTreeChangeListener() {
99         return QosPolicyChangeListener.this;
100     }
101
102     private void handleQosPolicyChanges(Collection<DataTreeModification<QosPolicy>> changes) {
103         Map<InstanceIdentifier<QosPolicy>, QosPolicy> qosPolicyOriginalMap =
104                 ChangeUtils.extractOriginal(changes, QosPolicy.class);
105
106         for (Entry<InstanceIdentifier<QosPolicy>, QosPolicy> qosPolicyMapEntry :
107                 ChangeUtils.extractCreated(changes, QosPolicy.class).entrySet()) {
108             add(qosPolicyMapEntry.getKey(), qosPolicyMapEntry.getValue());
109         }
110         for (Entry<InstanceIdentifier<QosPolicy>, QosPolicy> qosPolicyMapEntry :
111                 ChangeUtils.extractUpdated(changes, QosPolicy.class).entrySet()) {
112             update(qosPolicyMapEntry.getKey(), qosPolicyOriginalMap.get(qosPolicyMapEntry.getKey()),
113                     qosPolicyMapEntry.getValue());
114         }
115         for (InstanceIdentifier<QosPolicy> qosPolicyIid : ChangeUtils.extractRemoved(changes, QosPolicy.class)) {
116             remove(qosPolicyIid, qosPolicyOriginalMap.get(qosPolicyIid));
117         }
118     }
119
120     private void handleBandwidthLimitRulesChanges(Collection<DataTreeModification<QosPolicy>> changes) {
121         Map<InstanceIdentifier<BandwidthLimitRules>, BandwidthLimitRules> bwLimitOriginalMap =
122                 ChangeUtils.extractOriginal(changes, BandwidthLimitRules.class);
123
124         for (Entry<InstanceIdentifier<BandwidthLimitRules>, BandwidthLimitRules> bwLimitMapEntry :
125                 ChangeUtils.extractCreated(changes, BandwidthLimitRules.class).entrySet()) {
126             add(bwLimitMapEntry.getKey(), bwLimitMapEntry.getValue());
127         }
128         for (Entry<InstanceIdentifier<BandwidthLimitRules>, BandwidthLimitRules> bwLimitMapEntry :
129                 ChangeUtils.extractUpdated(changes, BandwidthLimitRules.class).entrySet()) {
130             update(bwLimitMapEntry.getKey(), bwLimitOriginalMap.get(bwLimitMapEntry.getKey()),
131                     bwLimitMapEntry.getValue());
132         }
133         for (InstanceIdentifier<BandwidthLimitRules> bwLimitIid :
134                 ChangeUtils.extractRemoved(changes, BandwidthLimitRules.class)) {
135             remove(bwLimitIid, bwLimitOriginalMap.get(bwLimitIid));
136         }
137     }
138
139     private void handleDscpMarkingRulesChanges(Collection<DataTreeModification<QosPolicy>> changes) {
140         Map<InstanceIdentifier<DscpmarkingRules>, DscpmarkingRules> dscpMarkOriginalMap =
141                 ChangeUtils.extractOriginal(changes, DscpmarkingRules.class);
142
143         for (Entry<InstanceIdentifier<DscpmarkingRules>, DscpmarkingRules> dscpMarkMapEntry :
144                 ChangeUtils.extractCreated(changes, DscpmarkingRules.class).entrySet()) {
145             add(dscpMarkMapEntry.getKey(), dscpMarkMapEntry.getValue());
146         }
147         for (Entry<InstanceIdentifier<DscpmarkingRules>, DscpmarkingRules> dscpMarkMapEntry :
148                 ChangeUtils.extractUpdated(changes, DscpmarkingRules.class).entrySet()) {
149             update(dscpMarkMapEntry.getKey(), dscpMarkOriginalMap.get(dscpMarkMapEntry.getKey()),
150                     dscpMarkMapEntry.getValue());
151         }
152         for (InstanceIdentifier<DscpmarkingRules> dscpMarkIid :
153                 ChangeUtils.extractRemoved(changes, DscpmarkingRules.class)) {
154             remove(dscpMarkIid, dscpMarkOriginalMap.get(dscpMarkIid));
155         }
156     }
157
158     @Override
159     protected void add(InstanceIdentifier<QosPolicy> identifier, QosPolicy input) {
160         LOG.debug("Adding  QosPolicy : key: {}, value={}",
161                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(),input);
162         qosNeutronUtils.addToQosPolicyCache(input);
163     }
164
165     protected void add(InstanceIdentifier<BandwidthLimitRules> identifier, BandwidthLimitRules input) {
166         LOG.debug("Adding BandwidthlimitRules : key: {}, value={}",
167                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), input);
168
169         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
170         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
171             qosNeutronUtils.handleNeutronNetworkQosUpdate(network, qosUuid);
172         }
173
174         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
175             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> Collections.singletonList(
176                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(
177                         tx -> qosNeutronUtils.setPortBandwidthLimits(port, input, tx))));
178         }
179     }
180
181     private void add(InstanceIdentifier<DscpmarkingRules> identifier, DscpmarkingRules input) {
182         LOG.debug("Adding DscpMarkingRules : key: {}, value={}",
183                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), input);
184
185         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
186
187         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
188             qosNeutronUtils.handleNeutronNetworkQosUpdate(network, qosUuid);
189         }
190
191         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
192             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
193                 qosNeutronUtils.setPortDscpMarking(port, input);
194                 return Collections.emptyList();
195             });
196         }
197     }
198
199     @Override
200     protected void remove(InstanceIdentifier<QosPolicy> identifier, QosPolicy input) {
201         LOG.debug("Removing QosPolicy : key: {}, value={}",
202                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), input);
203         qosNeutronUtils.removeFromQosPolicyCache(input);
204     }
205
206     private void remove(InstanceIdentifier<BandwidthLimitRules> identifier, BandwidthLimitRules input) {
207         LOG.debug("Removing BandwidthLimitRules : key: {}, value={}",
208                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), input);
209
210         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
211         BandwidthLimitRulesBuilder bwLimitBuilder = new BandwidthLimitRulesBuilder();
212         BandwidthLimitRules zeroBwLimitRule =
213                 bwLimitBuilder.setMaxBurstKbps(BigInteger.ZERO).setMaxKbps(BigInteger.ZERO).build();
214
215         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
216             qosNeutronUtils.handleNeutronNetworkQosBwRuleRemove(network, zeroBwLimitRule);
217         }
218
219         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
220             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> Collections.singletonList(
221                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(
222                         tx -> qosNeutronUtils.setPortBandwidthLimits(port, zeroBwLimitRule, tx))));
223         }
224     }
225
226     private void remove(InstanceIdentifier<DscpmarkingRules> identifier,DscpmarkingRules input) {
227         LOG.debug("Removing DscpMarkingRules : key: {}, value={}",
228                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), input);
229
230         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
231
232         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
233             qosNeutronUtils.handleNeutronNetworkQosDscpRuleRemove(network);
234         }
235
236         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
237             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
238                 qosNeutronUtils.unsetPortDscpMark(port);
239                 return Collections.emptyList();
240             });
241         }
242     }
243
244     public void reapplyPolicy(String entityid) {
245         Uuid policyUuid = Uuid.getDefaultInstance(entityid);
246         if (qosNeutronUtils.getQosPolicyMap().get(policyUuid) == null) {
247             LOG.debug("Policy with Uuid: {} does not exist", entityid);
248             return;
249         }
250
251         if (!qosNeutronUtils.getQosPolicyMap().get(policyUuid).getBandwidthLimitRules().isEmpty()) {
252             BandwidthLimitRules bandwidthLimitRules =
253                     qosNeutronUtils.getQosPolicyMap().get(policyUuid).getBandwidthLimitRules().get(0);
254             update(policyUuid, bandwidthLimitRules);
255         }
256
257         if (!qosNeutronUtils.getQosPolicyMap().get(policyUuid).getDscpmarkingRules().isEmpty()) {
258             DscpmarkingRules dscpmarkingRules =
259                     qosNeutronUtils.getQosPolicyMap().get(policyUuid).getDscpmarkingRules().get(0);
260             update(policyUuid, dscpmarkingRules);
261         }
262     }
263
264     @Override
265     protected void update(InstanceIdentifier<QosPolicy> identifier, QosPolicy original, QosPolicy update) {
266         LOG.debug("Updating QosPolicy : key: {}, original value={}, update value={}",
267                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), original, update);
268         qosNeutronUtils.addToQosPolicyCache(update);
269     }
270
271     private void update(InstanceIdentifier<BandwidthLimitRules> identifier, BandwidthLimitRules original,
272                         BandwidthLimitRules update) {
273         LOG.debug("Updating BandwidthLimitRules : key: {}, original value={}, update value={}",
274                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), original,
275                 update);
276         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
277         update(qosUuid, update);
278     }
279
280     private void update(Uuid qosUuid, BandwidthLimitRules update) {
281         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
282             qosNeutronUtils.handleNeutronNetworkQosUpdate(network, qosUuid);
283         }
284
285         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
286             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> Collections.singletonList(
287                     txRunner.callWithNewWriteOnlyTransactionAndSubmit(
288                         tx -> qosNeutronUtils.setPortBandwidthLimits(port, update, tx))));
289         }
290     }
291
292     private void update(InstanceIdentifier<DscpmarkingRules> identifier, DscpmarkingRules original,
293                         DscpmarkingRules update) {
294         LOG.debug("Updating DscpMarkingRules : key: {}, original value={}, update value={}",
295                 identifier.firstKeyOf(QosPolicy.class).getUuid().getValue(), original, update);
296         Uuid qosUuid = identifier.firstKeyOf(QosPolicy.class).getUuid();
297         update(qosUuid, update);
298     }
299
300     private void update(Uuid qosUuid, DscpmarkingRules update) {
301         for (Network network : qosNeutronUtils.getQosNetworks(qosUuid)) {
302             qosNeutronUtils.handleNeutronNetworkQosUpdate(network, qosUuid);
303         }
304
305         for (Port port : qosNeutronUtils.getQosPorts(qosUuid)) {
306             jobCoordinator.enqueueJob("QosPort-" + port.getUuid().getValue(), () -> {
307                 qosNeutronUtils.setPortDscpMarking(port, update);
308                 return Collections.emptyList();
309             });
310         }
311     }
312
313     private void supportedQoSRuleTypes() {
314         QosRuleTypesBuilder qrtBuilder = new QosRuleTypesBuilder();
315         List<RuleTypes> value = new ArrayList<>();
316
317         value.add(getRuleTypes("bandwidth_limit_rules"));
318         value.add(getRuleTypes("dscp_marking_rules"));
319
320         qrtBuilder.setRuleTypes(value);
321
322         ListenableFutures.addErrorLogging(txRunner.callWithNewWriteOnlyTransactionAndSubmit(tx -> {
323             InstanceIdentifier instanceIdentifier = InstanceIdentifier.create(Neutron.class).child(QosRuleTypes.class);
324             tx.merge(LogicalDatastoreType.OPERATIONAL, instanceIdentifier, qrtBuilder.build());
325         }), LOG, "Error setting up supported QoS rule types");
326     }
327
328     private RuleTypes getRuleTypes(String ruleType) {
329         RuleTypesBuilder rtBuilder = new RuleTypesBuilder();
330         rtBuilder.setRuleType(ruleType);
331         return rtBuilder.build();
332     }
333 }