blob: 219107154ddef31fd62093c79d142a4e7760cf27 [file] [log] [blame]
Daniele Moro464e5ed2019-07-25 14:45:01 -07001/*
2 * Copyright 2019-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.pipelines.fabric.impl.behaviour.bng;
18
19import com.google.common.collect.ImmutableBiMap;
20import com.google.common.collect.ImmutableSet;
Carmelo Casconeda15af82019-12-09 22:36:48 -080021import com.google.common.collect.Iterables;
Daniele Moro464e5ed2019-07-25 14:45:01 -070022import com.google.common.collect.Lists;
23import com.google.common.collect.Maps;
Carmelo Casconeda15af82019-12-09 22:36:48 -080024import org.onlab.util.ImmutableByteSequence;
Daniele Moro464e5ed2019-07-25 14:45:01 -070025import org.onosproject.core.ApplicationId;
26import org.onosproject.drivers.p4runtime.AbstractP4RuntimeHandlerBehaviour;
27import org.onosproject.net.behaviour.BngProgrammable;
28import org.onosproject.net.flow.DefaultFlowRule;
29import org.onosproject.net.flow.DefaultTrafficSelector;
30import org.onosproject.net.flow.DefaultTrafficTreatment;
31import org.onosproject.net.flow.FlowRule;
32import org.onosproject.net.flow.FlowRuleService;
33import org.onosproject.net.flow.TableId;
34import org.onosproject.net.flow.TrafficSelector;
35import org.onosproject.net.flow.TrafficTreatment;
36import org.onosproject.net.flow.criteria.Criterion;
37import org.onosproject.net.flow.criteria.PiCriterion;
38import org.onosproject.net.pi.model.PiCounterId;
Carmelo Casconeda15af82019-12-09 22:36:48 -080039import org.onosproject.net.pi.model.PiMatchType;
Daniele Moro464e5ed2019-07-25 14:45:01 -070040import org.onosproject.net.pi.runtime.PiAction;
41import org.onosproject.net.pi.runtime.PiActionParam;
42import org.onosproject.net.pi.runtime.PiCounterCell;
43import org.onosproject.net.pi.runtime.PiCounterCellData;
44import org.onosproject.net.pi.runtime.PiCounterCellHandle;
45import org.onosproject.net.pi.runtime.PiCounterCellId;
Carmelo Casconeda15af82019-12-09 22:36:48 -080046import org.onosproject.net.pi.runtime.PiExactFieldMatch;
Daniele Moro464e5ed2019-07-25 14:45:01 -070047import org.onosproject.p4runtime.api.P4RuntimeWriteClient;
Carmelo Casconeda15af82019-12-09 22:36:48 -080048import org.onosproject.pipelines.fabric.impl.behaviour.FabricCapabilities;
Carmelo Casconeb1f5cfd2020-12-04 16:54:24 -080049import org.onosproject.pipelines.fabric.FabricConstants;
Daniele Moro464e5ed2019-07-25 14:45:01 -070050
51import java.util.Collection;
52import java.util.List;
53import java.util.Map;
Carmelo Casconeda15af82019-12-09 22:36:48 -080054import java.util.Objects;
55import java.util.Optional;
Daniele Moro464e5ed2019-07-25 14:45:01 -070056import java.util.Set;
57import java.util.stream.Collectors;
Carmelo Casconeda15af82019-12-09 22:36:48 -080058import java.util.stream.StreamSupport;
Daniele Moro464e5ed2019-07-25 14:45:01 -070059
Carmelo Casconeda15af82019-12-09 22:36:48 -080060/**
61 * Implementation of BngProgrammable for fabric.p4.
62 */
Daniele Moro464e5ed2019-07-25 14:45:01 -070063public class FabricBngProgrammable extends AbstractP4RuntimeHandlerBehaviour
64 implements BngProgrammable {
65
66 // Default priority of the inserted BNG rules.
67 private static final int DEFAULT_PRIORITY = 10;
68 // The index at which control plane packets are counted before the attachment is created.
69 private static final int DEFAULT_CONTROL_INDEX = 0;
Daniele Moro464e5ed2019-07-25 14:45:01 -070070
71 private static final ImmutableBiMap<BngCounterType, PiCounterId> COUNTER_MAP =
72 ImmutableBiMap.<BngCounterType, PiCounterId>builder()
73 .put(BngCounterType.DOWNSTREAM_RX, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_C_LINE_RX)
74 .put(BngCounterType.DOWNSTREAM_TX, FabricConstants.FABRIC_EGRESS_BNG_EGRESS_DOWNSTREAM_C_LINE_TX)
75 .put(BngCounterType.UPSTREAM_TX, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_TERMINATED)
76 .put(BngCounterType.UPSTREAM_DROPPED, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_DROPPED)
77 .put(BngCounterType.CONTROL_PLANE, FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_C_CONTROL)
78 .build();
79
80 // FIXME: add these counters to the BNG pipeline
81 private static final ImmutableSet<BngCounterType> UNSUPPORTED_COUNTER =
82 ImmutableSet.of(BngCounterType.UPSTREAM_RX, BngCounterType.DOWNSTREAM_DROPPED);
83
84 private FlowRuleService flowRuleService;
Carmelo Casconeda15af82019-12-09 22:36:48 -080085 private FabricBngProgrammableService bngProgService;
86 private FabricCapabilities capabilities;
Daniele Moro464e5ed2019-07-25 14:45:01 -070087
88 @Override
89 protected boolean setupBehaviour(String opName) {
90 if (!super.setupBehaviour(opName)) {
91 return false;
92 }
93 flowRuleService = handler().get(FlowRuleService.class);
Carmelo Casconeda15af82019-12-09 22:36:48 -080094 bngProgService = handler().get(FabricBngProgrammableService.class);
95 capabilities = new FabricCapabilities(pipeconf);
96
97 if (!capabilities.supportBng()) {
98 log.warn("Pipeconf {} on {} does not support BNG capabilities, " +
99 "cannot perform {}",
100 pipeconf.id(), deviceId, opName);
101 return false;
102 }
103
Daniele Moro464e5ed2019-07-25 14:45:01 -0700104 return true;
105 }
106
107 @Override
108 public boolean init(ApplicationId appId) {
109 if (setupBehaviour("init()")) {
110 this.setupPuntToCpu(appId);
111 return true;
112 }
113 return false;
114 }
115
116 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800117 public void cleanUp(ApplicationId appId) {
Daniele Moro2832ec92019-12-05 22:10:48 -0800118 if (!setupBehaviour("cleanUp()")) {
119 return;
120 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800121 // Remove flow rules.
122 var flowEntries = flowRuleService.getFlowEntriesById(appId);
123 flowRuleService.removeFlowRules(
124 Iterables.toArray(flowEntries, FlowRule.class));
125 // Release line IDs found in removed flow rules.
126 getLineIdsFromFlowRules(flowEntries)
127 .forEach(this::releaseLineId);
128 // Reset counters.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700129 this.resetControlTrafficCounter();
130 }
131
132 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800133 public void setupAttachment(Attachment attachment) throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800134 if (!setupBehaviour("setupAttachment()")) {
135 return;
136 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800137 checkAttachment(attachment);
Daniele Moro464e5ed2019-07-25 14:45:01 -0700138 List<FlowRule> lstFlowRules = Lists.newArrayList();
Carmelo Casconeda15af82019-12-09 22:36:48 -0800139 lstFlowRules.add(buildTLineMapFlowRule(attachment));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700140 // If the line is not active do not generate the rule for the table
141 // t_pppoe_term_v4 since term_disabled is @defaultonly action
Carmelo Casconeda15af82019-12-09 22:36:48 -0800142 if (attachment.lineActive()) {
143 lstFlowRules.add(buildTPppoeTermV4FlowRule(attachment));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700144 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800145 lstFlowRules.add(buildTLineSessionMapFlowRule(attachment));
Daniele Moro893988e2019-11-27 16:14:38 -0800146
Daniele Moro464e5ed2019-07-25 14:45:01 -0700147 lstFlowRules.forEach(flowRule -> flowRuleService.applyFlowRules(flowRule));
148 }
149
150 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800151 public void removeAttachment(Attachment attachment) throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800152 if (!setupBehaviour("removeAttachment()")) {
153 return;
154 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800155 checkAttachment(attachment);
Daniele Moro464e5ed2019-07-25 14:45:01 -0700156 List<FlowRule> lstFlowRules = Lists.newArrayList();
Carmelo Casconeda15af82019-12-09 22:36:48 -0800157 lstFlowRules.add(buildTLineMapFlowRule(attachment));
158 lstFlowRules.add(buildTPppoeTermV4FlowRule(attachment));
159 lstFlowRules.add(buildTLineSessionMapFlowRule(attachment));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700160
161 lstFlowRules.forEach(flowRule -> flowRuleService.removeFlowRules(flowRule));
Carmelo Casconeda15af82019-12-09 22:36:48 -0800162
163 releaseLineId(attachment);
Daniele Moro464e5ed2019-07-25 14:45:01 -0700164 }
165
166 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800167 public Map<BngCounterType, PiCounterCellData> readCounters(Attachment attachment)
Daniele Moro464e5ed2019-07-25 14:45:01 -0700168 throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800169 if (!setupBehaviour("readCounters()")) {
170 return Maps.newHashMap();
171 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800172 checkAttachment(attachment);
173 return readCounters(lineId(attachment), Set.of(BngCounterType.values()));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700174 }
175
176 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800177 public PiCounterCellData readCounter(Attachment attachment, BngCounterType counter)
Daniele Moro464e5ed2019-07-25 14:45:01 -0700178 throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800179 if (!setupBehaviour("readCounter()")) {
180 return null;
181 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800182 checkAttachment(attachment);
183 return readCounters(lineId(attachment), Set.of(counter))
Daniele Moro464e5ed2019-07-25 14:45:01 -0700184 .getOrDefault(counter, null);
185 }
186
187 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800188 public void resetCounters(Attachment attachment)
Daniele Moro464e5ed2019-07-25 14:45:01 -0700189 throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800190 if (!setupBehaviour("resetCounters()")) {
191 return;
192 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800193 checkAttachment(attachment);
194 resetCounters(lineId(attachment), Set.of(BngCounterType.values()));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700195 }
196
197 @Override
198 public PiCounterCellData readControlTrafficCounter()
199 throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800200 if (!setupBehaviour("readControlTrafficCounter()")) {
201 return null;
202 }
Daniele Moro464e5ed2019-07-25 14:45:01 -0700203 return readCounters(DEFAULT_CONTROL_INDEX, Set.of(BngCounterType.CONTROL_PLANE))
204 .get(BngCounterType.CONTROL_PLANE);
205 }
206
207 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800208 public void resetCounter(Attachment attachment, BngCounterType counter)
Daniele Moro464e5ed2019-07-25 14:45:01 -0700209 throws BngProgrammableException {
Daniele Moro2832ec92019-12-05 22:10:48 -0800210 if (!setupBehaviour("resetCounter()")) {
211 return;
212 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800213 checkAttachment(attachment);
214 resetCounters(lineId(attachment), Set.of(counter));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700215 }
216
217 @Override
Carmelo Casconeda15af82019-12-09 22:36:48 -0800218 public void resetControlTrafficCounter() {
Daniele Moro2832ec92019-12-05 22:10:48 -0800219 if (!setupBehaviour("resetControlTrafficCounter()")) {
220 return;
221 }
Daniele Moro464e5ed2019-07-25 14:45:01 -0700222 resetCounters(DEFAULT_CONTROL_INDEX, Set.of((BngCounterType.CONTROL_PLANE)));
223 }
224
225 /**
226 * Read the specified counter at a specific index.
227 *
228 * @param index The index of the counter.
229 * @param counters The set of counters to read.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700230 */
231 private Map<BngCounterType, PiCounterCellData> readCounters(
232 long index,
233 Set<BngCounterType> counters) throws BngProgrammableException {
Daniele Moro464e5ed2019-07-25 14:45:01 -0700234 Map<BngCounterType, PiCounterCellData> readValues = Maps.newHashMap();
235 Set<PiCounterCellId> counterCellIds = counters.stream()
236 .filter(c -> !UNSUPPORTED_COUNTER.contains(c))
237 .map(c -> PiCounterCellId.ofIndirect(COUNTER_MAP.get(c), index))
238 .collect(Collectors.toSet());
239 // Check if there is any counter to read.
240 if (counterCellIds.size() != 0) {
241 Set<PiCounterCellHandle> counterCellHandles = counterCellIds.stream()
242 .map(cId -> PiCounterCellHandle.of(this.deviceId, cId))
243 .collect(Collectors.toSet());
244
245 // Query the device.
246 Collection<PiCounterCell> counterEntryResponse = client.read(
247 p4DeviceId, pipeconf)
248 .handles(counterCellHandles).submitSync()
249 .all(PiCounterCell.class);
250
251 if (counterEntryResponse.size() == 0) {
252 throw new BngProgrammableException(
253 String.format("Error in reading counters %s", counters.toString()));
254 }
255 readValues.putAll(counterEntryResponse.stream().collect(
256 Collectors.toMap(counterCell -> COUNTER_MAP.inverse()
Carmelo Casconeda15af82019-12-09 22:36:48 -0800257 .get(counterCell.cellId().counterId()),
258 PiCounterCell::data)));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700259 }
260 return readValues;
261 }
262
263 /**
264 * Reset the specified counters at a specific index.
265 *
266 * @param index The index of the counter.
267 * @param counters The set of counters to reset.
268 */
Carmelo Casconeda15af82019-12-09 22:36:48 -0800269 private void resetCounters(long index, Set<BngCounterType> counters) {
Daniele Moro464e5ed2019-07-25 14:45:01 -0700270 Set<PiCounterCellId> counterCellIds = counters.stream()
271 .filter(c -> !UNSUPPORTED_COUNTER.contains(c))
272 .map(c -> PiCounterCellId.ofIndirect(COUNTER_MAP.get(c), index))
273 .collect(Collectors.toSet());
274 if (counterCellIds.isEmpty()) {
275 // No counters to reset
276 log.info("No counters to reset.");
277 return;
278 }
279 Set<PiCounterCell> counterCellData = counterCellIds.stream()
280 .map(cId -> new PiCounterCell(cId, 0, 0))
281 .collect(Collectors.toSet());
282
283 // Query the device.
284 Collection<P4RuntimeWriteClient.EntityUpdateResponse> counterEntryResponse = client.write(
285 p4DeviceId, pipeconf)
286 .modify(counterCellData).submitSync()
287 .all();
288 counterEntryResponse.stream().filter(counterEntryResp -> !counterEntryResp.isSuccess())
289 .forEach(counterEntryResp -> log.warn("A counter was not reset correctly: {}",
Carmelo Casconeda15af82019-12-09 22:36:48 -0800290 counterEntryResp.explanation()));
Daniele Moro464e5ed2019-07-25 14:45:01 -0700291 }
292
293 /**
Daniele Moro6d84c182019-12-05 22:24:14 -0800294 * Preliminary check on the submitted attachment.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700295 */
Carmelo Casconeda15af82019-12-09 22:36:48 -0800296 private void checkAttachment(Attachment attachment) throws BngProgrammableException {
297 if (attachment.type() != Attachment.AttachmentType.PPPoE) {
Daniele Moro6d84c182019-12-05 22:24:14 -0800298 throw new BngProgrammableException(
299 "Attachment {} is not a PPPoE Attachment");
300 }
Daniele Moro464e5ed2019-07-25 14:45:01 -0700301 }
302
303 /**
304 * Set the punt to CPU rules of the BNG from a specific Application ID.
305 *
306 * @param appId Application ID asking to recive BNG control plane packets.
307 */
308 private void setupPuntToCpu(ApplicationId appId) {
309 for (Criterion c : PuntCpuCriterionFactory.getAllPuntCriterion()) {
310 FlowRule flPuntCpu = buildTPppoeCpFlowRule((PiCriterion) c, appId);
311 flowRuleService.applyFlowRules(flPuntCpu);
312 }
313 }
314
315 /**
316 * Build the Flow Rule for the table t_pppoe_term_v4 of the ingress
317 * upstream.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700318 */
Carmelo Casconeda15af82019-12-09 22:36:48 -0800319 private FlowRule buildTPppoeTermV4FlowRule(Attachment attachment)
320 throws BngProgrammableException {
Daniele Moro464e5ed2019-07-25 14:45:01 -0700321 PiCriterion criterion = PiCriterion.builder()
322 .matchExact(FabricConstants.HDR_LINE_ID,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800323 lineId(attachment))
Daniele Moro464e5ed2019-07-25 14:45:01 -0700324 .matchExact(FabricConstants.HDR_IPV4_SRC,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800325 attachment.ipAddress().toOctets())
Daniele Moro464e5ed2019-07-25 14:45:01 -0700326 .matchExact(FabricConstants.HDR_PPPOE_SESSION_ID,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800327 attachment.pppoeSessionId())
Daniele Moro464e5ed2019-07-25 14:45:01 -0700328 // TODO: match on MAC SRC address (antispoofing)
329// .matchExact(FabricConstants.HDR_ETH_SRC,
330// attachment.macAddress.toBytes())
331 .build();
332 TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
333 .matchPi(criterion)
334 .build();
335 PiAction action = PiAction.builder()
336 .withId(attachment.lineActive() ?
Carmelo Casconeda15af82019-12-09 22:36:48 -0800337 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_TERM_ENABLED_V4 :
338 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_TERM_DISABLED)
Daniele Moro464e5ed2019-07-25 14:45:01 -0700339 .build();
340 TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
341 .piTableAction(action)
342 .build();
343 return buildFlowRule(trafficSelector,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800344 instTreatment,
345 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_T_PPPOE_TERM_V4,
346 attachment.appId());
Daniele Moro464e5ed2019-07-25 14:45:01 -0700347 }
348
349 /**
350 * Build the Flow Rule for the table t_line_session_map of the ingress
351 * downstream.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700352 */
Carmelo Casconeda15af82019-12-09 22:36:48 -0800353 private FlowRule buildTLineSessionMapFlowRule(Attachment attachment)
354 throws BngProgrammableException {
Daniele Moro464e5ed2019-07-25 14:45:01 -0700355 PiCriterion criterion = PiCriterion.builder()
356 .matchExact(FabricConstants.HDR_LINE_ID,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800357 lineId(attachment))
Daniele Moro464e5ed2019-07-25 14:45:01 -0700358 .build();
359 TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
360 .matchPi(criterion)
361 .build();
362 PiAction action;
363 if (attachment.lineActive()) {
364 action = PiAction.builder()
365 .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_SET_SESSION)
366 .withParameter(new PiActionParam(FabricConstants.PPPOE_SESSION_ID,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800367 attachment.pppoeSessionId()))
Daniele Moro464e5ed2019-07-25 14:45:01 -0700368 .build();
369 } else {
370 action = PiAction.builder()
371 .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_DROP)
372 .build();
373 }
374 TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
375 .piTableAction(action)
376 .build();
377 return buildFlowRule(trafficSelector,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800378 instTreatment,
379 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_DOWNSTREAM_T_LINE_SESSION_MAP,
380 attachment.appId());
Daniele Moro464e5ed2019-07-25 14:45:01 -0700381 }
382
383 /**
384 * Build the flow rule for the table t_line_map of the BNG-U (common to both
385 * upstream and downstream).
Daniele Moro464e5ed2019-07-25 14:45:01 -0700386 */
Carmelo Casconeda15af82019-12-09 22:36:48 -0800387 private FlowRule buildTLineMapFlowRule(Attachment attachment)
388 throws BngProgrammableException {
Daniele Moro464e5ed2019-07-25 14:45:01 -0700389 PiCriterion criterion = PiCriterion.builder()
390 .matchExact(FabricConstants.HDR_S_TAG,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800391 attachment.sTag().toShort())
Daniele Moro464e5ed2019-07-25 14:45:01 -0700392 .matchExact(FabricConstants.HDR_C_TAG,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800393 attachment.cTag().toShort())
Daniele Moro464e5ed2019-07-25 14:45:01 -0700394 .build();
395 TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
396 .matchPi(criterion)
397 .build();
398 PiAction action = PiAction.builder()
399 .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_SET_LINE)
400 .withParameter(new PiActionParam(FabricConstants.LINE_ID,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800401 lineId(attachment)))
Daniele Moro464e5ed2019-07-25 14:45:01 -0700402 .build();
403 TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
404 .piTableAction(action)
405 .build();
406 return buildFlowRule(trafficSelector,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800407 instTreatment,
408 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_T_LINE_MAP,
409 attachment.appId());
Daniele Moro464e5ed2019-07-25 14:45:01 -0700410 }
411
412 /**
413 * Build the flow rule for the table t_pppoe_cp of the ingress upstream.
Daniele Moro464e5ed2019-07-25 14:45:01 -0700414 */
415 private FlowRule buildTPppoeCpFlowRule(PiCriterion criterion, ApplicationId appId) {
416 TrafficSelector trafficSelector = DefaultTrafficSelector.builder()
417 .matchPi(criterion)
418 .build();
419 TrafficTreatment instTreatment = DefaultTrafficTreatment.builder()
420 .piTableAction(PiAction.builder()
Carmelo Casconeda15af82019-12-09 22:36:48 -0800421 .withId(FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_PUNT_TO_CPU)
422 .build()
Daniele Moro464e5ed2019-07-25 14:45:01 -0700423 )
424 .build();
425 return buildFlowRule(trafficSelector,
Carmelo Casconeda15af82019-12-09 22:36:48 -0800426 instTreatment,
427 FabricConstants.FABRIC_INGRESS_BNG_INGRESS_UPSTREAM_T_PPPOE_CP,
428 appId);
Daniele Moro464e5ed2019-07-25 14:45:01 -0700429 }
430
431 private FlowRule buildFlowRule(TrafficSelector trafficSelector,
432 TrafficTreatment trafficTreatment,
433 TableId tableId,
434 ApplicationId appId) {
435 return DefaultFlowRule.builder()
436 .forDevice(data().deviceId())
437 .withSelector(trafficSelector)
438 .withTreatment(trafficTreatment)
439 .withPriority(DEFAULT_PRIORITY)
440 .forTable(tableId)
441 .fromApp(appId)
442 .makePermanent()
443 .build();
444 }
Carmelo Casconeda15af82019-12-09 22:36:48 -0800445
446 private long lineId(Attachment attachment) throws BngProgrammableException {
447 try {
448 return bngProgService.getLineIdAllocator(deviceId, capabilities.bngMaxLineCount()).allocate(attachment);
449 } catch (FabricBngLineIdAllocator.IdExhaustedException e) {
450 throw new BngProgrammableException("Line IDs exhausted, unable to allocate a new one");
451 }
452 }
453
454 private void releaseLineId(Attachment attachment) {
455 bngProgService.getLineIdAllocator(deviceId, capabilities.bngMaxLineCount()).release(attachment);
456 }
457
458 private void releaseLineId(long id) {
459 bngProgService.getLineIdAllocator(deviceId, capabilities.bngMaxLineCount()).release(id);
460 }
461
462 private Set<Long> getLineIdsFromFlowRules(Iterable<? extends FlowRule> rules) {
463 // Extract the line ID found in the flow rule selector.
464 return StreamSupport.stream(rules.spliterator(), true)
465 .map(f -> (PiCriterion) f.selector().getCriterion(Criterion.Type.PROTOCOL_INDEPENDENT))
466 .filter(Objects::nonNull)
467 .map(c -> c.fieldMatch(FabricConstants.HDR_LINE_ID))
468 .filter(Optional::isPresent)
469 .map(Optional::get)
470 .filter(m -> m.type() == PiMatchType.EXACT)
471 .map(m -> ((PiExactFieldMatch) m).value())
472 .map(b -> {
473 try {
474 return b.fit(Long.BYTES * 8);
475 } catch (ImmutableByteSequence.ByteSequenceTrimException e) {
476 log.error("Invalid line ID found in flow rule: {} is bigger than a long! BUG?", b);
477 return null;
478 }
479 })
480 .filter(Objects::nonNull)
481 .map(b -> b.asReadOnlyBuffer().getLong())
482 .collect(Collectors.toSet());
483 }
Daniele Moro464e5ed2019-07-25 14:45:01 -0700484}