blob: 324a4f529d9425b8f27bcfcea54e91925021521f [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
19import com.google.common.collect.ImmutableMap;
Yi Tseng0b809722017-11-03 10:23:26 -070020import org.onosproject.net.DeviceId;
21import 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;
29import org.onosproject.net.flowobjective.NextObjective;
30import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng1b154bd2017-11-20 17:48:19 -080031import org.onosproject.net.group.DefaultGroupBucket;
32import org.onosproject.net.group.DefaultGroupDescription;
33import org.onosproject.net.group.GroupBucket;
34import org.onosproject.net.group.GroupBuckets;
35import org.onosproject.net.group.GroupDescription;
Yi Tseng0b809722017-11-03 10:23:26 -070036import org.onosproject.net.pi.runtime.PiAction;
Yi Tseng1b154bd2017-11-20 17:48:19 -080037import org.onosproject.net.pi.runtime.PiActionGroupId;
Yi Tseng0b809722017-11-03 10:23:26 -070038import org.onosproject.net.pi.runtime.PiActionParam;
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 Tseng0b809722017-11-03 10:23:26 -070043import java.util.Map;
Yi Tseng1b154bd2017-11-20 17:48:19 -080044import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070045
Yi Tseng1b154bd2017-11-20 17:48:19 -080046import static org.onlab.util.ImmutableByteSequence.copyFrom;
47import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRF_ECMP_SELECTOR_ID;
48import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRM_NEXT_TYPE_ID;
49import static org.onosproject.pipelines.fabric.FabricConstants.ACT_SET_NEXT_TYPE_ID;
50import static org.onosproject.pipelines.fabric.FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID;
51import static org.onosproject.pipelines.fabric.FabricConstants.TBL_HASHED_ID;
52import static org.onosproject.pipelines.fabric.FabricConstants.TBL_NEXT_ID_MAPPING_ID;
53import static org.onosproject.pipelines.fabric.FabricConstants.TBL_SIMPLE_ID;
Yi Tseng0b809722017-11-03 10:23:26 -070054import static org.slf4j.LoggerFactory.getLogger;
55
56/**
57 * Handling next objective for fabric pipeliner.
58 */
59public class FabricNextPipeliner {
60 private static final Logger log = getLogger(FabricNextPipeliner.class);
61
62 // Next types
Yi Tseng1b154bd2017-11-20 17:48:19 -080063 private static final byte NXT_TYPE_SIMPLE = 0;
64 private static final byte NXT_TYPE_HASHED = 1;
65 private static final byte NXT_TYPE_BROADCAST = 2;
66 private static final byte NXT_TYPE_PUNT = 3;
Yi Tseng0b809722017-11-03 10:23:26 -070067 private static final Map<NextObjective.Type, Byte> NEXT_TYPE_MAP =
68 ImmutableMap.<NextObjective.Type, Byte>builder()
Yi Tseng1b154bd2017-11-20 17:48:19 -080069 .put(NextObjective.Type.SIMPLE, NXT_TYPE_SIMPLE)
70 .put(NextObjective.Type.HASHED, NXT_TYPE_HASHED)
71 .put(NextObjective.Type.BROADCAST, NXT_TYPE_BROADCAST)
Yi Tseng0b809722017-11-03 10:23:26 -070072 .build();
73
74 protected DeviceId deviceId;
75
76 public FabricNextPipeliner(DeviceId deviceId) {
77 this.deviceId = deviceId;
78 }
79
80 public PipelinerTranslationResult next(NextObjective nextObjective) {
81 PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
Yi Tseng1b154bd2017-11-20 17:48:19 -080082 processNextIdMapping(nextObjective, resultBuilder);
83
Yi Tseng0b809722017-11-03 10:23:26 -070084 switch (nextObjective.type()) {
85 case SIMPLE:
Yi Tseng1b154bd2017-11-20 17:48:19 -080086 processSimpleNext(nextObjective, resultBuilder);
87 break;
88 case HASHED:
89 processHashedNext(nextObjective, resultBuilder);
Yi Tseng0b809722017-11-03 10:23:26 -070090 break;
91 default:
92 log.warn("Unsupported next type {}", nextObjective);
93 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
94 break;
95 }
96
Yi Tseng0b809722017-11-03 10:23:26 -070097 return resultBuilder.build();
98 }
99
Yi Tseng1b154bd2017-11-20 17:48:19 -0800100 private void processNextIdMapping(NextObjective next,
101 PipelinerTranslationResult.Builder resultBuilder) {
Yi Tseng0b809722017-11-03 10:23:26 -0700102 // program the next id mapping table
103 TrafficSelector nextIdSelector = buildNextIdSelector(next.id());
104 TrafficTreatment setNextTypeTreatment = buildSetNextTypeTreatment(next.type());
105
Yi Tseng1b154bd2017-11-20 17:48:19 -0800106 resultBuilder.addFlowRule(DefaultFlowRule.builder()
107 .withSelector(nextIdSelector)
108 .withTreatment(setNextTypeTreatment)
109 .forDevice(deviceId)
110 .forTable(TBL_NEXT_ID_MAPPING_ID)
111 .makePermanent()
112 .withPriority(next.priority())
113 .fromApp(next.appId())
114 .build());
Yi Tseng0b809722017-11-03 10:23:26 -0700115 }
116
Yi Tseng1b154bd2017-11-20 17:48:19 -0800117 private void processSimpleNext(NextObjective next,
118 PipelinerTranslationResult.Builder resultBuilder) {
119
Yi Tseng0b809722017-11-03 10:23:26 -0700120 if (next.next().size() > 1) {
121 log.warn("Only one treatment in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -0800122 resultBuilder.setError(ObjectiveError.BADPARAMS);
123 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700124 }
125
126 TrafficSelector selector = buildNextIdSelector(next.id());
127 TrafficTreatment treatment = next.next().iterator().next();
128 OutputInstruction outputInst = treatment.allInstructions()
129 .stream()
130 .filter(inst -> inst.type() == Instruction.Type.OUTPUT)
131 .map(inst -> (OutputInstruction) inst)
132 .findFirst()
133 .orElse(null);
134
135 if (outputInst == null) {
136 log.warn("At least one output instruction in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -0800137 resultBuilder.setError(ObjectiveError.BADPARAMS);
138 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700139 }
Yi Tseng1b154bd2017-11-20 17:48:19 -0800140 resultBuilder.addFlowRule(DefaultFlowRule.builder()
141 .withSelector(selector)
142 .withTreatment(treatment)
143 .forTable(TBL_SIMPLE_ID)
144 .makePermanent()
145 .withPriority(next.priority())
146 .forDevice(deviceId)
147 .fromApp(next.appId())
148 .build());
149 }
150
151 private void processHashedNext(NextObjective nextObjective, PipelinerTranslationResult.Builder resultBuilder) {
152 // create hash groups
153 int groupId = nextObjective.id();
154 List<GroupBucket> bucketList = nextObjective.next().stream()
155 .map(DefaultGroupBucket::createSelectGroupBucket)
156 .collect(Collectors.toList());
157
158 if (bucketList.size() != nextObjective.next().size()) {
159 // some action not converted
160 // set error
161 log.warn("Expected bucket size {}, got {}", nextObjective.next().size(), bucketList.size());
162 resultBuilder.setError(ObjectiveError.BADPARAMS);
163 return;
164 }
165
166 GroupBuckets buckets = new GroupBuckets(bucketList);
167 PiGroupKey groupKey = new PiGroupKey(TBL_HASHED_ID,
168 ACT_PRF_ECMP_SELECTOR_ID,
169 groupId);
170
171 resultBuilder.addGroup(new DefaultGroupDescription(deviceId,
172 GroupDescription.Type.SELECT,
173 buckets,
174 groupKey,
175 groupId,
176 nextObjective.appId()));
177
178 // flow
179 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 }
203
204 private TrafficTreatment buildSetNextTypeTreatment(NextObjective.Type nextType) {
Yi Tseng1b154bd2017-11-20 17:48:19 -0800205 byte nextTypeVal = NEXT_TYPE_MAP.getOrDefault(nextType, NXT_TYPE_PUNT);
206 PiActionParam nextTypeParam = new PiActionParam(ACT_PRM_NEXT_TYPE_ID,
207 copyFrom(nextTypeVal));
Yi Tseng0b809722017-11-03 10:23:26 -0700208 PiAction nextTypeAction = PiAction.builder()
Yi Tseng1b154bd2017-11-20 17:48:19 -0800209 .withId(ACT_SET_NEXT_TYPE_ID)
Yi Tseng0b809722017-11-03 10:23:26 -0700210 .withParameter(nextTypeParam)
211 .build();
212 return DefaultTrafficTreatment.builder()
213 .piTableAction(nextTypeAction)
214 .build();
215 }
216}