blob: 6ed8b4b3c7ea2f3a2b6b9c7f561695bde8379227 [file] [log] [blame]
Andrea Campanella545edb42018-03-20 16:37:29 -07001/*
2 * Copyright 2015-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 */
16package org.onosproject.mcast.impl;
17
18import com.google.common.collect.ImmutableSet;
19import org.apache.felix.scr.annotations.Activate;
20import org.apache.felix.scr.annotations.Component;
21import org.apache.felix.scr.annotations.Deactivate;
22import org.apache.felix.scr.annotations.Reference;
23import org.apache.felix.scr.annotations.ReferenceCardinality;
24import org.apache.felix.scr.annotations.Service;
25import org.onlab.packet.IpAddress;
26import org.onosproject.event.AbstractListenerManager;
27import org.onosproject.mcast.api.McastEvent;
28import org.onosproject.mcast.api.McastListener;
29import org.onosproject.mcast.api.McastRoute;
30import org.onosproject.mcast.api.McastRouteData;
31import org.onosproject.mcast.api.McastStore;
32import org.onosproject.mcast.api.McastStoreDelegate;
33import org.onosproject.mcast.api.MulticastRouteService;
34import org.onosproject.net.ConnectPoint;
35import org.onosproject.net.Host;
36import org.onosproject.net.HostId;
37import org.onosproject.net.host.HostEvent;
38import org.onosproject.net.host.HostListener;
39import org.onosproject.net.host.HostService;
40import org.slf4j.Logger;
41
42import java.util.HashSet;
43import java.util.Optional;
44import java.util.Set;
45
46import static com.google.common.base.Preconditions.checkNotNull;
47import static org.slf4j.LoggerFactory.getLogger;
48
49/**
50 * An implementation of a multicast route table.
51 */
52@Component(immediate = true)
53@Service
54public class MulticastRouteManager
55 extends AbstractListenerManager<McastEvent, McastListener>
56 implements MulticastRouteService {
57 //TODO: add MulticastRouteAdminService
58
59 private Logger log = getLogger(getClass());
60
61 private final McastStoreDelegate delegate = new InternalMcastStoreDelegate();
62
63 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
64 protected McastStore store;
65
66 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
67 protected HostService hostService;
68
69 private HostListener hostListener = new InternalHostListener();
70
71 @Activate
72 public void activate() {
73 hostService.addListener(hostListener);
74 eventDispatcher.addSink(McastEvent.class, listenerRegistry);
75 store.setDelegate(delegate);
76 log.info("Started");
77 }
78
79 @Deactivate
80 public void deactivate() {
81 hostService.removeListener(hostListener);
82 store.unsetDelegate(delegate);
83 eventDispatcher.removeSink(McastEvent.class);
84 log.info("Stopped");
85 }
86
87 @Override
88 public void add(McastRoute route) {
89 checkNotNull(route, "Route cannot be null");
90 store.storeRoute(route);
91 }
92
93 @Override
94 public void remove(McastRoute route) {
95 checkNotNull(route, "Route cannot be null");
96 if (checkRoute(route)) {
97 store.removeRoute(route);
98 }
99 }
100
101 @Override
102 public Set<McastRoute> getRoutes() {
103 return store.getRoutes();
104 }
105
106 @Override
107 public Optional<McastRoute> getRoute(IpAddress groupIp, IpAddress sourceIp) {
108 return store.getRoutes().stream().filter(route ->
109 route.group().equals(groupIp) &&
110 route.source().isPresent() &&
111 route.source().get().equals(sourceIp)).findAny();
112 }
113
114 @Override
115 public void addSources(McastRoute route, Set<ConnectPoint> connectPoints) {
116 checkNotNull(route, "Route cannot be null");
117 checkNotNull(connectPoints, "Source cannot be null");
118 if (checkRoute(route)) {
119 store.storeSources(route, connectPoints);
120 }
121 }
122
123 @Override
124 public void removeSources(McastRoute route) {
125 checkNotNull(route, "Route cannot be null");
126 if (checkRoute(route)) {
127 store.removeSources(route);
128 }
129 }
130
131 @Override
132 public void removeSources(McastRoute route, Set<ConnectPoint> sources) {
133 checkNotNull(route, "Route cannot be null");
134 checkNotNull(sources, "Source cannot be null");
135 if (checkRoute(route)) {
136 store.removeSources(route, sources);
137 }
138 }
139
140 @Override
141 public void addSink(McastRoute route, HostId hostId) {
142 if (checkRoute(route)) {
143 Set<ConnectPoint> sinks = new HashSet<>();
144 Host host = hostService.getHost(hostId);
145 if (host != null) {
146 host.locations().forEach(hostLocation -> sinks.add(
147 ConnectPoint.deviceConnectPoint(hostLocation.deviceId() + "/" + hostLocation.port())));
148 }
149 store.addSink(route, hostId, sinks);
150 }
151
152 }
153
154 @Override
155 public void addSink(McastRoute route, Set<ConnectPoint> sinks) {
156 checkNotNull(route, "Route cannot be null");
157 checkNotNull(sinks, "Sinks cannot be null");
158 if (checkRoute(route)) {
159 store.addSinks(route, sinks);
160 }
161 }
162
163 @Override
164 public void removeSinks(McastRoute route) {
165 checkNotNull(route, "Route cannot be null");
166 if (checkRoute(route)) {
167 store.removeSinks(route);
168 }
169 }
170
171 @Override
172 public void removeSink(McastRoute route, HostId hostId) {
173 checkNotNull(route, "Route cannot be null");
174 checkNotNull(hostId, "Host cannot be null");
175 if (checkRoute(route)) {
176 store.removeSink(route, hostId);
177 }
178 }
179
180 @Override
181 public void removeSinks(McastRoute route, HostId hostId, Set<ConnectPoint> connectPoints) {
182 checkNotNull(route, "Route cannot be null");
183 if (checkRoute(route)) {
184 store.removeSinks(route, hostId, connectPoints);
185 }
186
187 }
188
189 @Override
190 public void removeSinks(McastRoute route, Set<ConnectPoint> connectPoints) {
191 checkNotNull(route, "Route cannot be null");
192 if (checkRoute(route)) {
193 store.removeSinks(route, HostId.NONE, connectPoints);
194 }
195 }
196
197 @Override
198 public McastRouteData routeData(McastRoute route) {
199 checkNotNull(route, "Route cannot be null");
200 return checkRoute(route) ? store.getRouteData(route) : null;
201 }
202
203 @Override
204 public Set<ConnectPoint> sources(McastRoute route) {
205 checkNotNull(route, "Route cannot be null");
206 return checkRoute(route) ? store.sourcesFor(route) : ImmutableSet.of();
207 }
208
209 @Override
210 public Set<ConnectPoint> sinks(McastRoute route) {
211 checkNotNull(route, "Route cannot be null");
212 return checkRoute(route) ? store.sinksFor(route) : ImmutableSet.of();
213 }
214
215 @Override
216 public Set<ConnectPoint> sinks(McastRoute route, HostId hostId) {
217 checkNotNull(route, "Route cannot be null");
218 return checkRoute(route) ? store.sinksFor(route, hostId) : ImmutableSet.of();
219 }
220
221 @Override
222 public Set<ConnectPoint> nonHostSinks(McastRoute route) {
223 checkNotNull(route, "Route cannot be null");
224 return checkRoute(route) ? store.sinksFor(route, HostId.NONE) : ImmutableSet.of();
225 }
226
227 private class InternalMcastStoreDelegate implements McastStoreDelegate {
228 @Override
229 public void notify(McastEvent event) {
230 log.debug("Event: {}", event);
231 post(event);
232 }
233 }
234
235 private boolean checkRoute(McastRoute route) {
236 if (store.getRoutes().contains(route)) {
237 return true;
238 } else {
239 log.warn("Route {} is not present in the store, please add it", route);
240 }
241 return false;
242 }
243
244 private class InternalHostListener implements HostListener {
245
246 @Override
247 public void event(HostEvent event) {
248 HostId hostId = event.subject().id();
249 Set<ConnectPoint> sinks = new HashSet<>();
250 log.debug("{} event", event);
251 //FIXME ther must be a better way
252 event.subject().locations().forEach(hostLocation -> sinks.add(
253 ConnectPoint.deviceConnectPoint(hostLocation.deviceId() + "/" + hostLocation.port())));
254 switch (event.type()) {
255 case HOST_ADDED:
256 case HOST_UPDATED:
257 case HOST_MOVED:
258 if ((event.prevSubject() == null && event.subject() != null)
259 || (event.prevSubject().locations().size() > event.subject().locations().size())) {
260 store.getRoutes().stream().filter(mcastRoute -> {
261 return store.getRouteData(mcastRoute).sinks().get(hostId) != null;
262 }).forEach(route -> {
263 store.removeSinks(route, hostId, sinks);
264 });
265 } else if (event.prevSubject().locations().size() < event.subject().locations().size()) {
266 store.getRoutes().stream().filter(mcastRoute -> {
267 return store.getRouteData(mcastRoute).sinks().get(hostId) != null;
268 }).forEach(route -> {
269 store.addSink(route, hostId, sinks);
270 });
271 }
272 break;
273 case HOST_REMOVED:
274 store.getRoutes().stream().filter(mcastRoute -> {
275 return store.getRouteData(mcastRoute).sinks().get(hostId) != null;
276 }).forEach(route -> {
277 store.removeSink(route, hostId);
278 });
279 default:
280 log.debug("Host event {} not supported", event.type());
281 }
282 }
283 }
284}