blob: 72b1a70761cab7c90413644dbad762fc4c2de1c3 [file] [log] [blame]
Pier Luigi83f919b2018-02-15 16:33:08 +01001/*
2 * Copyright 2018-present Open Networking Foundation
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.segmentrouting;
18
19import com.google.common.collect.Maps;
20import org.onosproject.event.Event;
21import org.onosproject.net.Device;
22import org.onosproject.net.DeviceId;
23import org.onosproject.net.Link;
24import org.onosproject.net.device.DeviceEvent;
25import org.onosproject.net.link.LinkEvent;
26import org.slf4j.Logger;
27import org.slf4j.LoggerFactory;
28
29import java.util.List;
30import java.util.Map;
31import java.util.stream.Collectors;
32
33/**
34 * Handler for topology events.
35 */
36class TopologyHandler {
37
38 // Logging instance
39 private static final Logger log = LoggerFactory.getLogger(TopologyHandler.class);
40 // Internal reference for SR manager and its services
41 private final SegmentRoutingManager srManager;
42
43 /**
44 * Constructs the TopologyHandler.
45 *
46 * @param srManager Segment Routing manager
47 */
48 TopologyHandler(SegmentRoutingManager srManager) {
49 this.srManager = srManager;
50 }
51
52 // Check if the link event is valid
53 private boolean isValid(LinkEvent linkEvent) {
54 Link link = linkEvent.subject();
55 // Verify if the link is valid with the link handler
56 if (!srManager.linkHandler.isLinkValid(link)) {
57 log.debug("Link {} ignored by the LinkHandler", link);
58 return false;
59 }
60 // Processing for LINK_REMOVED
61 if (linkEvent.type() == LinkEvent.Type.LINK_REMOVED) {
62 // device availability check helps to ensure that multiple link-removed
63 // events are actually treated as a single switch removed event.
64 // purgeSeenLink is necessary so we do rerouting (instead of rehashing)
65 // when switch comes back.
66 if (link.src().elementId() instanceof DeviceId
67 && !srManager.deviceService.isAvailable(link.src().deviceId())) {
68 log.debug("Link {} ignored device {} is down", link, link.src().deviceId());
69 return false;
70 }
71 if (link.dst().elementId() instanceof DeviceId
72 && !srManager.deviceService.isAvailable(link.dst().deviceId())) {
73 log.debug("Link {} ignored device {} is down", link, link.dst().deviceId());
74 return false;
75 }
76 // LINK_REMOVED is ok
77 return true;
78 }
79 // Processing for LINK_ADDED and LINK_UPDATED
80 // Verify if source device is configured
81 if (srManager.deviceConfiguration == null ||
82 !srManager.deviceConfiguration.isConfigured(link.src().deviceId())) {
83 // Source device is not configured, not valid for us
84 log.warn("Source device of this link is not configured.. "
85 + "not processing further");
86 return false;
87 }
88 // LINK_ADDED/LINK_UPDATED is ok
89 return true;
90 }
91
92 // Check if the device event is valid
93 private boolean isValid(DeviceEvent deviceEvent) {
94 Device device = deviceEvent.subject();
95 // We don't process the event if the device is available
96 return !srManager.deviceService.isAvailable(device.id());
97 }
98
99 /**
100 * Process the TOPOLOGY_CHANGE event. An initial optimization
101 * is performed to avoid the processing of not relevant events.
102 *
103 * @param reasons list of events that triggered topology change
104 */
105 void processTopologyChange(List<Event> reasons) {
106 // Store temporary in the map all the link events,
107 // events having the same subject will be automatically
108 // overridden.
109 Map<Link, LinkEvent> linkEvents = Maps.newHashMap();
110 // Store temporary in the map all the device events,
111 // events having the same subject will be automatically
112 // overridden.
113 Map<DeviceId, DeviceEvent> deviceEvents = Maps.newHashMap();
114 // Pre-process all the events putting them in the right map
115 reasons.forEach(reason -> {
116 // Relevant events for devices
117 if (reason.type() == DeviceEvent.Type.DEVICE_ADDED ||
118 reason.type() == DeviceEvent.Type.DEVICE_AVAILABILITY_CHANGED ||
119 reason.type() == DeviceEvent.Type.DEVICE_UPDATED) {
120 // Take the event and save in the map
121 DeviceEvent deviceEvent = (DeviceEvent) reason;
122 deviceEvents.put(deviceEvent.subject().id(), deviceEvent);
123 /// Relevant events for links
124 } else if (reason.type() == LinkEvent.Type.LINK_ADDED ||
125 reason.type() == LinkEvent.Type.LINK_UPDATED ||
126 reason.type() == LinkEvent.Type.LINK_REMOVED) {
127 // Take the event and store the link in the map
128 LinkEvent linkEvent = (LinkEvent) reason;
129 linkEvents.put(linkEvent.subject(), linkEvent);
130 // Other events are not relevant
131 } else {
132 log.debug("Unhandled event type: {}", reason.type());
133 }
134 });
135 // Verify if the link events are valid
136 // before sent for mcast handling
137 List<LinkEvent> toProcessLinkEvent = linkEvents.values()
138 .stream()
139 .filter(this::isValid)
140 .collect(Collectors.toList());
141 // Verify if the device events are valid
142 // before sent for mcast handling
143 List<DeviceEvent> toProcessDeviceEvent = deviceEvents.values()
144 .stream()
145 .filter(this::isValid)
146 .collect(Collectors.toList());
147
148 // Processing part of the received events
149 // We don't need to process all LINK_ADDED
150 boolean isLinkAdded = false;
151 // Iterate on link events
152 for (LinkEvent linkEvent : toProcessLinkEvent) {
153 // We process just the first one
154 if (linkEvent.type() == LinkEvent.Type.LINK_ADDED ||
155 linkEvent.type() == LinkEvent.Type.LINK_UPDATED) {
156 // Other ones are skipped
157 if (isLinkAdded) {
158 continue;
159 }
160 log.info("Processing - Event: {}", linkEvent);
161 // First time, let's process it
162 isLinkAdded = true;
163 // McastHandler, reroute all the mcast tree
164 srManager.mcastHandler.init();
165 } else {
166 log.info("Processing - Event: {}", linkEvent);
167 // We compute each time a LINK_DOWN event
168 srManager.mcastHandler.processLinkDown(linkEvent.subject());
169 }
170 }
171 // Process all the device events
172 toProcessDeviceEvent.forEach(deviceEvent -> {
173 log.info("Processing - Event: {}", deviceEvent);
174 srManager.mcastHandler.processDeviceDown(deviceEvent.subject().id());
175 });
176 }
177}