blob: 2aa9f1ffec58534a006ce926d83e5cba28cfd5bb [file] [log] [blame]
Hyunsun Moone7e4bb32016-05-16 04:32:45 -07001/*
2 * Copyright 2016-present Open Networking Laboratory
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 */
alshabibb4d31712016-06-01 18:51:03 -070016package org.opencord.cordvtn.impl;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070017
18import org.apache.felix.scr.annotations.Activate;
19import org.apache.felix.scr.annotations.Component;
20import org.apache.felix.scr.annotations.Deactivate;
21import org.apache.felix.scr.annotations.Reference;
22import org.apache.felix.scr.annotations.ReferenceCardinality;
23import org.apache.felix.scr.annotations.Service;
24import org.onlab.packet.Ethernet;
25import org.onlab.packet.IPv4;
26import org.onlab.packet.Ip4Address;
27import org.onlab.packet.IpAddress;
28import org.onlab.packet.TpPort;
29import org.onlab.packet.VlanId;
Hyunsun Moon315b9a62016-06-23 14:48:04 -070030import org.onlab.util.ItemNotFoundException;
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070031import org.opencord.cordvtn.api.Constants;
alshabibb4d31712016-06-01 18:51:03 -070032import org.opencord.cordvtn.api.CordVtnNode;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070033import org.onosproject.core.ApplicationId;
34import org.onosproject.core.CoreService;
35import org.onosproject.net.Device;
36import org.onosproject.net.DeviceId;
37import org.onosproject.net.PortNumber;
38import org.onosproject.net.behaviour.ExtensionTreatmentResolver;
39import org.onosproject.net.device.DeviceService;
40import org.onosproject.net.flow.DefaultFlowRule;
41import org.onosproject.net.flow.DefaultTrafficSelector;
42import org.onosproject.net.flow.DefaultTrafficTreatment;
43import org.onosproject.net.flow.FlowRule;
44import org.onosproject.net.flow.FlowRuleOperations;
45import org.onosproject.net.flow.FlowRuleOperationsContext;
46import org.onosproject.net.flow.FlowRuleService;
47import org.onosproject.net.flow.TrafficSelector;
48import org.onosproject.net.flow.TrafficTreatment;
49import org.onosproject.net.flow.instructions.ExtensionPropertyException;
50import org.onosproject.net.flow.instructions.ExtensionTreatment;
51import org.slf4j.Logger;
52
53import static com.google.common.base.Preconditions.checkNotNull;
54import static org.onosproject.net.flow.instructions.ExtensionTreatmentType.ExtensionTreatmentTypes.NICIRA_SET_TUNNEL_DST;
55import static org.slf4j.LoggerFactory.getLogger;
56
57/**
58 * Provides CORD VTN pipeline.
59 */
60@Component(immediate = true)
61@Service(value = CordVtnPipeline.class)
62public final class CordVtnPipeline {
63
64 protected final Logger log = getLogger(getClass());
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected CoreService coreService;
68
69 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
70 protected FlowRuleService flowRuleService;
71
72 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
73 protected DeviceService deviceService;
74
75 // tables
76 public static final int TABLE_ZERO = 0;
77 public static final int TABLE_IN_PORT = 1;
Hyunsun Moonfb417942016-06-23 14:48:20 -070078 public static final int TABLE_ACCESS_TYPE = 2;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070079 public static final int TABLE_IN_SERVICE = 3;
Hyunsun Moonfb417942016-06-23 14:48:20 -070080 public static final int TABLE_DST_IP = 4;
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070081 public static final int TABLE_TUNNEL_IN = 5;
82 public static final int TABLE_VLAN = 6;
83
84 // priorities
85 public static final int PRIORITY_MANAGEMENT = 55000;
86 public static final int PRIORITY_HIGH = 50000;
87 public static final int PRIORITY_DEFAULT = 5000;
88 public static final int PRIORITY_LOW = 4000;
89 public static final int PRIORITY_ZERO = 0;
90
91 public static final int VXLAN_UDP_PORT = 4789;
92 public static final VlanId VLAN_WAN = VlanId.vlanId((short) 500);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070093
94 private ApplicationId appId;
95
96 @Activate
97 protected void activate() {
Hyunsun Moon5401aaa2016-06-12 17:40:34 -070098 appId = coreService.registerApplication(Constants.CORDVTN_APP_ID);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -070099 log.info("Started");
100 }
101
102 @Deactivate
103 protected void deactivate() {
104 log.info("Stopped");
105 }
106
107 /**
108 * Flush flows installed by this application.
109 */
110 public void flushRules() {
111 flowRuleService.getFlowRulesById(appId).forEach(flowRule -> processFlowRule(false, flowRule));
112 }
113
114 /**
115 * Installs table miss rule to a give device.
116 *
117 * @param node cordvtn node
Hyunsun Moon81a13562016-08-04 13:48:08 -0700118 * @param dataPort data plane port number
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700119 * @param tunnelPort tunnel port number
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700120 */
Hyunsun Moon81a13562016-08-04 13:48:08 -0700121 public void initPipeline(CordVtnNode node, PortNumber dataPort, PortNumber tunnelPort) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700122 checkNotNull(node);
123
Hyunsun Moon81a13562016-08-04 13:48:08 -0700124 processTableZero(node.integrationBridgeId(), dataPort, node.dataIp().ip());
125 processInPortTable(node.integrationBridgeId(), tunnelPort, dataPort);
126 processAccessTypeTable(node.integrationBridgeId(), dataPort);
127 processVlanTable(node.integrationBridgeId(), dataPort);
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700128 }
129
Hyunsun Moon81a13562016-08-04 13:48:08 -0700130 private void processTableZero(DeviceId deviceId, PortNumber dataPort, IpAddress dataIp) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700131 // take vxlan packet out onto the physical port
132 TrafficSelector selector = DefaultTrafficSelector.builder()
133 .matchInPort(PortNumber.LOCAL)
134 .build();
135
136 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700137 .setOutput(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700138 .build();
139
140 FlowRule flowRule = DefaultFlowRule.builder()
141 .fromApp(appId)
142 .withSelector(selector)
143 .withTreatment(treatment)
144 .withPriority(PRIORITY_HIGH)
145 .forDevice(deviceId)
146 .forTable(TABLE_ZERO)
147 .makePermanent()
148 .build();
149
150 processFlowRule(true, flowRule);
151
152 // take a vxlan encap'd packet through the Linux stack
153 selector = DefaultTrafficSelector.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700154 .matchInPort(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700155 .matchEthType(Ethernet.TYPE_IPV4)
156 .matchIPProtocol(IPv4.PROTOCOL_UDP)
157 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
158 .build();
159
160 treatment = DefaultTrafficTreatment.builder()
161 .setOutput(PortNumber.LOCAL)
162 .build();
163
164 flowRule = DefaultFlowRule.builder()
165 .fromApp(appId)
166 .withSelector(selector)
167 .withTreatment(treatment)
168 .withPriority(PRIORITY_HIGH)
169 .forDevice(deviceId)
170 .forTable(TABLE_ZERO)
171 .makePermanent()
172 .build();
173
174 processFlowRule(true, flowRule);
175
176 // take a packet to the data plane ip through Linux stack
177 selector = DefaultTrafficSelector.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700178 .matchInPort(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700179 .matchEthType(Ethernet.TYPE_IPV4)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700180 .matchIPDst(dataIp.toIpPrefix())
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700181 .build();
182
183 treatment = DefaultTrafficTreatment.builder()
184 .setOutput(PortNumber.LOCAL)
185 .build();
186
187 flowRule = DefaultFlowRule.builder()
188 .fromApp(appId)
189 .withSelector(selector)
190 .withTreatment(treatment)
191 .withPriority(PRIORITY_HIGH)
192 .forDevice(deviceId)
193 .forTable(TABLE_ZERO)
194 .makePermanent()
195 .build();
196
197 processFlowRule(true, flowRule);
198
199 // take an arp packet from physical through Linux stack
200 selector = DefaultTrafficSelector.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700201 .matchInPort(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700202 .matchEthType(Ethernet.TYPE_ARP)
Hyunsun Moon81a13562016-08-04 13:48:08 -0700203 .matchArpTpa(dataIp.getIp4Address())
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700204 .build();
205
206 treatment = DefaultTrafficTreatment.builder()
207 .setOutput(PortNumber.LOCAL)
208 .build();
209
210 flowRule = DefaultFlowRule.builder()
211 .fromApp(appId)
212 .withSelector(selector)
213 .withTreatment(treatment)
214 .withPriority(PRIORITY_HIGH)
215 .forDevice(deviceId)
216 .forTable(TABLE_ZERO)
217 .makePermanent()
218 .build();
219
220 processFlowRule(true, flowRule);
221
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700222 // take all else to the next table
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700223 selector = DefaultTrafficSelector.builder()
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700224 .build();
225
226 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700227 .transition(TABLE_IN_PORT)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700228 .build();
229
230 flowRule = DefaultFlowRule.builder()
231 .fromApp(appId)
232 .withSelector(selector)
233 .withTreatment(treatment)
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700234 .withPriority(PRIORITY_ZERO)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700235 .forDevice(deviceId)
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700236 .forTable(TABLE_ZERO)
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700237 .makePermanent()
238 .build();
239
240 processFlowRule(true, flowRule);
241
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700242 // take all vlan tagged packet to the VLAN table
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700243 selector = DefaultTrafficSelector.builder()
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700244 .matchVlanId(VlanId.ANY)
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700245 .build();
246
247 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700248 .transition(TABLE_VLAN)
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700249 .build();
250
251 flowRule = DefaultFlowRule.builder()
252 .fromApp(appId)
253 .withSelector(selector)
254 .withTreatment(treatment)
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700255 .withPriority(PRIORITY_MANAGEMENT)
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700256 .forDevice(deviceId)
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700257 .forTable(TABLE_ZERO)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700258 .makePermanent()
259 .build();
260
261 processFlowRule(true, flowRule);
262 }
263
Hyunsun Moon81a13562016-08-04 13:48:08 -0700264 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dataPort) {
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700265 checkNotNull(tunnelPort);
266
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700267 TrafficSelector selector = DefaultTrafficSelector.builder()
268 .matchInPort(tunnelPort)
269 .build();
270
271 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
272 .transition(TABLE_TUNNEL_IN)
273 .build();
274
275 FlowRule flowRule = DefaultFlowRule.builder()
276 .fromApp(appId)
277 .withSelector(selector)
278 .withTreatment(treatment)
279 .withPriority(PRIORITY_DEFAULT)
280 .forDevice(deviceId)
281 .forTable(TABLE_IN_PORT)
282 .makePermanent()
283 .build();
284
285 processFlowRule(true, flowRule);
286
287 selector = DefaultTrafficSelector.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700288 .matchInPort(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700289 .build();
290
291 treatment = DefaultTrafficTreatment.builder()
Hyunsun Moonfb417942016-06-23 14:48:20 -0700292 .transition(TABLE_DST_IP)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700293 .build();
294
295 flowRule = DefaultFlowRule.builder()
296 .fromApp(appId)
297 .withSelector(selector)
298 .withTreatment(treatment)
299 .withPriority(PRIORITY_DEFAULT)
300 .forDevice(deviceId)
301 .forTable(TABLE_IN_PORT)
302 .makePermanent()
303 .build();
304
305 processFlowRule(true, flowRule);
306 }
307
Hyunsun Moon81a13562016-08-04 13:48:08 -0700308 private void processAccessTypeTable(DeviceId deviceId, PortNumber dataPort) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700309 TrafficSelector selector = DefaultTrafficSelector.builder()
310 .build();
311
312 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700313 .setOutput(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700314 .build();
315
316 FlowRule flowRule = DefaultFlowRule.builder()
317 .fromApp(appId)
318 .withSelector(selector)
319 .withTreatment(treatment)
320 .withPriority(PRIORITY_ZERO)
321 .forDevice(deviceId)
Hyunsun Moonfb417942016-06-23 14:48:20 -0700322 .forTable(TABLE_ACCESS_TYPE)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700323 .makePermanent()
324 .build();
325
326 processFlowRule(true, flowRule);
327 }
328
Hyunsun Moon81a13562016-08-04 13:48:08 -0700329 private void processVlanTable(DeviceId deviceId, PortNumber dataPort) {
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700330 // for traffic going out to WAN, strip vid 500 and take through data plane interface
331 TrafficSelector selector = DefaultTrafficSelector.builder()
332 .matchVlanId(VLAN_WAN)
333 .build();
334
335 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
336 .popVlan()
Hyunsun Moon81a13562016-08-04 13:48:08 -0700337 .setOutput(dataPort)
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700338 .build();
339
340 FlowRule flowRule = DefaultFlowRule.builder()
341 .fromApp(appId)
342 .withSelector(selector)
343 .withTreatment(treatment)
344 .withPriority(PRIORITY_DEFAULT)
345 .forDevice(deviceId)
346 .forTable(TABLE_VLAN)
347 .makePermanent()
348 .build();
349
350 processFlowRule(true, flowRule);
351
352 selector = DefaultTrafficSelector.builder()
353 .matchVlanId(VLAN_WAN)
354 .matchEthType(Ethernet.TYPE_ARP)
355 .build();
356
357 treatment = DefaultTrafficTreatment.builder()
358 .setOutput(PortNumber.CONTROLLER)
359 .build();
360
361 flowRule = DefaultFlowRule.builder()
362 .fromApp(appId)
363 .withSelector(selector)
364 .withTreatment(treatment)
365 .withPriority(PRIORITY_HIGH)
366 .forDevice(deviceId)
367 .forTable(TABLE_VLAN)
368 .makePermanent()
369 .build();
370
371 processFlowRule(true, flowRule);
372 }
373
374 public void processFlowRule(boolean install, FlowRule rule) {
375 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
376 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
377
378 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
379 @Override
380 public void onError(FlowRuleOperations ops) {
381 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
382 }
383 }));
384 }
385
386 public ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, Ip4Address remoteIp) {
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700387 try {
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700388 Device device = deviceService.getDevice(deviceId);
389 if (!device.is(ExtensionTreatmentResolver.class)) {
390 log.error("The extension treatment is not supported");
391 return null;
392
393 }
394
395 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
396 ExtensionTreatment treatment =
397 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
398 treatment.setPropertyValue("tunnelDst", remoteIp);
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700399 return treatment;
Hyunsun Moon315b9a62016-06-23 14:48:04 -0700400 } catch (ItemNotFoundException | UnsupportedOperationException |
401 ExtensionPropertyException e) {
402 log.error("Failed to get extension instruction {}", deviceId);
Hyunsun Moonacbc8ef2016-06-21 17:58:45 -0700403 return null;
404 }
405 }
Hyunsun Moone7e4bb32016-05-16 04:32:45 -0700406}