blob: 4bf1bb5d20229e710ea1bd87b2485443b27633ff [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;
Yi Tseng0b809722017-11-03 10:23:26 -070041import org.onosproject.store.serializers.KryoNamespaces;
42import org.slf4j.Logger;
43
44import java.util.Collection;
45import java.util.List;
Carmelo Casconeb5324e72018-11-25 02:26:32 -080046import java.util.Objects;
Yi Tsengfe13f3e2018-08-19 03:09:54 +080047import java.util.concurrent.CompletableFuture;
Yi Tsengfe13f3e2018-08-19 03:09:54 +080048import java.util.concurrent.ExecutorService;
Yi Tseng1b154bd2017-11-20 17:48:19 -080049import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070050
Carmelo Casconeb5324e72018-11-25 02:26:32 -080051import static java.lang.String.format;
52import static org.onosproject.pipelines.fabric.FabricUtils.outputPort;
Yi Tseng0b809722017-11-03 10:23:26 -070053import static org.slf4j.LoggerFactory.getLogger;
54
55/**
Carmelo Casconeb5324e72018-11-25 02:26:32 -080056 * Pipeliner implementation for fabric pipeline which uses ObjectiveTranslator
57 * implementations to translate flow objectives for the different blocks,
58 * filtering, forwarding and next.
Yi Tseng0b809722017-11-03 10:23:26 -070059 */
Carmelo Casconeb5324e72018-11-25 02:26:32 -080060public class FabricPipeliner extends AbstractFabricHandlerBehavior
61 implements Pipeliner {
62
Yi Tseng0b809722017-11-03 10:23:26 -070063 private static final Logger log = getLogger(FabricPipeliner.class);
64
65 protected static final KryoNamespace KRYO = new KryoNamespace.Builder()
66 .register(KryoNamespaces.API)
67 .register(FabricNextGroup.class)
68 .build("FabricPipeliner");
69
Yi Tseng0b809722017-11-03 10:23:26 -070070 protected DeviceId deviceId;
71 protected FlowRuleService flowRuleService;
72 protected GroupService groupService;
73 protected FlowObjectiveStore flowObjectiveStore;
Yi Tseng0b809722017-11-03 10:23:26 -070074
Carmelo Casconeb5324e72018-11-25 02:26:32 -080075 private FilteringObjectiveTranslator filteringTranslator;
76 private ForwardingObjectiveTranslator forwardingTranslator;
77 private NextObjectiveTranslator nextTranslator;
Charles Chan91ea9722018-08-30 15:56:32 -070078
Carmelo Casconeb5324e72018-11-25 02:26:32 -080079 private final ExecutorService callbackExecutor = SharedExecutors.getPoolThreadExecutor();
Yi Tseng0b809722017-11-03 10:23:26 -070080
81 @Override
82 public void init(DeviceId deviceId, PipelinerContext context) {
83 this.deviceId = deviceId;
84 this.flowRuleService = context.directory().get(FlowRuleService.class);
85 this.groupService = context.directory().get(GroupService.class);
86 this.flowObjectiveStore = context.directory().get(FlowObjectiveStore.class);
Carmelo Casconeb5324e72018-11-25 02:26:32 -080087 this.filteringTranslator = new FilteringObjectiveTranslator(deviceId, capabilities);
88 this.forwardingTranslator = new ForwardingObjectiveTranslator(deviceId, capabilities);
89 this.nextTranslator = new NextObjectiveTranslator(deviceId, capabilities);
Yi Tseng0b809722017-11-03 10:23:26 -070090 }
91
92 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -080093 public void filter(FilteringObjective obj) {
94 final ObjectiveTranslation result = filteringTranslator.translate(obj);
95 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -070096 }
97
98 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -080099 public void forward(ForwardingObjective obj) {
100 final ObjectiveTranslation result = forwardingTranslator.translate(obj);
101 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -0700102 }
103
104 @Override
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800105 public void next(NextObjective obj) {
106 if (obj.op() == Objective.Operation.VERIFY) {
Yi Tseng1b154bd2017-11-20 17:48:19 -0800107 // TODO: support VERIFY operation
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800108 log.debug("VERIFY operation not yet supported for NextObjective, will return success");
109 success(obj);
Yi Tseng1b154bd2017-11-20 17:48:19 -0800110 return;
111 }
112
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800113 if (obj.op() == Objective.Operation.MODIFY) {
Charles Chan91ea9722018-08-30 15:56:32 -0700114 // TODO: support MODIFY operation
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800115 log.warn("MODIFY operation not yet supported for NextObjective, will return failure :(");
116 fail(obj, ObjectiveError.UNSUPPORTED);
Charles Chan91ea9722018-08-30 15:56:32 -0700117 return;
118 }
119
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800120 final ObjectiveTranslation result = nextTranslator.translate(obj);
121 handleResult(obj, result);
Yi Tseng0b809722017-11-03 10:23:26 -0700122 }
123
124 @Override
125 public List<String> getNextMappings(NextGroup nextGroup) {
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800126 final FabricNextGroup fabricNextGroup = KRYO.deserialize(nextGroup.data());
127 return fabricNextGroup.nextMappings().stream()
128 .map(m -> format("%s -> %s", fabricNextGroup.type(), m))
Yi Tseng1b154bd2017-11-20 17:48:19 -0800129 .collect(Collectors.toList());
Yi Tseng0b809722017-11-03 10:23:26 -0700130 }
131
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800132 private void handleResult(Objective obj, ObjectiveTranslation result) {
133 if (result.error().isPresent()) {
134 fail(obj, result.error().get());
135 return;
136 }
137 processGroups(obj, result.groups());
138 processFlows(obj, result.flowRules());
139 if (obj instanceof NextObjective) {
140 handleNextGroup((NextObjective) obj);
141 }
142 success(obj);
Yi Tseng0b809722017-11-03 10:23:26 -0700143 }
144
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800145 private void handleNextGroup(NextObjective obj) {
146 switch (obj.op()) {
147 case REMOVE:
148 removeNextGroup(obj);
149 break;
150 case ADD:
151 case ADD_TO_EXISTING:
152 case REMOVE_FROM_EXISTING:
153 case MODIFY:
154 putNextGroup(obj);
155 break;
156 case VERIFY:
157 break;
158 default:
159 log.error("Unknown NextObjective operation '{}'", obj.op());
160 }
161 }
162
163 private void processFlows(Objective objective, Collection<FlowRule> flowRules) {
Yi Tseng0b809722017-11-03 10:23:26 -0700164 if (flowRules.isEmpty()) {
Yi Tsengf78e1742018-04-08 19:57:17 +0800165 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700166 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800167 final FlowRuleOperations.Builder ops = FlowRuleOperations.builder();
168 switch (objective.op()) {
169 case ADD:
170 case ADD_TO_EXISTING:
171 flowRules.forEach(ops::add);
172 break;
173 case REMOVE:
174 case REMOVE_FROM_EXISTING:
175 flowRules.forEach(ops::remove);
176 break;
177 default:
178 log.warn("Unsupported Objective operation '{}'", objective.op());
179 return;
wu914ed232018-10-23 11:19:53 +0800180 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800181 flowRuleService.apply(ops.build());
Yi Tseng0b809722017-11-03 10:23:26 -0700182 }
183
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800184 private void processGroups(Objective objective, Collection<GroupDescription> groups) {
Yi Tseng0b809722017-11-03 10:23:26 -0700185 if (groups.isEmpty()) {
Yi Tsengf78e1742018-04-08 19:57:17 +0800186 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700187 }
Yi Tseng0b809722017-11-03 10:23:26 -0700188 switch (objective.op()) {
189 case ADD:
190 groups.forEach(groupService::addGroup);
191 break;
192 case REMOVE:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800193 groups.forEach(group -> groupService.removeGroup(
194 deviceId, group.appCookie(), objective.appId()));
Yi Tseng0b809722017-11-03 10:23:26 -0700195 break;
Yi Tseng1b154bd2017-11-20 17:48:19 -0800196 case ADD_TO_EXISTING:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800197 groups.forEach(group -> groupService.addBucketsToGroup(
198 deviceId, group.appCookie(), group.buckets(),
199 group.appCookie(), group.appId())
Charles Chan91ea9722018-08-30 15:56:32 -0700200 );
Yi Tseng1b154bd2017-11-20 17:48:19 -0800201 break;
202 case REMOVE_FROM_EXISTING:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800203 groups.forEach(group -> groupService.removeBucketsFromGroup(
204 deviceId, group.appCookie(), group.buckets(),
205 group.appCookie(), group.appId())
Charles Chan91ea9722018-08-30 15:56:32 -0700206 );
Yi Tseng1b154bd2017-11-20 17:48:19 -0800207 break;
Yi Tseng0b809722017-11-03 10:23:26 -0700208 default:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800209 log.warn("Unsupported Objective operation {}", objective.op());
Yi Tseng0b809722017-11-03 10:23:26 -0700210 }
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800211 }
Yi Tseng0b809722017-11-03 10:23:26 -0700212
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800213 private void fail(Objective objective, ObjectiveError error) {
214 CompletableFuture.runAsync(
215 () -> objective.context().ifPresent(
216 ctx -> ctx.onError(objective, error)), callbackExecutor);
Yi Tsengfe13f3e2018-08-19 03:09:54 +0800217
Yi Tseng0b809722017-11-03 10:23:26 -0700218 }
219
Charles Chan91ea9722018-08-30 15:56:32 -0700220
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800221 private void success(Objective objective) {
222 CompletableFuture.runAsync(
223 () -> objective.context().ifPresent(
224 ctx -> ctx.onSuccess(objective)), callbackExecutor);
Yi Tseng0b809722017-11-03 10:23:26 -0700225 }
226
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800227 private void removeNextGroup(NextObjective obj) {
228 final NextGroup removed = flowObjectiveStore.removeNextGroup(obj.id());
229 if (removed == null) {
230 log.debug("NextGroup {} was not found in FlowObjectiveStore");
231 }
Charles Chan91ea9722018-08-30 15:56:32 -0700232 }
233
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800234 private void putNextGroup(NextObjective obj) {
235 final List<String> nextMappings = obj.nextTreatments().stream()
236 .map(this::nextTreatmentToMappingString)
237 .filter(Objects::nonNull)
238 .collect(Collectors.toList());
239 final FabricNextGroup nextGroup = new FabricNextGroup(obj.type(), nextMappings);
240 flowObjectiveStore.putNextGroup(obj.id(), nextGroup);
241 }
242
243 private String nextTreatmentToMappingString(NextTreatment n) {
244 switch (n.type()) {
245 case TREATMENT:
246 final PortNumber p = outputPort(n);
247 return p == null ? "UNKNOWN"
248 : format("OUTPUT:%s", p.toString());
249 case ID:
250 final IdNextTreatment id = (IdNextTreatment) n;
251 return format("NEXT_ID:%d", id.nextId());
Yi Tseng0b809722017-11-03 10:23:26 -0700252 default:
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800253 log.warn("Unknown NextTreatment type '{}'", n.type());
254 return "???";
Yi Tseng0b809722017-11-03 10:23:26 -0700255 }
Yi Tseng0b809722017-11-03 10:23:26 -0700256 }
257
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800258 /**
259 * NextGroup implementation.
260 */
261 private static class FabricNextGroup implements NextGroup {
Yi Tseng0b809722017-11-03 10:23:26 -0700262
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800263 private final NextObjective.Type type;
264 private final List<String> nextMappings;
265
266 FabricNextGroup(NextObjective.Type type, List<String> nextMappings) {
Yi Tseng0b809722017-11-03 10:23:26 -0700267 this.type = type;
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800268 this.nextMappings = ImmutableList.copyOf(nextMappings);
Yi Tseng0b809722017-11-03 10:23:26 -0700269 }
270
Charles Chan91ea9722018-08-30 15:56:32 -0700271 NextObjective.Type type() {
Yi Tseng0b809722017-11-03 10:23:26 -0700272 return type;
273 }
274
Carmelo Casconeb5324e72018-11-25 02:26:32 -0800275 Collection<String> nextMappings() {
276 return nextMappings;
Yi Tseng0b809722017-11-03 10:23:26 -0700277 }
278
279 @Override
280 public byte[] data() {
281 return KRYO.serialize(this);
282 }
283 }
Yi Tseng0b809722017-11-03 10:23:26 -0700284}