blob: 4e1b90b15462af65ab5c58c9d893c2dc715e9d38 [file] [log] [blame]
Jonathan Hartea750842015-04-23 17:44:49 -07001/*
2 * Copyright 2015 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 */
16
17package org.onosproject.cordfabric;
18
19import com.google.common.collect.HashMultimap;
20import com.google.common.collect.Multimap;
Jonathan Hartea750842015-04-23 17:44:49 -070021import org.apache.felix.scr.annotations.Activate;
22import org.apache.felix.scr.annotations.Component;
23import org.apache.felix.scr.annotations.Deactivate;
24import org.apache.felix.scr.annotations.Reference;
25import org.apache.felix.scr.annotations.ReferenceCardinality;
26import org.apache.felix.scr.annotations.Service;
Jonathan Hart0b989982015-05-14 15:40:07 -070027import org.onlab.packet.Ethernet;
28import org.onlab.packet.IPv4;
Jonathan Hartea750842015-04-23 17:44:49 -070029import org.onlab.packet.VlanId;
30import org.onosproject.core.ApplicationId;
31import org.onosproject.core.CoreService;
32import org.onosproject.net.ConnectPoint;
33import org.onosproject.net.DeviceId;
34import org.onosproject.net.PortNumber;
Jonathan Hart408d24d2015-06-02 10:21:47 -070035import org.onosproject.net.device.DeviceEvent;
36import org.onosproject.net.device.DeviceListener;
37import org.onosproject.net.device.DeviceService;
Jonathan Hartea750842015-04-23 17:44:49 -070038import org.onosproject.net.flow.DefaultTrafficSelector;
39import org.onosproject.net.flow.DefaultTrafficTreatment;
40import org.onosproject.net.flow.TrafficSelector;
41import org.onosproject.net.flow.TrafficTreatment;
42import org.onosproject.net.flowobjective.DefaultForwardingObjective;
43import org.onosproject.net.flowobjective.FlowObjectiveService;
44import org.onosproject.net.flowobjective.ForwardingObjective;
45import org.onosproject.net.flowobjective.Objective;
46import org.onosproject.net.flowobjective.ObjectiveContext;
47import org.onosproject.net.flowobjective.ObjectiveError;
48import org.slf4j.Logger;
49import org.slf4j.LoggerFactory;
50
Jonathan Hart443ebed2015-05-05 14:02:12 -070051import java.util.ArrayList;
Jonathan Hartab8b0c02015-06-10 14:06:51 -070052import java.util.Collection;
Jonathan Hartea750842015-04-23 17:44:49 -070053import java.util.List;
54import java.util.stream.Collectors;
55
56import static com.google.common.base.Preconditions.checkArgument;
57import static com.google.common.base.Preconditions.checkNotNull;
58import static org.slf4j.LoggerFactory.getLogger;
59
60/**
61 * CORD fabric application.
62 */
63@Service
64@Component(immediate = true)
65public class CordFabricManager implements FabricService {
66
67 private final Logger log = getLogger(getClass());
68
69 private ApplicationId appId;
70
71 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
72 protected CoreService coreService;
73
74 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
75 protected FlowObjectiveService flowObjectiveService;
76
Jonathan Hart408d24d2015-06-02 10:21:47 -070077 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected DeviceService deviceService;
Jonathan Hartea750842015-04-23 17:44:49 -070079
Jonathan Hart408d24d2015-06-02 10:21:47 -070080 private InternalDeviceListener deviceListener = new InternalDeviceListener();
81
82 private static final int PRIORITY = 50000;
Jonathan Hart0b989982015-05-14 15:40:07 -070083
alshabibc494f992015-05-15 09:51:54 -070084 private short radiusPort = 1812;
85
alshabib0603afb2015-06-05 14:10:33 -070086 private short ofPort = 6633;
87
Jonathan Hart0b989982015-05-14 15:40:07 -070088 private DeviceId fabricDeviceId = DeviceId.deviceId("of:5e3e486e73000187");
89
Jonathan Hartea750842015-04-23 17:44:49 -070090 private final Multimap<VlanId, ConnectPoint> vlans = HashMultimap.create();
91
92 @Activate
93 public void activate() {
94 appId = coreService.registerApplication("org.onosproject.cordfabric");
95
Jonathan Hart408d24d2015-06-02 10:21:47 -070096 deviceService.addListener(deviceListener);
97
98 if (deviceService.isAvailable(fabricDeviceId)) {
99 setupDefaultFlows();
100 }
Jonathan Hart0b989982015-05-14 15:40:07 -0700101
Jonathan Hartea750842015-04-23 17:44:49 -0700102 log.info("Started");
103 }
104
105 @Deactivate
106 public void deactivate() {
Jonathan Hart408d24d2015-06-02 10:21:47 -0700107 deviceService.removeListener(deviceListener);
108
Jonathan Hartea750842015-04-23 17:44:49 -0700109 log.info("Stopped");
110 }
111
Jonathan Hart0b989982015-05-14 15:40:07 -0700112 private void setupDefaultFlows() {
alshabib0603afb2015-06-05 14:10:33 -0700113 TrafficSelector ofInBandMatchUp = DefaultTrafficSelector.builder()
114 .matchEthType(Ethernet.TYPE_IPV4)
115 .matchIPProtocol(IPv4.PROTOCOL_TCP)
116 .matchTcpDst(ofPort)
117 .matchInPort(PortNumber.portNumber(6))
118 .build();
119
120 TrafficSelector ofInBandMatchDown = DefaultTrafficSelector.builder()
121 .matchEthType(Ethernet.TYPE_IPV4)
122 .matchIPProtocol(IPv4.PROTOCOL_TCP)
123 .matchTcpSrc(ofPort)
alshabib48dd9a12015-06-05 14:45:57 -0700124 .matchInPort(PortNumber.portNumber(1))
alshabib0603afb2015-06-05 14:10:33 -0700125 .build();
126
127 TrafficTreatment up = DefaultTrafficTreatment.builder()
alshabib48dd9a12015-06-05 14:45:57 -0700128 .setOutput(PortNumber.portNumber(1))
alshabib0603afb2015-06-05 14:10:33 -0700129 .build();
130
131 TrafficTreatment down = DefaultTrafficTreatment.builder()
132 .setOutput(PortNumber.portNumber(6))
133 .build();
134
135 TrafficSelector toRadius = DefaultTrafficSelector.builder()
alshabibaf734ff2015-07-01 16:35:26 -0700136 .matchInPort(PortNumber.portNumber(2))
Jonathan Hart0b989982015-05-14 15:40:07 -0700137 .matchEthType(Ethernet.TYPE_IPV4)
alshabibc494f992015-05-15 09:51:54 -0700138 .matchIPProtocol(IPv4.PROTOCOL_UDP)
139 .matchUdpDst(radiusPort)
140 .build();
141
alshabibaf734ff2015-07-01 16:35:26 -0700142 TrafficSelector fromRadius = DefaultTrafficSelector.builder()
143 .matchInPort(PortNumber.portNumber(5))
144 .matchEthType(Ethernet.TYPE_IPV4)
145 .matchIPProtocol(IPv4.PROTOCOL_UDP)
146 .matchUdpDst(radiusPort)
Jonathan Hart0b989982015-05-14 15:40:07 -0700147 .build();
148
alshabibaf734ff2015-07-01 16:35:26 -0700149 TrafficTreatment toOlt = DefaultTrafficTreatment.builder()
150 .setOutput(PortNumber.portNumber(2))
151 .build();
152
153
154 TrafficTreatment sentToRadius = DefaultTrafficTreatment.builder()
155 .setOutput(PortNumber.portNumber(5))
156 .build();
157
158 ForwardingObjective radiusToServer = DefaultForwardingObjective.builder()
Jonathan Hart0b989982015-05-14 15:40:07 -0700159 .fromApp(appId)
160 .makePermanent()
161 .withFlag(ForwardingObjective.Flag.VERSATILE)
162 .withPriority(PRIORITY)
alshabib0603afb2015-06-05 14:10:33 -0700163 .withSelector(toRadius)
alshabibaf734ff2015-07-01 16:35:26 -0700164 .withTreatment(sentToRadius)
Jonathan Hart0b989982015-05-14 15:40:07 -0700165 .add();
166
alshabibaf734ff2015-07-01 16:35:26 -0700167 ForwardingObjective serverToRadius = DefaultForwardingObjective.builder()
168 .fromApp(appId)
169 .makePermanent()
170 .withFlag(ForwardingObjective.Flag.VERSATILE)
171 .withPriority(PRIORITY)
172 .withSelector(fromRadius)
173 .withTreatment(toOlt)
174 .add();
175
176
177
alshabib0603afb2015-06-05 14:10:33 -0700178 ForwardingObjective upCtrl = DefaultForwardingObjective.builder()
179 .fromApp(appId)
180 .makePermanent()
181 .withFlag(ForwardingObjective.Flag.VERSATILE)
182 .withPriority(PRIORITY)
183 .withSelector(ofInBandMatchUp)
184 .withTreatment(up)
185 .add();
186
187 ForwardingObjective downCtrl = DefaultForwardingObjective.builder()
188 .fromApp(appId)
189 .makePermanent()
190 .withFlag(ForwardingObjective.Flag.VERSATILE)
191 .withPriority(PRIORITY)
192 .withSelector(ofInBandMatchDown)
193 .withTreatment(down)
194 .add();
195
alshabibc4b5d462015-06-08 23:06:24 -0700196
197
alshabib0603afb2015-06-05 14:10:33 -0700198 flowObjectiveService.forward(fabricDeviceId, upCtrl);
199 flowObjectiveService.forward(fabricDeviceId, downCtrl);
alshabibaf734ff2015-07-01 16:35:26 -0700200 flowObjectiveService.forward(fabricDeviceId, radiusToServer);
201 flowObjectiveService.forward(fabricDeviceId, serverToRadius);
Jonathan Hart0b989982015-05-14 15:40:07 -0700202 }
203
Jonathan Hartea750842015-04-23 17:44:49 -0700204 @Override
Jonathan Hart443ebed2015-05-05 14:02:12 -0700205 public void addVlan(FabricVlan vlan) {
206 checkNotNull(vlan);
207 checkArgument(vlan.ports().size() > 1);
208 verifyPorts(vlan.ports());
Jonathan Hartea750842015-04-23 17:44:49 -0700209
Jonathan Hart443ebed2015-05-05 14:02:12 -0700210 removeVlan(vlan.vlan());
Jonathan Hartea750842015-04-23 17:44:49 -0700211
alshabibc4b5d462015-06-08 23:06:24 -0700212 if (vlan.iptv()) {
213 provisionIPTV();
214 }
215
Jonathan Hart443ebed2015-05-05 14:02:12 -0700216 vlan.ports().forEach(cp -> {
217 if (vlans.put(vlan.vlan(), cp)) {
218 addForwarding(vlan.vlan(), cp.deviceId(), cp.port(),
219 vlan.ports().stream()
Jonathan Hartea750842015-04-23 17:44:49 -0700220 .filter(p -> p != cp)
221 .map(ConnectPoint::port)
222 .collect(Collectors.toList()));
223 }
224 });
225 }
226
alshabibc4b5d462015-06-08 23:06:24 -0700227 //FIXME: pass iptv vlan in here.
228 private void provisionIPTV() {
229 TrafficSelector ipTvUp = DefaultTrafficSelector.builder()
230 .matchVlanId(VlanId.vlanId((short) 7))
231 .matchInPort(PortNumber.portNumber(2))
232 .build();
233
234 TrafficTreatment ipTvActUp = DefaultTrafficTreatment.builder()
235 .setOutput(PortNumber.portNumber(7)).build();
236
237 TrafficSelector ipTvDown = DefaultTrafficSelector.builder()
238 .matchVlanId(VlanId.vlanId((short) 7))
239 .matchInPort(PortNumber.portNumber(7))
240 .build();
241
242 TrafficTreatment ipTvActDown = DefaultTrafficTreatment.builder()
243 .setOutput(PortNumber.portNumber(2)).build();
244
245 ForwardingObjective ipTvUpstream = DefaultForwardingObjective.builder()
246 .fromApp(appId)
247 .makePermanent()
248 .withFlag(ForwardingObjective.Flag.VERSATILE)
249 .withPriority(PRIORITY)
250 .withSelector(ipTvUp)
251 .withTreatment(ipTvActUp)
252 .add();
253
254 ForwardingObjective ipTvDownstream = DefaultForwardingObjective.builder()
255 .fromApp(appId)
256 .makePermanent()
257 .withFlag(ForwardingObjective.Flag.VERSATILE)
258 .withPriority(PRIORITY)
259 .withSelector(ipTvDown)
260 .withTreatment(ipTvActDown)
261 .add();
262
263 flowObjectiveService.forward(fabricDeviceId, ipTvUpstream);
264 flowObjectiveService.forward(fabricDeviceId, ipTvDownstream);
265 }
266
Jonathan Hartea750842015-04-23 17:44:49 -0700267 @Override
268 public void removeVlan(VlanId vlanId) {
Jonathan Hartab8b0c02015-06-10 14:06:51 -0700269 Collection<ConnectPoint> ports = vlans.removeAll(vlanId);
270
271 ports.forEach(cp -> removeForwarding(vlanId, cp.deviceId(), cp.port(),
272 ports.stream()
273 .filter(p -> p != cp)
274 .map(ConnectPoint::port)
275 .collect(Collectors.toList())));
Jonathan Hartea750842015-04-23 17:44:49 -0700276 }
277
278 @Override
Jonathan Hart443ebed2015-05-05 14:02:12 -0700279 public List<FabricVlan> getVlans() {
280 List<FabricVlan> fVlans = new ArrayList<>();
281 vlans.keySet().forEach(vlan -> fVlans.add(
alshabibc4b5d462015-06-08 23:06:24 -0700282 //FIXME: Very aweful but will fo for now
283 new FabricVlan(vlan, vlans.get(vlan),
284 vlan.toShort() == 201 ? true : false)));
Jonathan Hart443ebed2015-05-05 14:02:12 -0700285 return fVlans;
Jonathan Hartea750842015-04-23 17:44:49 -0700286 }
287
288 private static void verifyPorts(List<ConnectPoint> ports) {
289 DeviceId deviceId = ports.get(0).deviceId();
290 for (ConnectPoint connectPoint : ports) {
291 if (!connectPoint.deviceId().equals(deviceId)) {
292 throw new IllegalArgumentException("Ports must all be on the same device");
293 }
294 }
295 }
296
297 private void addForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort,
298 List<PortNumber> outPorts) {
alshabibc4b5d462015-06-08 23:06:24 -0700299
Jonathan Hartea750842015-04-23 17:44:49 -0700300 TrafficSelector selector = DefaultTrafficSelector.builder()
301 .matchVlanId(vlanId)
302 .matchInPort(inPort)
303 .build();
304
305 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
306
307 outPorts.forEach(p -> treatmentBuilder.setOutput(p));
308
309 ForwardingObjective objective = DefaultForwardingObjective.builder()
310 .fromApp(appId)
311 .makePermanent()
312 .withFlag(ForwardingObjective.Flag.VERSATILE)
313 .withPriority(PRIORITY)
314 .withSelector(selector)
315 .withTreatment(treatmentBuilder.build())
316 .add(new ObjectiveHandler());
317
318 flowObjectiveService.forward(deviceId, objective);
319 }
320
Jonathan Hartab8b0c02015-06-10 14:06:51 -0700321 private void removeForwarding(VlanId vlanId, DeviceId deviceId, PortNumber inPort,
322 List<PortNumber> outPorts) {
Jonathan Hartea750842015-04-23 17:44:49 -0700323 TrafficSelector selector = DefaultTrafficSelector.builder()
324 .matchVlanId(vlanId)
325 .matchInPort(inPort)
326 .build();
327
Jonathan Hartab8b0c02015-06-10 14:06:51 -0700328 TrafficTreatment.Builder treatmentBuilder = DefaultTrafficTreatment.builder();
329
330 outPorts.forEach(p -> treatmentBuilder.setOutput(p));
331
Jonathan Hartea750842015-04-23 17:44:49 -0700332 ForwardingObjective objective = DefaultForwardingObjective.builder()
333 .fromApp(appId)
334 .makePermanent()
335 .withFlag(ForwardingObjective.Flag.VERSATILE)
336 .withPriority(PRIORITY)
337 .withSelector(selector)
Jonathan Hartab8b0c02015-06-10 14:06:51 -0700338 .withTreatment(treatmentBuilder.build())
Jonathan Hartea750842015-04-23 17:44:49 -0700339 .remove(new ObjectiveHandler());
340
341 flowObjectiveService.forward(deviceId, objective);
342 }
343
344 private static class ObjectiveHandler implements ObjectiveContext {
345 private static Logger log = LoggerFactory.getLogger(ObjectiveHandler.class);
346
347 @Override
348 public void onSuccess(Objective objective) {
349 log.info("Flow objective operation successful: {}", objective);
350 }
351
352 @Override
353 public void onError(Objective objective, ObjectiveError error) {
354 log.info("Flow objective operation failed: {}", objective);
355 }
356 }
Jonathan Hart408d24d2015-06-02 10:21:47 -0700357
358 /**
359 * Internal listener for device service events.
360 */
361 private class InternalDeviceListener implements DeviceListener {
362 @Override
363 public void event(DeviceEvent event) {
364 switch (event.type()) {
365 case DEVICE_ADDED:
366 case DEVICE_AVAILABILITY_CHANGED:
367 if (event.subject().id().equals(fabricDeviceId) &&
368 deviceService.isAvailable(event.subject().id())) {
369 setupDefaultFlows();
370 }
371 default:
372 break;
373 }
374 }
375 }
Jonathan Hartea750842015-04-23 17:44:49 -0700376}