blob: d7a204e73d22e24f14f48c9edc020e3185489db4 [file] [log] [blame]
Frank Wangd7e3b4b2017-09-24 13:37:54 +09001/*
2 * Copyright 2017-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.drivers.p4runtime;
18
19import com.google.common.cache.LoadingCache;
20import com.google.common.cache.CacheBuilder;
21import com.google.common.cache.CacheLoader;
22import org.onosproject.drivers.p4runtime.mirror.P4RuntimeMeterMirror;
23import org.onosproject.net.meter.Band;
24import org.onosproject.net.meter.DefaultBand;
25import org.onosproject.net.meter.DefaultMeter;
26import org.onosproject.net.meter.Meter;
27import org.onosproject.net.meter.MeterOperation;
28import org.onosproject.net.meter.MeterProgrammable;
29import org.onosproject.net.meter.MeterState;
30import org.onosproject.net.pi.model.PiMeterId;
31import org.onosproject.net.pi.model.PiMeterModel;
32import org.onosproject.net.pi.model.PiPipelineModel;
33import org.onosproject.net.pi.runtime.PiMeterCellConfig;
34import org.onosproject.net.pi.runtime.PiMeterHandle;
35import org.onosproject.net.pi.service.PiMeterTranslator;
36import org.onosproject.net.pi.service.PiTranslationException;
37
38import java.util.Collection;
39import java.util.Collections;
40import java.util.Set;
41import java.util.HashSet;
42import java.util.concurrent.CompletableFuture;
43import java.util.concurrent.TimeUnit;
44import java.util.concurrent.ExecutionException;
45import java.util.concurrent.locks.Lock;
46import java.util.concurrent.locks.ReentrantLock;
47import java.util.stream.Collectors;
48
49import static com.google.common.collect.Lists.newArrayList;
50
51/**
52 * Implementation of MeterProgrammable behaviour for P4Runtime.
53 */
54public class P4RuntimeMeterProgrammable extends AbstractP4RuntimeHandlerBehaviour implements MeterProgrammable {
55
56 private static final int METER_LOCK_EXPIRE_TIME_IN_MIN = 10;
57 private static final LoadingCache<PiMeterHandle, Lock>
58 ENTRY_LOCKS = CacheBuilder.newBuilder()
59 .expireAfterAccess(METER_LOCK_EXPIRE_TIME_IN_MIN, TimeUnit.MINUTES)
60 .build(new CacheLoader<PiMeterHandle, Lock>() {
61 @Override
62 public Lock load(PiMeterHandle handle) {
63 return new ReentrantLock();
64 }
65 });
66
67 private PiMeterTranslator translator;
68 private P4RuntimeMeterMirror meterMirror;
69 private PiPipelineModel pipelineModel;
70
71 @Override
72 protected boolean setupBehaviour() {
73 if (!super.setupBehaviour()) {
74 return false;
75 }
76
77 translator = piTranslationService.meterTranslator();
78 meterMirror = handler().get(P4RuntimeMeterMirror.class);
79 pipelineModel = pipeconf.pipelineModel();
80 return true;
81 }
82
83 @Override
84 public CompletableFuture<Boolean> performMeterOperation(MeterOperation meterOp) {
85
Kevin Chuangc267df22018-05-02 16:26:04 +080086 if (!setupBehaviour()) {
87 return CompletableFuture.completedFuture(false);
88 }
89
Frank Wangd7e3b4b2017-09-24 13:37:54 +090090 return CompletableFuture.completedFuture(processMeterOp(meterOp));
91 }
92
93 private boolean processMeterOp(MeterOperation meterOp) {
94
95 if (meterOp.type() != MeterOperation.Type.MODIFY) {
96 log.warn("P4runtime meter operations must be MODIFY!");
97 return false;
98 }
99
100 PiMeterCellConfig piMeterCellConfig;
101 try {
102 piMeterCellConfig = translator.translate(meterOp.meter(), pipeconf);
103 } catch (PiTranslationException e) {
104 log.warn("Unable translate meter, aborting meter operation {}: {}", meterOp.type(), e.getMessage());
105 log.debug("exception", e);
106 return false;
107 }
108
109 final PiMeterHandle handle = PiMeterHandle.of(deviceId, piMeterCellConfig);
110 ENTRY_LOCKS.getUnchecked(handle).lock();
111 boolean result = false;
112 try {
113 if (client.writeMeterCells(newArrayList(piMeterCellConfig), pipeconf).get()) {
114 meterMirror.put(handle, piMeterCellConfig);
115 result = true;
116 }
117
118 } catch (InterruptedException | ExecutionException e) {
119 log.warn("Exception while modify meter entry:", e);
120 } finally {
121 ENTRY_LOCKS.getUnchecked(handle).unlock();
122 }
123
124 return result;
125 }
126
127 @Override
128 public CompletableFuture<Collection<Meter>> getMeters() {
129
130 if (!setupBehaviour()) {
131 return CompletableFuture.completedFuture(Collections.emptyList());
132 }
133
134 Collection<PiMeterCellConfig> piMeterCellConfigs;
135
136 Set<PiMeterId> meterIds = new HashSet<>();
137 for (PiMeterModel mode : pipelineModel.meters()) {
138 meterIds.add(mode.id());
139 }
140
141 try {
142 piMeterCellConfigs = client.readAllMeterCells(meterIds, pipeconf).get();
143 } catch (InterruptedException | ExecutionException e) {
144 log.warn("Exception while reading meters from {}: {}", deviceId, e.toString());
145 log.debug("", e);
146 return CompletableFuture.completedFuture(Collections.emptyList());
147 }
148
149 Collection<Meter> meters = piMeterCellConfigs.stream()
150 .map(p -> {
151 DefaultMeter meter = (DefaultMeter) DefaultMeter.builder()
152 .withBands(p.meterBands().stream().map(b -> DefaultBand.builder()
153 .withRate(b.rate())
154 .burstSize(b.burst())
155 .ofType(Band.Type.NONE)
156 .build()).collect(Collectors.toList()))
157 .withCellId(p.cellId()).build();
158 meter.setState(MeterState.ADDED);
159 return meter;
160 })
161 .collect(Collectors.toList());
162
163 return CompletableFuture.completedFuture(meters);
164 }
165}