blob: 91772371b8567c966a63e5bd113b49724a4d85b9 [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;
20import org.onosproject.net.flow.DefaultFlowRule;
21import org.onosproject.net.flow.DefaultTrafficSelector;
22import org.onosproject.net.flow.DefaultTrafficTreatment;
Yi Tseng0b809722017-11-03 10:23:26 -070023import org.onosproject.net.flow.TrafficSelector;
24import org.onosproject.net.flow.TrafficTreatment;
25import org.onosproject.net.flow.criteria.PiCriterion;
26import org.onosproject.net.flow.instructions.Instruction;
27import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
28import org.onosproject.net.flowobjective.NextObjective;
29import org.onosproject.net.flowobjective.ObjectiveError;
Yi Tseng1b154bd2017-11-20 17:48:19 -080030import org.onosproject.net.group.DefaultGroupBucket;
31import org.onosproject.net.group.DefaultGroupDescription;
32import org.onosproject.net.group.GroupBucket;
33import org.onosproject.net.group.GroupBuckets;
34import org.onosproject.net.group.GroupDescription;
Yi Tseng1b154bd2017-11-20 17:48:19 -080035import org.onosproject.net.pi.runtime.PiActionGroupId;
Yi Tseng1b154bd2017-11-20 17:48:19 -080036import org.onosproject.net.pi.runtime.PiGroupKey;
Yi Tseng0b809722017-11-03 10:23:26 -070037import org.slf4j.Logger;
38
Yi Tseng1b154bd2017-11-20 17:48:19 -080039import java.util.List;
Yi Tseng1b154bd2017-11-20 17:48:19 -080040import java.util.stream.Collectors;
Yi Tseng0b809722017-11-03 10:23:26 -070041
Yi Tsengf55eaa82017-11-29 15:51:28 -080042import static org.onosproject.pipelines.fabric.FabricConstants.ACT_PRF_NEXT_ECMP_SELECTOR_ID;
Yi Tseng1b154bd2017-11-20 17:48:19 -080043import static org.onosproject.pipelines.fabric.FabricConstants.HF_FABRIC_METADATA_NEXT_ID_ID;
44import static org.onosproject.pipelines.fabric.FabricConstants.TBL_HASHED_ID;
Yi Tseng1b154bd2017-11-20 17:48:19 -080045import static org.onosproject.pipelines.fabric.FabricConstants.TBL_SIMPLE_ID;
Yi Tseng0b809722017-11-03 10:23:26 -070046import static org.slf4j.LoggerFactory.getLogger;
47
48/**
49 * Handling next objective for fabric pipeliner.
50 */
51public class FabricNextPipeliner {
52 private static final Logger log = getLogger(FabricNextPipeliner.class);
53
Yi Tseng0b809722017-11-03 10:23:26 -070054 protected DeviceId deviceId;
55
56 public FabricNextPipeliner(DeviceId deviceId) {
57 this.deviceId = deviceId;
58 }
59
60 public PipelinerTranslationResult next(NextObjective nextObjective) {
61 PipelinerTranslationResult.Builder resultBuilder = PipelinerTranslationResult.builder();
Yi Tseng1b154bd2017-11-20 17:48:19 -080062
Yi Tseng0b809722017-11-03 10:23:26 -070063 switch (nextObjective.type()) {
64 case SIMPLE:
Yi Tseng1b154bd2017-11-20 17:48:19 -080065 processSimpleNext(nextObjective, resultBuilder);
66 break;
67 case HASHED:
68 processHashedNext(nextObjective, resultBuilder);
Yi Tseng0b809722017-11-03 10:23:26 -070069 break;
70 default:
71 log.warn("Unsupported next type {}", nextObjective);
72 resultBuilder.setError(ObjectiveError.UNSUPPORTED);
73 break;
74 }
75
Yi Tseng0b809722017-11-03 10:23:26 -070076 return resultBuilder.build();
77 }
78
Yi Tseng1b154bd2017-11-20 17:48:19 -080079 private void processSimpleNext(NextObjective next,
80 PipelinerTranslationResult.Builder resultBuilder) {
81
Yi Tseng0b809722017-11-03 10:23:26 -070082 if (next.next().size() > 1) {
83 log.warn("Only one treatment in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -080084 resultBuilder.setError(ObjectiveError.BADPARAMS);
85 return;
Yi Tseng0b809722017-11-03 10:23:26 -070086 }
87
88 TrafficSelector selector = buildNextIdSelector(next.id());
89 TrafficTreatment treatment = next.next().iterator().next();
90 OutputInstruction outputInst = treatment.allInstructions()
91 .stream()
92 .filter(inst -> inst.type() == Instruction.Type.OUTPUT)
93 .map(inst -> (OutputInstruction) inst)
94 .findFirst()
95 .orElse(null);
96
97 if (outputInst == null) {
98 log.warn("At least one output instruction in simple next objective");
Yi Tseng1b154bd2017-11-20 17:48:19 -080099 resultBuilder.setError(ObjectiveError.BADPARAMS);
100 return;
Yi Tseng0b809722017-11-03 10:23:26 -0700101 }
Yi Tseng1b154bd2017-11-20 17:48:19 -0800102 resultBuilder.addFlowRule(DefaultFlowRule.builder()
103 .withSelector(selector)
104 .withTreatment(treatment)
105 .forTable(TBL_SIMPLE_ID)
106 .makePermanent()
107 .withPriority(next.priority())
108 .forDevice(deviceId)
109 .fromApp(next.appId())
110 .build());
111 }
112
113 private void processHashedNext(NextObjective nextObjective, PipelinerTranslationResult.Builder resultBuilder) {
114 // create hash groups
115 int groupId = nextObjective.id();
116 List<GroupBucket> bucketList = nextObjective.next().stream()
117 .map(DefaultGroupBucket::createSelectGroupBucket)
118 .collect(Collectors.toList());
119
120 if (bucketList.size() != nextObjective.next().size()) {
121 // some action not converted
122 // set error
123 log.warn("Expected bucket size {}, got {}", nextObjective.next().size(), bucketList.size());
124 resultBuilder.setError(ObjectiveError.BADPARAMS);
125 return;
126 }
127
128 GroupBuckets buckets = new GroupBuckets(bucketList);
129 PiGroupKey groupKey = new PiGroupKey(TBL_HASHED_ID,
Yi Tsengf55eaa82017-11-29 15:51:28 -0800130 ACT_PRF_NEXT_ECMP_SELECTOR_ID,
Yi Tseng1b154bd2017-11-20 17:48:19 -0800131 groupId);
132
133 resultBuilder.addGroup(new DefaultGroupDescription(deviceId,
134 GroupDescription.Type.SELECT,
135 buckets,
136 groupKey,
137 groupId,
138 nextObjective.appId()));
139
140 // flow
141 TrafficSelector selector = buildNextIdSelector(nextObjective.id());
142 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
143 .piTableAction(PiActionGroupId.of(nextObjective.id()))
Yi Tseng0b809722017-11-03 10:23:26 -0700144 .build();
Yi Tseng1b154bd2017-11-20 17:48:19 -0800145
146 resultBuilder.addFlowRule(DefaultFlowRule.builder()
147 .withSelector(selector)
148 .withTreatment(treatment)
149 .forTable(TBL_HASHED_ID)
150 .makePermanent()
151 .withPriority(nextObjective.priority())
152 .forDevice(deviceId)
153 .fromApp(nextObjective.appId())
154 .build());
Yi Tseng0b809722017-11-03 10:23:26 -0700155 }
156
157 private TrafficSelector buildNextIdSelector(int nextId) {
Yi Tseng1b154bd2017-11-20 17:48:19 -0800158 PiCriterion nextIdCriterion = PiCriterion.builder()
159 .matchExact(HF_FABRIC_METADATA_NEXT_ID_ID, nextId)
Yi Tseng0b809722017-11-03 10:23:26 -0700160 .build();
161 return DefaultTrafficSelector.builder()
Yi Tseng1b154bd2017-11-20 17:48:19 -0800162 .matchPi(nextIdCriterion)
Yi Tseng0b809722017-11-03 10:23:26 -0700163 .build();
164 }
Yi Tseng0b809722017-11-03 10:23:26 -0700165}