blob: 73faf4585dd880b780147895f22415f20b06c04d [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
Frank Wangd7e3b4b2017-09-24 13:37:54 +090019import com.google.common.cache.CacheBuilder;
20import com.google.common.cache.CacheLoader;
Carmelo Casconee5b28722018-06-22 17:28:28 +020021import com.google.common.cache.LoadingCache;
Frank Wangd7e3b4b2017-09-24 13:37:54 +090022import 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;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080034import org.onosproject.net.pi.runtime.PiMeterCellHandle;
Frank Wangd7e3b4b2017-09-24 13:37:54 +090035import org.onosproject.net.pi.service.PiMeterTranslator;
36import org.onosproject.net.pi.service.PiTranslationException;
37
38import java.util.Collection;
39import java.util.Collections;
Frank Wangd7e3b4b2017-09-24 13:37:54 +090040import java.util.HashSet;
Carmelo Casconee5b28722018-06-22 17:28:28 +020041import java.util.Set;
Frank Wangd7e3b4b2017-09-24 13:37:54 +090042import java.util.concurrent.CompletableFuture;
Carmelo Casconee5b28722018-06-22 17:28:28 +020043import java.util.concurrent.TimeUnit;
Frank Wangd7e3b4b2017-09-24 13:37:54 +090044import java.util.concurrent.locks.Lock;
45import java.util.concurrent.locks.ReentrantLock;
46import java.util.stream.Collectors;
47
Frank Wangd7e3b4b2017-09-24 13:37:54 +090048/**
49 * Implementation of MeterProgrammable behaviour for P4Runtime.
50 */
51public class P4RuntimeMeterProgrammable extends AbstractP4RuntimeHandlerBehaviour implements MeterProgrammable {
52
53 private static final int METER_LOCK_EXPIRE_TIME_IN_MIN = 10;
Carmelo Cascone4c289b72019-01-22 15:30:45 -080054 private static final LoadingCache<PiMeterCellHandle, Lock>
Frank Wangd7e3b4b2017-09-24 13:37:54 +090055 ENTRY_LOCKS = CacheBuilder.newBuilder()
56 .expireAfterAccess(METER_LOCK_EXPIRE_TIME_IN_MIN, TimeUnit.MINUTES)
Carmelo Cascone4c289b72019-01-22 15:30:45 -080057 .build(new CacheLoader<PiMeterCellHandle, Lock>() {
Frank Wangd7e3b4b2017-09-24 13:37:54 +090058 @Override
Carmelo Cascone4c289b72019-01-22 15:30:45 -080059 public Lock load(PiMeterCellHandle handle) {
Frank Wangd7e3b4b2017-09-24 13:37:54 +090060 return new ReentrantLock();
61 }
62 });
63
64 private PiMeterTranslator translator;
65 private P4RuntimeMeterMirror meterMirror;
66 private PiPipelineModel pipelineModel;
67
68 @Override
Carmelo Casconec32976e2019-04-08 14:50:52 -070069 protected boolean setupBehaviour(String opName) {
70 if (!super.setupBehaviour(opName)) {
Frank Wangd7e3b4b2017-09-24 13:37:54 +090071 return false;
72 }
73
Yi Tsengd7716482018-10-31 15:34:30 -070074 translator = translationService.meterTranslator();
Frank Wangd7e3b4b2017-09-24 13:37:54 +090075 meterMirror = handler().get(P4RuntimeMeterMirror.class);
76 pipelineModel = pipeconf.pipelineModel();
77 return true;
78 }
79
80 @Override
81 public CompletableFuture<Boolean> performMeterOperation(MeterOperation meterOp) {
82
Carmelo Casconec32976e2019-04-08 14:50:52 -070083 if (!setupBehaviour("performMeterOperation()")) {
Kevin Chuangc267df22018-05-02 16:26:04 +080084 return CompletableFuture.completedFuture(false);
85 }
86
Frank Wangd7e3b4b2017-09-24 13:37:54 +090087 return CompletableFuture.completedFuture(processMeterOp(meterOp));
88 }
89
90 private boolean processMeterOp(MeterOperation meterOp) {
91
92 if (meterOp.type() != MeterOperation.Type.MODIFY) {
Carmelo Cascone4c289b72019-01-22 15:30:45 -080093 log.warn("P4Runtime meter operations must be MODIFY!");
Frank Wangd7e3b4b2017-09-24 13:37:54 +090094 return false;
95 }
96
97 PiMeterCellConfig piMeterCellConfig;
98 try {
99 piMeterCellConfig = translator.translate(meterOp.meter(), pipeconf);
100 } catch (PiTranslationException e) {
101 log.warn("Unable translate meter, aborting meter operation {}: {}", meterOp.type(), e.getMessage());
102 log.debug("exception", e);
103 return false;
104 }
105
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800106 final PiMeterCellHandle handle = PiMeterCellHandle.of(deviceId, piMeterCellConfig);
Frank Wangd7e3b4b2017-09-24 13:37:54 +0900107 ENTRY_LOCKS.getUnchecked(handle).lock();
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800108 final boolean result = client.write(pipeconf)
109 .modify(piMeterCellConfig).submitSync().isSuccess();
Carmelo Casconee5b28722018-06-22 17:28:28 +0200110 if (result) {
111 meterMirror.put(handle, piMeterCellConfig);
Frank Wangd7e3b4b2017-09-24 13:37:54 +0900112 }
Carmelo Casconee5b28722018-06-22 17:28:28 +0200113 ENTRY_LOCKS.getUnchecked(handle).unlock();
Frank Wangd7e3b4b2017-09-24 13:37:54 +0900114
115 return result;
116 }
117
118 @Override
119 public CompletableFuture<Collection<Meter>> getMeters() {
120
Carmelo Casconec32976e2019-04-08 14:50:52 -0700121 if (!setupBehaviour("getMeters()")) {
Frank Wangd7e3b4b2017-09-24 13:37:54 +0900122 return CompletableFuture.completedFuture(Collections.emptyList());
123 }
124
125 Collection<PiMeterCellConfig> piMeterCellConfigs;
126
127 Set<PiMeterId> meterIds = new HashSet<>();
128 for (PiMeterModel mode : pipelineModel.meters()) {
129 meterIds.add(mode.id());
130 }
131
Carmelo Cascone4c289b72019-01-22 15:30:45 -0800132 piMeterCellConfigs = client.read(pipeconf)
133 .meterCells(meterIds).submitSync().all(PiMeterCellConfig.class);
Frank Wangd7e3b4b2017-09-24 13:37:54 +0900134
135 Collection<Meter> meters = piMeterCellConfigs.stream()
136 .map(p -> {
137 DefaultMeter meter = (DefaultMeter) DefaultMeter.builder()
138 .withBands(p.meterBands().stream().map(b -> DefaultBand.builder()
139 .withRate(b.rate())
140 .burstSize(b.burst())
141 .ofType(Band.Type.NONE)
142 .build()).collect(Collectors.toList()))
143 .withCellId(p.cellId()).build();
144 meter.setState(MeterState.ADDED);
145 return meter;
146 })
147 .collect(Collectors.toList());
148
149 return CompletableFuture.completedFuture(meters);
150 }
Carmelo Casconee5b28722018-06-22 17:28:28 +0200151}