blob: 012e7ed2b8a21ae1b2a0cfda4292126ce6f1db8d [file] [log] [blame]
alshabib3b1eadc2016-02-01 17:57:00 -08001/*
Brian O'Connoraf764bf2016-04-09 01:19:45 -07002 * Copyright 2016-present Open Networking Laboratory
alshabib3b1eadc2016-02-01 17:57:00 -08003 *
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;
alshabib09069c92016-02-21 14:49:51 -080023import org.apache.commons.lang3.tuple.ImmutablePair;
alshabib3b1eadc2016-02-01 17:57:00 -080024import org.apache.felix.scr.annotations.Activate;
25import org.apache.felix.scr.annotations.Component;
26import org.apache.felix.scr.annotations.Deactivate;
Jonathan Hart28271642016-02-10 16:13:54 -080027import org.apache.felix.scr.annotations.Modified;
28import org.apache.felix.scr.annotations.Property;
alshabib3b1eadc2016-02-01 17:57:00 -080029import org.apache.felix.scr.annotations.Reference;
30import org.apache.felix.scr.annotations.ReferenceCardinality;
Jian Li46472d72016-03-09 10:52:49 -080031import org.glassfish.jersey.client.ClientConfig;
32import org.glassfish.jersey.client.ClientProperties;
33import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
alshabib3b1eadc2016-02-01 17:57:00 -080034import org.onlab.packet.Ethernet;
alshabib3b1eadc2016-02-01 17:57:00 -080035import org.onlab.packet.IpAddress;
36import org.onlab.packet.VlanId;
Jonathan Hart28271642016-02-10 16:13:54 -080037import org.onosproject.cfg.ComponentConfigService;
38import org.onosproject.codec.CodecService;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080039import org.onosproject.codec.JsonCodec;
alshabib3b1eadc2016-02-01 17:57:00 -080040import org.onosproject.core.ApplicationId;
41import org.onosproject.core.CoreService;
42import org.onosproject.net.ConnectPoint;
alshabib09069c92016-02-21 14:49:51 -080043import org.onosproject.net.DeviceId;
44import org.onosproject.net.config.ConfigFactory;
45import org.onosproject.net.config.NetworkConfigEvent;
46import org.onosproject.net.config.NetworkConfigListener;
47import org.onosproject.net.config.NetworkConfigRegistry;
48import org.onosproject.net.config.basics.SubjectFactories;
alshabib3b1eadc2016-02-01 17:57:00 -080049import org.onosproject.net.flow.DefaultTrafficSelector;
50import org.onosproject.net.flow.DefaultTrafficTreatment;
51import org.onosproject.net.flow.TrafficSelector;
52import org.onosproject.net.flowobjective.DefaultForwardingObjective;
53import org.onosproject.net.flowobjective.DefaultNextObjective;
54import org.onosproject.net.flowobjective.FlowObjectiveService;
55import org.onosproject.net.flowobjective.ForwardingObjective;
56import org.onosproject.net.flowobjective.NextObjective;
57import org.onosproject.net.flowobjective.Objective;
58import org.onosproject.net.flowobjective.ObjectiveContext;
59import org.onosproject.net.flowobjective.ObjectiveError;
alshabib3b1eadc2016-02-01 17:57:00 -080060import org.onosproject.net.mcast.McastEvent;
61import org.onosproject.net.mcast.McastListener;
Jonathan Hart28271642016-02-10 16:13:54 -080062import org.onosproject.net.mcast.McastRoute;
alshabib3b1eadc2016-02-01 17:57:00 -080063import org.onosproject.net.mcast.McastRouteInfo;
64import org.onosproject.net.mcast.MulticastRouteService;
alshabib09069c92016-02-21 14:49:51 -080065import org.onosproject.olt.AccessDeviceConfig;
66import org.onosproject.olt.AccessDeviceData;
Jonathan Hart28271642016-02-10 16:13:54 -080067import org.onosproject.rest.AbstractWebResource;
68import org.osgi.service.component.ComponentContext;
alshabib3b1eadc2016-02-01 17:57:00 -080069import org.slf4j.Logger;
70
Jian Li46472d72016-03-09 10:52:49 -080071import javax.ws.rs.ProcessingException;
72import javax.ws.rs.client.Client;
73import javax.ws.rs.client.ClientBuilder;
74import javax.ws.rs.client.Entity;
75import javax.ws.rs.client.Invocation;
76import javax.ws.rs.client.WebTarget;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080077import javax.ws.rs.core.MediaType;
78import java.io.IOException;
Jonathan Hart28271642016-02-10 16:13:54 -080079import java.util.Dictionary;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080080import java.util.List;
alshabib3b1eadc2016-02-01 17:57:00 -080081import java.util.Map;
alshabibfc1cb032016-02-17 15:37:56 -080082import java.util.Properties;
alshabib09069c92016-02-21 14:49:51 -080083import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart28271642016-02-10 16:13:54 -080084import java.util.concurrent.atomic.AtomicBoolean;
alshabib3b1eadc2016-02-01 17:57:00 -080085
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080086import static com.google.common.base.Preconditions.checkNotNull;
alshabibfc1cb032016-02-17 15:37:56 -080087import static com.google.common.base.Strings.isNullOrEmpty;
Jonathan Hart28271642016-02-10 16:13:54 -080088import static com.google.common.net.MediaType.JSON_UTF_8;
alshabibfc1cb032016-02-17 15:37:56 -080089import static org.onlab.util.Tools.get;
alshabib3b1eadc2016-02-01 17:57:00 -080090import static org.slf4j.LoggerFactory.getLogger;
91
92/**
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080093 * CORD multicast provisioning application. Operates by listening to
Jonathan Hart28271642016-02-10 16:13:54 -080094 * events on the multicast rib and provisioning groups to program multicast
alshabib3b1eadc2016-02-01 17:57:00 -080095 * flows on the dataplane.
96 */
97@Component(immediate = true)
98public class CordMcast {
99
alshabib09069c92016-02-21 14:49:51 -0800100
Jonathan Hart0212f642016-02-20 11:32:43 -0800101 private static final int DEFAULT_REST_TIMEOUT_MS = 2000;
alshabib09069c92016-02-21 14:49:51 -0800102 private static final int DEFAULT_PRIORITY = 500;
alshabib3b1eadc2016-02-01 17:57:00 -0800103 private static final short DEFAULT_MCAST_VLAN = 4000;
alshabibfc1cb032016-02-17 15:37:56 -0800104 private static final String DEFAULT_SYNC_HOST = "10.90.0.8:8181";
105 private static final String DEFAULT_USER = "karaf";
106 private static final String DEFAULT_PASSWORD = "karaf";
alshabib09069c92016-02-21 14:49:51 -0800107 private static final boolean DEFAULT_VLAN_ENABLED = true;
alshabibfc1cb032016-02-17 15:37:56 -0800108
alshabib3b1eadc2016-02-01 17:57:00 -0800109 private final Logger log = getLogger(getClass());
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected MulticastRouteService mcastService;
113
114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib3b1eadc2016-02-01 17:57:00 -0800115 protected FlowObjectiveService flowObjectiveService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected CoreService coreService;
119
Jonathan Hart28271642016-02-10 16:13:54 -0800120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
121 protected CodecService codecService;
122
123 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
124 protected ComponentConfigService componentConfigService;
125
alshabib09069c92016-02-21 14:49:51 -0800126 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
127 protected NetworkConfigRegistry networkConfig;
128
alshabib3b1eadc2016-02-01 17:57:00 -0800129 protected McastListener listener = new InternalMulticastListener();
alshabib09069c92016-02-21 14:49:51 -0800130 private InternalNetworkConfigListener configListener =
131 new InternalNetworkConfigListener();
alshabib3b1eadc2016-02-01 17:57:00 -0800132
alshabib3b1eadc2016-02-01 17:57:00 -0800133 //TODO: move this to a ec map
134 private Map<IpAddress, Integer> groups = Maps.newConcurrentMap();
135
alshabib3b1eadc2016-02-01 17:57:00 -0800136 private ApplicationId appId;
137
alshabibfc1cb032016-02-17 15:37:56 -0800138 @Property(name = "mcastVlan", intValue = DEFAULT_MCAST_VLAN,
139 label = "VLAN for multicast traffic")
140 private int mcastVlan = DEFAULT_MCAST_VLAN;
alshabib3b1eadc2016-02-01 17:57:00 -0800141
alshabib09069c92016-02-21 14:49:51 -0800142 @Property(name = "vlanEnabled", boolValue = DEFAULT_VLAN_ENABLED,
143 label = "Use vlan for multicast traffic?")
144 private boolean vlanEnabled = DEFAULT_VLAN_ENABLED;
alshabibfc1cb032016-02-17 15:37:56 -0800145
146 @Property(name = "priority", intValue = DEFAULT_PRIORITY,
147 label = "Priority for multicast rules")
alshabib3b1eadc2016-02-01 17:57:00 -0800148 private int priority = DEFAULT_PRIORITY;
149
alshabibfc1cb032016-02-17 15:37:56 -0800150 @Property(name = "syncHost", value = DEFAULT_SYNC_HOST,
Jonathan Hart28271642016-02-10 16:13:54 -0800151 label = "host:port to synchronize routes to")
alshabibfc1cb032016-02-17 15:37:56 -0800152 private String syncHost = DEFAULT_SYNC_HOST;
Jonathan Hart28271642016-02-10 16:13:54 -0800153
154 @Property(name = "username", value = DEFAULT_USER,
155 label = "Username for REST password authentication")
156 private String user = DEFAULT_USER;
157
158 @Property(name = "password", value = DEFAULT_PASSWORD,
159 label = "Password for REST authentication")
160 private String password = DEFAULT_PASSWORD;
161
162 private String fabricOnosUrl;
163
alshabib09069c92016-02-21 14:49:51 -0800164 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
165
166 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
167 AccessDeviceConfig.class;
168
169 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
170 new ConfigFactory<DeviceId, AccessDeviceConfig>(
171 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
172 @Override
173 public AccessDeviceConfig createConfig() {
174 return new AccessDeviceConfig();
175 }
176 };
177
alshabib3b1eadc2016-02-01 17:57:00 -0800178 @Activate
Jonathan Hart435ffc42016-02-19 10:32:05 -0800179 public void activate(ComponentContext context) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800180 componentConfigService.registerProperties(getClass());
Jonathan Hart435ffc42016-02-19 10:32:05 -0800181 modified(context);
182
alshabib3b1eadc2016-02-01 17:57:00 -0800183 appId = coreService.registerApplication("org.onosproject.cordmcast");
Jonathan Hart28271642016-02-10 16:13:54 -0800184
alshabib09069c92016-02-21 14:49:51 -0800185
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800186 clearRemoteRoutes();
187
alshabib09069c92016-02-21 14:49:51 -0800188 networkConfig.registerConfigFactory(configFactory);
189 networkConfig.addListener(configListener);
190
191 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
192 subject -> {
193 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
194 if (config != null) {
195 AccessDeviceData data = config.getOlt();
196 oltData.put(data.deviceId(), data);
197 }
198 }
199 );
200
201
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800202 mcastService.addListener(listener);
203
alshabib09069c92016-02-21 14:49:51 -0800204 mcastService.getRoutes().stream()
205 .map(r -> new ImmutablePair<>(r, mcastService.fetchSinks(r)))
206 .filter(pair -> pair.getRight() != null && !pair.getRight().isEmpty())
207 .forEach(pair -> pair.getRight().forEach(sink -> provisionGroup(pair.getLeft(),
Jian Li46472d72016-03-09 10:52:49 -0800208 sink)));
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800209
alshabib3b1eadc2016-02-01 17:57:00 -0800210 log.info("Started");
211 }
212
213 @Deactivate
214 public void deactivate() {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800215 componentConfigService.unregisterProperties(getClass(), false);
alshabib3b1eadc2016-02-01 17:57:00 -0800216 mcastService.removeListener(listener);
alshabib09069c92016-02-21 14:49:51 -0800217 networkConfig.unregisterConfigFactory(configFactory);
218 networkConfig.removeListener(configListener);
alshabib3b1eadc2016-02-01 17:57:00 -0800219 log.info("Stopped");
220 }
221
Jonathan Hart28271642016-02-10 16:13:54 -0800222 @Modified
223 public void modified(ComponentContext context) {
alshabibfc1cb032016-02-17 15:37:56 -0800224 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
225
alshabibfc1cb032016-02-17 15:37:56 -0800226 try {
227 String s = get(properties, "username");
228 user = isNullOrEmpty(s) ? DEFAULT_USER : s.trim();
229
230 s = get(properties, "password");
231 password = isNullOrEmpty(s) ? DEFAULT_PASSWORD : s.trim();
232
233 s = get(properties, "mcastVlan");
234 mcastVlan = isNullOrEmpty(s) ? DEFAULT_MCAST_VLAN : Short.parseShort(s.trim());
235
236 s = get(properties, "vlanEnabled");
alshabib09069c92016-02-21 14:49:51 -0800237 vlanEnabled = isNullOrEmpty(s) ? DEFAULT_VLAN_ENABLED : Boolean.parseBoolean(s.trim());
alshabibfc1cb032016-02-17 15:37:56 -0800238
239 s = get(properties, "priority");
240 priority = isNullOrEmpty(s) ? DEFAULT_PRIORITY : Integer.parseInt(s.trim());
241
Jonathan Hart0212f642016-02-20 11:32:43 -0800242 s = get(properties, "syncHost");
alshabibfc1cb032016-02-17 15:37:56 -0800243 syncHost = isNullOrEmpty(s) ? DEFAULT_SYNC_HOST : s.trim();
244 } catch (Exception e) {
245 user = DEFAULT_USER;
246 password = DEFAULT_PASSWORD;
247 syncHost = DEFAULT_SYNC_HOST;
248 mcastVlan = DEFAULT_MCAST_VLAN;
249 vlanEnabled = false;
250 priority = DEFAULT_PRIORITY;
251 }
Jonathan Hart0212f642016-02-20 11:32:43 -0800252 fabricOnosUrl = createRemoteUrl(syncHost);
253 }
254
255 private static String createRemoteUrl(String remoteHost) {
256 return "http://" + remoteHost + "/onos/v1/mcast";
Jonathan Hart28271642016-02-10 16:13:54 -0800257 }
258
alshabib3b1eadc2016-02-01 17:57:00 -0800259 private class InternalMulticastListener implements McastListener {
260 @Override
261 public void event(McastEvent event) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800262 McastRouteInfo info = event.subject();
alshabib3b1eadc2016-02-01 17:57:00 -0800263 switch (event.type()) {
264 case ROUTE_ADDED:
265 break;
266 case ROUTE_REMOVED:
267 break;
268 case SOURCE_ADDED:
269 break;
270 case SINK_ADDED:
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800271 if (!info.sink().isPresent()) {
272 log.warn("No sink given after sink added event: {}", info);
273 return;
274 }
275 provisionGroup(info.route(), info.sink().get());
alshabib3b1eadc2016-02-01 17:57:00 -0800276 break;
277 case SINK_REMOVED:
alshabibfc1cb032016-02-17 15:37:56 -0800278 unprovisionGroup(event.subject());
alshabib3b1eadc2016-02-01 17:57:00 -0800279 break;
280 default:
281 log.warn("Unknown mcast event {}", event.type());
282 }
283 }
284 }
285
alshabibfc1cb032016-02-17 15:37:56 -0800286 private void unprovisionGroup(McastRouteInfo info) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800287 if (info.sinks().isEmpty()) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800288 removeRemoteRoute(info.route());
Jonathan Hart718c0452016-02-18 15:56:22 -0800289 }
290
alshabibfc1cb032016-02-17 15:37:56 -0800291 if (!info.sink().isPresent()) {
292 log.warn("No sink given after sink removed event: {}", info);
293 return;
294 }
295 ConnectPoint loc = info.sink().get();
296
297 NextObjective next = DefaultNextObjective.builder()
298 .fromApp(appId)
299 .addTreatment(DefaultTrafficTreatment.builder().setOutput(loc.port()).build())
300 .withType(NextObjective.Type.BROADCAST)
301 .withId(groups.get(info.route().group()))
302 .removeFromExisting(new ObjectiveContext() {
303 @Override
304 public void onSuccess(Objective objective) {
305 //TODO: change to debug
306 log.info("Next Objective {} installed", objective.id());
307 }
308
309 @Override
310 public void onError(Objective objective, ObjectiveError error) {
311 //TODO: change to debug
312 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800313 objective.id(),
314 error);
alshabibfc1cb032016-02-17 15:37:56 -0800315 }
316 });
317
318 flowObjectiveService.next(loc.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800319 }
320
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800321 private void provisionGroup(McastRoute route, ConnectPoint sink) {
322 checkNotNull(route, "Route cannot be null");
323 checkNotNull(sink, "Sink cannot be null");
alshabib3b1eadc2016-02-01 17:57:00 -0800324
alshabib09069c92016-02-21 14:49:51 -0800325 AccessDeviceData oltInfo = oltData.get(sink.deviceId());
326
327 if (oltInfo == null) {
328 log.warn("Unknown OLT device : {}", sink.deviceId());
329 return;
330 }
331
Jonathan Hart28271642016-02-10 16:13:54 -0800332 final AtomicBoolean sync = new AtomicBoolean(false);
alshabib3b1eadc2016-02-01 17:57:00 -0800333
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800334 Integer nextId = groups.computeIfAbsent(route.group(), (g) -> {
Zsolt Harasztiab436262016-02-25 09:39:10 -0800335 Integer id = flowObjectiveService.allocateNextId();
alshabib3b1eadc2016-02-01 17:57:00 -0800336
alshabibfc1cb032016-02-17 15:37:56 -0800337 NextObjective next = DefaultNextObjective.builder()
338 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800339 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800340 .withType(NextObjective.Type.BROADCAST)
341 .withId(id)
342 .add(new ObjectiveContext() {
343 @Override
344 public void onSuccess(Objective objective) {
345 //TODO: change to debug
346 log.info("Next Objective {} installed", objective.id());
347 }
348
349 @Override
350 public void onError(Objective objective, ObjectiveError error) {
351 //TODO: change to debug
352 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800353 objective.id(),
354 error);
alshabibfc1cb032016-02-17 15:37:56 -0800355 }
356 });
357
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800358 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800359
360 TrafficSelector.Builder mcast = DefaultTrafficSelector.builder()
alshabib09069c92016-02-21 14:49:51 -0800361 .matchInPort(oltInfo.uplink())
alshabib3b1eadc2016-02-01 17:57:00 -0800362 .matchEthType(Ethernet.TYPE_IPV4)
alshabibfc1cb032016-02-17 15:37:56 -0800363 .matchIPDst(g.toIpPrefix());
364
alshabibfc1cb032016-02-17 15:37:56 -0800365 if (vlanEnabled) {
366 mcast.matchVlanId(VlanId.vlanId((short) mcastVlan));
367 }
alshabib3b1eadc2016-02-01 17:57:00 -0800368
alshabib3b1eadc2016-02-01 17:57:00 -0800369 ForwardingObjective fwd = DefaultForwardingObjective.builder()
370 .fromApp(appId)
371 .nextStep(id)
372 .makePermanent()
373 .withFlag(ForwardingObjective.Flag.VERSATILE)
374 .withPriority(priority)
alshabibfc1cb032016-02-17 15:37:56 -0800375 .withSelector(mcast.build())
alshabib3b1eadc2016-02-01 17:57:00 -0800376 .add(new ObjectiveContext() {
377 @Override
378 public void onSuccess(Objective objective) {
379 //TODO: change to debug
380 log.info("Forwarding objective installed {}", objective);
381 }
382
383 @Override
384 public void onError(Objective objective, ObjectiveError error) {
385 //TODO: change to debug
386 log.info("Forwarding objective failed {}", objective);
387 }
388 });
389
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800390 flowObjectiveService.forward(sink.deviceId(), fwd);
alshabib3b1eadc2016-02-01 17:57:00 -0800391
Jonathan Hart28271642016-02-10 16:13:54 -0800392 sync.set(true);
393
alshabib09069c92016-02-21 14:49:51 -0800394 return id;
alshabib3b1eadc2016-02-01 17:57:00 -0800395 });
396
alshabibfc1cb032016-02-17 15:37:56 -0800397 if (!sync.get()) {
398 NextObjective next = DefaultNextObjective.builder()
399 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800400 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800401 .withType(NextObjective.Type.BROADCAST)
402 .withId(nextId)
403 .addToExisting(new ObjectiveContext() {
404 @Override
405 public void onSuccess(Objective objective) {
406 //TODO: change to debug
407 log.info("Next Objective {} installed", objective.id());
408 }
alshabib3b1eadc2016-02-01 17:57:00 -0800409
alshabibfc1cb032016-02-17 15:37:56 -0800410 @Override
411 public void onError(Objective objective, ObjectiveError error) {
412 //TODO: change to debug
413 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800414 objective.id(),
415 error);
alshabibfc1cb032016-02-17 15:37:56 -0800416 }
417 });
alshabib3b1eadc2016-02-01 17:57:00 -0800418
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800419 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800420 }
Jonathan Hart28271642016-02-10 16:13:54 -0800421
alshabib09069c92016-02-21 14:49:51 -0800422
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800423 addRemoteRoute(route);
alshabib3b1eadc2016-02-01 17:57:00 -0800424 }
425
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800426 private void addRemoteRoute(McastRoute route) {
427 checkNotNull(route);
Jonathan Hart28271642016-02-10 16:13:54 -0800428 if (syncHost == null) {
429 log.warn("No host configured for synchronization; route will be dropped");
430 return;
431 }
432
Jonathan Hart0212f642016-02-20 11:32:43 -0800433 log.debug("Sending route {} to other ONOS {}", route, fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800434
Jian Li46472d72016-03-09 10:52:49 -0800435 Invocation.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800436
437 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800438 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800439
440 try {
Jian Li46472d72016-03-09 10:52:49 -0800441 builder.post(Entity.json(json.toString()));
442 } catch (ProcessingException e) {
Jonathan Hart0212f642016-02-20 11:32:43 -0800443 log.warn("Unable to send route to remote controller: {}", e.getMessage());
444 }
alshabib3b1eadc2016-02-01 17:57:00 -0800445 }
Jonathan Hart28271642016-02-10 16:13:54 -0800446
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800447 private void removeRemoteRoute(McastRoute route) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800448 if (syncHost == null) {
449 log.warn("No host configured for synchronization; route will be dropped");
450 return;
451 }
452
Jonathan Hart0212f642016-02-20 11:32:43 -0800453 log.debug("Removing route {} from other ONOS {}", route, fabricOnosUrl);
Jonathan Hart718c0452016-02-18 15:56:22 -0800454
Jian Li46472d72016-03-09 10:52:49 -0800455 Invocation.Builder builder = getClientBuilder(fabricOnosUrl)
456 .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
Jonathan Hart718c0452016-02-18 15:56:22 -0800457
458 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800459 .encode(route, new AbstractWebResource());
Jian Li46472d72016-03-09 10:52:49 -0800460
461 builder.method("DELETE", Entity.entity(json.asText(),
462 MediaType.APPLICATION_OCTET_STREAM));
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
Jian Li46472d72016-03-09 10:52:49 -0800473 Invocation.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
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800491 } catch (IOException e) {
492 log.warn("Error clearing remote routes", e);
493 }
494
495 mcastRoutes.forEach(this::removeRemoteRoute);
496 }
497
Jian Li46472d72016-03-09 10:52:49 -0800498 private Invocation.Builder getClientBuilder(String uri) {
499 ClientConfig config = new ClientConfig();
500 Client client = ClientBuilder.newClient(config);
501
502 client.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
503 client.property(ClientProperties.READ_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
504 client.register(HttpAuthenticationFeature.basic(user, password));
505
506 WebTarget wt = client.target(uri);
507 return wt.request(JSON_UTF_8.toString());
Jonathan Hart28271642016-02-10 16:13:54 -0800508 }
509
alshabib09069c92016-02-21 14:49:51 -0800510 private class InternalNetworkConfigListener implements NetworkConfigListener {
511 @Override
512 public void event(NetworkConfigEvent event) {
513 switch (event.type()) {
514
515 case CONFIG_ADDED:
516 case CONFIG_UPDATED:
517 AccessDeviceConfig config =
518 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
519 if (config != null) {
520 oltData.put(config.getOlt().deviceId(), config.getOlt());
521 }
522
523 break;
524 case CONFIG_REGISTERED:
525 case CONFIG_UNREGISTERED:
526 break;
527 case CONFIG_REMOVED:
528 oltData.remove(event.subject());
529 break;
530 default:
531 break;
532 }
533 }
534
535 @Override
536 public boolean isRelevant(NetworkConfigEvent event) {
537 return event.configClass().equals(CONFIG_CLASS);
538 }
alshabib09069c92016-02-21 14:49:51 -0800539 }
alshabib3b1eadc2016-02-01 17:57:00 -0800540}