blob: 13500dd2f4f8ff3cbc06be49db27db87fb874ddf [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;
Jonathan Hart0c194962016-05-23 17:08:15 -070040import org.onosproject.cordconfig.access.AccessAgentData;
alshabib6a379852016-04-28 15:52:22 -070041import org.onosproject.cordconfig.access.AccessDeviceData;
Jonathan Hart0c194962016-05-23 17:08:15 -070042import org.onosproject.cordconfig.access.CordConfigService;
alshabib3b1eadc2016-02-01 17:57:00 -080043import org.onosproject.core.ApplicationId;
44import org.onosproject.core.CoreService;
45import org.onosproject.net.ConnectPoint;
46import org.onosproject.net.flow.DefaultTrafficSelector;
47import org.onosproject.net.flow.DefaultTrafficTreatment;
48import org.onosproject.net.flow.TrafficSelector;
49import org.onosproject.net.flowobjective.DefaultForwardingObjective;
50import org.onosproject.net.flowobjective.DefaultNextObjective;
51import org.onosproject.net.flowobjective.FlowObjectiveService;
52import org.onosproject.net.flowobjective.ForwardingObjective;
53import org.onosproject.net.flowobjective.NextObjective;
54import org.onosproject.net.flowobjective.Objective;
55import org.onosproject.net.flowobjective.ObjectiveContext;
56import org.onosproject.net.flowobjective.ObjectiveError;
alshabib3b1eadc2016-02-01 17:57:00 -080057import org.onosproject.net.mcast.McastEvent;
58import org.onosproject.net.mcast.McastListener;
Jonathan Hart28271642016-02-10 16:13:54 -080059import org.onosproject.net.mcast.McastRoute;
alshabib3b1eadc2016-02-01 17:57:00 -080060import org.onosproject.net.mcast.McastRouteInfo;
61import org.onosproject.net.mcast.MulticastRouteService;
Jonathan Hart28271642016-02-10 16:13:54 -080062import org.onosproject.rest.AbstractWebResource;
63import org.osgi.service.component.ComponentContext;
alshabib3b1eadc2016-02-01 17:57:00 -080064import org.slf4j.Logger;
65
Jian Li46472d72016-03-09 10:52:49 -080066import javax.ws.rs.ProcessingException;
67import javax.ws.rs.client.Client;
68import javax.ws.rs.client.ClientBuilder;
69import javax.ws.rs.client.Entity;
70import javax.ws.rs.client.Invocation;
71import javax.ws.rs.client.WebTarget;
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;
Jonathan Hart0c194962016-05-23 17:08:15 -070077import java.util.Optional;
alshabibfc1cb032016-02-17 15:37:56 -080078import java.util.Properties;
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
Jonathan Hart0c194962016-05-23 17:08:15 -070095 private final Logger log = getLogger(getClass());
alshabib09069c92016-02-21 14:49:51 -080096
Jonathan Hart0c194962016-05-23 17:08:15 -070097 private static final int DEFAULT_REST_TIMEOUT_MS = 1000;
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 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
106 protected MulticastRouteService mcastService;
107
108 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
alshabib3b1eadc2016-02-01 17:57:00 -0800109 protected FlowObjectiveService flowObjectiveService;
110
111 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
112 protected CoreService coreService;
113
Jonathan Hart28271642016-02-10 16:13:54 -0800114 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
115 protected CodecService codecService;
116
117 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
118 protected ComponentConfigService componentConfigService;
119
alshabib09069c92016-02-21 14:49:51 -0800120 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Jonathan Hart0c194962016-05-23 17:08:15 -0700121 protected CordConfigService cordConfigService;
alshabib09069c92016-02-21 14:49:51 -0800122
alshabib3b1eadc2016-02-01 17:57:00 -0800123 protected McastListener listener = new InternalMulticastListener();
124
alshabib3b1eadc2016-02-01 17:57:00 -0800125 //TODO: move this to a ec map
126 private Map<IpAddress, Integer> groups = Maps.newConcurrentMap();
127
alshabib3b1eadc2016-02-01 17:57:00 -0800128 private ApplicationId appId;
129
alshabibfc1cb032016-02-17 15:37:56 -0800130 @Property(name = "mcastVlan", intValue = DEFAULT_MCAST_VLAN,
131 label = "VLAN for multicast traffic")
132 private int mcastVlan = DEFAULT_MCAST_VLAN;
alshabib3b1eadc2016-02-01 17:57:00 -0800133
alshabib09069c92016-02-21 14:49:51 -0800134 @Property(name = "vlanEnabled", boolValue = DEFAULT_VLAN_ENABLED,
135 label = "Use vlan for multicast traffic?")
136 private boolean vlanEnabled = DEFAULT_VLAN_ENABLED;
alshabibfc1cb032016-02-17 15:37:56 -0800137
138 @Property(name = "priority", intValue = DEFAULT_PRIORITY,
139 label = "Priority for multicast rules")
alshabib3b1eadc2016-02-01 17:57:00 -0800140 private int priority = DEFAULT_PRIORITY;
141
alshabibfc1cb032016-02-17 15:37:56 -0800142 @Property(name = "syncHost", value = DEFAULT_SYNC_HOST,
Jonathan Hart28271642016-02-10 16:13:54 -0800143 label = "host:port to synchronize routes to")
alshabibfc1cb032016-02-17 15:37:56 -0800144 private String syncHost = DEFAULT_SYNC_HOST;
Jonathan Hart28271642016-02-10 16:13:54 -0800145
146 @Property(name = "username", value = DEFAULT_USER,
147 label = "Username for REST password authentication")
148 private String user = DEFAULT_USER;
149
150 @Property(name = "password", value = DEFAULT_PASSWORD,
151 label = "Password for REST authentication")
152 private String password = DEFAULT_PASSWORD;
153
154 private String fabricOnosUrl;
155
alshabib3b1eadc2016-02-01 17:57:00 -0800156 @Activate
Jonathan Hart435ffc42016-02-19 10:32:05 -0800157 public void activate(ComponentContext context) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800158 componentConfigService.registerProperties(getClass());
Jonathan Hart435ffc42016-02-19 10:32:05 -0800159 modified(context);
160
alshabib3b1eadc2016-02-01 17:57:00 -0800161 appId = coreService.registerApplication("org.onosproject.cordmcast");
Jonathan Hart28271642016-02-10 16:13:54 -0800162
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800163 clearRemoteRoutes();
164
165 mcastService.addListener(listener);
166
alshabib09069c92016-02-21 14:49:51 -0800167 mcastService.getRoutes().stream()
168 .map(r -> new ImmutablePair<>(r, mcastService.fetchSinks(r)))
169 .filter(pair -> pair.getRight() != null && !pair.getRight().isEmpty())
170 .forEach(pair -> pair.getRight().forEach(sink -> provisionGroup(pair.getLeft(),
Jian Li46472d72016-03-09 10:52:49 -0800171 sink)));
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800172
alshabib3b1eadc2016-02-01 17:57:00 -0800173 log.info("Started");
174 }
175
176 @Deactivate
177 public void deactivate() {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800178 componentConfigService.unregisterProperties(getClass(), false);
alshabib3b1eadc2016-02-01 17:57:00 -0800179 mcastService.removeListener(listener);
180 log.info("Stopped");
181 }
182
Jonathan Hart28271642016-02-10 16:13:54 -0800183 @Modified
184 public void modified(ComponentContext context) {
alshabibfc1cb032016-02-17 15:37:56 -0800185 Dictionary<?, ?> properties = context != null ? context.getProperties() : new Properties();
186
alshabibfc1cb032016-02-17 15:37:56 -0800187 try {
188 String s = get(properties, "username");
189 user = isNullOrEmpty(s) ? DEFAULT_USER : s.trim();
190
191 s = get(properties, "password");
192 password = isNullOrEmpty(s) ? DEFAULT_PASSWORD : s.trim();
193
194 s = get(properties, "mcastVlan");
195 mcastVlan = isNullOrEmpty(s) ? DEFAULT_MCAST_VLAN : Short.parseShort(s.trim());
196
197 s = get(properties, "vlanEnabled");
alshabib09069c92016-02-21 14:49:51 -0800198 vlanEnabled = isNullOrEmpty(s) ? DEFAULT_VLAN_ENABLED : Boolean.parseBoolean(s.trim());
alshabibfc1cb032016-02-17 15:37:56 -0800199
200 s = get(properties, "priority");
201 priority = isNullOrEmpty(s) ? DEFAULT_PRIORITY : Integer.parseInt(s.trim());
202
Jonathan Hart0212f642016-02-20 11:32:43 -0800203 s = get(properties, "syncHost");
alshabibfc1cb032016-02-17 15:37:56 -0800204 syncHost = isNullOrEmpty(s) ? DEFAULT_SYNC_HOST : s.trim();
205 } catch (Exception e) {
206 user = DEFAULT_USER;
207 password = DEFAULT_PASSWORD;
208 syncHost = DEFAULT_SYNC_HOST;
209 mcastVlan = DEFAULT_MCAST_VLAN;
210 vlanEnabled = false;
211 priority = DEFAULT_PRIORITY;
212 }
Jonathan Hart0212f642016-02-20 11:32:43 -0800213 fabricOnosUrl = createRemoteUrl(syncHost);
214 }
215
216 private static String createRemoteUrl(String remoteHost) {
217 return "http://" + remoteHost + "/onos/v1/mcast";
Jonathan Hart28271642016-02-10 16:13:54 -0800218 }
219
alshabib3b1eadc2016-02-01 17:57:00 -0800220 private class InternalMulticastListener implements McastListener {
221 @Override
222 public void event(McastEvent event) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800223 McastRouteInfo info = event.subject();
alshabib3b1eadc2016-02-01 17:57:00 -0800224 switch (event.type()) {
225 case ROUTE_ADDED:
226 break;
227 case ROUTE_REMOVED:
228 break;
229 case SOURCE_ADDED:
230 break;
231 case SINK_ADDED:
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800232 if (!info.sink().isPresent()) {
233 log.warn("No sink given after sink added event: {}", info);
234 return;
235 }
236 provisionGroup(info.route(), info.sink().get());
alshabib3b1eadc2016-02-01 17:57:00 -0800237 break;
238 case SINK_REMOVED:
alshabibfc1cb032016-02-17 15:37:56 -0800239 unprovisionGroup(event.subject());
alshabib3b1eadc2016-02-01 17:57:00 -0800240 break;
241 default:
242 log.warn("Unknown mcast event {}", event.type());
243 }
244 }
245 }
246
alshabibfc1cb032016-02-17 15:37:56 -0800247 private void unprovisionGroup(McastRouteInfo info) {
Jonathan Hart718c0452016-02-18 15:56:22 -0800248 if (info.sinks().isEmpty()) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800249 removeRemoteRoute(info.route());
Jonathan Hart718c0452016-02-18 15:56:22 -0800250 }
251
alshabibfc1cb032016-02-17 15:37:56 -0800252 if (!info.sink().isPresent()) {
253 log.warn("No sink given after sink removed event: {}", info);
254 return;
255 }
256 ConnectPoint loc = info.sink().get();
257
258 NextObjective next = DefaultNextObjective.builder()
259 .fromApp(appId)
260 .addTreatment(DefaultTrafficTreatment.builder().setOutput(loc.port()).build())
261 .withType(NextObjective.Type.BROADCAST)
262 .withId(groups.get(info.route().group()))
263 .removeFromExisting(new ObjectiveContext() {
264 @Override
265 public void onSuccess(Objective objective) {
266 //TODO: change to debug
267 log.info("Next Objective {} installed", objective.id());
268 }
269
270 @Override
271 public void onError(Objective objective, ObjectiveError error) {
272 //TODO: change to debug
273 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800274 objective.id(),
275 error);
alshabibfc1cb032016-02-17 15:37:56 -0800276 }
277 });
278
279 flowObjectiveService.next(loc.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800280 }
281
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800282 private void provisionGroup(McastRoute route, ConnectPoint sink) {
283 checkNotNull(route, "Route cannot be null");
284 checkNotNull(sink, "Sink cannot be null");
alshabib3b1eadc2016-02-01 17:57:00 -0800285
Jonathan Hart0c194962016-05-23 17:08:15 -0700286 Optional<AccessDeviceData> oltInfo = cordConfigService.getAccessDevice(sink.deviceId());
alshabib09069c92016-02-21 14:49:51 -0800287
Jonathan Hart0c194962016-05-23 17:08:15 -0700288 if (!oltInfo.isPresent()) {
alshabib09069c92016-02-21 14:49:51 -0800289 log.warn("Unknown OLT device : {}", sink.deviceId());
290 return;
291 }
292
Jonathan Hart28271642016-02-10 16:13:54 -0800293 final AtomicBoolean sync = new AtomicBoolean(false);
alshabib3b1eadc2016-02-01 17:57:00 -0800294
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800295 Integer nextId = groups.computeIfAbsent(route.group(), (g) -> {
Zsolt Harasztiab436262016-02-25 09:39:10 -0800296 Integer id = flowObjectiveService.allocateNextId();
alshabib3b1eadc2016-02-01 17:57:00 -0800297
alshabibfc1cb032016-02-17 15:37:56 -0800298 NextObjective next = DefaultNextObjective.builder()
299 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800300 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800301 .withType(NextObjective.Type.BROADCAST)
302 .withId(id)
303 .add(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
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800319 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800320
321 TrafficSelector.Builder mcast = DefaultTrafficSelector.builder()
Jonathan Hart0c194962016-05-23 17:08:15 -0700322 .matchInPort(oltInfo.get().uplink())
alshabib3b1eadc2016-02-01 17:57:00 -0800323 .matchEthType(Ethernet.TYPE_IPV4)
alshabibfc1cb032016-02-17 15:37:56 -0800324 .matchIPDst(g.toIpPrefix());
325
alshabibfc1cb032016-02-17 15:37:56 -0800326 if (vlanEnabled) {
327 mcast.matchVlanId(VlanId.vlanId((short) mcastVlan));
328 }
alshabib3b1eadc2016-02-01 17:57:00 -0800329
alshabib3b1eadc2016-02-01 17:57:00 -0800330 ForwardingObjective fwd = DefaultForwardingObjective.builder()
331 .fromApp(appId)
332 .nextStep(id)
333 .makePermanent()
334 .withFlag(ForwardingObjective.Flag.VERSATILE)
335 .withPriority(priority)
alshabibfc1cb032016-02-17 15:37:56 -0800336 .withSelector(mcast.build())
alshabib3b1eadc2016-02-01 17:57:00 -0800337 .add(new ObjectiveContext() {
338 @Override
339 public void onSuccess(Objective objective) {
340 //TODO: change to debug
341 log.info("Forwarding objective installed {}", objective);
342 }
343
344 @Override
345 public void onError(Objective objective, ObjectiveError error) {
346 //TODO: change to debug
347 log.info("Forwarding objective failed {}", objective);
348 }
349 });
350
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800351 flowObjectiveService.forward(sink.deviceId(), fwd);
alshabib3b1eadc2016-02-01 17:57:00 -0800352
Jonathan Hart28271642016-02-10 16:13:54 -0800353 sync.set(true);
354
alshabib09069c92016-02-21 14:49:51 -0800355 return id;
alshabib3b1eadc2016-02-01 17:57:00 -0800356 });
357
alshabibfc1cb032016-02-17 15:37:56 -0800358 if (!sync.get()) {
359 NextObjective next = DefaultNextObjective.builder()
360 .fromApp(appId)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800361 .addTreatment(DefaultTrafficTreatment.builder().setOutput(sink.port()).build())
alshabibfc1cb032016-02-17 15:37:56 -0800362 .withType(NextObjective.Type.BROADCAST)
363 .withId(nextId)
364 .addToExisting(new ObjectiveContext() {
365 @Override
366 public void onSuccess(Objective objective) {
367 //TODO: change to debug
368 log.info("Next Objective {} installed", objective.id());
369 }
alshabib3b1eadc2016-02-01 17:57:00 -0800370
alshabibfc1cb032016-02-17 15:37:56 -0800371 @Override
372 public void onError(Objective objective, ObjectiveError error) {
373 //TODO: change to debug
374 log.info("Next Objective {} failed, because {}",
Jian Li46472d72016-03-09 10:52:49 -0800375 objective.id(),
376 error);
alshabibfc1cb032016-02-17 15:37:56 -0800377 }
378 });
alshabib3b1eadc2016-02-01 17:57:00 -0800379
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800380 flowObjectiveService.next(sink.deviceId(), next);
alshabibfc1cb032016-02-17 15:37:56 -0800381 }
Jonathan Hart28271642016-02-10 16:13:54 -0800382
Jonathan Hart0c194962016-05-23 17:08:15 -0700383 addRemoteRoute(route, sink);
alshabib3b1eadc2016-02-01 17:57:00 -0800384 }
385
Jonathan Hart0c194962016-05-23 17:08:15 -0700386 private void addRemoteRoute(McastRoute route, ConnectPoint inPort) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800387 checkNotNull(route);
Jonathan Hart28271642016-02-10 16:13:54 -0800388 if (syncHost == null) {
389 log.warn("No host configured for synchronization; route will be dropped");
390 return;
391 }
392
Jonathan Hart0c194962016-05-23 17:08:15 -0700393 Optional<AccessAgentData> accessAgent = cordConfigService.getAccessAgent(inPort.deviceId());
394 if (!accessAgent.isPresent()) {
395 log.warn("No accessAgent config found for in port {}", inPort);
396 return;
397 }
398
399 if (!accessAgent.get().getOltConnectPoint(inPort).isPresent()) {
400 log.warn("No OLT configured for in port {}", inPort);
401 return;
402 }
403
404 ConnectPoint oltConnectPoint = accessAgent.get().getOltConnectPoint(inPort).get();
405
Jonathan Hart0212f642016-02-20 11:32:43 -0800406 log.debug("Sending route {} to other ONOS {}", route, fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800407
Jian Li46472d72016-03-09 10:52:49 -0800408 Invocation.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hart28271642016-02-10 16:13:54 -0800409
410 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800411 .encode(route, new AbstractWebResource());
Jonathan Hart0212f642016-02-20 11:32:43 -0800412
413 try {
Jian Li46472d72016-03-09 10:52:49 -0800414 builder.post(Entity.json(json.toString()));
Jonathan Hart0c194962016-05-23 17:08:15 -0700415
416 builder = getClientBuilder(fabricOnosUrl + "/sinks/" + route.group() + "/" + route.source());
417 ObjectMapper mapper = new ObjectMapper();
418 ObjectNode obj = mapper.createObjectNode();
419 obj.putArray("sinks").add(oltConnectPoint.deviceId() + "/" + oltConnectPoint.port());
420
421 builder.post(Entity.json(obj.toString()));
Jian Li46472d72016-03-09 10:52:49 -0800422 } catch (ProcessingException e) {
Jonathan Hart0212f642016-02-20 11:32:43 -0800423 log.warn("Unable to send route to remote controller: {}", e.getMessage());
424 }
alshabib3b1eadc2016-02-01 17:57:00 -0800425 }
Jonathan Hart28271642016-02-10 16:13:54 -0800426
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800427 private void removeRemoteRoute(McastRoute route) {
Jonathan Hart718c0452016-02-18 15:56:22 -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("Removing route {} from other ONOS {}", route, fabricOnosUrl);
Jonathan Hart718c0452016-02-18 15:56:22 -0800434
Jian Li46472d72016-03-09 10:52:49 -0800435 Invocation.Builder builder = getClientBuilder(fabricOnosUrl)
436 .property(ClientProperties.SUPPRESS_HTTP_COMPLIANCE_VALIDATION, true);
Jonathan Hart718c0452016-02-18 15:56:22 -0800437
438 ObjectNode json = codecService.getCodec(McastRoute.class)
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800439 .encode(route, new AbstractWebResource());
Jian Li46472d72016-03-09 10:52:49 -0800440
441 builder.method("DELETE", Entity.entity(json.asText(),
442 MediaType.APPLICATION_OCTET_STREAM));
Jonathan Hart718c0452016-02-18 15:56:22 -0800443 }
444
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800445 private void clearRemoteRoutes() {
446 if (syncHost == null) {
447 log.warn("No host configured for synchronization");
448 return;
449 }
450
Jonathan Hart0212f642016-02-20 11:32:43 -0800451 log.debug("Clearing remote multicast routes from {}", fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800452
Jian Li46472d72016-03-09 10:52:49 -0800453 Invocation.Builder builder = getClientBuilder(fabricOnosUrl);
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800454 List<McastRoute> mcastRoutes = Lists.newArrayList();
Jonathan Hart0212f642016-02-20 11:32:43 -0800455
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800456 try {
Jonathan Hart0212f642016-02-20 11:32:43 -0800457 String response = builder
458 .accept(MediaType.APPLICATION_JSON_TYPE)
459 .get(String.class);
460
461 JsonCodec<McastRoute> routeCodec = codecService.getCodec(McastRoute.class);
462 ObjectMapper mapper = new ObjectMapper();
463
464
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800465 ObjectNode node = (ObjectNode) mapper.readTree(response);
466 ArrayNode list = (ArrayNode) node.path("routes");
467
468 list.forEach(n -> mcastRoutes.add(
469 routeCodec.decode((ObjectNode) n, new AbstractWebResource())));
Jonathan Hart0212f642016-02-20 11:32:43 -0800470
Jonathan Hart0c194962016-05-23 17:08:15 -0700471 } catch (IOException | ProcessingException e) {
Jonathan Hartc3f84eb2016-02-19 12:44:36 -0800472 log.warn("Error clearing remote routes", e);
473 }
474
475 mcastRoutes.forEach(this::removeRemoteRoute);
476 }
477
Jian Li46472d72016-03-09 10:52:49 -0800478 private Invocation.Builder getClientBuilder(String uri) {
479 ClientConfig config = new ClientConfig();
480 Client client = ClientBuilder.newClient(config);
481
482 client.property(ClientProperties.CONNECT_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
483 client.property(ClientProperties.READ_TIMEOUT, DEFAULT_REST_TIMEOUT_MS);
484 client.register(HttpAuthenticationFeature.basic(user, password));
485
486 WebTarget wt = client.target(uri);
487 return wt.request(JSON_UTF_8.toString());
Jonathan Hart28271642016-02-10 16:13:54 -0800488 }
489
alshabib3b1eadc2016-02-01 17:57:00 -0800490}