511aeed51f42017bb4d448306f02658ef506ea1b
[unimgr.git] / netvirt / src / main / java / org / opendaylight / unimgr / mef / netvirt / UniQosManager.java
1 /*
2  * Copyright (c) 2016 Hewlett Packard Enterprise, Co. 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.unimgr.mef.netvirt;
10
11 import com.google.common.base.Optional;
12
13 import jline.internal.Log;
14
15 import java.math.BigInteger;
16 import java.util.Iterator;
17 import java.util.concurrent.ConcurrentHashMap;
18 import java.util.concurrent.ExecutionException;
19 import java.util.concurrent.Future;
20 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.mdsalutil.MDSALUtil;
23 import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
24 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.MefGlobal;
25 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.Profiles;
26 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.bwp.flows.group.BwpFlow;
27 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.bwp.flows.group.BwpFlowKey;
28 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.global.rev150526.mef.global.profiles.IngressBwpFlows;
29 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.interfaces.rev150526.mef.interfaces.unis.uni.physical.layers.links.Link;
30 import org.opendaylight.yang.gen.v1.http.metroethernetforum.org.ns.yang.mef.types.rev150526.Identifier45;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.BridgeRefInfo;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntry;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.meta.rev160406.bridge.ref.info.BridgeRefEntryKey;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceInputBuilder;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.GetDpidFromInterfaceOutput;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.genius.interfacemanager.rpcs.rev160406.OdlInterfaceRpcService;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeRef;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentation;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbTerminationPointAugmentationBuilder;
41 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
42 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
43 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
44 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
45 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
46 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointBuilder;
47 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPointKey;
48 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
49 import org.opendaylight.yangtools.yang.common.RpcResult;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52
53 public class UniQosManager {
54     private static final Logger LOG = LoggerFactory.getLogger(UniQosManager.class);
55     private OdlInterfaceRpcService odlInterfaceRpcService;
56     private DataBroker dataBroker;
57     private final Long noLimit = 0l;
58
59     // key in first map is uniId, key in second map is logical portId
60     private ConcurrentHashMap<String, ConcurrentHashMap<String, BandwidthLimits>> uniPortBandwidthLimits;
61
62     // map of current values per uni
63     private ConcurrentHashMap<String, BandwidthLimits> uniBandwidthLimits;
64     
65     private ConcurrentHashMap<String, BigInteger> uniToDpn;
66
67     public UniQosManager(final DataBroker dataBroker, OdlInterfaceRpcService odlInterfaceRpcService) {
68         this.dataBroker = dataBroker;
69         this.odlInterfaceRpcService = odlInterfaceRpcService;
70         this.uniPortBandwidthLimits = new ConcurrentHashMap<>();
71         this.uniBandwidthLimits = new ConcurrentHashMap<>();
72         this.uniToDpn = new ConcurrentHashMap<>();
73     }
74
75     public void mapUniPortBandwidthLimits(String uniId, String portId, Long maxKbps, Long maxBurstKb) {
76         Log.info("Record rate limits for Uni {} port {} maxKbps {} maxBurstKb {}", uniId, portId, maxKbps, maxBurstKb);
77         uniPortBandwidthLimits.putIfAbsent(uniId, new ConcurrentHashMap<>());
78         ConcurrentHashMap<String, BandwidthLimits> uniMap = uniPortBandwidthLimits.get(uniId);
79         uniMap.put(portId, new BandwidthLimits(maxKbps, maxBurstKb));
80     }
81
82     public void mapUniPortBandwidthLimits(String uniId, String portId, Identifier45 bwProfile) {
83         Long maxKbps = noLimit;
84         Long maxBurstKb = noLimit;
85         if (bwProfile != null) {
86
87             Optional<BwpFlow> bwFlowOp = MdsalUtils.read(dataBroker, LogicalDatastoreType.CONFIGURATION,
88                     getBwFlowInstanceIdentifier(bwProfile));
89             if (!bwFlowOp.isPresent()) {
90                 Log.trace("Can't read bw profile {} for Uni {}", bwProfile, uniId);
91                 return;
92             }
93             // Kb per second
94             maxKbps = bwFlowOp.get().getCir().getValue();
95             // burst in bytes, ovs requires in Kb
96             maxBurstKb = bwFlowOp.get().getCbs().getValue() * 8 / 1024;
97             Log.info("Record rate limits for Uni {} Profile {}", uniId, bwProfile);
98         }
99         mapUniPortBandwidthLimits(uniId, portId, maxKbps, maxBurstKb);
100     }
101
102     public void unMapUniPortBandwidthLimits(String uniId, String portId) {
103         Log.debug("Delete rate limits for Uni {} port {}", uniId, portId);
104         ConcurrentHashMap<String, BandwidthLimits> uniMap = uniPortBandwidthLimits.get(uniId);
105         if (uniMap == null) {
106             Log.error("Trying to delete limits for non-exsting uni {}", uniId);
107             return;
108         }
109         uniMap.remove(portId);
110         if (uniMap.isEmpty()) {
111             uniMap.put(portId, new BandwidthLimits(noLimit, noLimit));
112         }
113     }
114
115     public void setUniBandwidthLimits(Identifier45 uniIden) {
116         String uniId = uniIden.getValue();
117         if (!uniPortBandwidthLimits.containsKey(uniId)) {
118             Log.debug("Uni {} doesn't have rate limits configured", uniId);
119             return;
120         }
121         Iterator<String> uniPorts = uniPortBandwidthLimits.get(uniId).keySet().iterator();
122         if (uniPorts == null || !uniPorts.hasNext()) {
123             Log.debug("Uni {} doesn't have rate limits configured", uniId);
124             return;
125         }
126         String logicalPort = uniPorts.next();
127
128         BandwidthLimits newLimits = recalculateLimitsForUni(uniId, uniPortBandwidthLimits.get(uniId));
129         if (newLimits.equals(uniBandwidthLimits.get(uniId))) {
130             Log.debug("Uni {} rate limits has not changed", uniId);
131             return;
132         }
133
134         setPortBandwidthLimits(uniId, logicalPort, newLimits.getMaxKbps(), newLimits.getMaxBurstKb());
135         uniBandwidthLimits.put(uniId, newLimits);
136     }
137
138     private BandwidthLimits recalculateLimitsForUni(String uniId,
139             ConcurrentHashMap<String, BandwidthLimits> uniLimits) {
140         Long sumOfRate = noLimit;
141         Long sumOfBurst = noLimit;
142         Boolean hasNullRate = false;
143         Boolean hasNullBurst = false;
144
145         if (uniLimits == null || uniLimits.keySet() == null) {
146             return new BandwidthLimits(sumOfRate, sumOfBurst);
147         }
148
149         for (BandwidthLimits v : uniLimits.values()) {
150             if (v.maxKbps == null) {
151                 hasNullRate = true;
152                 break;
153             }
154             if (v.maxBurstKb == null) {
155                 hasNullBurst = true;
156             }
157             sumOfRate = sumOfRate + v.maxKbps;
158             sumOfBurst = sumOfBurst + v.maxBurstKb;
159
160         }
161         if (hasNullRate) {
162             sumOfRate = noLimit;
163             sumOfBurst = noLimit;
164         } else if (hasNullBurst) {
165             sumOfBurst = noLimit;
166         }
167         return new BandwidthLimits(sumOfRate, sumOfBurst);
168     }
169
170     private void setPortBandwidthLimits(String uniId, String logicalPortId, Long maxKbps, Long maxBurstKb) {
171         LOG.trace("Setting bandwidth limits {} {} on Port {}", maxKbps, maxBurstKb, logicalPortId);
172
173         BigInteger dpId = BigInteger.ZERO;
174         if(uniToDpn.containsKey(uniId)) {
175             dpId = uniToDpn.get(uniId);
176         } else {        
177             dpId = getDpnForInterface(odlInterfaceRpcService, logicalPortId);
178             uniToDpn.put(uniId, dpId);
179         }
180         if (dpId.equals(BigInteger.ZERO)) {
181             LOG.error("DPN ID for interface {} not found", logicalPortId);
182             return;
183         }
184
185         OvsdbBridgeRef bridgeRefEntry = getBridgeRefEntryFromOperDS(dpId, dataBroker);
186         Optional<Node> bridgeNode = MDSALUtil.read(LogicalDatastoreType.OPERATIONAL,
187                 bridgeRefEntry.getValue().firstIdentifierOf(Node.class), dataBroker);
188         if (bridgeNode == null) {
189             LOG.error("Bridge ref for interface {} not found", logicalPortId);
190             return;
191         }
192
193         String physicalPort = getPhysicalPortForUni(dataBroker, uniId);
194         if (physicalPort == null) {
195             LOG.error("Physical port for interface {} not found", logicalPortId);
196             return;
197         }
198
199         TerminationPoint tp = getTerminationPoint(bridgeNode.get(), physicalPort);
200         if (tp == null) {
201             LOG.error("Termination point for port {} not found", physicalPort);
202             return;
203         }
204
205         OvsdbTerminationPointAugmentation ovsdbTp = tp.getAugmentation(OvsdbTerminationPointAugmentation.class);
206         OvsdbTerminationPointAugmentationBuilder tpAugmentationBuilder = new OvsdbTerminationPointAugmentationBuilder();
207         tpAugmentationBuilder.setName(ovsdbTp.getName());
208         tpAugmentationBuilder.setIngressPolicingRate(maxKbps);
209         tpAugmentationBuilder.setIngressPolicingBurst(maxBurstKb);
210
211         TerminationPointBuilder tpBuilder = new TerminationPointBuilder();
212         tpBuilder.setKey(tp.getKey());
213         tpBuilder.addAugmentation(OvsdbTerminationPointAugmentation.class, tpAugmentationBuilder.build());
214         MdsalUtils.syncUpdate(dataBroker, LogicalDatastoreType.CONFIGURATION,
215                 InstanceIdentifier.create(NetworkTopology.class)
216                         .child(Topology.class, new TopologyKey(SouthboundUtils.OVSDB_TOPOLOGY_ID))
217                         .child(Node.class, bridgeNode.get().getKey())
218                         .child(TerminationPoint.class, new TerminationPointKey(tp.getKey())),
219                 tpBuilder.build());
220     }
221
222     private static TerminationPoint getTerminationPoint(Node bridgeNode, String portName) {
223         for (TerminationPoint tp : bridgeNode.getTerminationPoint()) {
224             String tpIdStr = tp.getTpId().getValue();
225             if (tpIdStr != null && tpIdStr.equals(portName))
226                 return tp;
227         }
228         return null;
229     }
230
231     private static BigInteger getDpnForInterface(OdlInterfaceRpcService interfaceManagerRpcService, String ifName) {
232         BigInteger nodeId = BigInteger.ZERO;
233         try {
234             GetDpidFromInterfaceInput dpIdInput = new GetDpidFromInterfaceInputBuilder().setIntfName(ifName).build();
235             Future<RpcResult<GetDpidFromInterfaceOutput>> dpIdOutput = interfaceManagerRpcService
236                     .getDpidFromInterface(dpIdInput);
237             RpcResult<GetDpidFromInterfaceOutput> dpIdResult = dpIdOutput.get();
238             if (dpIdResult.isSuccessful()) {
239                 nodeId = dpIdResult.getResult().getDpid();
240             } else {
241                 LOG.error("Could not retrieve DPN Id for interface {}", ifName);
242             }
243         } catch (NullPointerException | InterruptedException | ExecutionException e) {
244             LOG.error("Exception when getting dpn for interface {}", ifName, e);
245         }
246         return nodeId;
247     }
248
249     private static String getPhysicalPortForUni(DataBroker dataBroker, String uniId) {
250         String nodeId = null;
251         try {
252             Link link = MefInterfaceUtils.getLink(dataBroker, uniId, LogicalDatastoreType.OPERATIONAL);
253             String parentInterfaceName = MefInterfaceUtils.getTrunkParentName(link);
254             return parentInterfaceName.split(":")[1];
255         } catch (Exception e) {
256             LOG.error("Exception when getting physical port for Uni {}", uniId, e);
257         }
258         return nodeId;
259     }
260
261     private static BridgeRefEntry getBridgeRefEntryFromOperDS(InstanceIdentifier<BridgeRefEntry> dpnBridgeEntryIid,
262             DataBroker dataBroker) {
263         Optional<BridgeRefEntry> bridgeRefEntryOptional = MdsalUtils.read(dataBroker, LogicalDatastoreType.OPERATIONAL,
264                 dpnBridgeEntryIid);
265         if (!bridgeRefEntryOptional.isPresent()) {
266             return null;
267         }
268         return bridgeRefEntryOptional.get();
269     }
270
271     private static OvsdbBridgeRef getBridgeRefEntryFromOperDS(BigInteger dpId, DataBroker dataBroker) {
272         BridgeRefEntryKey bridgeRefEntryKey = new BridgeRefEntryKey(dpId);
273         InstanceIdentifier<BridgeRefEntry> bridgeRefEntryIid = getBridgeRefEntryIdentifier(bridgeRefEntryKey);
274         BridgeRefEntry bridgeRefEntry = getBridgeRefEntryFromOperDS(bridgeRefEntryIid, dataBroker);
275         return (bridgeRefEntry != null) ? bridgeRefEntry.getBridgeReference() : null;
276     }
277
278     private static InstanceIdentifier<BridgeRefEntry> getBridgeRefEntryIdentifier(BridgeRefEntryKey bridgeRefEntryKey) {
279         InstanceIdentifier.InstanceIdentifierBuilder<BridgeRefEntry> bridgeRefEntryInstanceIdentifierBuilder = InstanceIdentifier
280                 .builder(BridgeRefInfo.class).child(BridgeRefEntry.class, bridgeRefEntryKey);
281         return bridgeRefEntryInstanceIdentifierBuilder.build();
282     }
283
284     private static InstanceIdentifier<BwpFlow> getBwFlowInstanceIdentifier(Identifier45 bwProfile) {
285         InstanceIdentifier.InstanceIdentifierBuilder<BwpFlow> bwProfileInstanceIdentifierBuilder = InstanceIdentifier
286                 .builder(MefGlobal.class).child(Profiles.class).child(IngressBwpFlows.class)
287                 .child(BwpFlow.class, new BwpFlowKey(bwProfile));
288         return bwProfileInstanceIdentifierBuilder.build();
289     }
290
291     private class BandwidthLimits {
292         private final Long maxKbps;
293         private final Long maxBurstKb;
294
295         public BandwidthLimits(Long maxKbps, Long maxBurstKb) {
296             this.maxKbps = replaceNull(maxKbps);
297             this.maxBurstKb = replaceNull(maxBurstKb);
298         }
299
300         public Long getMaxKbps() {
301             return maxKbps;
302         }
303
304         public Long getMaxBurstKb() {
305             return maxBurstKb;
306         }
307
308         private Long replaceNull(Long value) {
309             return (value == null) ? Long.valueOf(0) : value;
310         }
311
312         @Override
313         public boolean equals(Object obj) {
314             if (this == obj)
315                 return true;
316             if (obj == null)
317                 return false;
318             if (getClass() != obj.getClass())
319                 return false;
320             BandwidthLimits other = (BandwidthLimits) obj;
321             if (!getOuterType().equals(other.getOuterType()))
322                 return false;
323             if (maxBurstKb == null) {
324                 if (other.maxBurstKb != null)
325                     return false;
326             } else if (!maxBurstKb.equals(other.maxBurstKb))
327                 return false;
328             if (maxKbps == null) {
329                 if (other.maxKbps != null)
330                     return false;
331             } else if (!maxKbps.equals(other.maxKbps))
332                 return false;
333             return true;
334         }
335
336         @Override
337         public String toString() {
338             return "BandwidthLimitsBandwidthLimitsalues [maxKbps=" + maxKbps + ", maxBurstKb=" + maxBurstKb + "]";
339         }
340
341         private UniQosManager getOuterType() {
342             return UniQosManager.this;
343         }
344     }
345 }