blob: 87282b46115834b0888c47dd0755d0952bcb382c [file] [log] [blame]
sanghob35a6192015-04-01 13:05:26 -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 */
16package org.onosproject.segmentrouting;
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.onlab.packet.Ethernet;
24import org.onlab.packet.IPv4;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070025import org.onlab.util.KryoNamespace;
sanghob35a6192015-04-01 13:05:26 -070026import org.onosproject.core.ApplicationId;
27import org.onosproject.core.CoreService;
28import org.onosproject.event.Event;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070029import org.onosproject.segmentrouting.grouphandler.DefaultGroupHandler;
30import org.onosproject.segmentrouting.grouphandler.NeighborSet;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070031import org.onosproject.segmentrouting.grouphandler.NeighborSetNextObjectiveStoreKey;
sanghob35a6192015-04-01 13:05:26 -070032import org.onosproject.mastership.MastershipService;
33import org.onosproject.net.Device;
34import org.onosproject.net.DeviceId;
35import org.onosproject.net.Link;
sanghob35a6192015-04-01 13:05:26 -070036import org.onosproject.net.Port;
37import org.onosproject.net.device.DeviceEvent;
38import org.onosproject.net.device.DeviceListener;
39import org.onosproject.net.device.DeviceService;
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070040import org.onosproject.net.flowobjective.FlowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070041import org.onosproject.net.group.GroupKey;
sanghob35a6192015-04-01 13:05:26 -070042import org.onosproject.net.host.HostService;
43import org.onosproject.net.intent.IntentService;
44import org.onosproject.net.link.LinkEvent;
45import org.onosproject.net.link.LinkListener;
46import org.onosproject.net.link.LinkService;
47import org.onosproject.net.packet.InboundPacket;
48import org.onosproject.net.packet.PacketContext;
49import org.onosproject.net.packet.PacketProcessor;
50import org.onosproject.net.packet.PacketService;
51import org.onosproject.net.topology.TopologyService;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -070052import org.onosproject.segmentrouting.config.NetworkConfigManager;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070053import org.onosproject.store.service.EventuallyConsistentMap;
54import org.onosproject.store.service.EventuallyConsistentMapBuilder;
55import org.onosproject.store.service.StorageService;
56import org.onosproject.store.service.WallClockTimestamp;
57import org.onosproject.store.service.WallclockClockManager;
sanghob35a6192015-04-01 13:05:26 -070058import org.slf4j.Logger;
59import org.slf4j.LoggerFactory;
60
Srikanth Vavilapalli23181912015-05-04 09:48:09 -070061import java.net.URI;
62import java.util.HashSet;
sanghob35a6192015-04-01 13:05:26 -070063import java.util.Map;
64import java.util.concurrent.ConcurrentHashMap;
65import java.util.concurrent.ConcurrentLinkedQueue;
66import java.util.concurrent.Executors;
67import java.util.concurrent.ScheduledExecutorService;
68import java.util.concurrent.ScheduledFuture;
69import java.util.concurrent.TimeUnit;
70
71@SuppressWarnings("ALL")
72@Component(immediate = true)
73public class SegmentRoutingManager {
74
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070075 private static Logger log = LoggerFactory
76 .getLogger(SegmentRoutingManager.class);
sanghob35a6192015-04-01 13:05:26 -070077
78 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
79 protected CoreService coreService;
80
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected TopologyService topologyService;
83
84 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
85 protected PacketService packetService;
86
87 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
88 protected IntentService intentService;
89
90 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
91 protected HostService hostService;
92
93 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
94 protected DeviceService deviceService;
95
96 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -070097 protected FlowObjectiveService flowObjectiveService;
sanghob35a6192015-04-01 13:05:26 -070098
99 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
100 protected LinkService linkService;
101
102 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
sanghob35a6192015-04-01 13:05:26 -0700103 protected MastershipService mastershipService;
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700104 protected ArpHandler arpHandler = null;
105 protected IcmpHandler icmpHandler = null;
106 protected IpHandler ipHandler = null;
107 protected RoutingRulePopulator routingRulePopulator = null;
sanghob35a6192015-04-01 13:05:26 -0700108 protected ApplicationId appId;
sangho666cd6d2015-04-14 16:27:13 -0700109 protected DeviceConfiguration deviceConfiguration = null;
sanghob35a6192015-04-01 13:05:26 -0700110
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700111 private DefaultRoutingHandler defaultRoutingHandler = null;
sanghob35a6192015-04-01 13:05:26 -0700112 private InternalPacketProcessor processor = new InternalPacketProcessor();
113 private InternalEventHandler eventHandler = new InternalEventHandler();
114
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700115 private ScheduledExecutorService executorService = Executors
116 .newScheduledThreadPool(1);
sanghob35a6192015-04-01 13:05:26 -0700117
118 private static ScheduledFuture<?> eventHandlerFuture = null;
119 private ConcurrentLinkedQueue<Event> eventQueue = new ConcurrentLinkedQueue<Event>();
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700120 private Map<DeviceId, DefaultGroupHandler> groupHandlerMap = new ConcurrentHashMap<DeviceId, DefaultGroupHandler>();
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700121 // Per device next objective ID store with (device id + neighbor set) as key
122 private EventuallyConsistentMap<NeighborSetNextObjectiveStoreKey,
123 Integer> nsNextObjStore = null;
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected StorageService storageService;
sanghob35a6192015-04-01 13:05:26 -0700126
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700127 private NetworkConfigManager networkConfigService = new NetworkConfigManager();;
128
sanghob35a6192015-04-01 13:05:26 -0700129 private static int numOfEvents = 0;
130 private static int numOfHandlerExecution = 0;
131 private static int numOfHandlerScheduled = 0;
132
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700133 private KryoNamespace.Builder kryoBuilder = null;
134
sanghob35a6192015-04-01 13:05:26 -0700135 @Activate
136 protected void activate() {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700137 appId = coreService
138 .registerApplication("org.onosproject.segmentrouting");
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700139
140 kryoBuilder = new KryoNamespace.Builder()
141 .register(NeighborSetNextObjectiveStoreKey.class,
142 NeighborSet.class,
143 DeviceId.class,
144 URI.class,
145 WallClockTimestamp.class,
146 org.onosproject.cluster.NodeId.class,
147 HashSet.class
148 );
149
150 log.debug("Creating EC map nsnextobjectivestore");
151 EventuallyConsistentMapBuilder<NeighborSetNextObjectiveStoreKey, Integer>
152 nsNextObjMapBuilder = storageService.eventuallyConsistentMapBuilder();
153
154 nsNextObjStore = nsNextObjMapBuilder
155 .withName("nsnextobjectivestore")
156 .withSerializer(kryoBuilder)
157 .withClockService(new WallclockClockManager<>())
158 .build();
159 log.trace("Current size {}", nsNextObjStore.size());
160
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700161 networkConfigService.init();
162 deviceConfiguration = new DeviceConfiguration(networkConfigService);
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700163 arpHandler = new ArpHandler(this);
164 icmpHandler = new IcmpHandler(this);
165 ipHandler = new IpHandler(this);
166 routingRulePopulator = new RoutingRulePopulator(this);
167 defaultRoutingHandler = new DefaultRoutingHandler(this);
168
sanghob35a6192015-04-01 13:05:26 -0700169 packetService.addProcessor(processor, PacketProcessor.ADVISOR_MAX + 2);
170 linkService.addListener(new InternalLinkListener());
sanghob35a6192015-04-01 13:05:26 -0700171 deviceService.addListener(new InternalDeviceListener());
172
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700173 for (Device device : deviceService.getDevices()) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700174 //Irrespective whether the local is a MASTER or not for this device,
175 //create group handler instance and push default TTP flow rules.
176 //Because in a multi-instance setup, instances can initiate
177 //groups for any devices. Also the default TTP rules are needed
178 //to be pushed before inserting any IP table entries for any device
179 DefaultGroupHandler groupHandler = DefaultGroupHandler
180 .createGroupHandler(device.id(), appId,
181 deviceConfiguration, linkService,
182 flowObjectiveService,
183 nsNextObjStore);
184 groupHandlerMap.put(device.id(), groupHandler);
185 defaultRoutingHandler.populateTtpRules(device.id());
sanghob35a6192015-04-01 13:05:26 -0700186 }
187
sangho20eff1d2015-04-13 15:15:58 -0700188 defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700189 log.info("Started");
190 }
191
192 @Deactivate
193 protected void deactivate() {
194 packetService.removeProcessor(processor);
195 processor = null;
196 log.info("Stopped");
197 }
198
199 /**
200 * Returns the GrouopKey object for the device and the NighborSet given.
201 *
202 * @param ns NeightborSet object for the GroupKey
203 * @return GroupKey object for the NeighborSet
204 */
205 public GroupKey getGroupKey(NeighborSet ns) {
206
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700207 for (DefaultGroupHandler groupHandler : groupHandlerMap.values()) {
sanghob35a6192015-04-01 13:05:26 -0700208 return groupHandler.getGroupKey(ns);
209 }
210
211 return null;
212 }
213
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700214 public int getNextObjectiveId(DeviceId deviceId, NeighborSet ns) {
215
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700216 if (groupHandlerMap.get(deviceId) != null) {
217 log.trace("getNextObjectiveId query in device {}", deviceId);
218 return groupHandlerMap
219 .get(deviceId).getNextObjectiveId(ns);
220 } else {
221 log.warn("getNextObjectiveId query in device {} not found", deviceId);
222 return -1;
223 }
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700224 }
225
sanghob35a6192015-04-01 13:05:26 -0700226 private class InternalPacketProcessor implements PacketProcessor {
227
228 @Override
229 public void process(PacketContext context) {
230
231 if (context.isHandled()) {
232 return;
233 }
234
235 InboundPacket pkt = context.inPacket();
236 Ethernet ethernet = pkt.parsed();
237
238 if (ethernet.getEtherType() == Ethernet.TYPE_ARP) {
239 arpHandler.processPacketIn(pkt);
240 } else if (ethernet.getEtherType() == Ethernet.TYPE_IPV4) {
241 IPv4 ipPacket = (IPv4) ethernet.getPayload();
242 ipHandler.addToPacketBuffer(ipPacket);
243 if (ipPacket.getProtocol() == IPv4.PROTOCOL_ICMP) {
244 icmpHandler.processPacketIn(pkt);
245 } else {
246 ipHandler.processPacketIn(pkt);
247 }
248 }
249 }
250 }
251
252 private class InternalLinkListener implements LinkListener {
253 @Override
254 public void event(LinkEvent event) {
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700255 if (event.type() == LinkEvent.Type.LINK_ADDED
256 || event.type() == LinkEvent.Type.LINK_REMOVED) {
sanghob35a6192015-04-01 13:05:26 -0700257 scheduleEventHandlerIfNotScheduled(event);
258 }
259 }
260 }
261
262 private class InternalDeviceListener implements DeviceListener {
263
264 @Override
265 public void event(DeviceEvent event) {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700266 /*if (mastershipService.getLocalRole(event.subject().id()) != MastershipRole.MASTER) {
sanghob35a6192015-04-01 13:05:26 -0700267 log.debug("Local role {} is not MASTER for device {}",
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700268 mastershipService.getLocalRole(event.subject().id()),
269 event.subject().id());
sanghob35a6192015-04-01 13:05:26 -0700270 return;
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700271 }*/
sanghob35a6192015-04-01 13:05:26 -0700272
273 switch (event.type()) {
274 case DEVICE_ADDED:
275 case PORT_REMOVED:
sangho20eff1d2015-04-13 15:15:58 -0700276 case DEVICE_UPDATED:
277 case DEVICE_AVAILABILITY_CHANGED:
sanghob35a6192015-04-01 13:05:26 -0700278 scheduleEventHandlerIfNotScheduled(event);
279 break;
280 default:
281 }
282 }
283 }
284
sanghob35a6192015-04-01 13:05:26 -0700285 private void scheduleEventHandlerIfNotScheduled(Event event) {
286
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700287 synchronized (eventQueue) {
288 eventQueue.add(event);
289 numOfEvents++;
290 if (eventHandlerFuture == null || eventHandlerFuture.isDone()) {
291 eventHandlerFuture = executorService
292 .schedule(eventHandler, 100, TimeUnit.MILLISECONDS);
293 numOfHandlerScheduled++;
294 }
sanghob35a6192015-04-01 13:05:26 -0700295 }
296
297 log.trace("numOfEvents {}, numOfEventHanlderScheduled {}", numOfEvents,
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700298 numOfHandlerScheduled);
sanghob35a6192015-04-01 13:05:26 -0700299
300 }
301
302 private class InternalEventHandler implements Runnable {
303
Srikanth Vavilapalli4db76e32015-04-07 15:12:32 -0700304 @Override
sanghob35a6192015-04-01 13:05:26 -0700305 public void run() {
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700306 try {
307 synchronized (eventQueue) {
308 numOfHandlerExecution++;
309 while (!eventQueue.isEmpty()) {
310 Event event = eventQueue.poll();
311 if (event.type() == LinkEvent.Type.LINK_ADDED) {
312 processLinkAdded((Link) event.subject());
313 } else if (event.type() == LinkEvent.Type.LINK_REMOVED) {
314 processLinkRemoved((Link) event.subject());
315 //} else if (event.type() == GroupEvent.Type.GROUP_ADDED) {
316 // processGroupAdded((Group) event.subject());
317 } else if (event.type() == DeviceEvent.Type.DEVICE_ADDED ||
318 event.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
319 event.type() == DeviceEvent.Type.DEVICE_UPDATED) {
320 if (deviceService.isAvailable(((Device) event.subject()).id())) {
321 processDeviceAdded((Device) event.subject());
322 }
323 } else if (event.type() == DeviceEvent.Type.PORT_REMOVED) {
324 processPortRemoved((Device) event.subject(),
325 ((DeviceEvent) event).port());
326 } else {
327 log.warn("Unhandled event type: {}", event.type());
328 }
sangho20eff1d2015-04-13 15:15:58 -0700329 }
sanghob35a6192015-04-01 13:05:26 -0700330 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700331 log.debug("numOfHandlerExecution {} numOfEventHanlderScheduled {} numOfEvents {}",
332 numOfHandlerExecution, numOfHandlerScheduled, numOfEvents);
333 } catch (Exception e) {
334 log.error("SegmentRouting event handler "
335 + "thread thrown an exception: {}", e);
sanghob35a6192015-04-01 13:05:26 -0700336 }
sanghob35a6192015-04-01 13:05:26 -0700337 }
338 }
339
sanghob35a6192015-04-01 13:05:26 -0700340 private void processLinkAdded(Link link) {
341 log.debug("A new link {} was added", link.toString());
342
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700343 //Irrespective whether the local is a MASTER or not for this device,
344 //create group handler instance and push default TTP flow rules.
345 //Because in a multi-instance setup, instances can initiate
346 //groups for any devices. Also the default TTP rules are needed
347 //to be pushed before inserting any IP table entries for any device
348 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src()
349 .deviceId());
350 if (groupHandler != null) {
351 groupHandler.linkUp(link);
352 } else {
353 Device device = deviceService.getDevice(link.src().deviceId());
354 if (device != null) {
355 log.warn("processLinkAdded: Link Added "
356 + "Notification without Device Added "
357 + "event, still handling it");
358 processDeviceAdded(device);
359 groupHandler = groupHandlerMap.get(link.src()
360 .deviceId());
sanghob35a6192015-04-01 13:05:26 -0700361 groupHandler.linkUp(link);
362 }
363 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700364
365 //defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(null);
366 log.trace("processLinkAdded: re-starting route population process");
367 defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700368 }
369
370 private void processLinkRemoved(Link link) {
371 log.debug("A link {} was removed", link.toString());
sangho834e4b02015-05-01 09:38:25 -0700372 DefaultGroupHandler groupHandler = groupHandlerMap.get(link.src().deviceId());
373 if (groupHandler != null) {
374 groupHandler.portDown(link.src().port());
375 }
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700376 //defaultRoutingHandler.populateRoutingRulesForLinkStatusChange(link);
377 log.trace("processLinkRemoved: re-starting route population process");
378 defaultRoutingHandler.startPopulationProcess();
sanghob35a6192015-04-01 13:05:26 -0700379 }
380
381 private void processDeviceAdded(Device device) {
382 log.debug("A new device with ID {} was added", device.id());
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700383 //Irrespective whether the local is a MASTER or not for this device,
384 //create group handler instance and push default TTP flow rules.
385 //Because in a multi-instance setup, instances can initiate
386 //groups for any devices. Also the default TTP rules are needed
387 //to be pushed before inserting any IP table entries for any device
388 DefaultGroupHandler dgh = DefaultGroupHandler.
389 createGroupHandler(device.id(),
390 appId,
391 deviceConfiguration,
392 linkService,
393 flowObjectiveService,
394 nsNextObjStore);
sanghob35a6192015-04-01 13:05:26 -0700395 groupHandlerMap.put(device.id(), dgh);
Srikanth Vavilapalli23181912015-05-04 09:48:09 -0700396 defaultRoutingHandler.populateTtpRules(device.id());
sanghob35a6192015-04-01 13:05:26 -0700397 }
398
399 private void processPortRemoved(Device device, Port port) {
400 log.debug("Port {} was removed", port.toString());
Srikanth Vavilapallif5b234a2015-04-21 13:04:13 -0700401 DefaultGroupHandler groupHandler = groupHandlerMap.get(device.id());
sanghob35a6192015-04-01 13:05:26 -0700402 if (groupHandler != null) {
403 groupHandler.portDown(port.number());
404 }
405 }
406}