blob: ed1083977d9ebc573e0ce91dbc69cdfc66fce780 [file] [log] [blame]
Yi Tseng0b809722017-11-03 10:23:26 -07001/*
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.pipelines.fabric.pipeliner;
18
Yi Tseng0b809722017-11-03 10:23:26 -070019import org.onosproject.net.DeviceId;
Yi Tseng4fd28432018-02-01 14:48:03 -080020import org.onosproject.net.driver.Driver;
Yi Tseng0b809722017-11-03 10:23:26 -070021import org.onosproject.net.flow.DefaultFlowRule;
22import org.onosproject.net.flow.DefaultTrafficSelector;
23import org.onosproject.net.flow.DefaultTrafficTreatment;
Yi Tseng0b809722017-11-03 10:23:26 -070024import org.onosproject.net.flow.TrafficSelector;
25import org.onosproject.net.flow.TrafficTreatment;
26import org.onosproject.net.flow.criteria.PiCriterion;
27import org.onosproject.net.flow.instructions.Instruction;
28import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
Yi Tseng4fd28432018-02-01 14:48:03 -080029import org.onosproject.net.flowobjective.DefaultNextObjective;
Yi Tseng0b809722017-11-03 10:23:26 -070030import org.onosproject.net.flowobjective.NextObjective;
Yi Tseng6e9b6f52018-02-27 10:40:51 +010031import org.onosproject.net.flowobjective.Objective;
Yi Tseng0b809722017-11-03 10:23:26 -070032import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng1b154bd2017-11-20 17:48:19 -080033import org.onosproject.net.group.DefaultGroupBucket;
34import org.onosproject.net.group.DefaultGroupDescription;
35import org.onosproject.net.group.GroupBucket;
36import org.onosproject.net.group.GroupBuckets;
37import org.onosproject.net.group.GroupDescription;
Yi Tseng1b154bd2017-11-20 17:48:19 -080038import org.onosproject.net.pi.runtime.PiActionGroupId;
Yi Tseng1b154bd2017-11-20 17:48:19 -080039import org.onosproject.net.pi.runtime.PiGroupKey;
Yi Tseng0b809722017-11-03 10:23:26 -070040import org.slf4j.Logger;
41
Yi Tseng1b154bd2017-11-20 17:48:19 -080042import java.util.List;
Yi Tseng1b154bd2017-11-20 17:48:19 -080043import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070044
Yi Tsengf55eaa82017-11-29 15:51:28 -080045import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRF_NEXT_ECMP_SELECTOR_ID;
Yi Tseng1b154bd2017-11-20 17:48:19 -080046import static org.onosproject.pipelines.fabric.FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID;
47import static org.onosproject.pipelines.fabric.FabricConstants.TBL_HASHED_ID;
Yi Tseng1b154bd2017-11-20 17:48:19 -080048import static org.onosproject.pipelines.fabric.FabricConstants.TBL_SIMPLE_ID;
Yi Tseng0b809722017-11-03 10:23:26 -070049import static org.slf4j.LoggerFactory.getLogger;
50
51/**
52 * Handling next objective for fabric pipeliner.
53 */
54public class FabricNextPipeliner {
55 private static final Logger log = getLogger(FabricNextPipeliner.class);
Yi Tseng4fd28432018-02-01 14:48:03 -080056 private static final String NO_HASHED_TABLE = "noHashedTable";
Yi Tseng0b809722017-11-03 10:23:26 -070057
Yi Tseng0b809722017-11-03 10:23:26 -070058 protected DeviceId deviceId;
Yi Tseng4fd28432018-02-01 14:48:03 -080059 protected Driver driver;
Yi Tseng0b809722017-11-03 10:23:26 -070060
Yi Tseng4fd28432018-02-01 14:48:03 -080061 public FabricNextPipeliner(DeviceId deviceId, Driver driver) {
Yi Tseng0b809722017-11-03 10:23:26 -070062 this.deviceId = deviceId;
Yi Tseng4fd28432018-02-01 14:48:03 -080063 this.driver = driver;
Yi Tseng0b809722017-11-03 10:23:26 -070064 }
65
66 public PipelinerTranslationResult next(NextObjective nextObjective) {
67 PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
Yi Tseng1b154bd2017-11-20 17:48:19 -080068
Yi Tseng0b809722017-11-03 10:23:26 -070069 switch (nextObjective.type()) {
70 case SIMPLE:
Yi Tseng1b154bd2017-11-20 17:48:19 -080071 processSimpleNext(nextObjective, resultBuilder);
72 break;
73 case HASHED:
74 processHashedNext(nextObjective, resultBuilder);
Yi Tseng0b809722017-11-03 10:23:26 -070075 break;
76 default:
77 log.warn("Unsupported next type {}", nextObjective);
78 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
79 break;
80 }
81
Yi Tseng0b809722017-11-03 10:23:26 -070082 return resultBuilder.build();
83 }
84
Yi Tseng1b154bd2017-11-20 17:48:19 -080085 private void processSimpleNext(NextObjective next,
86 PipelinerTranslationResult.Builder resultBuilder) {
87
Yi Tseng0b809722017-11-03 10:23:26 -070088 if (next.next().size() > 1) {
89 log.warn("Only one treatment in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -080090 resultBuilder.setError(ObjectiveError.BADPARAMS);
91 return;
Yi Tseng0b809722017-11-03 10:23:26 -070092 }
93
94 TrafficSelector selector = buildNextIdSelector(next.id());
95 TrafficTreatment treatment = next.next().iterator().next();
96 OutputInstruction outputInst = treatment.allInstructions()
97 .stream()
98 .filter(inst -> inst.type() == Instruction.Type.OUTPUT)
99 .map(inst -> (OutputInstruction) inst)
100 .findFirst()
101 .orElse(null);
102
103 if (outputInst == null) {
104 log.warn("At least one output instruction in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -0800105 resultBuilder.setError(ObjectiveError.BADPARAMS);
106 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700107 }
Yi Tseng1b154bd2017-11-20 17:48:19 -0800108 resultBuilder.addFlowRule(DefaultFlowRule.builder()
109 .withSelector(selector)
110 .withTreatment(treatment)
111 .forTable(TBL_SIMPLE_ID)
112 .makePermanent()
113 .withPriority(next.priority())
114 .forDevice(deviceId)
115 .fromApp(next.appId())
116 .build());
117 }
118
119 private void processHashedNext(NextObjective nextObjective, PipelinerTranslationResult.Builder resultBuilder) {
Yi Tseng4fd28432018-02-01 14:48:03 -0800120 boolean noHashedTable = Boolean.parseBoolean(driver.getProperty(NO_HASHED_TABLE));
121
122 if (noHashedTable) {
123 if (nextObjective.next().isEmpty()) {
124 return;
125 }
126 // use first action if not support hashed group
127 TrafficTreatment treatment = nextObjective.next().iterator().next();
128
129 NextObjective.Builder simpleNext = DefaultNextObjective.builder()
130 .addTreatment(treatment)
131 .withId(nextObjective.id())
132 .fromApp(nextObjective.appId())
133 .makePermanent()
134 .withMeta(nextObjective.meta())
135 .withPriority(nextObjective.priority())
136 .withType(NextObjective.Type.SIMPLE);
137
138 if (nextObjective.context().isPresent()) {
139 processSimpleNext(simpleNext.add(nextObjective.context().get()), resultBuilder);
140 } else {
141 processSimpleNext(simpleNext.add(), resultBuilder);
142 }
143 return;
144 }
145
Yi Tseng1b154bd2017-11-20 17:48:19 -0800146 // create hash groups
147 int groupId = nextObjective.id();
148 List<GroupBucket> bucketList = nextObjective.next().stream()
149 .map(DefaultGroupBucket::createSelectGroupBucket)
150 .collect(Collectors.toList());
151
152 if (bucketList.size() != nextObjective.next().size()) {
153 // some action not converted
154 // set error
155 log.warn("Expected bucket size {}, got {}", nextObjective.next().size(), bucketList.size());
156 resultBuilder.setError(ObjectiveError.BADPARAMS);
157 return;
158 }
159
160 GroupBuckets buckets = new GroupBuckets(bucketList);
161 PiGroupKey groupKey = new PiGroupKey(TBL_HASHED_ID,
Yi Tsengf55eaa82017-11-29 15:51:28 -0800162 ACT_PRF_NEXT_ECMP_SELECTOR_ID,
Yi Tseng1b154bd2017-11-20 17:48:19 -0800163 groupId);
164
165 resultBuilder.addGroup(new DefaultGroupDescription(deviceId,
166 GroupDescription.Type.SELECT,
167 buckets,
168 groupKey,
169 groupId,
170 nextObjective.appId()));
171
172 // flow
Yi Tseng6e9b6f52018-02-27 10:40:51 +0100173 // If operation is ADD_TO_EXIST or REMOVE_FROM_EXIST, means we modify
174 // group buckets only, no changes for flow rule
175 if (nextObjective.op() == Objective.Operation.ADD_TO_EXISTING ||
176 nextObjective.op() == Objective.Operation.REMOVE_FROM_EXISTING) {
177 return;
178 }
Yi Tseng1b154bd2017-11-20 17:48:19 -0800179 TrafficSelector selector = buildNextIdSelector(nextObjective.id());
180 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
181 .piTableAction(PiActionGroupId.of(nextObjective.id()))
Yi Tseng0b809722017-11-03 10:23:26 -0700182 .build();
Yi Tseng1b154bd2017-11-20 17:48:19 -0800183
184 resultBuilder.addFlowRule(DefaultFlowRule.builder()
185 .withSelector(selector)
186 .withTreatment(treatment)
187 .forTable(TBL_HASHED_ID)
188 .makePermanent()
189 .withPriority(nextObjective.priority())
190 .forDevice(deviceId)
191 .fromApp(nextObjective.appId())
192 .build());
Yi Tseng0b809722017-11-03 10:23:26 -0700193 }
194
195 private TrafficSelector buildNextIdSelector(int nextId) {
Yi Tseng1b154bd2017-11-20 17:48:19 -0800196 PiCriterion nextIdCriterion = PiCriterion.builder()
197 .matchExact(HF_FABRIC_METADATA_NEXT_ID_ID, nextId)
Yi Tseng0b809722017-11-03 10:23:26 -0700198 .build();
199 return DefaultTrafficSelector.builder()
Yi Tseng1b154bd2017-11-20 17:48:19 -0800200 .matchPi(nextIdCriterion)
Yi Tseng0b809722017-11-03 10:23:26 -0700201 .build();
202 }
Yi Tseng0b809722017-11-03 10:23:26 -0700203}