blob: 20cafde5145d54b44682c341aee0dd11830268a1 [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.ImmutableList;
Yi Tseng0b809722017-11-03 10:23:26 -070020import org.onlab.util.KryoNamespace;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080021import org.onlab.util.SharedExecutors;
Yi Tseng0b809722017-11-03 10:23:26 -070022import org.onosproject.net.DeviceId;
23import org.onosproject.net.PortNumber;
24import org.onosproject.net.behaviour.NextGroup;
25import org.onosproject.net.behaviour.Pipeliner;
26import org.onosproject.net.behaviour.PipelinerContext;
Yi Tseng0b809722017-11-03 10:23:26 -070027import org.onosproject.net.flow.FlowRule;
28import org.onosproject.net.flow.FlowRuleOperations;
Yi Tseng0b809722017-11-03 10:23:26 -070029import org.onosproject.net.flow.FlowRuleService;
Yi Tseng0b809722017-11-03 10:23:26 -070030import org.onosproject.net.flowobjective.FilteringObjective;
31import org.onosproject.net.flowobjective.FlowObjectiveStore;
32import org.onosproject.net.flowobjective.ForwardingObjective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080033import org.onosproject.net.flowobjective.IdNextTreatment;
Yi Tseng0b809722017-11-03 10:23:26 -070034import org.onosproject.net.flowobjective.NextObjective;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080035import org.onosproject.net.flowobjective.NextTreatment;
Yi Tseng0b809722017-11-03 10:23:26 -070036import org.onosproject.net.flowobjective.Objective;
37import org.onosproject.net.flowobjective.ObjectiveError;
38import org.onosproject.net.group.GroupDescription;
Yi Tseng0b809722017-11-03 10:23:26 -070039import org.onosproject.net.group.GroupService;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080040import org.onosproject.pipelines.fabric.AbstractFabricHandlerBehavior;
Daniele Morof51d0c12019-07-30 10:43:10 -070041import org.onosproject.pipelines.fabric.FabricCapabilities;
Yi Tseng0b809722017-11-03 10:23:26 -070042import org.onosproject.store.serializers.KryoNamespaces;
43import org.slf4j.Logger;
44
45import java.util.Collection;
46import java.util.List;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080047import java.util.Objects;
Yi Tsengfe13f3e2018-08-19 03:09:54 +080048import java.util.concurrent.CompletableFuture;
Yi Tsengfe13f3e2018-08-19 03:09:54 +080049import java.util.concurrent.ExecutorService;
Yi Tseng1b154bd2017-11-20 17:48:19 -080050import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070051
Carmelo Casconeb5324e72018-11-25 02:26:32 -080052import static java.lang.String.format;
53import static org.onosproject.pipelines.fabric.FabricUtils.outputPort;
Yi Tseng0b809722017-11-03 10:23:26 -070054import static org.slf4j.LoggerFactory.getLogger;
55
56/**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080057 * Pipeliner implementation for fabric pipeline which uses ObjectiveTranslator
58 * implementations to translate flow objectives for the different blocks,
59 * filtering, forwarding and next.
Yi Tseng0b809722017-11-03 10:23:26 -070060 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080061public class FabricPipeliner extends AbstractFabricHandlerBehavior
62 implements Pipeliner {
63
Yi Tseng0b809722017-11-03 10:23:26 -070064 private static final Logger log = getLogger(FabricPipeliner.class);
65
66 protected static final KryoNamespace KRYO = new KryoNamespace.Builder()
67 .register(KryoNamespaces.API)
68 .register(FabricNextGroup.class)
69 .build("FabricPipeliner");
70
Yi Tseng0b809722017-11-03 10:23:26 -070071 protected DeviceId deviceId;
72 protected FlowRuleService flowRuleService;
73 protected GroupService groupService;
74 protected FlowObjectiveStore flowObjectiveStore;
Yi Tseng0b809722017-11-03 10:23:26 -070075
Carmelo Casconeb5324e72018-11-25 02:26:32 -080076 private FilteringObjectiveTranslator filteringTranslator;
77 private ForwardingObjectiveTranslator forwardingTranslator;
78 private NextObjectiveTranslator nextTranslator;
Charles Chan91ea9722018-08-30 15:56:32 -070079
Carmelo Casconeb5324e72018-11-25 02:26:32 -080080 private final ExecutorService callbackExecutor = SharedExecutors.getPoolThreadExecutor();
Yi Tseng0b809722017-11-03 10:23:26 -070081
Daniele Morof51d0c12019-07-30 10:43:10 -070082 /**
83 * Creates a new instance of this behavior with the given capabilities.
84 *
85 * @param capabilities capabilities
86 */
87 public FabricPipeliner(FabricCapabilities capabilities) {
88 super(capabilities);
89 }
90
91 /**
92 * Create a new instance of this behaviour. Used by the abstract projectable
93 * model (i.e., {@link org.onosproject.net.Device#as(Class)}.
94 */
95 public FabricPipeliner() {
96 super();
97 }
98
Yi Tseng0b809722017-11-03 10:23:26 -070099 @Override
100 public void init(DeviceId deviceId, PipelinerContext context) {
101 this.deviceId = deviceId;
102 this.flowRuleService = context.directory().get(FlowRuleService.class);
103 this.groupService = context.directory().get(GroupService.class);
104 this.flowObjectiveStore = context.directory().get(FlowObjectiveStore.class);
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800105 this.filteringTranslator = new FilteringObjectiveTranslator(deviceId, capabilities);
106 this.forwardingTranslator = new ForwardingObjectiveTranslator(deviceId, capabilities);
107 this.nextTranslator = new NextObjectiveTranslator(deviceId, capabilities);
Yi Tseng0b809722017-11-03 10:23:26 -0700108 }
109
110 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800111 public void filter(FilteringObjective obj) {
112 final ObjectiveTranslation result = filteringTranslator.translate(obj);
113 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -0700114 }
115
116 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800117 public void forward(ForwardingObjective obj) {
118 final ObjectiveTranslation result = forwardingTranslator.translate(obj);
119 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -0700120 }
121
122 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800123 public void next(NextObjective obj) {
124 if (obj.op() == Objective.Operation.VERIFY) {
Yi Tseng1b154bd2017-11-20 17:48:19 -0800125 // TODO: support VERIFY operation
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800126 log.debug("VERIFY operation not yet supported for NextObjective, will return success");
127 success(obj);
Yi Tseng1b154bd2017-11-20 17:48:19 -0800128 return;
129 }
130
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800131 if (obj.op() == Objective.Operation.MODIFY) {
Charles Chan91ea9722018-08-30 15:56:32 -0700132 // TODO: support MODIFY operation
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800133 log.warn("MODIFY operation not yet supported for NextObjective, will return failure :(");
134 fail(obj, ObjectiveError.UNSUPPORTED);
Charles Chan91ea9722018-08-30 15:56:32 -0700135 return;
136 }
137
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800138 final ObjectiveTranslation result = nextTranslator.translate(obj);
139 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -0700140 }
141
142 @Override
143 public List<String> getNextMappings(NextGroup nextGroup) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800144 final FabricNextGroup fabricNextGroup = KRYO.deserialize(nextGroup.data());
145 return fabricNextGroup.nextMappings().stream()
146 .map(m -> format("%s -> %s", fabricNextGroup.type(), m))
Yi Tseng1b154bd2017-11-20 17:48:19 -0800147 .collect(Collectors.toList());
Yi Tseng0b809722017-11-03 10:23:26 -0700148 }
149
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800150 private void handleResult(Objective obj, ObjectiveTranslation result) {
151 if (result.error().isPresent()) {
152 fail(obj, result.error().get());
153 return;
154 }
155 processGroups(obj, result.groups());
156 processFlows(obj, result.flowRules());
157 if (obj instanceof NextObjective) {
158 handleNextGroup((NextObjective) obj);
159 }
160 success(obj);
Yi Tseng0b809722017-11-03 10:23:26 -0700161 }
162
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800163 private void handleNextGroup(NextObjective obj) {
164 switch (obj.op()) {
165 case REMOVE:
166 removeNextGroup(obj);
167 break;
168 case ADD:
169 case ADD_TO_EXISTING:
170 case REMOVE_FROM_EXISTING:
171 case MODIFY:
172 putNextGroup(obj);
173 break;
174 case VERIFY:
175 break;
176 default:
177 log.error("Unknown NextObjective operation '{}'", obj.op());
178 }
179 }
180
181 private void processFlows(Objective objective, Collection<FlowRule> flowRules) {
Yi Tseng0b809722017-11-03 10:23:26 -0700182 if (flowRules.isEmpty()) {
Yi Tsengf78e1742018-04-08 19:57:17 +0800183 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700184 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800185 final FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
186 switch (objective.op()) {
187 case ADD:
188 case ADD_TO_EXISTING:
189 flowRules.forEach(ops::add);
190 break;
191 case REMOVE:
192 case REMOVE_FROM_EXISTING:
193 flowRules.forEach(ops::remove);
194 break;
195 default:
196 log.warn("Unsupported Objective operation '{}'", objective.op());
197 return;
wu914ed232018-10-23 11:19:53 +0800198 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800199 flowRuleService.apply(ops.build());
Yi Tseng0b809722017-11-03 10:23:26 -0700200 }
201
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800202 private void processGroups(Objective objective, Collection<GroupDescription> groups) {
Yi Tseng0b809722017-11-03 10:23:26 -0700203 if (groups.isEmpty()) {
Yi Tsengf78e1742018-04-08 19:57:17 +0800204 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700205 }
Yi Tseng0b809722017-11-03 10:23:26 -0700206 switch (objective.op()) {
207 case ADD:
208 groups.forEach(groupService::addGroup);
209 break;
210 case REMOVE:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800211 groups.forEach(group -> groupService.removeGroup(
212 deviceId, group.appCookie(), objective.appId()));
Yi Tseng0b809722017-11-03 10:23:26 -0700213 break;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800214 case ADD_TO_EXISTING:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800215 groups.forEach(group -> groupService.addBucketsToGroup(
216 deviceId, group.appCookie(), group.buckets(),
217 group.appCookie(), group.appId())
Charles Chan91ea9722018-08-30 15:56:32 -0700218 );
Yi Tseng1b154bd2017-11-20 17:48:19 -0800219 break;
220 case REMOVE_FROM_EXISTING:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800221 groups.forEach(group -> groupService.removeBucketsFromGroup(
222 deviceId, group.appCookie(), group.buckets(),
223 group.appCookie(), group.appId())
Charles Chan91ea9722018-08-30 15:56:32 -0700224 );
Yi Tseng1b154bd2017-11-20 17:48:19 -0800225 break;
Yi Tseng0b809722017-11-03 10:23:26 -0700226 default:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800227 log.warn("Unsupported Objective operation {}", objective.op());
Yi Tseng0b809722017-11-03 10:23:26 -0700228 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800229 }
Yi Tseng0b809722017-11-03 10:23:26 -0700230
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800231 private void fail(Objective objective, ObjectiveError error) {
232 CompletableFuture.runAsync(
233 () -> objective.context().ifPresent(
234 ctx -> ctx.onError(objective, error)), callbackExecutor);
Yi Tsengfe13f3e2018-08-19 03:09:54 +0800235
Yi Tseng0b809722017-11-03 10:23:26 -0700236 }
237
Charles Chan91ea9722018-08-30 15:56:32 -0700238
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800239 private void success(Objective objective) {
240 CompletableFuture.runAsync(
241 () -> objective.context().ifPresent(
242 ctx -> ctx.onSuccess(objective)), callbackExecutor);
Yi Tseng0b809722017-11-03 10:23:26 -0700243 }
244
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800245 private void removeNextGroup(NextObjective obj) {
246 final NextGroup removed = flowObjectiveStore.removeNextGroup(obj.id());
247 if (removed == null) {
248 log.debug("NextGroup {} was not found in FlowObjectiveStore");
249 }
Charles Chan91ea9722018-08-30 15:56:32 -0700250 }
251
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800252 private void putNextGroup(NextObjective obj) {
253 final List<String> nextMappings = obj.nextTreatments().stream()
254 .map(this::nextTreatmentToMappingString)
255 .filter(Objects::nonNull)
256 .collect(Collectors.toList());
257 final FabricNextGroup nextGroup = new FabricNextGroup(obj.type(), nextMappings);
258 flowObjectiveStore.putNextGroup(obj.id(), nextGroup);
259 }
260
261 private String nextTreatmentToMappingString(NextTreatment n) {
262 switch (n.type()) {
263 case TREATMENT:
264 final PortNumber p = outputPort(n);
265 return p == null ? "UNKNOWN"
266 : format("OUTPUT:%s", p.toString());
267 case ID:
268 final IdNextTreatment id = (IdNextTreatment) n;
269 return format("NEXT_ID:%d", id.nextId());
Yi Tseng0b809722017-11-03 10:23:26 -0700270 default:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800271 log.warn("Unknown NextTreatment type '{}'", n.type());
272 return "???";
Yi Tseng0b809722017-11-03 10:23:26 -0700273 }
Yi Tseng0b809722017-11-03 10:23:26 -0700274 }
275
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800276 /**
277 * NextGroup implementation.
278 */
279 private static class FabricNextGroup implements NextGroup {
Yi Tseng0b809722017-11-03 10:23:26 -0700280
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800281 private final NextObjective.Type type;
282 private final List<String> nextMappings;
283
284 FabricNextGroup(NextObjective.Type type, List<String> nextMappings) {
Yi Tseng0b809722017-11-03 10:23:26 -0700285 this.type = type;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800286 this.nextMappings = ImmutableList.copyOf(nextMappings);
Yi Tseng0b809722017-11-03 10:23:26 -0700287 }
288
Charles Chan91ea9722018-08-30 15:56:32 -0700289 NextObjective.Type type() {
Yi Tseng0b809722017-11-03 10:23:26 -0700290 return type;
291 }
292
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800293 Collection<String> nextMappings() {
294 return nextMappings;
Yi Tseng0b809722017-11-03 10:23:26 -0700295 }
296
297 @Override
298 public byte[] data() {
299 return KRYO.serialize(this);
300 }
301 }
Yi Tseng0b809722017-11-03 10:23:26 -0700302}