blob: 19b4e2d50be908e2eaacaf9041c05991f64d23b9 [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;
alshabib6a379852016-04-28 15:52:22 -070040import org.onosproject.cordconfig.access.AccessDeviceConfig;
41import org.onosproject.cordconfig.access.AccessDeviceData;
alshabib3b1eadc2016-02-01 17:57:00 -080042import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.net.ConnectPoint;
alshabib09069c92016-02-21 14:49:51 -080045import org.onosproject.net.DeviceId;
46import org.onosproject.net.config.ConfigFactory;
47import org.onosproject.net.config.NetworkConfigEvent;
48import org.onosproject.net.config.NetworkConfigListener;
49import org.onosproject.net.config.NetworkConfigRegistry;
50import org.onosproject.net.config.basics.SubjectFactories;
alshabib3b1eadc2016-02-01 17:57:00 -080051import org.onosproject.net.flow.DefaultTrafficSelector;
52import org.onosproject.net.flow.DefaultTrafficTreatment;
53import org.onosproject.net.flow.TrafficSelector;
54import org.onosproject.net.flowobjective.DefaultForwardingObjective;
55import org.onosproject.net.flowobjective.DefaultNextObjective;
56import org.onosproject.net.flowobjective.FlowObjectiveService;
57import org.onosproject.net.flowobjective.ForwardingObjective;
58import org.onosproject.net.flowobjective.NextObjective;
59import org.onosproject.net.flowobjective.Objective;
60import org.onosproject.net.flowobjective.ObjectiveContext;
61import org.onosproject.net.flowobjective.ObjectiveError;
alshabib3b1eadc2016-02-01 17:57:00 -080062import org.onosproject.net.mcast.McastEvent;
63import org.onosproject.net.mcast.McastListener;
Jonathan Hart28271642016-02-10 16:13:54 -080064import org.onosproject.net.mcast.McastRoute;
alshabib3b1eadc2016-02-01 17:57:00 -080065import org.onosproject.net.mcast.McastRouteInfo;
66import org.onosproject.net.mcast.MulticastRouteService;
alshabib6a379852016-04-28 15:52:22 -070067
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
Jian Li46472d72016-03-09 10:52:49 -080072import javax.ws.rs.ProcessingException;
73import javax.ws.rs.client.Client;
74import javax.ws.rs.client.ClientBuilder;
75import javax.ws.rs.client.Entity;
76import javax.ws.rs.client.Invocation;
77import javax.ws.rs.client.WebTarget;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080078import javax.ws.rs.core.MediaType;
79import java.io.IOException;
Jonathan Hart28271642016-02-10 16:13:54 -080080import java.util.Dictionary;
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080081import java.util.List;
alshabib3b1eadc2016-02-01 17:57:00 -080082import java.util.Map;
alshabibfc1cb032016-02-17 15:37:56 -080083import java.util.Properties;
alshabib09069c92016-02-21 14:49:51 -080084import java.util.concurrent.ConcurrentHashMap;
Jonathan Hart28271642016-02-10 16:13:54 -080085import java.util.concurrent.atomic.AtomicBoolean;
alshabib3b1eadc2016-02-01 17:57:00 -080086
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080087import static com.google.common.base.Preconditions.checkNotNull;
alshabibfc1cb032016-02-17 15:37:56 -080088import static com.google.common.base.Strings.isNullOrEmpty;
Jonathan Hart28271642016-02-10 16:13:54 -080089import static com.google.common.net.MediaType.JSON_UTF_8;
alshabibfc1cb032016-02-17 15:37:56 -080090import static org.onlab.util.Tools.get;
alshabib3b1eadc2016-02-01 17:57:00 -080091import static org.slf4j.LoggerFactory.getLogger;
92
93/**
Jonathan Hartc3f84eb2016-02-19 12:44:36 -080094 * CORD multicast provisioning application. Operates by listening to
Jonathan Hart28271642016-02-10 16:13:54 -080095 * events on the multicast rib and provisioning groups to program multicast
alshabib3b1eadc2016-02-01 17:57:00 -080096 * flows on the dataplane.
97 */
98@Component(immediate = true)
99public class CordMcast {
100
alshabib09069c92016-02-21 14:49:51 -0800101
Jonathan Hart0212f642016-02-20 11:32:43 -0800102 private static final int DEFAULT_REST_TIMEOUT_MS = 2000;
alshabib09069c92016-02-21 14:49:51 -0800103 private static final int DEFAULT_PRIORITY = 500;
alshabib3b1eadc2016-02-01 17:57:00 -0800104 private static final short DEFAULT_MCAST_VLAN = 4000;
alshabibfc1cb032016-02-17 15:37:56 -0800105 private static final String DEFAULT_SYNC_HOST = "10.90.0.8:8181";
106 private static final String DEFAULT_USER = "karaf";
107 private static final String DEFAULT_PASSWORD = "karaf";
alshabib09069c92016-02-21 14:49:51 -0800108 private static final boolean DEFAULT_VLAN_ENABLED = true;
alshabibfc1cb032016-02-17 15:37:56 -0800109
alshabib3b1eadc2016-02-01 17:57:00 -0800110 private final Logger log = getLogger(getClass());
111
112 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
113 protected MulticastRouteService mcastService;
114
115 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib3b1eadc2016-02-01 17:57:00 -0800116 protected FlowObjectiveService flowObjectiveService;
117
118 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
119 protected CoreService coreService;
120
Jonathan Hart28271642016-02-10 16:13:54 -0800121 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
122 protected CodecService codecService;
123
124 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
125 protected ComponentConfigService componentConfigService;
126
alshabib09069c92016-02-21 14:49:51 -0800127 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
128 protected NetworkConfigRegistry networkConfig;
129
alshabib3b1eadc2016-02-01 17:57:00 -0800130 protected McastListener listener = new InternalMulticastListener();
alshabib09069c92016-02-21 14:49:51 -0800131 private InternalNetworkConfigListener configListener =
132 new InternalNetworkConfigListener();
alshabib3b1eadc2016-02-01 17:57:00 -0800133
alshabib3b1eadc2016-02-01 17:57:00 -0800134 //TODO: move this to a ec map
135 private Map<IpAddress, Integer> groups = Maps.newConcurrentMap();
136
alshabib3b1eadc2016-02-01 17:57:00 -0800137 private ApplicationId appId;
138
alshabibfc1cb032016-02-17 15:37:56 -0800139 @Property(name = "mcastVlan", intValue = DEFAULT_MCAST_VLAN,
140 label = "VLAN for multicast traffic")
141 private int mcastVlan = DEFAULT_MCAST_VLAN;
alshabib3b1eadc2016-02-01 17:57:00 -0800142
alshabib09069c92016-02-21 14:49:51 -0800143 @Property(name = "vlanEnabled", boolValue = DEFAULT_VLAN_ENABLED,
144 label = "Use vlan for multicast traffic?")
145 private boolean vlanEnabled = DEFAULT_VLAN_ENABLED;
alshabibfc1cb032016-02-17 15:37:56 -0800146
147 @Property(name = "priority", intValue = DEFAULT_PRIORITY,
148 label = "Priority for multicast rules")
alshabib3b1eadc2016-02-01 17:57:00 -0800149 private int priority = DEFAULT_PRIORITY;
150
alshabibfc1cb032016-02-17 15:37:56 -0800151 @Property(name = "syncHost", value = DEFAULT_SYNC_HOST,
Jonathan Hart28271642016-02-10 16:13:54 -0800152 label = "host:port to synchronize routes to")
alshabibfc1cb032016-02-17 15:37:56 -0800153 private String syncHost = DEFAULT_SYNC_HOST;
Jonathan Hart28271642016-02-10 16:13:54 -0800154
155 @Property(name = "username", value = DEFAULT_USER,
156 label = "Username for REST password authentication")
157 private String user = DEFAULT_USER;
158
159 @Property(name = "password", value = DEFAULT_PASSWORD,
160 label = "Password for REST authentication")
161 private String password = DEFAULT_PASSWORD;
162
163 private String fabricOnosUrl;
164
alshabib09069c92016-02-21 14:49:51 -0800165 private Map<DeviceId, AccessDeviceData> oltData = new ConcurrentHashMap<>();
166
167 private static final Class<AccessDeviceConfig> CONFIG_CLASS =
168 AccessDeviceConfig.class;
169
170 private ConfigFactory<DeviceId, AccessDeviceConfig> configFactory =
171 new ConfigFactory<DeviceId, AccessDeviceConfig>(
172 SubjectFactories.DEVICE_SUBJECT_FACTORY, CONFIG_CLASS, "accessDevice") {
173 @Override
174 public AccessDeviceConfig createConfig() {
175 return new AccessDeviceConfig();
176 }
177 };
178
alshabib3b1eadc2016-02-01 17:57:00 -0800179 @Activate
Jonathan Hart435ffc42016-02-19 10:32:05 -0800180 public void activate(ComponentContext context) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800181 componentConfigService.registerProperties(getClass());
Jonathan Hart435ffc42016-02-19 10:32:05 -0800182 modified(context);
183
alshabib3b1eadc2016-02-01 17:57:00 -0800184 appId = coreService.registerApplication("org.onosproject.cordmcast");
Jonathan Hart28271642016-02-10 16:13:54 -0800185
alshabib09069c92016-02-21 14:49:51 -0800186
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800187 clearRemoteRoutes();
188
alshabib09069c92016-02-21 14:49:51 -0800189 networkConfig.registerConfigFactory(configFactory);
190 networkConfig.addListener(configListener);
191
192 networkConfig.getSubjects(DeviceId.class, AccessDeviceConfig.class).forEach(
193 subject -> {
194 AccessDeviceConfig config = networkConfig.getConfig(subject, AccessDeviceConfig.class);
195 if (config != null) {
196 AccessDeviceData data = config.getOlt();
197 oltData.put(data.deviceId(), data);
198 }
199 }
200 );
201
202
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800203 mcastService.addListener(listener);
204
alshabib09069c92016-02-21 14:49:51 -0800205 mcastService.getRoutes().stream()
206 .map(r -> new ImmutablePair<>(r, mcastService.fetchSinks(r)))
207 .filter(pair -> pair.getRight() != null && !pair.getRight().isEmpty())
208 .forEach(pair -> pair.getRight().forEach(sink -> provisionGroup(pair.getLeft(),
Jian Li46472d72016-03-09 10:52:49 -0800209 sink)));
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800210
alshabib3b1eadc2016-02-01 17:57:00 -0800211 log.info("Started");
212 }
213
214 @Deactivate
215 public void deactivate() {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800216 componentConfigService.unregisterProperties(getClass(), false);
alshabib3b1eadc2016-02-01 17:57:00 -0800217 mcastService.removeListener(listener);
alshabib09069c92016-02-21 14:49:51 -0800218 networkConfig.unregisterConfigFactory(configFactory);
219 networkConfig.removeListener(configListener);
alshabib3b1eadc2016-02-01 17:57:00 -0800220 log.info("Stopped");
221 }
222
Jonathan Hart28271642016-02-10 16:13:54 -0800223 @Modified
224 public void modified(ComponentContext context) {
alshabibfc1cb032016-02-17 15:37:56 -0800225 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
226
alshabibfc1cb032016-02-17 15:37:56 -0800227 try {
228 String s = get(properties, "username");
229 user = isNullOrEmpty(s) ? DEFAULT_USER : s.trim();
230
231 s = get(properties, "password");
232 password = isNullOrEmpty(s) ? DEFAULT_PASSWORD : s.trim();
233
234 s = get(properties, "mcastVlan");
235 mcastVlan = isNullOrEmpty(s) ? DEFAULT_MCAST_VLAN : Short.parseShort(s.trim());
236
237 s = get(properties, "vlanEnabled");
alshabib09069c92016-02-21 14:49:51 -0800238 vlanEnabled = isNullOrEmpty(s) ? DEFAULT_VLAN_ENABLED : Boolean.parseBoolean(s.trim());
alshabibfc1cb032016-02-17 15:37:56 -0800239
240 s = get(properties, "priority");
241 priority = isNullOrEmpty(s) ? DEFAULT_PRIORITY : Integer.parseInt(s.trim());
242
Jonathan Hart0212f642016-02-20 11:32:43 -0800243 s = get(properties, "syncHost");
alshabibfc1cb032016-02-17 15:37:56 -0800244 syncHost = isNullOrEmpty(s) ? DEFAULT_SYNC_HOST : s.trim();
245 } catch (Exception e) {
246 user = DEFAULT_USER;
247 password = DEFAULT_PASSWORD;
248 syncHost = DEFAULT_SYNC_HOST;
249 mcastVlan = DEFAULT_MCAST_VLAN;
250 vlanEnabled = false;
251 priority = DEFAULT_PRIORITY;
252 }
Jonathan Hart0212f642016-02-20 11:32:43 -0800253 fabricOnosUrl = createRemoteUrl(syncHost);
254 }
255
256 private static String createRemoteUrl(String remoteHost) {
257 return "http://" + remoteHost + "/onos/v1/mcast";
Jonathan Hart28271642016-02-10 16:13:54 -0800258 }
259
alshabib3b1eadc2016-02-01 17:57:00 -0800260 private class InternalMulticastListener implements McastListener {
261 @Override
262 public void event(McastEvent event) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800263 McastRouteInfo info = event.subject();
alshabib3b1eadc2016-02-01 17:57:00 -0800264 switch (event.type()) {
265 case ROUTE_ADDED:
266 break;
267 case ROUTE_REMOVED:
268 break;
269 case SOURCE_ADDED:
270 break;
271 case SINK_ADDED:
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800272 if (!info.sink().isPresent()) {
273 log.warn("No sink given after sink added event: {}", info);
274 return;
275 }
276 provisionGroup(info.route(), info.sink().get());
alshabib3b1eadc2016-02-01 17:57:00 -0800277 break;
278 case SINK_REMOVED:
alshabibfc1cb032016-02-17 15:37:56 -0800279 unprovisionGroup(event.subject());
alshabib3b1eadc2016-02-01 17:57:00 -0800280 break;
281 default:
282 log.warn("Unknown mcast event {}", event.type());
283 }
284 }
285 }
286
alshabibfc1cb032016-02-17 15:37:56 -0800287 private void unprovisionGroup(McastRouteInfo info) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800288 if (info.sinks().isEmpty()) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800289 removeRemoteRoute(info.route());
Jonathan Hart718c0452016-02-18 15:56:22 -0800290 }
291
alshabibfc1cb032016-02-17 15:37:56 -0800292 if (!info.sink().isPresent()) {
293 log.warn("No sink given after sink removed event: {}", info);
294 return;
295 }
296 ConnectPoint loc = info.sink().get();
297
298 NextObjective next = DefaultNextObjective.builder()
299 .fromApp(appId)
300 .addTreatment(DefaultTrafficTreatment.builder().setOutput(loc.port()).build())
301 .withType(NextObjective.Type.BROADCAST)
302 .withId(groups.get(info.route().group()))
303 .removeFromExisting(new ObjectiveContext() {
304 @Override
305 public void onSuccess(Objective objective) {
306 //TODO: change to debug
307 log.info("Next Objective {} installed", objective.id());
308 }
309
310 @Override
311 public void onError(Objective objective, ObjectiveError error) {
312 //TODO: change to debug
313 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800314 objective.id(),
315 error);
alshabibfc1cb032016-02-17 15:37:56 -0800316 }
317 });
318
319 flowObjectiveService.next(loc.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800320 }
321
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800322 private void provisionGroup(McastRoute route, ConnectPoint sink) {
323 checkNotNull(route, "Route cannot be null");
324 checkNotNull(sink, "Sink cannot be null");
alshabib3b1eadc2016-02-01 17:57:00 -0800325
alshabib09069c92016-02-21 14:49:51 -0800326 AccessDeviceData oltInfo = oltData.get(sink.deviceId());
327
328 if (oltInfo == null) {
329 log.warn("Unknown OLT device : {}", sink.deviceId());
330 return;
331 }
332
Jonathan Hart28271642016-02-10 16:13:54 -0800333 final AtomicBoolean sync = new AtomicBoolean(false);
alshabib3b1eadc2016-02-01 17:57:00 -0800334
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800335 Integer nextId = groups.computeIfAbsent(route.group(), (g) -> {
Zsolt Harasztiab436262016-02-25 09:39:10 -0800336 Integer id = flowObjectiveService.allocateNextId();
alshabib3b1eadc2016-02-01 17:57:00 -0800337
alshabibfc1cb032016-02-17 15:37:56 -0800338 NextObjective next = DefaultNextObjective.builder()
339 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800340 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800341 .withType(NextObjective.Type.BROADCAST)
342 .withId(id)
343 .add(new ObjectiveContext() {
344 @Override
345 public void onSuccess(Objective objective) {
346 //TODO: change to debug
347 log.info("Next Objective {} installed", objective.id());
348 }
349
350 @Override
351 public void onError(Objective objective, ObjectiveError error) {
352 //TODO: change to debug
353 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800354 objective.id(),
355 error);
alshabibfc1cb032016-02-17 15:37:56 -0800356 }
357 });
358
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800359 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800360
361 TrafficSelector.Builder mcast = DefaultTrafficSelector.builder()
alshabib09069c92016-02-21 14:49:51 -0800362 .matchInPort(oltInfo.uplink())
alshabib3b1eadc2016-02-01 17:57:00 -0800363 .matchEthType(Ethernet.TYPE_IPV4)
alshabibfc1cb032016-02-17 15:37:56 -0800364 .matchIPDst(g.toIpPrefix());
365
alshabibfc1cb032016-02-17 15:37:56 -0800366 if (vlanEnabled) {
367 mcast.matchVlanId(VlanId.vlanId((short) mcastVlan));
368 }
alshabib3b1eadc2016-02-01 17:57:00 -0800369
alshabib3b1eadc2016-02-01 17:57:00 -0800370 ForwardingObjective fwd = DefaultForwardingObjective.builder()
371 .fromApp(appId)
372 .nextStep(id)
373 .makePermanent()
374 .withFlag(ForwardingObjective.Flag.VERSATILE)
375 .withPriority(priority)
alshabibfc1cb032016-02-17 15:37:56 -0800376 .withSelector(mcast.build())
alshabib3b1eadc2016-02-01 17:57:00 -0800377 .add(new ObjectiveContext() {
378 @Override
379 public void onSuccess(Objective objective) {
380 //TODO: change to debug
381 log.info("Forwarding objective installed {}", objective);
382 }
383
384 @Override
385 public void onError(Objective objective, ObjectiveError error) {
386 //TODO: change to debug
387 log.info("Forwarding objective failed {}", objective);
388 }
389 });
390
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800391 flowObjectiveService.forward(sink.deviceId(), fwd);
alshabib3b1eadc2016-02-01 17:57:00 -0800392
Jonathan Hart28271642016-02-10 16:13:54 -0800393 sync.set(true);
394
alshabib09069c92016-02-21 14:49:51 -0800395 return id;
alshabib3b1eadc2016-02-01 17:57:00 -0800396 });
397
alshabibfc1cb032016-02-17 15:37:56 -0800398 if (!sync.get()) {
399 NextObjective next = DefaultNextObjective.builder()
400 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800401 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800402 .withType(NextObjective.Type.BROADCAST)
403 .withId(nextId)
404 .addToExisting(new ObjectiveContext() {
405 @Override
406 public void onSuccess(Objective objective) {
407 //TODO: change to debug
408 log.info("Next Objective {} installed", objective.id());
409 }
alshabib3b1eadc2016-02-01 17:57:00 -0800410
alshabibfc1cb032016-02-17 15:37:56 -0800411 @Override
412 public void onError(Objective objective, ObjectiveError error) {
413 //TODO: change to debug
414 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800415 objective.id(),
416 error);
alshabibfc1cb032016-02-17 15:37:56 -0800417 }
418 });
alshabib3b1eadc2016-02-01 17:57:00 -0800419
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800420 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800421 }
Jonathan Hart28271642016-02-10 16:13:54 -0800422
alshabib09069c92016-02-21 14:49:51 -0800423
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800424 addRemoteRoute(route);
alshabib3b1eadc2016-02-01 17:57:00 -0800425 }
426
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800427 private void addRemoteRoute(McastRoute route) {
428 checkNotNull(route);
Jonathan Hart28271642016-02-10 16:13:54 -0800429 if (syncHost == null) {
430 log.warn("No host configured for synchronization; route will be dropped");
431 return;
432 }
433
Jonathan Hart0212f642016-02-20 11:32:43 -0800434 log.debug("Sending route {} to other ONOS {}", route, fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800435
Jian Li46472d72016-03-09 10:52:49 -0800436 Invocation.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800437
438 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800439 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800440
441 try {
Jian Li46472d72016-03-09 10:52:49 -0800442 builder.post(Entity.json(json.toString()));
443 } catch (ProcessingException e) {
Jonathan Hart0212f642016-02-20 11:32:43 -0800444 log.warn("Unable to send route to remote controller: {}", e.getMessage());
445 }
alshabib3b1eadc2016-02-01 17:57:00 -0800446 }
Jonathan Hart28271642016-02-10 16:13:54 -0800447
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800448 private void removeRemoteRoute(McastRoute route) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800449 if (syncHost == null) {
450 log.warn("No host configured for synchronization; route will be dropped");
451 return;
452 }
453
Jonathan Hart0212f642016-02-20 11:32:43 -0800454 log.debug("Removing route {} from other ONOS {}", route, fabricOnosUrl);
Jonathan Hart718c0452016-02-18 15:56:22 -0800455
Jian Li46472d72016-03-09 10:52:49 -0800456 Invocation.Builder builder = getClientBuilder(fabricOnosUrl)
457 .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
Jonathan Hart718c0452016-02-18 15:56:22 -0800458
459 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800460 .encode(route, new AbstractWebResource());
Jian Li46472d72016-03-09 10:52:49 -0800461
462 builder.method("DELETE", Entity.entity(json.asText(),
463 MediaType.APPLICATION_OCTET_STREAM));
Jonathan Hart718c0452016-02-18 15:56:22 -0800464 }
465
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800466 private void clearRemoteRoutes() {
467 if (syncHost == null) {
468 log.warn("No host configured for synchronization");
469 return;
470 }
471
Jonathan Hart0212f642016-02-20 11:32:43 -0800472 log.debug("Clearing remote multicast routes from {}", fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800473
Jian Li46472d72016-03-09 10:52:49 -0800474 Invocation.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800475 List<McastRoute> mcastRoutes = Lists.newArrayList();
Jonathan Hart0212f642016-02-20 11:32:43 -0800476
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800477 try {
Jonathan Hart0212f642016-02-20 11:32:43 -0800478 String response = builder
479 .accept(MediaType.APPLICATION_JSON_TYPE)
480 .get(String.class);
481
482 JsonCodec<McastRoute> routeCodec = codecService.getCodec(McastRoute.class);
483 ObjectMapper mapper = new ObjectMapper();
484
485
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800486 ObjectNode node = (ObjectNode) mapper.readTree(response);
487 ArrayNode list = (ArrayNode) node.path("routes");
488
489 list.forEach(n -> mcastRoutes.add(
490 routeCodec.decode((ObjectNode) n, new AbstractWebResource())));
Jonathan Hart0212f642016-02-20 11:32:43 -0800491
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800492 } catch (IOException e) {
493 log.warn("Error clearing remote routes", e);
494 }
495
496 mcastRoutes.forEach(this::removeRemoteRoute);
497 }
498
Jian Li46472d72016-03-09 10:52:49 -0800499 private Invocation.Builder getClientBuilder(String uri) {
500 ClientConfig config = new ClientConfig();
501 Client client = ClientBuilder.newClient(config);
502
503 client.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
504 client.property(ClientProperties.READ_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
505 client.register(HttpAuthenticationFeature.basic(user, password));
506
507 WebTarget wt = client.target(uri);
508 return wt.request(JSON_UTF_8.toString());
Jonathan Hart28271642016-02-10 16:13:54 -0800509 }
510
alshabib09069c92016-02-21 14:49:51 -0800511 private class InternalNetworkConfigListener implements NetworkConfigListener {
512 @Override
513 public void event(NetworkConfigEvent event) {
514 switch (event.type()) {
515
516 case CONFIG_ADDED:
517 case CONFIG_UPDATED:
518 AccessDeviceConfig config =
519 networkConfig.getConfig((DeviceId) event.subject(), CONFIG_CLASS);
520 if (config != null) {
521 oltData.put(config.getOlt().deviceId(), config.getOlt());
522 }
523
524 break;
525 case CONFIG_REGISTERED:
526 case CONFIG_UNREGISTERED:
527 break;
528 case CONFIG_REMOVED:
529 oltData.remove(event.subject());
530 break;
531 default:
532 break;
533 }
534 }
535
536 @Override
537 public boolean isRelevant(NetworkConfigEvent event) {
538 return event.configClass().equals(CONFIG_CLASS);
539 }
alshabib09069c92016-02-21 14:49:51 -0800540 }
alshabib3b1eadc2016-02-01 17:57:00 -0800541}