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