blob: 09818798a42acc86968547d7c0c115539f34c315 [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 -080080import java.util.concurrent.atomic.AtomicInteger;
81
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080082import static com.google.common.base.Preconditions.checkNotNull;
alshabibfc1cb032016-02-17 15:37:56 -080083import static com.google.common.base.Strings.isNullOrEmpty;
Jonathan Hart28271642016-02-10 16:13:54 -080084import static com.google.common.net.MediaType.JSON_UTF_8;
alshabibfc1cb032016-02-17 15:37:56 -080085import static org.onlab.util.Tools.get;
alshabib3b1eadc2016-02-01 17:57:00 -080086import static org.slf4j.LoggerFactory.getLogger;
87
88/**
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080089 * CORD multicast provisioning application. Operates by listening to
Jonathan Hart28271642016-02-10 16:13:54 -080090 * events on the multicast rib and provisioning groups to program multicast
alshabib3b1eadc2016-02-01 17:57:00 -080091 * flows on the dataplane.
92 */
93@Component(immediate = true)
94public class CordMcast {
95
alshabib09069c92016-02-21 14:49:51 -080096
Jonathan Hart0212f642016-02-20 11:32:43 -080097 private static final int DEFAULT_REST_TIMEOUT_MS = 2000;
alshabib09069c92016-02-21 14:49:51 -080098 private static final int DEFAULT_PRIORITY = 500;
alshabib3b1eadc2016-02-01 17:57:00 -080099 private static final short DEFAULT_MCAST_VLAN = 4000;
alshabibfc1cb032016-02-17 15:37:56 -0800100 private static final String DEFAULT_SYNC_HOST = "10.90.0.8:8181";
101 private static final String DEFAULT_USER = "karaf";
102 private static final String DEFAULT_PASSWORD = "karaf";
alshabib09069c92016-02-21 14:49:51 -0800103 private static final boolean DEFAULT_VLAN_ENABLED = true;
alshabibfc1cb032016-02-17 15:37:56 -0800104
alshabib3b1eadc2016-02-01 17:57:00 -0800105 private final Logger log = getLogger(getClass());
106
107 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
108 protected MulticastRouteService mcastService;
109
110 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib3b1eadc2016-02-01 17:57:00 -0800111 protected FlowObjectiveService flowObjectiveService;
112
113 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
114 protected CoreService coreService;
115
Jonathan Hart28271642016-02-10 16:13:54 -0800116 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
117 protected CodecService codecService;
118
119 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
120 protected ComponentConfigService componentConfigService;
121
alshabib09069c92016-02-21 14:49:51 -0800122 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
123 protected NetworkConfigRegistry networkConfig;
124
alshabib3b1eadc2016-02-01 17:57:00 -0800125 protected McastListener listener = new InternalMulticastListener();
alshabib09069c92016-02-21 14:49:51 -0800126 private InternalNetworkConfigListener configListener =
127 new InternalNetworkConfigListener();
alshabib3b1eadc2016-02-01 17:57:00 -0800128
alshabib3b1eadc2016-02-01 17:57:00 -0800129 //TODO: move this to a ec map
130 private Map<IpAddress, Integer> groups = Maps.newConcurrentMap();
131
132 //TODO: move this to distributed atomic long
133 private AtomicInteger channels = new AtomicInteger(0);
134
135 private ApplicationId appId;
136
alshabibfc1cb032016-02-17 15:37:56 -0800137 @Property(name = "mcastVlan", intValue = DEFAULT_MCAST_VLAN,
138 label = "VLAN for multicast traffic")
139 private int mcastVlan = DEFAULT_MCAST_VLAN;
alshabib3b1eadc2016-02-01 17:57:00 -0800140
alshabib09069c92016-02-21 14:49:51 -0800141 @Property(name = "vlanEnabled", boolValue = DEFAULT_VLAN_ENABLED,
142 label = "Use vlan for multicast traffic?")
143 private boolean vlanEnabled = DEFAULT_VLAN_ENABLED;
alshabibfc1cb032016-02-17 15:37:56 -0800144
145 @Property(name = "priority", intValue = DEFAULT_PRIORITY,
146 label = "Priority for multicast rules")
alshabib3b1eadc2016-02-01 17:57:00 -0800147 private int priority = DEFAULT_PRIORITY;
148
alshabibfc1cb032016-02-17 15:37:56 -0800149 @Property(name = "syncHost", value = DEFAULT_SYNC_HOST,
Jonathan Hart28271642016-02-10 16:13:54 -0800150 label = "host:port to synchronize routes to")
alshabibfc1cb032016-02-17 15:37:56 -0800151 private String syncHost = DEFAULT_SYNC_HOST;
Jonathan Hart28271642016-02-10 16:13:54 -0800152
153 @Property(name = "username", value = DEFAULT_USER,
154 label = "Username for REST password authentication")
155 private String user = DEFAULT_USER;
156
157 @Property(name = "password", value = DEFAULT_PASSWORD,
158 label = "Password for REST authentication")
159 private String password = DEFAULT_PASSWORD;
160
161 private String fabricOnosUrl;
162
alshabib09069c92016-02-21 14:49:51 -0800163 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
164
165 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
166 AccessDeviceConfig.class;
167
168 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
169 new ConfigFactory<DeviceId, AccessDeviceConfig>(
170 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
171 @Override
172 public AccessDeviceConfig createConfig() {
173 return new AccessDeviceConfig();
174 }
175 };
176
alshabib3b1eadc2016-02-01 17:57:00 -0800177 @Activate
Jonathan Hart435ffc42016-02-19 10:32:05 -0800178 public void activate(ComponentContext context) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800179 componentConfigService.registerProperties(getClass());
Jonathan Hart435ffc42016-02-19 10:32:05 -0800180 modified(context);
181
alshabib3b1eadc2016-02-01 17:57:00 -0800182 appId = coreService.registerApplication("org.onosproject.cordmcast");
Jonathan Hart28271642016-02-10 16:13:54 -0800183
alshabib09069c92016-02-21 14:49:51 -0800184
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800185 clearRemoteRoutes();
186
alshabib09069c92016-02-21 14:49:51 -0800187 networkConfig.registerConfigFactory(configFactory);
188 networkConfig.addListener(configListener);
189
190 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
191 subject -> {
192 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
193 if (config != null) {
194 AccessDeviceData data = config.getOlt();
195 oltData.put(data.deviceId(), data);
196 }
197 }
198 );
199
200
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800201 mcastService.addListener(listener);
202
alshabib09069c92016-02-21 14:49:51 -0800203 mcastService.getRoutes().stream()
204 .map(r -> new ImmutablePair<>(r, mcastService.fetchSinks(r)))
205 .filter(pair -> pair.getRight() != null && !pair.getRight().isEmpty())
206 .forEach(pair -> pair.getRight().forEach(sink -> provisionGroup(pair.getLeft(),
207 sink)));
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800208
alshabib3b1eadc2016-02-01 17:57:00 -0800209 log.info("Started");
210 }
211
212 @Deactivate
213 public void deactivate() {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800214 componentConfigService.unregisterProperties(getClass(), false);
alshabib3b1eadc2016-02-01 17:57:00 -0800215 mcastService.removeListener(listener);
alshabib09069c92016-02-21 14:49:51 -0800216 networkConfig.unregisterConfigFactory(configFactory);
217 networkConfig.removeListener(configListener);
alshabib3b1eadc2016-02-01 17:57:00 -0800218 log.info("Stopped");
219 }
220
Jonathan Hart28271642016-02-10 16:13:54 -0800221 @Modified
222 public void modified(ComponentContext context) {
alshabibfc1cb032016-02-17 15:37:56 -0800223 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
224
alshabibfc1cb032016-02-17 15:37:56 -0800225 try {
226 String s = get(properties, "username");
227 user = isNullOrEmpty(s) ? DEFAULT_USER : s.trim();
228
229 s = get(properties, "password");
230 password = isNullOrEmpty(s) ? DEFAULT_PASSWORD : s.trim();
231
232 s = get(properties, "mcastVlan");
233 mcastVlan = isNullOrEmpty(s) ? DEFAULT_MCAST_VLAN : Short.parseShort(s.trim());
234
235 s = get(properties, "vlanEnabled");
alshabib09069c92016-02-21 14:49:51 -0800236 vlanEnabled = isNullOrEmpty(s) ? DEFAULT_VLAN_ENABLED : Boolean.parseBoolean(s.trim());
alshabibfc1cb032016-02-17 15:37:56 -0800237
238 s = get(properties, "priority");
239 priority = isNullOrEmpty(s) ? DEFAULT_PRIORITY : Integer.parseInt(s.trim());
240
Jonathan Hart0212f642016-02-20 11:32:43 -0800241 s = get(properties, "syncHost");
alshabibfc1cb032016-02-17 15:37:56 -0800242 syncHost = isNullOrEmpty(s) ? DEFAULT_SYNC_HOST : s.trim();
243 } catch (Exception e) {
244 user = DEFAULT_USER;
245 password = DEFAULT_PASSWORD;
246 syncHost = DEFAULT_SYNC_HOST;
247 mcastVlan = DEFAULT_MCAST_VLAN;
248 vlanEnabled = false;
249 priority = DEFAULT_PRIORITY;
250 }
Jonathan Hart0212f642016-02-20 11:32:43 -0800251 fabricOnosUrl = createRemoteUrl(syncHost);
252 }
253
254 private static String createRemoteUrl(String remoteHost) {
255 return "http://" + remoteHost + "/onos/v1/mcast";
Jonathan Hart28271642016-02-10 16:13:54 -0800256 }
257
alshabib3b1eadc2016-02-01 17:57:00 -0800258 private class InternalMulticastListener implements McastListener {
259 @Override
260 public void event(McastEvent event) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800261 McastRouteInfo info = event.subject();
alshabib3b1eadc2016-02-01 17:57:00 -0800262 switch (event.type()) {
263 case ROUTE_ADDED:
264 break;
265 case ROUTE_REMOVED:
266 break;
267 case SOURCE_ADDED:
268 break;
269 case SINK_ADDED:
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800270 if (!info.sink().isPresent()) {
271 log.warn("No sink given after sink added event: {}", info);
272 return;
273 }
274 provisionGroup(info.route(), info.sink().get());
alshabib3b1eadc2016-02-01 17:57:00 -0800275 break;
276 case SINK_REMOVED:
alshabibfc1cb032016-02-17 15:37:56 -0800277 unprovisionGroup(event.subject());
alshabib3b1eadc2016-02-01 17:57:00 -0800278 break;
279 default:
280 log.warn("Unknown mcast event {}", event.type());
281 }
282 }
283 }
284
alshabibfc1cb032016-02-17 15:37:56 -0800285 private void unprovisionGroup(McastRouteInfo info) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800286 if (info.sinks().isEmpty()) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800287 removeRemoteRoute(info.route());
Jonathan Hart718c0452016-02-18 15:56:22 -0800288 }
289
alshabibfc1cb032016-02-17 15:37:56 -0800290 if (!info.sink().isPresent()) {
291 log.warn("No sink given after sink removed event: {}", info);
292 return;
293 }
294 ConnectPoint loc = info.sink().get();
295
296 NextObjective next = DefaultNextObjective.builder()
297 .fromApp(appId)
298 .addTreatment(DefaultTrafficTreatment.builder().setOutput(loc.port()).build())
299 .withType(NextObjective.Type.BROADCAST)
300 .withId(groups.get(info.route().group()))
301 .removeFromExisting(new ObjectiveContext() {
302 @Override
303 public void onSuccess(Objective objective) {
304 //TODO: change to debug
305 log.info("Next Objective {} installed", objective.id());
306 }
307
308 @Override
309 public void onError(Objective objective, ObjectiveError error) {
310 //TODO: change to debug
311 log.info("Next Objective {} failed, because {}",
312 objective.id(),
313 error);
314 }
315 });
316
317 flowObjectiveService.next(loc.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800318 }
319
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800320 private void provisionGroup(McastRoute route, ConnectPoint sink) {
321 checkNotNull(route, "Route cannot be null");
322 checkNotNull(sink, "Sink cannot be null");
alshabib3b1eadc2016-02-01 17:57:00 -0800323
alshabib09069c92016-02-21 14:49:51 -0800324 AccessDeviceData oltInfo = oltData.get(sink.deviceId());
325
326 if (oltInfo == null) {
327 log.warn("Unknown OLT device : {}", sink.deviceId());
328 return;
329 }
330
Jonathan Hart28271642016-02-10 16:13:54 -0800331 final AtomicBoolean sync = new AtomicBoolean(false);
alshabib3b1eadc2016-02-01 17:57:00 -0800332
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800333 Integer nextId = groups.computeIfAbsent(route.group(), (g) -> {
Jonathan Hart28271642016-02-10 16:13:54 -0800334 Integer id = allocateId();
alshabib3b1eadc2016-02-01 17:57:00 -0800335
alshabibfc1cb032016-02-17 15:37:56 -0800336 NextObjective next = DefaultNextObjective.builder()
337 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800338 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800339 .withType(NextObjective.Type.BROADCAST)
340 .withId(id)
341 .add(new ObjectiveContext() {
342 @Override
343 public void onSuccess(Objective objective) {
344 //TODO: change to debug
345 log.info("Next Objective {} installed", objective.id());
346 }
347
348 @Override
349 public void onError(Objective objective, ObjectiveError error) {
350 //TODO: change to debug
351 log.info("Next Objective {} failed, because {}",
352 objective.id(),
353 error);
354 }
355 });
356
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800357 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800358
359 TrafficSelector.Builder mcast = DefaultTrafficSelector.builder()
alshabib09069c92016-02-21 14:49:51 -0800360 .matchInPort(oltInfo.uplink())
alshabib3b1eadc2016-02-01 17:57:00 -0800361 .matchEthType(Ethernet.TYPE_IPV4)
alshabibfc1cb032016-02-17 15:37:56 -0800362 .matchIPDst(g.toIpPrefix());
363
alshabibfc1cb032016-02-17 15:37:56 -0800364 if (vlanEnabled) {
365 mcast.matchVlanId(VlanId.vlanId((short) mcastVlan));
366 }
alshabib3b1eadc2016-02-01 17:57:00 -0800367
alshabib3b1eadc2016-02-01 17:57:00 -0800368 ForwardingObjective fwd = DefaultForwardingObjective.builder()
369 .fromApp(appId)
370 .nextStep(id)
371 .makePermanent()
372 .withFlag(ForwardingObjective.Flag.VERSATILE)
373 .withPriority(priority)
alshabibfc1cb032016-02-17 15:37:56 -0800374 .withSelector(mcast.build())
alshabib3b1eadc2016-02-01 17:57:00 -0800375 .add(new ObjectiveContext() {
376 @Override
377 public void onSuccess(Objective objective) {
378 //TODO: change to debug
379 log.info("Forwarding objective installed {}", objective);
380 }
381
382 @Override
383 public void onError(Objective objective, ObjectiveError error) {
384 //TODO: change to debug
385 log.info("Forwarding objective failed {}", objective);
386 }
387 });
388
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800389 flowObjectiveService.forward(sink.deviceId(), fwd);
alshabib3b1eadc2016-02-01 17:57:00 -0800390
Jonathan Hart28271642016-02-10 16:13:54 -0800391 sync.set(true);
392
alshabib09069c92016-02-21 14:49:51 -0800393 return id;
alshabib3b1eadc2016-02-01 17:57:00 -0800394 });
395
alshabibfc1cb032016-02-17 15:37:56 -0800396 if (!sync.get()) {
397 NextObjective next = DefaultNextObjective.builder()
398 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800399 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800400 .withType(NextObjective.Type.BROADCAST)
401 .withId(nextId)
402 .addToExisting(new ObjectiveContext() {
403 @Override
404 public void onSuccess(Objective objective) {
405 //TODO: change to debug
406 log.info("Next Objective {} installed", objective.id());
407 }
alshabib3b1eadc2016-02-01 17:57:00 -0800408
alshabibfc1cb032016-02-17 15:37:56 -0800409 @Override
410 public void onError(Objective objective, ObjectiveError error) {
411 //TODO: change to debug
412 log.info("Next Objective {} failed, because {}",
413 objective.id(),
414 error);
415 }
416 });
alshabib3b1eadc2016-02-01 17:57:00 -0800417
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800418 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800419 }
Jonathan Hart28271642016-02-10 16:13:54 -0800420
alshabib09069c92016-02-21 14:49:51 -0800421
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800422 addRemoteRoute(route);
alshabib3b1eadc2016-02-01 17:57:00 -0800423 }
424
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800425 private void addRemoteRoute(McastRoute route) {
426 checkNotNull(route);
Jonathan Hart28271642016-02-10 16:13:54 -0800427 if (syncHost == null) {
428 log.warn("No host configured for synchronization; route will be dropped");
429 return;
430 }
431
Jonathan Hart0212f642016-02-20 11:32:43 -0800432 log.debug("Sending route {} to other ONOS {}", route, fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800433
434 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
435
436 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800437 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800438
439 try {
440 builder.post(json.toString());
441 } catch (ClientHandlerException e) {
442 log.warn("Unable to send route to remote controller: {}", e.getMessage());
443 }
alshabib3b1eadc2016-02-01 17:57:00 -0800444 }
Jonathan Hart28271642016-02-10 16:13:54 -0800445
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800446 private void removeRemoteRoute(McastRoute route) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800447 if (syncHost == null) {
448 log.warn("No host configured for synchronization; route will be dropped");
449 return;
450 }
451
Jonathan Hart0212f642016-02-20 11:32:43 -0800452 log.debug("Removing route {} from other ONOS {}", route, fabricOnosUrl);
Jonathan Hart718c0452016-02-18 15:56:22 -0800453
454 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
455
456 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800457 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800458 try {
459 builder.delete(json.toString());
460 } catch (ClientHandlerException e) {
461 log.warn("Unable to delete route from remote controller: {}", e.getMessage());
462 }
Jonathan Hart718c0452016-02-18 15:56:22 -0800463 }
464
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800465 private void clearRemoteRoutes() {
466 if (syncHost == null) {
467 log.warn("No host configured for synchronization");
468 return;
469 }
470
Jonathan Hart0212f642016-02-20 11:32:43 -0800471 log.debug("Clearing remote multicast routes from {}", fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800472
473 WebResource.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800474 List<McastRoute> mcastRoutes = Lists.newArrayList();
Jonathan Hart0212f642016-02-20 11:32:43 -0800475
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800476 try {
Jonathan Hart0212f642016-02-20 11:32:43 -0800477 String response = builder
478 .accept(MediaType.APPLICATION_JSON_TYPE)
479 .get(String.class);
480
481 JsonCodec<McastRoute> routeCodec = codecService.getCodec(McastRoute.class);
482 ObjectMapper mapper = new ObjectMapper();
483
484
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800485 ObjectNode node = (ObjectNode) mapper.readTree(response);
486 ArrayNode list = (ArrayNode) node.path("routes");
487
488 list.forEach(n -> mcastRoutes.add(
489 routeCodec.decode((ObjectNode) n, new AbstractWebResource())));
Jonathan Hart0212f642016-02-20 11:32:43 -0800490
491 } catch (ClientHandlerException e) {
492 log.warn("Unable to clear routes from remote controller: {}", e.getMessage());
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800493 } catch (IOException e) {
494 log.warn("Error clearing remote routes", e);
495 }
496
497 mcastRoutes.forEach(this::removeRemoteRoute);
498 }
499
Jonathan Hart28271642016-02-10 16:13:54 -0800500 private Integer allocateId() {
501 return channels.getAndIncrement();
502 }
503
504 private WebResource.Builder getClientBuilder(String uri) {
505 Client client = Client.create();
Jonathan Hart0212f642016-02-20 11:32:43 -0800506 client.setConnectTimeout(DEFAULT_REST_TIMEOUT_MS);
507 client.setReadTimeout(DEFAULT_REST_TIMEOUT_MS);
Jonathan Hart28271642016-02-10 16:13:54 -0800508 client.addFilter(new HTTPBasicAuthFilter(user, password));
509 WebResource resource = client.resource(uri);
510 return resource.accept(JSON_UTF_8.toString())
511 .type(JSON_UTF_8.toString());
512 }
513
alshabib09069c92016-02-21 14:49:51 -0800514 private class InternalNetworkConfigListener implements NetworkConfigListener {
515 @Override
516 public void event(NetworkConfigEvent event) {
517 switch (event.type()) {
518
519 case CONFIG_ADDED:
520 case CONFIG_UPDATED:
521 AccessDeviceConfig config =
522 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
523 if (config != null) {
524 oltData.put(config.getOlt().deviceId(), config.getOlt());
525 }
526
527 break;
528 case CONFIG_REGISTERED:
529 case CONFIG_UNREGISTERED:
530 break;
531 case CONFIG_REMOVED:
532 oltData.remove(event.subject());
533 break;
534 default:
535 break;
536 }
537 }
538
539 @Override
540 public boolean isRelevant(NetworkConfigEvent event) {
541 return event.configClass().equals(CONFIG_CLASS);
542 }
543
544
545 }
546
alshabib3b1eadc2016-02-01 17:57:00 -0800547}