blob: 44c2268e1f0bbd3c5edaa19f333df70fca3e5b70 [file] [log] [blame]
danielc8620b12015-11-30 15:50:59 +09001/*
Brian O'Connor5ab426f2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
danielc8620b12015-11-30 15:50:59 +09003 *
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 */
Hyunsun Moon21d17ba2015-12-04 16:16:25 -080016package org.onosproject.driver.pipeline;
danielc8620b12015-11-30 15:50:59 +090017
18import org.onlab.osgi.ServiceDirectory;
sanghofb3b5012016-11-10 15:47:53 +090019import org.onlab.packet.MacAddress;
danielc8620b12015-11-30 15:50:59 +090020import org.onosproject.core.ApplicationId;
21import org.onosproject.core.CoreService;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.behaviour.Pipeliner;
24import org.onosproject.net.behaviour.PipelinerContext;
25import org.onosproject.net.flow.DefaultFlowRule;
26import org.onosproject.net.flow.DefaultTrafficSelector;
27import org.onosproject.net.flow.DefaultTrafficTreatment;
28import org.onosproject.net.flow.FlowRule;
29import org.onosproject.net.flow.FlowRuleOperations;
30import org.onosproject.net.flow.FlowRuleOperationsContext;
31import org.onosproject.net.flow.FlowRuleService;
32import org.onosproject.net.flow.TrafficSelector;
33import org.onosproject.net.flow.TrafficTreatment;
34import org.onosproject.net.flow.criteria.Criterion;
sanghofb3b5012016-11-10 15:47:53 +090035import org.onosproject.net.flow.criteria.IPCriterion;
36import org.onosproject.net.flow.criteria.PortCriterion;
37import org.onosproject.net.flow.criteria.TunnelIdCriterion;
daniel parkac348902017-04-26 13:49:05 +090038import org.onosproject.net.flow.criteria.VlanIdCriterion;
sanghofb3b5012016-11-10 15:47:53 +090039import org.onosproject.net.flow.instructions.Instruction;
danielc8620b12015-11-30 15:50:59 +090040import org.onosproject.net.flowobjective.FilteringObjective;
41import org.onosproject.net.flowobjective.FlowObjectiveStore;
42import org.onosproject.net.flowobjective.ForwardingObjective;
43import org.onosproject.net.flowobjective.NextObjective;
44import org.onosproject.net.flowobjective.Objective;
45import org.onosproject.net.flowobjective.ObjectiveError;
46import org.slf4j.Logger;
47
sanghofb3b5012016-11-10 15:47:53 +090048import java.util.Optional;
danielc8620b12015-11-30 15:50:59 +090049
50import static org.slf4j.LoggerFactory.getLogger;
51
52/**
53 * Driver for OpenstackSwitching.
54 */
55public class OpenstackPipeline extends DefaultSingleTablePipeline
56 implements Pipeliner {
57
58 private final Logger log = getLogger(getClass());
danielc8620b12015-11-30 15:50:59 +090059 protected FlowObjectiveStore flowObjectiveStore;
60 protected DeviceId deviceId;
61 protected ApplicationId appId;
62 protected FlowRuleService flowRuleService;
63
Hyunsun Moon4e252f22017-02-18 02:07:49 +090064 private static final int SRC_VNI_TABLE = 0;
sangho6a9ff0d2017-03-27 11:23:37 +090065 private static final int ACL_TABLE = 1;
66 private static final int JUMP_TABLE = 2;
67 private static final int ROUTING_TABLE = 3;
68 private static final int FORWARDING_TABLE = 4;
Hyunsun Moon4e252f22017-02-18 02:07:49 +090069 private static final int DUMMY_TABLE = 10;
70 private static final int LAST_TABLE = FORWARDING_TABLE;
danielc8620b12015-11-30 15:50:59 +090071
72 private static final int DROP_PRIORITY = 0;
sanghofb3b5012016-11-10 15:47:53 +090073 private static final int HIGH_PRIORITY = 30000;
danielc8620b12015-11-30 15:50:59 +090074 private static final int TIME_OUT = 0;
sanghofb3b5012016-11-10 15:47:53 +090075 private static final String VIRTUAL_GATEWAY_MAC = "fe:00:00:00:00:02";
danielc8620b12015-11-30 15:50:59 +090076
77
78 @Override
79 public void init(DeviceId deviceId, PipelinerContext context) {
80 super.init(deviceId, context);
Hyunsun Moon4e252f22017-02-18 02:07:49 +090081 ServiceDirectory serviceDirectory = context.directory();
danielc8620b12015-11-30 15:50:59 +090082 this.deviceId = deviceId;
83
Hyunsun Moon4e252f22017-02-18 02:07:49 +090084 CoreService coreService = serviceDirectory.get(CoreService.class);
danielc8620b12015-11-30 15:50:59 +090085 flowRuleService = serviceDirectory.get(FlowRuleService.class);
86 flowObjectiveStore = context.store();
87
88 appId = coreService.registerApplication(
89 "org.onosproject.driver.OpenstackPipeline");
90
91 initializePipeline();
92 }
93
94 @Override
95 public void filter(FilteringObjective filteringObjective) {
96 super.filter(filteringObjective);
97 }
98
99 @Override
100 public void next(NextObjective nextObjective) {
101 super.next(nextObjective);
102 }
103
104 @Override
105 public void forward(ForwardingObjective forwardingObjective) {
sanghofb3b5012016-11-10 15:47:53 +0900106 FlowRule flowRule;
danielc8620b12015-11-30 15:50:59 +0900107
sanghofb3b5012016-11-10 15:47:53 +0900108 switch (forwardingObjective.flag()) {
109 case SPECIFIC:
110 flowRule = processSpecific(forwardingObjective);
danielc8620b12015-11-30 15:50:59 +0900111 break;
sanghofb3b5012016-11-10 15:47:53 +0900112 case VERSATILE:
113 flowRule = processVersatile(forwardingObjective);
danielc8620b12015-11-30 15:50:59 +0900114 break;
115 default:
116 fail(forwardingObjective, ObjectiveError.UNKNOWN);
sanghofb3b5012016-11-10 15:47:53 +0900117 log.warn("Unknown forwarding flag {}", forwardingObjective.flag());
118 return;
danielc8620b12015-11-30 15:50:59 +0900119 }
120
sanghofb3b5012016-11-10 15:47:53 +0900121 if (forwardingObjective.op().equals(Objective.Operation.ADD)) {
122 applyRules(true, flowRule);
123 } else {
124 applyRules(false, flowRule);
125 }
danielc8620b12015-11-30 15:50:59 +0900126
danielc8620b12015-11-30 15:50:59 +0900127 }
128
129 private void initializePipeline() {
sangho6a9ff0d2017-03-27 11:23:37 +0900130 connectTables(SRC_VNI_TABLE, ACL_TABLE);
131 connectTables(ACL_TABLE, JUMP_TABLE);
132 setUpTableMissEntry(ACL_TABLE);
sanghofb3b5012016-11-10 15:47:53 +0900133 setupJumpTable();
danielc8620b12015-11-30 15:50:59 +0900134 }
135
sanghofb3b5012016-11-10 15:47:53 +0900136 private void connectTables(int fromTable, int toTable) {
danielc8620b12015-11-30 15:50:59 +0900137 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
138 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
139
sanghofb3b5012016-11-10 15:47:53 +0900140 treatment.transition(toTable);
141
142 FlowRule flowRule = DefaultFlowRule.builder()
143 .forDevice(deviceId)
144 .withSelector(selector.build())
145 .withTreatment(treatment.build())
146 .withPriority(DROP_PRIORITY)
147 .fromApp(appId)
148 .makePermanent()
149 .forTable(fromTable)
150 .build();
151
152 applyRules(true, flowRule);
153 }
154
sangho6a9ff0d2017-03-27 11:23:37 +0900155 private void setUpTableMissEntry(int table) {
156 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
157 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
158
159 treatment.drop();
160
161 FlowRule flowRule = DefaultFlowRule.builder()
162 .forDevice(deviceId)
163 .withSelector(selector.build())
164 .withTreatment(treatment.build())
165 .withPriority(DROP_PRIORITY)
166 .fromApp(appId)
167 .makePermanent()
168 .forTable(table)
169 .build();
170
171 applyRules(true, flowRule);
172 }
173
sanghofb3b5012016-11-10 15:47:53 +0900174 private void setupJumpTable() {
175 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
176 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
177
178 selector.matchEthDst(MacAddress.valueOf(VIRTUAL_GATEWAY_MAC));
179 treatment.transition(ROUTING_TABLE);
180
181 FlowRule flowRule = DefaultFlowRule.builder()
182 .forDevice(deviceId)
183 .withSelector(selector.build())
184 .withTreatment(treatment.build())
185 .withPriority(HIGH_PRIORITY)
186 .fromApp(appId)
187 .makePermanent()
188 .forTable(JUMP_TABLE)
189 .build();
190
191 applyRules(true, flowRule);
192
193 selector = DefaultTrafficSelector.builder();
194 treatment = DefaultTrafficTreatment.builder();
195
danielc8620b12015-11-30 15:50:59 +0900196 treatment.transition(FORWARDING_TABLE);
197
sanghofb3b5012016-11-10 15:47:53 +0900198 flowRule = DefaultFlowRule.builder()
danielc8620b12015-11-30 15:50:59 +0900199 .forDevice(deviceId)
200 .withSelector(selector.build())
201 .withTreatment(treatment.build())
202 .withPriority(DROP_PRIORITY)
203 .fromApp(appId)
204 .makePermanent()
sanghofb3b5012016-11-10 15:47:53 +0900205 .forTable(JUMP_TABLE)
danielc8620b12015-11-30 15:50:59 +0900206 .build();
207
sanghofb3b5012016-11-10 15:47:53 +0900208 applyRules(true, flowRule);
sangho90088532016-02-25 18:06:12 +0900209 }
210
danielc8620b12015-11-30 15:50:59 +0900211 private void applyRules(boolean install, FlowRule flowRule) {
212 FlowRuleOperations.Builder flowOpsBuilder = FlowRuleOperations.builder();
213
214 flowOpsBuilder = install ? flowOpsBuilder.add(flowRule) : flowOpsBuilder.remove(flowRule);
215
216 flowRuleService.apply(flowOpsBuilder.build(new FlowRuleOperationsContext() {
217 @Override
218 public void onSuccess(FlowRuleOperations ops) {
219 log.debug("Provisioned vni or forwarding table");
220 }
221
222 @Override
223 public void onError(FlowRuleOperations ops) {
224 log.debug("Failed to privision vni or forwarding table");
225 }
226 }));
227 }
228
sanghofb3b5012016-11-10 15:47:53 +0900229 private FlowRule processVersatile(ForwardingObjective forwardingObjective) {
danielc8620b12015-11-30 15:50:59 +0900230 log.debug("Processing versatile forwarding objective");
231
232 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
233 .forDevice(deviceId)
234 .withSelector(forwardingObjective.selector())
235 .withTreatment(forwardingObjective.treatment())
236 .withPriority(forwardingObjective.priority())
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900237 .fromApp(forwardingObjective.appId())
238 .forTable(SRC_VNI_TABLE);
danielc8620b12015-11-30 15:50:59 +0900239
240 if (forwardingObjective.permanent()) {
241 ruleBuilder.makePermanent();
242 } else {
243 ruleBuilder.makeTemporary(TIME_OUT);
244 }
245
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900246 return ruleBuilder.build();
danielc8620b12015-11-30 15:50:59 +0900247 }
248
sanghofb3b5012016-11-10 15:47:53 +0900249 private FlowRule processSpecific(ForwardingObjective forwardingObjective) {
danielc8620b12015-11-30 15:50:59 +0900250 log.debug("Processing specific forwarding objective");
251
sanghofb3b5012016-11-10 15:47:53 +0900252 TrafficTreatment.Builder treatment = DefaultTrafficTreatment.builder();
sanghofb3b5012016-11-10 15:47:53 +0900253 Optional<Instruction> group = forwardingObjective.treatment().immediate().stream()
254 .filter(i -> i.type() == Instruction.Type.GROUP).findAny();
255 int tableType = tableType(forwardingObjective);
256 if (tableType != LAST_TABLE && !group.isPresent()) {
257 treatment.transition(nextTable(tableType));
258 }
259 forwardingObjective.treatment().allInstructions().stream()
260 .filter(i -> i.type() != Instruction.Type.NOACTION).forEach(treatment::add);
261
danielc8620b12015-11-30 15:50:59 +0900262 FlowRule.Builder ruleBuilder = DefaultFlowRule.builder()
263 .forDevice(deviceId)
264 .withSelector(forwardingObjective.selector())
sanghofb3b5012016-11-10 15:47:53 +0900265 .withTreatment(treatment.build())
danielc8620b12015-11-30 15:50:59 +0900266 .withPriority(forwardingObjective.priority())
sanghofb3b5012016-11-10 15:47:53 +0900267 .fromApp(forwardingObjective.appId())
268 .forTable(tableType);
danielc8620b12015-11-30 15:50:59 +0900269
270 if (forwardingObjective.permanent()) {
271 ruleBuilder.makePermanent();
272 } else {
273 ruleBuilder.makeTemporary(TIME_OUT);
274 }
275
sanghofb3b5012016-11-10 15:47:53 +0900276 return ruleBuilder.build();
danielc8620b12015-11-30 15:50:59 +0900277 }
278
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900279 private int tableType(ForwardingObjective fo) {
danielc8620b12015-11-30 15:50:59 +0900280
sanghofb3b5012016-11-10 15:47:53 +0900281 IPCriterion ipSrc = (IPCriterion) fo.selector().getCriterion(Criterion.Type.IPV4_SRC);
282 IPCriterion ipDst = (IPCriterion) fo.selector().getCriterion(Criterion.Type.IPV4_DST);
283 TunnelIdCriterion tunnelId =
284 (TunnelIdCriterion) fo.selector().getCriterion(Criterion.Type.TUNNEL_ID);
daniel parkac348902017-04-26 13:49:05 +0900285 VlanIdCriterion vlanId = (VlanIdCriterion) fo.selector().getCriterion(Criterion.Type.VLAN_VID);
sanghofb3b5012016-11-10 15:47:53 +0900286 PortCriterion inPort = (PortCriterion) fo.selector().getCriterion(Criterion.Type.IN_PORT);
287 Optional<Instruction> output = fo.treatment().immediate().stream()
288 .filter(i -> i.type() == Instruction.Type.OUTPUT).findAny();
289 Optional<Instruction> group = fo.treatment().immediate().stream()
290 .filter(i -> i.type() == Instruction.Type.GROUP).findAny();
291
292 // TODO: Add the Connection Tracking Table
293 if (inPort != null) {
294 return SRC_VNI_TABLE;
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900295 } else if ((tunnelId != null && ipSrc != null && ipDst != null) ||
daniel parkac348902017-04-26 13:49:05 +0900296 (vlanId != null && ipSrc != null && ipDst != null) ||
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900297 (ipSrc != null && group.isPresent())) {
sanghofb3b5012016-11-10 15:47:53 +0900298 return ROUTING_TABLE;
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900299 } else if (output.isPresent() || (ipDst != null && group.isPresent())) {
300 return FORWARDING_TABLE;
sangho6a9ff0d2017-03-27 11:23:37 +0900301 } else if ((ipSrc != null && ipSrc.ip().prefixLength() == 32 &&
302 ipDst != null && ipDst.ip().prefixLength() == 32) ||
303 (ipSrc != null && ipSrc.ip().prefixLength() == 32 && ipDst == null) ||
304 (ipDst != null && ipDst.ip().prefixLength() == 32 && ipSrc == null) ||
305 (ipDst != null && ipDst.ip().prefixLength() == 32 && ipSrc != null) ||
306 (ipSrc != null && ipSrc.ip().prefixLength() == 32 && ipDst != null)) {
307 return ACL_TABLE;
sanghofb3b5012016-11-10 15:47:53 +0900308 }
309
310 return DUMMY_TABLE;
311 }
312
Hyunsun Moon4e252f22017-02-18 02:07:49 +0900313 private int nextTable(int baseTable) {
sanghofb3b5012016-11-10 15:47:53 +0900314 return baseTable + 1;
danielc8620b12015-11-30 15:50:59 +0900315 }
316
317 private void fail(Objective obj, ObjectiveError error) {
Sho SHIMIZUef7e2902016-02-12 18:38:29 -0800318 obj.context().ifPresent(context -> context.onError(obj, error));
danielc8620b12015-11-30 15:50:59 +0900319 }
320}
321