MRI version bumpup for Aluminium
[netvirt.git] / qosservice / impl / src / main / java / org / opendaylight / netvirt / qosservice / QosTerminationPointListener.java
1 /*
2  * Copyright (c) 2017 Ericsson India Global Services Pvt Ltd. 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
9 package org.opendaylight.netvirt.qosservice;
10
11 import static org.opendaylight.genius.infra.Datastore.CONFIGURATION;
12
13 import java.util.Collections;
14 import javax.annotation.PreDestroy;
15 import javax.inject.Inject;
16 import javax.inject.Singleton;
17 import org.eclipse.jdt.annotation.Nullable;
18 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
19 import org.opendaylight.genius.infra.ManagedNewTransactionRunnerImpl;
20 import org.opendaylight.infrautils.jobcoordinator.JobCoordinator;
21 import org.opendaylight.infrautils.utils.concurrent.Executors;
22 import org.opendaylight.mdsal.binding.api.DataBroker;
23 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
24 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
25 import org.opendaylight.serviceutils.tools.listener.AbstractClusteredAsyncDataTreeChangeListener;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.ports.rev150712.ports.attributes.ports.Port;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.QosPolicy;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.neutron.qos.rev160613.qos.attributes.qos.policies.qos.policy.BandwidthLimitRules;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.InterfaceExternalIds;
32 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
33 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
34 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
35 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
36 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 @Singleton
42 public class QosTerminationPointListener extends
43         AbstractClusteredAsyncDataTreeChangeListener<OvsdbTerminationPointAugmentation> {
44     private static final Logger LOG = LoggerFactory.getLogger(QosTerminationPointListener.class);
45     private static final String EXTERNAL_ID_INTERFACE_ID = "iface-id";
46     private final DataBroker dataBroker;
47     private final QosNeutronUtils qosNeutronUtils;
48     private final QosEosHandler qosEosHandler;
49     private final QosAlertManager qosAlertManager;
50     private final ManagedNewTransactionRunner txRunner;
51     private final JobCoordinator jobCoordinator;
52
53     @Inject
54     public QosTerminationPointListener(final DataBroker dataBroker,
55                                        final QosNeutronUtils qosNeutronUtils,
56                                        final QosEosHandler qosEosHandler,
57                                        final QosAlertManager qosAlertManager,
58                                        final JobCoordinator jobCoordinator) {
59         super(dataBroker, LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(NetworkTopology.class)
60                 .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
61                 .child(Node.class).child(TerminationPoint.class)
62                 .augmentation(OvsdbTerminationPointAugmentation.class),
63                 Executors.newListeningSingleThreadExecutor("QosTerminationPointListener", LOG));
64         this.dataBroker = dataBroker;
65         this.qosNeutronUtils = qosNeutronUtils;
66         this.qosEosHandler = qosEosHandler;
67         this.qosAlertManager = qosAlertManager;
68         this.txRunner = new ManagedNewTransactionRunnerImpl(dataBroker);
69         this.jobCoordinator = jobCoordinator;
70     }
71
72     public void init() {
73         LOG.trace("{} init and registerListener done", getClass().getSimpleName());
74     }
75
76     @Override
77     @PreDestroy
78     public void close() {
79         super.close();
80         Executors.shutdownAndAwaitTermination(getExecutorService());
81     }
82
83     @Override
84     public void remove(InstanceIdentifier<OvsdbTerminationPointAugmentation> instanceIdentifier,
85                           OvsdbTerminationPointAugmentation tp) {
86         if (isBandwidthRuleApplied(tp)) {
87             String ifaceId = getIfaceId(tp);
88             if (ifaceId != null) {
89                 qosAlertManager.removeInterfaceIdFromQosAlertCache(ifaceId);
90             }
91         }
92     }
93
94     private boolean isBandwidthRuleCleared(OvsdbTerminationPointAugmentation original,
95                                          OvsdbTerminationPointAugmentation update) {
96         if ((update.getIngressPolicingRate().toJava() == 0 && update.getIngressPolicingBurst().toJava() == 0)
97                 && (original.getIngressPolicingRate().toJava() != 0
98                 || original.getIngressPolicingBurst().toJava() != 0)) {
99             return true;
100         }
101         return false;
102     }
103
104     private boolean isBandwidthRuleApplied(OvsdbTerminationPointAugmentation tp) {
105         if (tp.getIngressPolicingRate().toJava() != 0 || tp.getIngressPolicingBurst().toJava() != 0) {
106             return true;
107         }
108         return false;
109     }
110
111     private boolean isBandwidthRuleApplied(OvsdbTerminationPointAugmentation original,
112                                            OvsdbTerminationPointAugmentation update) {
113         if ((original.getIngressPolicingRate().toJava() == 0 && original.getIngressPolicingBurst().toJava() == 0)
114                 && (update.getIngressPolicingRate().toJava() != 0 || update.getIngressPolicingBurst().toJava() != 0)) {
115             return true;
116         }
117         return false;
118     }
119
120     @Override
121     public void update(InstanceIdentifier<OvsdbTerminationPointAugmentation> instanceIdentifier,
122                           OvsdbTerminationPointAugmentation original,
123                           OvsdbTerminationPointAugmentation update) {
124         String ifaceId = getIfaceId(update);
125         if (ifaceId != null) {
126             if (isBandwidthRuleCleared(original, update)) {
127                 qosAlertManager.removeInterfaceIdFromQosAlertCache(ifaceId);
128             } else if (isBandwidthRuleApplied(original, update)) {
129                 qosAlertManager.addInterfaceIdInQoSAlertCache(ifaceId);
130             }
131         }
132         if (!qosEosHandler.isQosClusterOwner()) {
133             return;
134         }
135         // switch restart scenario with openstack newton onwards results in deletion and addition
136         // of vhu ports with ovs-dpdk and as a side effect of that, qos parameters for rate limiting
137         // get cleared from the port.
138         // To resolve the issue, in TP update event, check is done to see if old port configuration
139         // has qos parameters set but cleared in updated port configuration and qos policy with
140         // bandwidth rules is present for the port, then reapply the qos policy configuration.
141
142         if (ifaceId != null && isBandwidthRuleCleared(original, update)) {
143             LOG.debug("update tp augment: iface-id: {}, name: {}, old bw rate, burst = {}, {}, "
144                             + "updated bw rate, burst = {}, {}", ifaceId, update.getName(),
145                     original.getIngressPolicingRate(), original.getIngressPolicingBurst(),
146                     update.getIngressPolicingRate(), update.getIngressPolicingBurst());
147             Port port = qosNeutronUtils.getNeutronPort(ifaceId);
148             if (port != null) {
149                 setPortBandwidthRule(instanceIdentifier, update, port);
150             }
151         }
152     }
153
154     @Override
155     public void add(InstanceIdentifier<OvsdbTerminationPointAugmentation> instanceIdentifier,
156                        OvsdbTerminationPointAugmentation tpAugment) {
157         String ifaceId = getIfaceId(tpAugment);
158         if ((ifaceId != null) && isBandwidthRuleApplied(tpAugment)) {
159             qosAlertManager.addInterfaceIdInQoSAlertCache(ifaceId);
160         }
161         if ((ifaceId != null) && qosEosHandler.isQosClusterOwner()) {
162             Port port = qosNeutronUtils.getNeutronPort(ifaceId);
163             if (port != null) {
164                 LOG.debug("add tp augmentation: iface-id: {}, name: {} ", ifaceId, tpAugment.getName());
165                 setPortBandwidthRule(instanceIdentifier, tpAugment, port);
166             }
167         }
168     }
169
170     private void setPortBandwidthRule(InstanceIdentifier<OvsdbTerminationPointAugmentation> identifier,
171                                       OvsdbTerminationPointAugmentation update, Port port) {
172         QosPolicy qosPolicy = qosNeutronUtils.getQosPolicy(port);
173         if (qosPolicy == null || qosPolicy.getBandwidthLimitRules() == null
174                 || qosPolicy.getBandwidthLimitRules().isEmpty()) {
175             return;
176         }
177         LOG.debug("setting bandwidth rule for port: {}, {}, qos policy: {}",
178                 port.getUuid(), update.getName(), qosPolicy.getName());
179
180         jobCoordinator.enqueueJob("QosPort-" + port.getUuid(), () ->
181                 Collections.singletonList(txRunner.callWithNewWriteOnlyTransactionAndSubmit(CONFIGURATION, tx -> {
182                     BandwidthLimitRules bwRule = qosPolicy.getBandwidthLimitRules().get(0);
183                     OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder =
184                             new OvsdbTerminationPointAugmentationBuilder();
185                     tpAugmentationBuilder.setName(update.getName());
186                     tpAugmentationBuilder.setIngressPolicingRate(bwRule.getMaxKbps().longValue());
187                     tpAugmentationBuilder.setIngressPolicingBurst(bwRule.getMaxBurstKbps().longValue());
188
189                     tx.mergeParentStructureMerge(InstanceIdentifier.create(NetworkTopology.class)
190                             .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
191                             .child(Node.class, identifier.firstKeyOf(Node.class))
192                             .child(TerminationPoint.class, identifier.firstKeyOf(TerminationPoint.class))
193                             .augmentation(OvsdbTerminationPointAugmentation.class),
194                             tpAugmentationBuilder.build());
195
196                 })));
197     }
198
199     @Nullable
200     private String getIfaceId(OvsdbTerminationPointAugmentation tpAugmentation) {
201         if (tpAugmentation.getInterfaceExternalIds() != null) {
202             for (InterfaceExternalIds entry: tpAugmentation.getInterfaceExternalIds().values()) {
203                 if (EXTERNAL_ID_INTERFACE_ID.equals(entry.getExternalIdKey())) {
204                     return entry.getExternalIdValue();
205                 }
206             }
207         }
208         return null;
209     }
210 }