blob: edd7901f806a972c78cb6328d8f7ffe8d2df403f [file] [log] [blame]
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +02001/*
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 */
16
17package org.onosproject.sdxl2;
18
Carolina Fernandezad893432016-07-18 11:11:34 +020019import org.apache.felix.scr.annotations.Activate;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020020import org.apache.felix.scr.annotations.Component;
Carolina Fernandezad893432016-07-18 11:11:34 +020021import org.apache.felix.scr.annotations.Deactivate;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020022import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
pierventrebbb2e362016-06-26 19:42:48 +020025import org.onlab.packet.Ethernet;
26import org.onlab.packet.ICMP6;
27import org.onlab.packet.IPv6;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020028import org.onosproject.core.ApplicationId;
29import org.onosproject.core.CoreService;
pierventre1483e642016-06-08 18:52:29 +020030import org.onosproject.net.ConnectPoint;
pierventrebbb2e362016-06-26 19:42:48 +020031import org.onosproject.net.DeviceId;
pierventre1483e642016-06-08 18:52:29 +020032import org.onosproject.net.edge.EdgePortService;
pierventrebbb2e362016-06-26 19:42:48 +020033import org.onosproject.net.flow.DefaultTrafficSelector;
34import org.onosproject.net.flow.TrafficSelector;
pierventre1483e642016-06-08 18:52:29 +020035import org.onosproject.net.intent.IntentService;
36import org.onosproject.net.intent.Key;
pierventrebbb2e362016-06-26 19:42:48 +020037import org.onosproject.net.packet.InboundPacket;
38import org.onosproject.net.packet.PacketContext;
39import org.onosproject.net.packet.PacketProcessor;
40import org.onosproject.net.packet.PacketService;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020041import org.osgi.service.component.ComponentContext;
42import org.slf4j.Logger;
43import org.slf4j.LoggerFactory;
pierventre3849e562016-05-11 11:47:32 +020044
45import java.util.Collections;
46import java.util.Optional;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020047import java.util.Set;
Carolina Fernandezad893432016-07-18 11:11:34 +020048import java.util.stream.Collectors;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020049
50import static com.google.common.base.Preconditions.checkNotNull;
51import static com.google.common.base.Preconditions.checkState;
pierventrebbb2e362016-06-26 19:42:48 +020052import static org.onlab.packet.Ethernet.TYPE_ARP;
53import static org.onlab.packet.Ethernet.TYPE_IPV6;
54import static org.onlab.packet.ICMP6.NEIGHBOR_ADVERTISEMENT;
55import static org.onlab.packet.ICMP6.NEIGHBOR_SOLICITATION;
56import static org.onlab.packet.IPv6.PROTOCOL_ICMP6;
57import static org.onosproject.net.packet.PacketPriority.CONTROL;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020058
Carolina Fernandezad893432016-07-18 11:11:34 +020059
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020060/**
Carolina Fernandezad893432016-07-18 11:11:34 +020061 * Implements SdxL2Service.
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020062 */
63@Component(immediate = true)
64@Service
65public class SdxL2Manager implements SdxL2Service {
66
67 private static final String SDXL2_APP = "org.onosproject.sdxl2";
Carolina Fernandezad893432016-07-18 11:11:34 +020068 private static final String ERROR_ADD_VC_VLANS =
69 "Cannot create VC when CPs have different number of VLANs";
70 private static final String ERROR_ADD_VC_VLANS_CLI =
71 "\u001B[0;31mError executing command: " + ERROR_ADD_VC_VLANS + "\u001B[0;49m";
72 private static final String VC_0 = "MAC";
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020073 private static Logger log = LoggerFactory.getLogger(SdxL2Manager.class);
Carolina Fernandezad893432016-07-18 11:11:34 +020074 private static final String ERROR_ADD_VC_CPS = "Unable to find %s and %s in sdxl2=%s";
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020075 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
76 protected SdxL2Store sdxL2Store;
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020077 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
78 protected CoreService coreService;
pierventre1483e642016-06-08 18:52:29 +020079 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
80 protected IntentService intentService;
pierventre1483e642016-06-08 18:52:29 +020081 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected EdgePortService edgePortService;
pierventrebbb2e362016-06-26 19:42:48 +020083 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
84 protected PacketService packetService;
pierventrebbb2e362016-06-26 19:42:48 +020085 protected SdxL2Processor processor = new SdxL2Processor();
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020086 protected ApplicationId appId;
pierventre1483e642016-06-08 18:52:29 +020087 protected SdxL2MonitoringService monitoringManager;
Carolina Fernandezad893432016-07-18 11:11:34 +020088 protected SdxL2ArpNdpHandler arpndpHandler;
89 protected SdxL2VCService vcManager;
pierventrebbb2e362016-06-26 19:42:48 +020090
91
Carolina Fernandezad893432016-07-18 11:11:34 +020092 /**
93 * Activates the implementation of the SDX-L2 service.
94 * @param context ComponentContext object
95 */
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +020096 @Activate
97 protected void activate(ComponentContext context) {
98 appId = coreService.registerApplication(SDXL2_APP);
pierventre1483e642016-06-08 18:52:29 +020099 monitoringManager = new SdxL2MonitoringManager(appId, intentService, edgePortService);
Carolina Fernandezad893432016-07-18 11:11:34 +0200100 SdxL2ArpNdpHandler.vcType = VC_0;
101 vcManager = new SdxL2MacVCManager(appId, sdxL2Store, intentService);
pierventrebbb2e362016-06-26 19:42:48 +0200102 handleArpNdp();
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200103 log.info("Started");
104 }
105
Carolina Fernandezad893432016-07-18 11:11:34 +0200106 /**
107 * Deactivates the implementation of the SDX-L2 service.
108 */
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200109 @Deactivate
110 protected void deactivate() {
pierventre1483e642016-06-08 18:52:29 +0200111 this.cleanSdxL2();
pierventrebbb2e362016-06-26 19:42:48 +0200112 unhandleArpNdp();
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200113 log.info("Stopped");
114 }
115
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200116 @Override
117 public void createSdxL2(String sdxl2) {
pierventre3849e562016-05-11 11:47:32 +0200118
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200119 checkNotNull(sdxl2, "sdxl2 name cannot be null");
120 checkState(!sdxl2.contains(","), "sdxl2 names cannot contain commas");
121 checkState(!sdxl2.contains("|"), "sdxl2 names cannot contain pipe");
122 checkState(!sdxl2.contains("-"), "sdxl2 names cannot contain dash");
123 checkState(!sdxl2.contains(":"), "sdxl2 names cannot contain colon");
124
125 try {
126 this.sdxL2Store.putSdxL2(sdxl2);
127 } catch (SdxL2Exception e) {
pierventre3849e562016-05-11 11:47:32 +0200128 log.info(e.getMessage());
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200129 }
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200130 }
131
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200132 @Override
133 public void deleteSdxL2(String sdxl2) {
pierventre3849e562016-05-11 11:47:32 +0200134
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200135 checkNotNull(sdxl2, "sdxl2 name cannot be null");
136
137 try {
138 this.sdxL2Store.removeSdxL2(sdxl2);
139 } catch (SdxL2Exception e) {
pierventre3849e562016-05-11 11:47:32 +0200140 log.info(e.getMessage());
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200141 }
142
143 }
144
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200145 @Override
146 public Set<String> getSdxL2s() {
147 return this.sdxL2Store.getSdxL2s();
148 }
149
pierventre3849e562016-05-11 11:47:32 +0200150 @Override
151 public void addSdxL2ConnectionPoint(String sdxl2, SdxL2ConnectionPoint sdxl2cp) {
152
153 checkNotNull(sdxl2, "sdxl2 name cannot be null");
154 checkNotNull(sdxl2cp, "SdxL2ConnectionPoint cannot be null");
155
156 try {
157 this.sdxL2Store.addSdxL2ConnectionPoint(sdxl2, sdxl2cp);
158 } catch (SdxL2Exception e) {
159 log.info(e.getMessage());
160 }
161
162 }
163
pierventre3849e562016-05-11 11:47:32 +0200164 @Override
165 public Set<String> getSdxL2ConnectionPoints(Optional<String> sdxl2) {
166
167 try {
168 return this.sdxL2Store.getSdxL2ConnectionPoints(sdxl2);
169 } catch (SdxL2Exception e) {
170 log.info(e.getMessage());
171 }
172
173 return Collections.emptySet();
pierventre3849e562016-05-11 11:47:32 +0200174 }
175
pierventre3849e562016-05-11 11:47:32 +0200176 @Override
177 public void removeSdxL2ConnectionPoint(String sdxl2cp) {
178
179 checkNotNull(sdxl2cp, "SdxL2ConnectionPoint name cannot be null");
180
181 try {
182 this.sdxL2Store.removeSdxL2ConnectionPoint(sdxl2cp);
183 } catch (SdxL2Exception e) {
184 log.info(e.getMessage());
185 }
186
187 }
188
Carolina Fernandezad893432016-07-18 11:11:34 +0200189 @Override
190 public void addVC(String sdxl2, String sdxl2cplhs, String sdxl2cprhs) {
191 SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(sdxl2cplhs);
192 SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(sdxl2cprhs);
193
194 Set<String> cps = this.getSdxL2ConnectionPoints(Optional.of(sdxl2))
195 .parallelStream()
196 .filter(cptemp -> (cptemp.equals(sdxl2cplhs) || cptemp.equals(sdxl2cprhs)))
197 .collect(Collectors.toSet());
198
199 checkState(cps.size() == 2, ERROR_ADD_VC_CPS, sdxl2cplhs, sdxl2cprhs, sdxl2);
200
201 if ((lhs.vlanIds().size() != rhs.vlanIds().size()) &&
202 (lhs.vlanIds().size() > 1 || rhs.vlanIds().size() > 1)) {
203 // User can correct this issue in the CLI. Show in console and log
204 System.err.println(ERROR_ADD_VC_VLANS_CLI);
205 log.info(ERROR_ADD_VC_VLANS);
206 return;
207 }
208 this.vcManager.addVC(sdxl2, lhs, rhs);
209 }
210
211 @Override
212 public void removeVC(String vc) {
213 checkNotNull(vc, "VC name cannot be null");
214 String[] splitKeyCPs = vc.split(":");
215 checkState(splitKeyCPs.length == 2, "Bad name format $sdx:$something");
216 String[] cps = splitKeyCPs[1].split("-");
217 checkState(cps.length == 2, "Bad name format $sdx:$lhs-$rhs");
218
219 String lhsName = cps[0];
220 String rhsName = cps[1];
221 SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(lhsName);
222 SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(rhsName);
223 if (lhs == null || rhs == null) {
224 return;
225 }
226
227 Set<String> cpsByVC = this.getSdxL2ConnectionPoints(Optional.of(splitKeyCPs[0]))
228 .parallelStream()
229 .filter(tempCP -> (tempCP.equals(lhs.name()) || tempCP.equals(rhs.name())))
230 .collect(Collectors.toSet());
231
232 if (cpsByVC.size() != 2) {
233 return;
234 }
235 this.vcManager.removeVC(lhs, rhs);
236 }
237
pierventre1483e642016-06-08 18:52:29 +0200238 @Override
239 public SdxL2ConnectionPoint getSdxL2ConnectionPoint(String sdxl2cp) {
240 checkNotNull(sdxl2cp, "SdxL2ConnectionPoint name cannot be null");
241 try {
242 return this.sdxL2Store.getSdxL2ConnectionPoint(sdxl2cp);
243 } catch (SdxL2Exception e) {
244 log.info(e.getMessage());
245 }
pierventre1483e642016-06-08 18:52:29 +0200246 return null;
247 }
248
Carolina Fernandezad893432016-07-18 11:11:34 +0200249 @Override
250 public Set<String> getVirtualCircuits(Optional<String> sdxl2) {
251 return this.vcManager.getVCs(sdxl2);
252 }
253
254 @Override
255 public VirtualCircuit getVirtualCircuit(String sdxl2vc) {
256 checkNotNull(sdxl2vc, "VC name cannot be null");
257 String[] splitKeyCPs = sdxl2vc.split(":");
258 checkState(splitKeyCPs.length == 2, "Bad name format $sdx:$something");
259 String[] cps = splitKeyCPs[1].split("-");
260 checkState(cps.length == 2, "Bad name format $sdx:$lhs-$rhs");
261
262 SdxL2ConnectionPoint lhs = this.getSdxL2ConnectionPoint(cps[0]);
263 SdxL2ConnectionPoint rhs = this.getSdxL2ConnectionPoint(cps[1]);
264 VirtualCircuit vc = null;
265 if (lhs == null || rhs == null) {
266 return vc;
267 }
268
269 String result = this.vcManager.getVC(lhs, rhs);
270 if (result != null) {
271 vc = new VirtualCircuit(lhs, rhs);
272 }
273 return vc;
274 }
275
pierventre1483e642016-06-08 18:52:29 +0200276 @Override
277 public SdxL2State getIntentState(Key intentKey) {
278 checkNotNull(intentKey, "Intent key cannot be null");
279 return this.monitoringManager.getIntentState(intentKey);
280 }
281
pierventre1483e642016-06-08 18:52:29 +0200282 @Override
283 public SdxL2State getEdgePortState(ConnectPoint edgeport) {
284 checkNotNull(edgeport, "Edge port cannot be null");
285 return this.monitoringManager.getEdgePortState(edgeport);
286 }
287
288 /**
289 * Cleans the state of the Application.
290 */
291 @Override
292 public void cleanSdxL2() {
293 this.monitoringManager.cleanup();
294 }
295
pierventrebbb2e362016-06-26 19:42:48 +0200296 /**
Carolina Fernandezad893432016-07-18 11:11:34 +0200297 * Requests ARP and NDP packets to the PacketService
pierventrebbb2e362016-06-26 19:42:48 +0200298 * and registers the SDX-L2 PacketProcessor.
299 */
300 private void handleArpNdp() {
Carolina Fernandezad893432016-07-18 11:11:34 +0200301 SdxL2ArpNdpHandler.vcType = VC_0;
pierventrebbb2e362016-06-26 19:42:48 +0200302 arpndpHandler = new SdxL2ArpNdpHandler(intentService, packetService, appId);
303 packetService.addProcessor(processor, PacketProcessor.director(1));
304
305 // ARP packet
306 TrafficSelector.Builder selectorBuilder =
307 DefaultTrafficSelector.builder();
308 selectorBuilder.matchEthType(TYPE_ARP);
309 packetService.requestPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200310 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200311
312 // IPv6 Neighbor Solicitation packet.
313 selectorBuilder = DefaultTrafficSelector.builder();
314 selectorBuilder.matchEthType(TYPE_IPV6);
315 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
316 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
317 packetService.requestPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200318 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200319
320 // IPv6 Neighbor Advertisement packet.
321 selectorBuilder = DefaultTrafficSelector.builder();
322 selectorBuilder.matchEthType(TYPE_IPV6);
323 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
324 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
325 packetService.requestPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200326 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200327 }
328
329 /**
330 * Withdraws the requests for ARP/NDP packets and
331 * unregisters the SDX-L2 PacketProcessor.
332 */
333 private void unhandleArpNdp() {
334 arpndpHandler = null;
335 packetService.removeProcessor(processor);
336 processor = null;
337
338 TrafficSelector.Builder selectorBuilder =
339 DefaultTrafficSelector.builder();
340 selectorBuilder.matchEthType(TYPE_ARP);
341 packetService.cancelPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200342 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200343
344 selectorBuilder = DefaultTrafficSelector.builder();
345 selectorBuilder.matchEthType(TYPE_IPV6);
346 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
347 selectorBuilder.matchIcmpv6Type(NEIGHBOR_SOLICITATION);
348 packetService.cancelPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200349 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200350
351 selectorBuilder = DefaultTrafficSelector.builder();
352 selectorBuilder.matchEthType(TYPE_IPV6);
353 selectorBuilder.matchIPProtocol(PROTOCOL_ICMP6);
354 selectorBuilder.matchIcmpv6Type(NEIGHBOR_ADVERTISEMENT);
355 packetService.cancelPackets(selectorBuilder.build(),
Carolina Fernandezad893432016-07-18 11:11:34 +0200356 CONTROL, appId, Optional.<DeviceId>empty());
pierventrebbb2e362016-06-26 19:42:48 +0200357 }
358
359 /**
360 * Packet processor responsible for forwarding packets along their paths.
361 */
362 private class SdxL2Processor implements PacketProcessor {
363
364 /**
365 * Processes the inbound packet as specified in the given context.
366 *
367 * @param context packet processing context
368 */
369 @Override
370 public void process(PacketContext context) {
371
372 /** Stop processing if the packet has been handled, since we
373 * can't do any more to it
374 */
375 if (context.isHandled()) {
376 return;
377 }
378
379 InboundPacket pkt = context.inPacket();
380 Ethernet ethPkt = pkt.parsed();
381 if (ethPkt == null) {
382 return;
383 }
384
385 boolean handled = false;
386 if (ethPkt.getEtherType() == TYPE_ARP) {
387 //handle the arp packet.
388 handled = arpndpHandler.handlePacket(context);
389 } else if (ethPkt.getEtherType() == TYPE_IPV6) {
390 IPv6 ipv6Pkt = (IPv6) ethPkt.getPayload();
391 if (ipv6Pkt.getNextHeader() == IPv6.PROTOCOL_ICMP6) {
392 ICMP6 icmp6Pkt = (ICMP6) ipv6Pkt.getPayload();
393 if (icmp6Pkt.getIcmpType() == NEIGHBOR_SOLICITATION ||
394 icmp6Pkt.getIcmpType() == NEIGHBOR_ADVERTISEMENT) {
395 // handle ICMPv6 solicitations and advertisements
396 handled = arpndpHandler.handlePacket(context);
397 }
398 }
399 }
400
401 if (handled) {
402 context.block();
403 }
404
405 }
406 }
Pier Luigi Ventre0a023f42016-04-30 11:03:15 +0200407}