blob: 661141489aa7a0dba50d15128b656d86cc52384a [file] [log] [blame]
alshabib3b1eadc2016-02-01 17:57:00 -08001/*
2 * Copyright 2015-2016 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.cordmcast;
17
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080018import com.fasterxml.jackson.databind.ObjectMapper;
19import com.fasterxml.jackson.databind.node.ArrayNode;
Jonathan Hart28271642016-02-10 16:13:54 -080020import com.fasterxml.jackson.databind.node.ObjectNode;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080021import com.google.common.collect.Lists;
alshabib3b1eadc2016-02-01 17:57:00 -080022import com.google.common.collect.Maps;
Jonathan Hart28271642016-02-10 16:13:54 -080023import com.sun.jersey.api.client.Client;
Jonathan Hart0212f642016-02-20 11:32:43 -080024import com.sun.jersey.api.client.ClientHandlerException;
Jonathan Hart28271642016-02-10 16:13:54 -080025import com.sun.jersey.api.client.WebResource;
26import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
alshabib09069c92016-02-21 14:49:51 -080027import org.apache.commons.lang3.tuple.ImmutablePair;
alshabib3b1eadc2016-02-01 17:57:00 -080028import org.apache.felix.scr.annotations.Activate;
29import org.apache.felix.scr.annotations.Component;
30import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hart28271642016-02-10 16:13:54 -080031import org.apache.felix.scr.annotations.Modified;
32import org.apache.felix.scr.annotations.Property;
alshabib3b1eadc2016-02-01 17:57:00 -080033import org.apache.felix.scr.annotations.Reference;
34import org.apache.felix.scr.annotations.ReferenceCardinality;
35import org.onlab.packet.Ethernet;
alshabib3b1eadc2016-02-01 17:57:00 -080036import org.onlab.packet.IpAddress;
37import org.onlab.packet.VlanId;
Jonathan Hart28271642016-02-10 16:13:54 -080038import org.onosproject.cfg.ComponentConfigService;
39import org.onosproject.codec.CodecService;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080040import org.onosproject.codec.JsonCodec;
alshabib3b1eadc2016-02-01 17:57:00 -080041import org.onosproject.core.ApplicationId;
42import org.onosproject.core.CoreService;
43import org.onosproject.net.ConnectPoint;
alshabib09069c92016-02-21 14:49:51 -080044import org.onosproject.net.DeviceId;
45import org.onosproject.net.config.ConfigFactory;
46import org.onosproject.net.config.NetworkConfigEvent;
47import org.onosproject.net.config.NetworkConfigListener;
48import org.onosproject.net.config.NetworkConfigRegistry;
49import org.onosproject.net.config.basics.SubjectFactories;
alshabib3b1eadc2016-02-01 17:57:00 -080050import org.onosproject.net.flow.DefaultTrafficSelector;
51import org.onosproject.net.flow.DefaultTrafficTreatment;
52import org.onosproject.net.flow.TrafficSelector;
53import org.onosproject.net.flowobjective.DefaultForwardingObjective;
54import org.onosproject.net.flowobjective.DefaultNextObjective;
55import org.onosproject.net.flowobjective.FlowObjectiveService;
56import org.onosproject.net.flowobjective.ForwardingObjective;
57import org.onosproject.net.flowobjective.NextObjective;
58import org.onosproject.net.flowobjective.Objective;
59import org.onosproject.net.flowobjective.ObjectiveContext;
60import org.onosproject.net.flowobjective.ObjectiveError;
alshabib3b1eadc2016-02-01 17:57:00 -080061import org.onosproject.net.mcast.McastEvent;
62import org.onosproject.net.mcast.McastListener;
Jonathan Hart28271642016-02-10 16:13:54 -080063import org.onosproject.net.mcast.McastRoute;
alshabib3b1eadc2016-02-01 17:57:00 -080064import org.onosproject.net.mcast.McastRouteInfo;
65import org.onosproject.net.mcast.MulticastRouteService;
alshabib09069c92016-02-21 14:49:51 -080066import org.onosproject.olt.AccessDeviceConfig;
67import org.onosproject.olt.AccessDeviceData;
Jonathan Hart28271642016-02-10 16:13:54 -080068import org.onosproject.rest.AbstractWebResource;
69import org.osgi.service.component.ComponentContext;
alshabib3b1eadc2016-02-01 17:57:00 -080070import org.slf4j.Logger;
71
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080072import javax.ws.rs.core.MediaType;
73import java.io.IOException;
Jonathan Hart28271642016-02-10 16:13:54 -080074import java.util.Dictionary;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080075import java.util.List;
alshabib3b1eadc2016-02-01 17:57:00 -080076import java.util.Map;
alshabibfc1cb032016-02-17 15:37:56 -080077import java.util.Properties;
alshabib09069c92016-02-21 14:49:51 -080078import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart28271642016-02-10 16:13:54 -080079import java.util.concurrent.atomic.AtomicBoolean;
alshabib3b1eadc2016-02-01 17:57:00 -080080
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080081import static com.google.common.base.Preconditions.checkNotNull;
alshabibfc1cb032016-02-17 15:37:56 -080082import static com.google.common.base.Strings.isNullOrEmpty;
Jonathan Hart28271642016-02-10 16:13:54 -080083import static com.google.common.net.MediaType.JSON_UTF_8;
alshabibfc1cb032016-02-17 15:37:56 -080084import static org.onlab.util.Tools.get;
alshabib3b1eadc2016-02-01 17:57:00 -080085import static org.slf4j.LoggerFactory.getLogger;
86
87/**
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080088 * CORD multicast provisioning application. Operates by listening to
Jonathan Hart28271642016-02-10 16:13:54 -080089 * events on the multicast rib and provisioning groups to program multicast
alshabib3b1eadc2016-02-01 17:57:00 -080090 * flows on the dataplane.
91 */
92@Component(immediate = true)
93public class CordMcast {
94
alshabib09069c92016-02-21 14:49:51 -080095
Jonathan Hart0212f642016-02-20 11:32:43 -080096 private static final int DEFAULT_REST_TIMEOUT_MS = 2000;
alshabib09069c92016-02-21 14:49:51 -080097 private static final int DEFAULT_PRIORITY = 500;
alshabib3b1eadc2016-02-01 17:57:00 -080098 private static final short DEFAULT_MCAST_VLAN = 4000;
alshabibfc1cb032016-02-17 15:37:56 -080099 private static final String DEFAULT_SYNC_HOST = "10.90.0.8:8181";
100 private static final String DEFAULT_USER = "karaf";
101 private static final String DEFAULT_PASSWORD = "karaf";
alshabib09069c92016-02-21 14:49:51 -0800102 private static final boolean DEFAULT_VLAN_ENABLED = true;
alshabibfc1cb032016-02-17 15:37:56 -0800103
alshabib3b1eadc2016-02-01 17:57:00 -0800104 private final Logger log = getLogger(getClass());
105
106 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
107 protected MulticastRouteService mcastService;
108
109 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib3b1eadc2016-02-01 17:57:00 -0800110 protected FlowObjectiveService flowObjectiveService;
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected CoreService coreService;
114
Jonathan Hart28271642016-02-10 16:13:54 -0800115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
116 protected CodecService codecService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected ComponentConfigService componentConfigService;
120
alshabib09069c92016-02-21 14:49:51 -0800121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected NetworkConfigRegistry networkConfig;
123
alshabib3b1eadc2016-02-01 17:57:00 -0800124 protected McastListener listener = new InternalMulticastListener();
alshabib09069c92016-02-21 14:49:51 -0800125 private InternalNetworkConfigListener configListener =
126 new InternalNetworkConfigListener();
alshabib3b1eadc2016-02-01 17:57:00 -0800127
alshabib3b1eadc2016-02-01 17:57:00 -0800128 //TODO: move this to a ec map
129 private Map<IpAddress, Integer> groups = Maps.newConcurrentMap();
130
alshabib3b1eadc2016-02-01 17:57:00 -0800131 private ApplicationId appId;
132
alshabibfc1cb032016-02-17 15:37:56 -0800133 @Property(name = "mcastVlan", intValue = DEFAULT_MCAST_VLAN,
134 label = "VLAN for multicast traffic")
135 private int mcastVlan = DEFAULT_MCAST_VLAN;
alshabib3b1eadc2016-02-01 17:57:00 -0800136
alshabib09069c92016-02-21 14:49:51 -0800137 @Property(name = "vlanEnabled", boolValue = DEFAULT_VLAN_ENABLED,
138 label = "Use vlan for multicast traffic?")
139 private boolean vlanEnabled = DEFAULT_VLAN_ENABLED;
alshabibfc1cb032016-02-17 15:37:56 -0800140
141 @Property(name = "priority", intValue = DEFAULT_PRIORITY,
142 label = "Priority for multicast rules")
alshabib3b1eadc2016-02-01 17:57:00 -0800143 private int priority = DEFAULT_PRIORITY;
144
alshabibfc1cb032016-02-17 15:37:56 -0800145 @Property(name = "syncHost", value = DEFAULT_SYNC_HOST,
Jonathan Hart28271642016-02-10 16:13:54 -0800146 label = "host:port to synchronize routes to")
alshabibfc1cb032016-02-17 15:37:56 -0800147 private String syncHost = DEFAULT_SYNC_HOST;
Jonathan Hart28271642016-02-10 16:13:54 -0800148
149 @Property(name = "username", value = DEFAULT_USER,
150 label = "Username for REST password authentication")
151 private String user = DEFAULT_USER;
152
153 @Property(name = "password", value = DEFAULT_PASSWORD,
154 label = "Password for REST authentication")
155 private String password = DEFAULT_PASSWORD;
156
157 private String fabricOnosUrl;
158
alshabib09069c92016-02-21 14:49:51 -0800159 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
160
161 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
162 AccessDeviceConfig.class;
163
164 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
165 new ConfigFactory<DeviceId, AccessDeviceConfig>(
166 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
167 @Override
168 public AccessDeviceConfig createConfig() {
169 return new AccessDeviceConfig();
170 }
171 };
172
alshabib3b1eadc2016-02-01 17:57:00 -0800173 @Activate
Jonathan Hart435ffc42016-02-19 10:32:05 -0800174 public void activate(ComponentContext context) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800175 componentConfigService.registerProperties(getClass());
Jonathan Hart435ffc42016-02-19 10:32:05 -0800176 modified(context);
177
alshabib3b1eadc2016-02-01 17:57:00 -0800178 appId = coreService.registerApplication("org.onosproject.cordmcast");
Jonathan Hart28271642016-02-10 16:13:54 -0800179
alshabib09069c92016-02-21 14:49:51 -0800180
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800181 clearRemoteRoutes();
182
alshabib09069c92016-02-21 14:49:51 -0800183 networkConfig.registerConfigFactory(configFactory);
184 networkConfig.addListener(configListener);
185
186 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
187 subject -> {
188 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
189 if (config != null) {
190 AccessDeviceData data = config.getOlt();
191 oltData.put(data.deviceId(), data);
192 }
193 }
194 );
195
196
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800197 mcastService.addListener(listener);
198
alshabib09069c92016-02-21 14:49:51 -0800199 mcastService.getRoutes().stream()
200 .map(r -> new ImmutablePair<>(r, mcastService.fetchSinks(r)))
201 .filter(pair -> pair.getRight() != null && !pair.getRight().isEmpty())
202 .forEach(pair -> pair.getRight().forEach(sink -> provisionGroup(pair.getLeft(),
203 sink)));
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800204
alshabib3b1eadc2016-02-01 17:57:00 -0800205 log.info("Started");
206 }
207
208 @Deactivate
209 public void deactivate() {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800210 componentConfigService.unregisterProperties(getClass(), false);
alshabib3b1eadc2016-02-01 17:57:00 -0800211 mcastService.removeListener(listener);
alshabib09069c92016-02-21 14:49:51 -0800212 networkConfig.unregisterConfigFactory(configFactory);
213 networkConfig.removeListener(configListener);
alshabib3b1eadc2016-02-01 17:57:00 -0800214 log.info("Stopped");
215 }
216
Jonathan Hart28271642016-02-10 16:13:54 -0800217 @Modified
218 public void modified(ComponentContext context) {
alshabibfc1cb032016-02-17 15:37:56 -0800219 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
220
alshabibfc1cb032016-02-17 15:37:56 -0800221 try {
222 String s = get(properties, "username");
223 user = isNullOrEmpty(s) ? DEFAULT_USER : s.trim();
224
225 s = get(properties, "password");
226 password = isNullOrEmpty(s) ? DEFAULT_PASSWORD : s.trim();
227
228 s = get(properties, "mcastVlan");
229 mcastVlan = isNullOrEmpty(s) ? DEFAULT_MCAST_VLAN : Short.parseShort(s.trim());
230
231 s = get(properties, "vlanEnabled");
alshabib09069c92016-02-21 14:49:51 -0800232 vlanEnabled = isNullOrEmpty(s) ? DEFAULT_VLAN_ENABLED : Boolean.parseBoolean(s.trim());
alshabibfc1cb032016-02-17 15:37:56 -0800233
234 s = get(properties, "priority");
235 priority = isNullOrEmpty(s) ? DEFAULT_PRIORITY : Integer.parseInt(s.trim());
236
Jonathan Hart0212f642016-02-20 11:32:43 -0800237 s = get(properties, "syncHost");
alshabibfc1cb032016-02-17 15:37:56 -0800238 syncHost = isNullOrEmpty(s) ? DEFAULT_SYNC_HOST : s.trim();
239 } catch (Exception e) {
240 user = DEFAULT_USER;
241 password = DEFAULT_PASSWORD;
242 syncHost = DEFAULT_SYNC_HOST;
243 mcastVlan = DEFAULT_MCAST_VLAN;
244 vlanEnabled = false;
245 priority = DEFAULT_PRIORITY;
246 }
Jonathan Hart0212f642016-02-20 11:32:43 -0800247 fabricOnosUrl = createRemoteUrl(syncHost);
248 }
249
250 private static String createRemoteUrl(String remoteHost) {
251 return "http://" + remoteHost + "/onos/v1/mcast";
Jonathan Hart28271642016-02-10 16:13:54 -0800252 }
253
alshabib3b1eadc2016-02-01 17:57:00 -0800254 private class InternalMulticastListener implements McastListener {
255 @Override
256 public void event(McastEvent event) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800257 McastRouteInfo info = event.subject();
alshabib3b1eadc2016-02-01 17:57:00 -0800258 switch (event.type()) {
259 case ROUTE_ADDED:
260 break;
261 case ROUTE_REMOVED:
262 break;
263 case SOURCE_ADDED:
264 break;
265 case SINK_ADDED:
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800266 if (!info.sink().isPresent()) {
267 log.warn("No sink given after sink added event: {}", info);
268 return;
269 }
270 provisionGroup(info.route(), info.sink().get());
alshabib3b1eadc2016-02-01 17:57:00 -0800271 break;
272 case SINK_REMOVED:
alshabibfc1cb032016-02-17 15:37:56 -0800273 unprovisionGroup(event.subject());
alshabib3b1eadc2016-02-01 17:57:00 -0800274 break;
275 default:
276 log.warn("Unknown mcast event {}", event.type());
277 }
278 }
279 }
280
alshabibfc1cb032016-02-17 15:37:56 -0800281 private void unprovisionGroup(McastRouteInfo info) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800282 if (info.sinks().isEmpty()) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800283 removeRemoteRoute(info.route());
Jonathan Hart718c0452016-02-18 15:56:22 -0800284 }
285
alshabibfc1cb032016-02-17 15:37:56 -0800286 if (!info.sink().isPresent()) {
287 log.warn("No sink given after sink removed event: {}", info);
288 return;
289 }
290 ConnectPoint loc = info.sink().get();
291
292 NextObjective next = DefaultNextObjective.builder()
293 .fromApp(appId)
294 .addTreatment(DefaultTrafficTreatment.builder().setOutput(loc.port()).build())
295 .withType(NextObjective.Type.BROADCAST)
296 .withId(groups.get(info.route().group()))
297 .removeFromExisting(new ObjectiveContext() {
298 @Override
299 public void onSuccess(Objective objective) {
300 //TODO: change to debug
301 log.info("Next Objective {} installed", objective.id());
302 }
303
304 @Override
305 public void onError(Objective objective, ObjectiveError error) {
306 //TODO: change to debug
307 log.info("Next Objective {} failed, because {}",
308 objective.id(),
309 error);
310 }
311 });
312
313 flowObjectiveService.next(loc.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800314 }
315
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800316 private void provisionGroup(McastRoute route, ConnectPoint sink) {
317 checkNotNull(route, "Route cannot be null");
318 checkNotNull(sink, "Sink cannot be null");
alshabib3b1eadc2016-02-01 17:57:00 -0800319
alshabib09069c92016-02-21 14:49:51 -0800320 AccessDeviceData oltInfo = oltData.get(sink.deviceId());
321
322 if (oltInfo == null) {
323 log.warn("Unknown OLT device : {}", sink.deviceId());
324 return;
325 }
326
Jonathan Hart28271642016-02-10 16:13:54 -0800327 final AtomicBoolean sync = new AtomicBoolean(false);
alshabib3b1eadc2016-02-01 17:57:00 -0800328
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800329 Integer nextId = groups.computeIfAbsent(route.group(), (g) -> {
Zsolt Harasztiab436262016-02-25 09:39:10 -0800330 Integer id = flowObjectiveService.allocateNextId();
alshabib3b1eadc2016-02-01 17:57:00 -0800331
alshabibfc1cb032016-02-17 15:37:56 -0800332 NextObjective next = DefaultNextObjective.builder()
333 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800334 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800335 .withType(NextObjective.Type.BROADCAST)
336 .withId(id)
337 .add(new ObjectiveContext() {
338 @Override
339 public void onSuccess(Objective objective) {
340 //TODO: change to debug
341 log.info("Next Objective {} installed", objective.id());
342 }
343
344 @Override
345 public void onError(Objective objective, ObjectiveError error) {
346 //TODO: change to debug
347 log.info("Next Objective {} failed, because {}",
348 objective.id(),
349 error);
350 }
351 });
352
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800353 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800354
355 TrafficSelector.Builder mcast = DefaultTrafficSelector.builder()
alshabib09069c92016-02-21 14:49:51 -0800356 .matchInPort(oltInfo.uplink())
alshabib3b1eadc2016-02-01 17:57:00 -0800357 .matchEthType(Ethernet.TYPE_IPV4)
alshabibfc1cb032016-02-17 15:37:56 -0800358 .matchIPDst(g.toIpPrefix());
359
alshabibfc1cb032016-02-17 15:37:56 -0800360 if (vlanEnabled) {
361 mcast.matchVlanId(VlanId.vlanId((short) mcastVlan));
362 }
alshabib3b1eadc2016-02-01 17:57:00 -0800363
alshabib3b1eadc2016-02-01 17:57:00 -0800364 ForwardingObjective fwd = DefaultForwardingObjective.builder()
365 .fromApp(appId)
366 .nextStep(id)
367 .makePermanent()
368 .withFlag(ForwardingObjective.Flag.VERSATILE)
369 .withPriority(priority)
alshabibfc1cb032016-02-17 15:37:56 -0800370 .withSelector(mcast.build())
alshabib3b1eadc2016-02-01 17:57:00 -0800371 .add(new ObjectiveContext() {
372 @Override
373 public void onSuccess(Objective objective) {
374 //TODO: change to debug
375 log.info("Forwarding objective installed {}", objective);
376 }
377
378 @Override
379 public void onError(Objective objective, ObjectiveError error) {
380 //TODO: change to debug
381 log.info("Forwarding objective failed {}", objective);
382 }
383 });
384
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800385 flowObjectiveService.forward(sink.deviceId(), fwd);
alshabib3b1eadc2016-02-01 17:57:00 -0800386
Jonathan Hart28271642016-02-10 16:13:54 -0800387 sync.set(true);
388
alshabib09069c92016-02-21 14:49:51 -0800389 return id;
alshabib3b1eadc2016-02-01 17:57:00 -0800390 });
391
alshabibfc1cb032016-02-17 15:37:56 -0800392 if (!sync.get()) {
393 NextObjective next = DefaultNextObjective.builder()
394 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800395 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800396 .withType(NextObjective.Type.BROADCAST)
397 .withId(nextId)
398 .addToExisting(new ObjectiveContext() {
399 @Override
400 public void onSuccess(Objective objective) {
401 //TODO: change to debug
402 log.info("Next Objective {} installed", objective.id());
403 }
alshabib3b1eadc2016-02-01 17:57:00 -0800404
alshabibfc1cb032016-02-17 15:37:56 -0800405 @Override
406 public void onError(Objective objective, ObjectiveError error) {
407 //TODO: change to debug
408 log.info("Next Objective {} failed, because {}",
409 objective.id(),
410 error);
411 }
412 });
alshabib3b1eadc2016-02-01 17:57:00 -0800413
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800414 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800415 }
Jonathan Hart28271642016-02-10 16:13:54 -0800416
alshabib09069c92016-02-21 14:49:51 -0800417
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800418 addRemoteRoute(route);
alshabib3b1eadc2016-02-01 17:57:00 -0800419 }
420
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800421 private void addRemoteRoute(McastRoute route) {
422 checkNotNull(route);
Jonathan Hart28271642016-02-10 16:13:54 -0800423 if (syncHost == null) {
424 log.warn("No host configured for synchronization; route will be dropped");
425 return;
426 }
427
Jonathan Hart0212f642016-02-20 11:32:43 -0800428 log.debug("Sending route {} to other ONOS {}", route, fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800429
430 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
431
432 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800433 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800434
435 try {
436 builder.post(json.toString());
437 } catch (ClientHandlerException e) {
438 log.warn("Unable to send route to remote controller: {}", e.getMessage());
439 }
alshabib3b1eadc2016-02-01 17:57:00 -0800440 }
Jonathan Hart28271642016-02-10 16:13:54 -0800441
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800442 private void removeRemoteRoute(McastRoute route) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800443 if (syncHost == null) {
444 log.warn("No host configured for synchronization; route will be dropped");
445 return;
446 }
447
Jonathan Hart0212f642016-02-20 11:32:43 -0800448 log.debug("Removing route {} from other ONOS {}", route, fabricOnosUrl);
Jonathan Hart718c0452016-02-18 15:56:22 -0800449
450 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
451
452 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800453 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800454 try {
455 builder.delete(json.toString());
456 } catch (ClientHandlerException e) {
457 log.warn("Unable to delete route from remote controller: {}", e.getMessage());
458 }
Jonathan Hart718c0452016-02-18 15:56:22 -0800459 }
460
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800461 private void clearRemoteRoutes() {
462 if (syncHost == null) {
463 log.warn("No host configured for synchronization");
464 return;
465 }
466
Jonathan Hart0212f642016-02-20 11:32:43 -0800467 log.debug("Clearing remote multicast routes from {}", fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800468
469 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800470 List<McastRoute> mcastRoutes = Lists.newArrayList();
Jonathan Hart0212f642016-02-20 11:32:43 -0800471
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800472 try {
Jonathan Hart0212f642016-02-20 11:32:43 -0800473 String response = builder
474 .accept(MediaType.APPLICATION_JSON_TYPE)
475 .get(String.class);
476
477 JsonCodec<McastRoute> routeCodec = codecService.getCodec(McastRoute.class);
478 ObjectMapper mapper = new ObjectMapper();
479
480
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800481 ObjectNode node = (ObjectNode) mapper.readTree(response);
482 ArrayNode list = (ArrayNode) node.path("routes");
483
484 list.forEach(n -> mcastRoutes.add(
485 routeCodec.decode((ObjectNode) n, new AbstractWebResource())));
Jonathan Hart0212f642016-02-20 11:32:43 -0800486
487 } catch (ClientHandlerException e) {
488 log.warn("Unable to clear routes from remote controller: {}", e.getMessage());
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800489 } catch (IOException e) {
490 log.warn("Error clearing remote routes", e);
491 }
492
493 mcastRoutes.forEach(this::removeRemoteRoute);
494 }
495
Jonathan Hart28271642016-02-10 16:13:54 -0800496 private WebResource.Builder getClientBuilder(String uri) {
497 Client client = Client.create();
Jonathan Hart0212f642016-02-20 11:32:43 -0800498 client.setConnectTimeout(DEFAULT_REST_TIMEOUT_MS);
499 client.setReadTimeout(DEFAULT_REST_TIMEOUT_MS);
Jonathan Hart28271642016-02-10 16:13:54 -0800500 client.addFilter(new HTTPBasicAuthFilter(user, password));
501 WebResource resource = client.resource(uri);
502 return resource.accept(JSON_UTF_8.toString())
503 .type(JSON_UTF_8.toString());
504 }
505
alshabib09069c92016-02-21 14:49:51 -0800506 private class InternalNetworkConfigListener implements NetworkConfigListener {
507 @Override
508 public void event(NetworkConfigEvent event) {
509 switch (event.type()) {
510
511 case CONFIG_ADDED:
512 case CONFIG_UPDATED:
513 AccessDeviceConfig config =
514 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
515 if (config != null) {
516 oltData.put(config.getOlt().deviceId(), config.getOlt());
517 }
518
519 break;
520 case CONFIG_REGISTERED:
521 case CONFIG_UNREGISTERED:
522 break;
523 case CONFIG_REMOVED:
524 oltData.remove(event.subject());
525 break;
526 default:
527 break;
528 }
529 }
530
531 @Override
532 public boolean isRelevant(NetworkConfigEvent event) {
533 return event.configClass().equals(CONFIG_CLASS);
534 }
535
536
537 }
538
alshabib3b1eadc2016-02-01 17:57:00 -0800539}