blob: 4abbcf046548fce3066714e33828797537520de6 [file] [log] [blame]
Hyunsun Moon17f0cf82016-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 */
16package org.onosproject.cordvtn.impl;
17
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;
30import org.onlab.util.ItemNotFoundException;
31import org.onosproject.cordvtn.api.CordVtnNode;
32import org.onosproject.cordvtn.api.CordVtnService;
33import 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;
78 public static final int TABLE_ACCESS_TYPE = 2;
79 public static final int TABLE_IN_SERVICE = 3;
80 public static final int TABLE_DST_IP = 4;
81 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);
93 public static final String DEFAULT_TUNNEL = "vxlan";
94 private static final String PORT_NAME = "portName";
95
96 private ApplicationId appId;
97
98 @Activate
99 protected void activate() {
100 appId = coreService.registerApplication(CordVtnService.CORDVTN_APP_ID);
101 log.info("Started");
102 }
103
104 @Deactivate
105 protected void deactivate() {
106 log.info("Stopped");
107 }
108
109 /**
110 * Flush flows installed by this application.
111 */
112 public void flushRules() {
113 flowRuleService.getFlowRulesById(appId).forEach(flowRule -> processFlowRule(false, flowRule));
114 }
115
116 /**
117 * Installs table miss rule to a give device.
118 *
119 * @param node cordvtn node
120 * @param dpPort data plane port number
121 * @param tunnelPort tunnel port number
122 */
123 public void initPipeline(CordVtnNode node, PortNumber dpPort, PortNumber tunnelPort) {
124 checkNotNull(node);
125
126 processTableZero(node.intBrId(), dpPort, node.dpIp().ip());
127 processInPortTable(node.intBrId(), tunnelPort, dpPort);
128 processAccessTypeTable(node.intBrId(), dpPort);
129 processVlanTable(node.intBrId(), dpPort);
130 }
131
132 private void processTableZero(DeviceId deviceId, PortNumber dpPort, IpAddress dpIp) {
133 // take vxlan packet out onto the physical port
134 TrafficSelector selector = DefaultTrafficSelector.builder()
135 .matchInPort(PortNumber.LOCAL)
136 .build();
137
138 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
139 .setOutput(dpPort)
140 .build();
141
142 FlowRule flowRule = DefaultFlowRule.builder()
143 .fromApp(appId)
144 .withSelector(selector)
145 .withTreatment(treatment)
146 .withPriority(PRIORITY_HIGH)
147 .forDevice(deviceId)
148 .forTable(TABLE_ZERO)
149 .makePermanent()
150 .build();
151
152 processFlowRule(true, flowRule);
153
154 // take a vxlan encap'd packet through the Linux stack
155 selector = DefaultTrafficSelector.builder()
156 .matchInPort(dpPort)
157 .matchEthType(Ethernet.TYPE_IPV4)
158 .matchIPProtocol(IPv4.PROTOCOL_UDP)
159 .matchUdpDst(TpPort.tpPort(VXLAN_UDP_PORT))
160 .build();
161
162 treatment = DefaultTrafficTreatment.builder()
163 .setOutput(PortNumber.LOCAL)
164 .build();
165
166 flowRule = DefaultFlowRule.builder()
167 .fromApp(appId)
168 .withSelector(selector)
169 .withTreatment(treatment)
170 .withPriority(PRIORITY_HIGH)
171 .forDevice(deviceId)
172 .forTable(TABLE_ZERO)
173 .makePermanent()
174 .build();
175
176 processFlowRule(true, flowRule);
177
178 // take a packet to the data plane ip through Linux stack
179 selector = DefaultTrafficSelector.builder()
180 .matchInPort(dpPort)
181 .matchEthType(Ethernet.TYPE_IPV4)
182 .matchIPDst(dpIp.toIpPrefix())
183 .build();
184
185 treatment = DefaultTrafficTreatment.builder()
186 .setOutput(PortNumber.LOCAL)
187 .build();
188
189 flowRule = DefaultFlowRule.builder()
190 .fromApp(appId)
191 .withSelector(selector)
192 .withTreatment(treatment)
193 .withPriority(PRIORITY_HIGH)
194 .forDevice(deviceId)
195 .forTable(TABLE_ZERO)
196 .makePermanent()
197 .build();
198
199 processFlowRule(true, flowRule);
200
201 // take an arp packet from physical through Linux stack
202 selector = DefaultTrafficSelector.builder()
203 .matchInPort(dpPort)
204 .matchEthType(Ethernet.TYPE_ARP)
205 .matchArpTpa(dpIp.getIp4Address())
206 .build();
207
208 treatment = DefaultTrafficTreatment.builder()
209 .setOutput(PortNumber.LOCAL)
210 .build();
211
212 flowRule = DefaultFlowRule.builder()
213 .fromApp(appId)
214 .withSelector(selector)
215 .withTreatment(treatment)
216 .withPriority(PRIORITY_HIGH)
217 .forDevice(deviceId)
218 .forTable(TABLE_ZERO)
219 .makePermanent()
220 .build();
221
222 processFlowRule(true, flowRule);
223
224 // take all else to the next table
225 selector = DefaultTrafficSelector.builder()
226 .build();
227
228 treatment = DefaultTrafficTreatment.builder()
229 .transition(TABLE_IN_PORT)
230 .build();
231
232 flowRule = DefaultFlowRule.builder()
233 .fromApp(appId)
234 .withSelector(selector)
235 .withTreatment(treatment)
236 .withPriority(PRIORITY_ZERO)
237 .forDevice(deviceId)
238 .forTable(TABLE_ZERO)
239 .makePermanent()
240 .build();
241
242 processFlowRule(true, flowRule);
243
244 // take all vlan tagged packet to the VLAN table
245 selector = DefaultTrafficSelector.builder()
246 .matchVlanId(VlanId.ANY)
247 .build();
248
249 treatment = DefaultTrafficTreatment.builder()
250 .transition(TABLE_VLAN)
251 .build();
252
253 flowRule = DefaultFlowRule.builder()
254 .fromApp(appId)
255 .withSelector(selector)
256 .withTreatment(treatment)
257 .withPriority(PRIORITY_MANAGEMENT)
258 .forDevice(deviceId)
259 .forTable(TABLE_ZERO)
260 .makePermanent()
261 .build();
262
263 processFlowRule(true, flowRule);
264 }
265
266 private void processInPortTable(DeviceId deviceId, PortNumber tunnelPort, PortNumber dpPort) {
267 checkNotNull(tunnelPort);
268
269 TrafficSelector selector = DefaultTrafficSelector.builder()
270 .matchInPort(tunnelPort)
271 .build();
272
273 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
274 .transition(TABLE_TUNNEL_IN)
275 .build();
276
277 FlowRule flowRule = DefaultFlowRule.builder()
278 .fromApp(appId)
279 .withSelector(selector)
280 .withTreatment(treatment)
281 .withPriority(PRIORITY_DEFAULT)
282 .forDevice(deviceId)
283 .forTable(TABLE_IN_PORT)
284 .makePermanent()
285 .build();
286
287 processFlowRule(true, flowRule);
288
289 selector = DefaultTrafficSelector.builder()
290 .matchInPort(dpPort)
291 .build();
292
293 treatment = DefaultTrafficTreatment.builder()
294 .transition(TABLE_DST_IP)
295 .build();
296
297 flowRule = DefaultFlowRule.builder()
298 .fromApp(appId)
299 .withSelector(selector)
300 .withTreatment(treatment)
301 .withPriority(PRIORITY_DEFAULT)
302 .forDevice(deviceId)
303 .forTable(TABLE_IN_PORT)
304 .makePermanent()
305 .build();
306
307 processFlowRule(true, flowRule);
308 }
309
310 private void processAccessTypeTable(DeviceId deviceId, PortNumber dpPort) {
311 TrafficSelector selector = DefaultTrafficSelector.builder()
312 .build();
313
314 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
315 .setOutput(dpPort)
316 .build();
317
318 FlowRule flowRule = DefaultFlowRule.builder()
319 .fromApp(appId)
320 .withSelector(selector)
321 .withTreatment(treatment)
322 .withPriority(PRIORITY_ZERO)
323 .forDevice(deviceId)
324 .forTable(TABLE_ACCESS_TYPE)
325 .makePermanent()
326 .build();
327
328 processFlowRule(true, flowRule);
329 }
330
331 private void processVlanTable(DeviceId deviceId, PortNumber dpPort) {
332 // for traffic going out to WAN, strip vid 500 and take through data plane interface
333 TrafficSelector selector = DefaultTrafficSelector.builder()
334 .matchVlanId(VLAN_WAN)
335 .build();
336
337 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
338 .popVlan()
339 .setOutput(dpPort)
340 .build();
341
342 FlowRule flowRule = DefaultFlowRule.builder()
343 .fromApp(appId)
344 .withSelector(selector)
345 .withTreatment(treatment)
346 .withPriority(PRIORITY_DEFAULT)
347 .forDevice(deviceId)
348 .forTable(TABLE_VLAN)
349 .makePermanent()
350 .build();
351
352 processFlowRule(true, flowRule);
353
354 selector = DefaultTrafficSelector.builder()
355 .matchVlanId(VLAN_WAN)
356 .matchEthType(Ethernet.TYPE_ARP)
357 .build();
358
359 treatment = DefaultTrafficTreatment.builder()
360 .setOutput(PortNumber.CONTROLLER)
361 .build();
362
363 flowRule = DefaultFlowRule.builder()
364 .fromApp(appId)
365 .withSelector(selector)
366 .withTreatment(treatment)
367 .withPriority(PRIORITY_HIGH)
368 .forDevice(deviceId)
369 .forTable(TABLE_VLAN)
370 .makePermanent()
371 .build();
372
373 processFlowRule(true, flowRule);
374 }
375
376 public void processFlowRule(boolean install, FlowRule rule) {
377 FlowRuleOperations.Builder oBuilder = FlowRuleOperations.builder();
378 oBuilder = install ? oBuilder.add(rule) : oBuilder.remove(rule);
379
380 flowRuleService.apply(oBuilder.build(new FlowRuleOperationsContext() {
381 @Override
382 public void onError(FlowRuleOperations ops) {
383 log.error(String.format("Failed %s, %s", ops.toString(), rule.toString()));
384 }
385 }));
386 }
387
388 public ExtensionTreatment tunnelDstTreatment(DeviceId deviceId, Ip4Address remoteIp) {
389 try {
390 Device device = deviceService.getDevice(deviceId);
391
392 if (device.is(ExtensionTreatmentResolver.class)) {
393 ExtensionTreatmentResolver resolver = device.as(ExtensionTreatmentResolver.class);
394 ExtensionTreatment treatment =
395 resolver.getExtensionInstruction(NICIRA_SET_TUNNEL_DST.type());
396 treatment.setPropertyValue("tunnelDst", remoteIp);
397 return treatment;
398 } else {
399 log.warn("The extension treatment resolving behaviour is not supported in device {}",
400 device.id().toString());
401 return null;
402 }
403 } catch (ItemNotFoundException | UnsupportedOperationException |
404 ExtensionPropertyException e) {
405 log.error("Failed to get extension instruction {}", deviceId);
406 return null;
407 }
408 }
409}