2 * Copyright (c) 2015 CableLabs and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.packetcable.provider;
11 import static com.google.common.base.Preconditions.checkNotNull;
13 import com.google.common.base.Optional;
14 import com.google.common.collect.Maps;
15 import com.google.common.collect.Sets;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.Futures;
19 import java.net.InetAddress;
20 import java.net.UnknownHostException;
21 import java.text.DateFormat;
22 import java.text.SimpleDateFormat;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.List;
28 import java.util.Objects;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ExecutionException;
32 import java.util.concurrent.Executor;
33 import java.util.concurrent.Executors;
34 import java.util.concurrent.Future;
36 import javax.annotation.Nonnull;
37 import javax.annotation.concurrent.ThreadSafe;
39 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
40 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
41 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
42 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
43 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
44 import org.opendaylight.controller.packetcable.provider.validation.DataValidator;
45 import org.opendaylight.controller.packetcable.provider.validation.ValidationException;
46 import org.opendaylight.controller.packetcable.provider.validation.Validator;
47 import org.opendaylight.controller.packetcable.provider.validation.impl.CcapsValidatorProviderFactory;
48 import org.opendaylight.controller.packetcable.provider.validation.impl.QosValidatorProviderFactory;
49 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
50 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
51 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
52 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpPrefix;
53 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Prefix;
54 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.DateAndTime;
55 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.AppContext;
56 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapContext;
57 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapPollConnectionInput;
58 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapPollConnectionOutput;
59 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapPollConnectionOutputBuilder;
60 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapSetConnectionInput;
61 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapSetConnectionOutput;
62 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.CcapSetConnectionOutputBuilder;
63 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.Ccaps;
64 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.PacketcableService;
65 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.Qos;
66 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.QosPollGatesInput;
67 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.QosPollGatesOutput;
68 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.QosPollGatesOutputBuilder;
69 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ServiceClassName;
70 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ServiceFlowDirection;
71 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.attributes.ConnectionBuilder;
72 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccaps.Ccap;
73 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccaps.CcapBuilder;
74 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gate.spec.GateSpec;
75 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gate.spec.GateSpecBuilder;
76 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.Apps;
77 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.App;
78 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.AppBuilder;
79 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.AppKey;
80 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.Subscribers;
81 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.SubscribersBuilder;
82 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.Subscriber;
83 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.SubscriberBuilder;
84 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.SubscriberKey;
85 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.subscriber.Gates;
86 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.subscriber.GatesBuilder;
87 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.Gate;
88 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateBuilder;
89 import org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.pcmm.qos.gates.apps.app.subscribers.subscriber.gates.GateKey;
90 import org.opendaylight.yangtools.concepts.ListenerRegistration;
91 import org.opendaylight.yangtools.yang.binding.DataObject;
92 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
93 import org.opendaylight.yangtools.yang.common.RpcResult;
94 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
95 import org.pcmm.gates.impl.DOCSISServiceClassNameTrafficProfile;
96 import org.pcmm.gates.IGateSpec.Direction;
97 import org.pcmm.rcd.IPCMMClient;
98 import org.slf4j.Logger;
99 import org.slf4j.LoggerFactory;
102 * Called by ODL framework to start this bundle.
104 * This class is responsible for processing messages received from ODL's restconf interface.
105 * TODO - Remove some of these state maps and move some of this into the PCMMService
106 * TODO Don't implement PacketcableService, move that into an inner class
109 public class PacketcableProvider implements BindingAwareProvider, AutoCloseable, PacketcableService {
111 private static final Logger logger = LoggerFactory.getLogger(PacketcableProvider.class);
113 // keys to the /restconf/config/packetcable:ccaps and /restconf/config/packetcable:qos config datastore
114 private static final InstanceIdentifier<Ccaps> ccapsIID = InstanceIdentifier.builder(Ccaps.class).build();
115 private static final InstanceIdentifier<Qos> qosIID = InstanceIdentifier.builder(Qos.class).build();
117 // TODO - Revisit these maps and remove the ones no longer necessary
118 private final Map<String, Ccap> ccapMap = new ConcurrentHashMap<>();
119 private final Map<String, Gate> gateMap = new ConcurrentHashMap<>();
120 private final Map<String, String> gateCcapMap = new ConcurrentHashMap<>();
121 private final Map<Subnet, Ccap> subscriberSubnetsMap = new ConcurrentHashMap<>();
122 private final Map<ServiceClassName, List<Ccap>> downstreamScnMap = new ConcurrentHashMap<>();
123 private final Map<ServiceClassName, List<Ccap>> upstreamScnMap = new ConcurrentHashMap<>();
125 private final Executor executor = Executors.newSingleThreadExecutor();
128 * Holds a PCMMService object for each CCAP being managed.
130 private final Map<String, PCMMService> pcmmServiceMap = new ConcurrentHashMap<>();
133 * The ODL object used to broker messages throughout the framework
135 private DataBroker dataBroker;
136 private MdsalUtils mdsalUtils;
138 //Routed RPC Registration
139 private RoutedRpcRegistration<PacketcableService> rpcRegistration;
141 // Data change listeners/registrations
142 private final CcapsDataChangeListener ccapsDataChangeListener = new CcapsDataChangeListener();
143 private final QosDataChangeListener qosDataChangeListener = new QosDataChangeListener();
145 private ListenerRegistration<DataChangeListener> ccapsDataChangeListenerRegistration;
146 private ListenerRegistration<DataChangeListener> qosDataChangeListenerRegistration;
151 public PacketcableProvider() {
152 logger.info("Starting provider");
156 public void onSessionInitiated(ProviderContext session) {
157 logger.info("Packetcable Session Initiated");
158 logger.info("logging levels: error={}, warn={}, info={}, debug={}, trace={}", logger.isErrorEnabled(), logger.isWarnEnabled(), logger.isInfoEnabled(), logger.isDebugEnabled(), logger.isTraceEnabled());
160 dataBroker = session.getSALService(DataBroker.class);
162 mdsalUtils = new MdsalUtils(dataBroker);
164 ccapsDataChangeListenerRegistration =
165 dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, ccapsIID.child(Ccap.class),
166 ccapsDataChangeListener, DataBroker.DataChangeScope.SUBTREE);
168 qosDataChangeListenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
169 PacketcableProvider.qosIID.child(Apps.class).child(App.class), qosDataChangeListener,
170 DataBroker.DataChangeScope.SUBTREE);
172 rpcRegistration = session.addRoutedRpcImplementation(PacketcableService.class, this);
173 logger.info("onSessionInitiated().rpcRgistration: {}", rpcRegistration);
178 * Implemented from the AutoCloseable interface.
181 public void close() throws ExecutionException, InterruptedException {
182 if (ccapsDataChangeListenerRegistration != null) {
183 ccapsDataChangeListenerRegistration.close();
186 if (qosDataChangeListenerRegistration != null) {
187 qosDataChangeListenerRegistration.close();
191 private void updateCcapMaps(final Ccap ccap) {
192 // add ccap to the subscriberSubnets map
193 for (final IpPrefix ipPrefix : ccap.getSubscriberSubnets()) {
195 subscriberSubnetsMap.put(Subnet.createInstance(getIpPrefixStr(ipPrefix)), ccap);
196 } catch (UnknownHostException e) {
197 logger.error("updateSubscriberSubnets: {}:{} FAILED: {}", ipPrefix, ccap, e.getMessage());
200 // ccap to upstream SCN map
201 for (final ServiceClassName scn : ccap.getUpstreamScns()) {
202 if (upstreamScnMap.containsKey(scn)) {
203 upstreamScnMap.get(scn).add(ccap);
205 final List<Ccap> ccapList = new ArrayList<>();
207 upstreamScnMap.put(scn, ccapList);
210 // ccap to downstream SCN map
211 for (final ServiceClassName scn : ccap.getDownstreamScns()) {
212 if (downstreamScnMap.containsKey(scn)) {
213 downstreamScnMap.get(scn).add(ccap);
215 final List<Ccap> ccapList = new ArrayList<>();
217 downstreamScnMap.put(scn, ccapList);
222 private String getIpPrefixStr(final IpPrefix ipPrefix) {
223 final Ipv4Prefix ipv4 = ipPrefix.getIpv4Prefix();
225 return ipv4.getValue();
227 return ipPrefix.getIpv6Prefix().getValue();
231 public InetAddress getInetAddress(final String subId) {
233 return InetAddress.getByName(subId);
234 } catch (UnknownHostException e) {
235 logger.error("getInetAddress: {} FAILED: {}", subId, e.getMessage());
240 private Ccap findCcapForSubscriberId(final InetAddress inetAddr) {
241 // TODO replace this with a loading cache, https://github.com/google/guava/wiki/CachesExplained
242 Ccap matchedCcap = null;
243 int longestPrefixLen = -1;
244 for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
245 final Subnet subnet = entry.getKey();
246 if (subnet.isInNet(inetAddr)) {
247 int prefixLen = subnet.getPrefixLen();
248 if (prefixLen > longestPrefixLen) {
249 matchedCcap = entry.getValue();
250 longestPrefixLen = prefixLen;
257 private ServiceFlowDirection findScnOnCcap(final ServiceClassName scn, final Ccap ccap) {
261 if (upstreamScnMap.containsKey(scn)) {
262 final List<Ccap> ccapList = upstreamScnMap.get(scn);
263 if (ccapList.contains(ccap)) {
264 return ServiceFlowDirection.Us;
266 } else if (downstreamScnMap.containsKey(scn)) {
267 final List<Ccap> ccapList = downstreamScnMap.get(scn);
268 if (ccapList.contains(ccap)) {
269 return ServiceFlowDirection.Ds;
275 private void removeCcapFromAllMaps(final Ccap ccap) {
276 // remove the ccap from all maps
277 // subscriberSubnets map
278 for (final Map.Entry<Subnet, Ccap> entry : subscriberSubnetsMap.entrySet()) {
279 if (entry.getValue() == ccap) {
280 subscriberSubnetsMap.remove(entry.getKey());
283 // ccap to upstream SCN map
284 for (final Map.Entry<ServiceClassName, List<Ccap>> entry : upstreamScnMap.entrySet()) {
285 final List<Ccap> ccapList = entry.getValue();
286 ccapList.remove(ccap);
287 if (ccapList.isEmpty()) {
288 upstreamScnMap.remove(entry.getKey());
291 // ccap to downstream SCN map
292 for (final Map.Entry<ServiceClassName, List<Ccap>> entry : downstreamScnMap.entrySet()) {
293 final List<Ccap> ccapList = entry.getValue();
294 ccapList.remove(ccap);
295 if (ccapList.isEmpty()) {
296 downstreamScnMap.remove(entry.getKey());
300 final PCMMService service = pcmmServiceMap.remove(ccap.getCcapId());
301 if (service != null) {
306 // ValidationException does not need to be thrown again
307 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
308 private <T extends DataObject> void saveErrors(@Nonnull Map<InstanceIdentifier<T>, ValidationException> errorMap,
309 @Nonnull Map<InstanceIdentifier<T>, T> dataMap) {
311 final WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
314 for (InstanceIdentifier<T> iid : errorMap.keySet()) {
316 final ValidationException exception = errorMap.get(iid);
317 final T badData = dataMap.get(iid);
319 if (!badData.getImplementedInterface().isAssignableFrom(iid.getTargetType())) {
320 // InstanceIdentifier<T> does not have the same type as the DataObject
321 logger.error("Bad InstanceIdentifier to DataObject mapping, {} : {}", iid, badData);
325 if (badData instanceof Ccap) {
326 final Ccap ccap = (Ccap) badData;
328 final Ccap opperationalCcap =
329 new CcapBuilder().setCcapId(ccap.getCcapId()).setError(exception.getErrorMessages()).build();
332 // type match between iid and badData is done at start of loop
333 @SuppressWarnings("unchecked") final InstanceIdentifier<Ccap> ccapIID = (InstanceIdentifier<Ccap>) iid;
334 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, ccapIID, opperationalCcap);
335 } else if (badData instanceof Gate) {
336 final Gate gate = (Gate) badData;
338 final Gate operationalGate =
339 new GateBuilder().setGateId(gate.getGateId()).setError(exception.getErrorMessages()).build();
341 final Gates operationalGates =
342 new GatesBuilder().setGate(Collections.singletonList(operationalGate)).build();
344 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(iid.firstIdentifierOf(Subscriber.class));
345 final Subscriber operationalSubscriber =
346 new SubscriberBuilder().setSubscriberId(subscriberKey.getSubscriberId())
347 .setGates(operationalGates)
350 final Subscribers operationalSubscribers =
351 new SubscribersBuilder().setSubscriber(Collections.singletonList(operationalSubscriber))
354 final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
355 final AppKey appKey = InstanceIdentifier.keyOf(appIID);
356 final App operationalApp =
357 new AppBuilder().setAppId(appKey.getAppId()).setSubscribers(operationalSubscribers).build();
360 writeTransaction.put(LogicalDatastoreType.OPERATIONAL, appIID, operationalApp);
362 // If you get here a developer forgot to add a type above
363 logger.error("Unexpected type requested for error saving: {}", badData);
364 throw new IllegalStateException("Unsupported type for error saving");
370 CheckedFuture<Void, TransactionCommitFailedException> future = writeTransaction.submit();
374 } catch (TransactionCommitFailedException e) {
375 logger.error("Failed to write errors to operational datastore", e);
380 * Removes Ccaps if all Ccap instances are removed
382 private class CcapsCleaner extends AbstractCleaner<Ccaps> {
384 public CcapsCleaner(final InstanceIdentifier<?> removedIID) {
385 super(removedIID, Ccaps.class, LogicalDatastoreType.OPERATIONAL);
389 protected boolean shouldClean(final Ccaps ccaps) {
390 return ccaps.getCcap().isEmpty();
396 * Removes Subscriber if all Gate instances are removed
398 private class SubscriberCleaner extends AbstractCleaner<Subscriber> {
400 public SubscriberCleaner(InstanceIdentifier<Gate> removedGateIID) {
401 super(removedGateIID, Subscriber.class, LogicalDatastoreType.OPERATIONAL);
405 protected boolean shouldClean(final Subscriber subscriber) {
406 return subscriber.getGates().getGate().isEmpty();
410 protected void postRemove(InstanceIdentifier<Subscriber> subscriberIID) {
411 executor.execute(new AppCleaner(subscriberIID));
417 * Removes App if all Subscribers are removed.
419 private class AppCleaner extends AbstractCleaner<App> {
421 public AppCleaner(InstanceIdentifier<Subscriber> removedSubscriberIID) {
422 super(removedSubscriberIID, App.class, LogicalDatastoreType.OPERATIONAL);
426 boolean shouldClean(final App app) {
427 return app.getSubscribers().getSubscriber().isEmpty();
431 void postRemove(final InstanceIdentifier<App> appIID) {
432 //unregister app rpc path
433 logger.info("Un-Registering App Routed RPC Path...");
434 rpcRegistration.unregisterPath(AppContext.class, appIID);
435 executor.execute(new AppsCleaner(appIID));
441 * Removes Apps if all App instances are removed.
443 private class AppsCleaner extends AbstractCleaner<Apps> {
445 public AppsCleaner(InstanceIdentifier<App> removedAppIID) {
446 super(removedAppIID, Apps.class, LogicalDatastoreType.OPERATIONAL);
450 protected boolean shouldClean(final Apps apps) {
451 return apps.getApp().isEmpty();
457 * Helper class to do the heavy lifting in removing object. Lets subclasses decide with
458 * {@link #shouldClean(DataObject)}. <br>
460 * Subclasses can react after an instance is removed by overriding {@link #postRemove(InstanceIdentifier)}
463 * The type that will be removed
465 private abstract class AbstractCleaner<T extends DataObject> implements Runnable {
466 final InstanceIdentifier<?> removedIID;
467 final Class<T> tClass;
468 final LogicalDatastoreType datastoreType;
470 public AbstractCleaner(InstanceIdentifier<?> removedIID, Class<T> tClass, LogicalDatastoreType datastoreType) {
471 this.removedIID = checkNotNull(removedIID);
472 this.tClass = checkNotNull(tClass);
473 this.datastoreType = checkNotNull(datastoreType);
478 InstanceIdentifier<T> tIID = removedIID.firstIdentifierOf(tClass);
480 Optional<T> optional = mdsalUtils.read(datastoreType, tIID);
481 if (optional.isPresent()) {
483 if (shouldClean(optional.get())) {
484 if (mdsalUtils.delete(datastoreType, tIID)) {
493 logger.error("Expected to find InstanceIdentifier<{}> but was not found: {}", tClass.getSimpleName(),
499 * If returns true the object will be removed from the datastore
502 * The object that might be removed.
503 * @return true if it should be removed.
505 abstract boolean shouldClean(final T object);
508 * Called after an instance is removed.
511 * the InstanceIdentifier of the removed object
513 void postRemove(InstanceIdentifier<T> tIID) {
517 void removeFailed(InstanceIdentifier<T> tIID) {
518 logger.error("Failed to remove {}", tIID);
524 * Listener for the packetcable:ccaps tree
526 private class CcapsDataChangeListener extends AbstractDataChangeListener<Ccap> {
528 private final DataValidator ccapsDataValidator = new DataValidator(new CcapsValidatorProviderFactory().build());
530 private final Set<InstanceIdentifier<Ccap>> updateQueue = Sets.newConcurrentHashSet();
532 public CcapsDataChangeListener() {
537 protected void handleCreatedData(final Map<InstanceIdentifier<Ccap>, Ccap> createdCcaps) {
538 if (createdCcaps.isEmpty()) {
542 final Map<InstanceIdentifier<Ccap>, ValidationException> errorMap =
543 ccapsDataValidator.validateOneType(createdCcaps, Validator.Extent.NODE_AND_SUBTREE);
545 // validate all new objects an update operational datastore
546 if (!errorMap.isEmpty()) {
547 // bad data write errors to operational datastore
548 saveErrors(errorMap, createdCcaps);
551 if (createdCcaps.size() > errorMap.size()) {
552 final Map<InstanceIdentifier<Ccap>, Ccap> goodData =
553 Maps.newHashMapWithExpectedSize(createdCcaps.size() - errorMap.size());
554 for (InstanceIdentifier<Ccap> iid : createdCcaps.keySet()) {
555 if (!errorMap.containsKey(iid)) {
556 goodData.put(iid, createdCcaps.get(iid));
559 addNewCcaps(goodData);
563 private void addNewCcaps(final Map<InstanceIdentifier<Ccap>, Ccap> goodData) {
564 for (InstanceIdentifier<Ccap> iid : goodData.keySet()) {
565 final Ccap ccap = goodData.get(iid);
568 if (pcmmServiceMap.containsKey(ccap.getCcapId())) {
569 logger.error("Already monitoring CCAP - " + ccap);
572 final PCMMService pcmmService = new PCMMService(IPCMMClient.CLIENT_TYPE, ccap);
573 // TODO - may want to use the AMID but for the client type but probably not???
575 final PCMMService pcmmService = new PCMMService(
576 thisCcap.getAmId().getAmType().shortValue(), thisCcap);
578 ConnectionBuilder connectionBuilder = new ConnectionBuilder();
579 String message = pcmmService.addCcap();
580 if (message.contains("200 OK")) {
581 pcmmServiceMap.put(ccap.getCcapId(), pcmmService);
582 ccapMap.put(ccap.getCcapId(), ccap);
583 updateCcapMaps(ccap);
584 logger.info("Created CCAP: {}/{} : {}", iid, ccap, message);
585 logger.info("Created CCAP: {} : {}", iid, message);
587 connectionBuilder.setConnected(true).setError(Collections.<String>emptyList());
589 logger.error("Create CCAP Failed: {} : {}", iid, message);
591 connectionBuilder.setConnected(false).setError(Collections.singletonList(message));
595 logger.info("Registering CCAP Routed RPC Path...");
596 rpcRegistration.registerPath(CcapContext.class, iid);
598 Optional<Ccap> optionalCcap = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, iid);
600 final CcapBuilder responseCcapBuilder;
601 if (optionalCcap.isPresent()) {
602 responseCcapBuilder = new CcapBuilder(optionalCcap.get());
604 responseCcapBuilder = new CcapBuilder();
605 responseCcapBuilder.setCcapId(ccap.getCcapId());
608 responseCcapBuilder.setConnection(connectionBuilder.build());
610 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, iid, responseCcapBuilder.build());
616 protected void handleUpdatedData(final Map<InstanceIdentifier<Ccap>, Ccap> updatedCcaps,
617 final Map<InstanceIdentifier<Ccap>, Ccap> originalCcaps) {
619 // TODO actually support updates
621 // update operation not allowed -- restore the original config object and complain
622 for (final Map.Entry<InstanceIdentifier<Ccap>, Ccap> entry : updatedCcaps.entrySet()) {
623 if (!originalCcaps.containsKey(entry.getKey())) {
624 logger.error("No original data found for supposedly updated data: {}", entry.getValue());
628 // If this notification is coming from our modification ignore it.
629 if (updateQueue.contains(entry.getKey())) {
630 updateQueue.remove(entry.getKey());
634 final Ccap originalCcap = originalCcaps.get(entry.getKey());
635 //final Ccap updatedCcap = entry.getValue();
638 logger.info("Registering CCAP Routed RPC Path...");
639 rpcRegistration.registerPath(CcapContext.class, entry.getKey());
641 // restore the original data
642 updateQueue.add(entry.getKey());
643 mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalCcap);
644 logger.error("CCAP update not permitted {}", entry.getKey());
649 protected void handleRemovedData(final Set<InstanceIdentifier<Ccap>> removedCcapPaths,
650 final Map<InstanceIdentifier<Ccap>, Ccap> originalCcaps) {
652 for (InstanceIdentifier<Ccap> iid : removedCcapPaths) {
653 final Ccap nukedCcap = originalCcaps.get(iid);
654 removeCcapFromAllMaps(nukedCcap);
656 //unregister ccap rpc path
657 logger.info("Un-Registering CCAP Routed RPC Path...");
658 rpcRegistration.unregisterPath(CcapContext.class, iid);
660 mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, iid);
662 // clean up ccaps level if it is now empty
663 executor.execute(new CcapsCleaner(iid));
670 private class QosDataChangeListener extends AbstractDataChangeListener<Gate> {
672 private final DataValidator qosDataValidator = new DataValidator(new QosValidatorProviderFactory().build());
673 private final Set<InstanceIdentifier<Gate>> updateQueue = Sets.newConcurrentHashSet();
675 public QosDataChangeListener() {
680 protected void handleCreatedData(final Map<InstanceIdentifier<Gate>, Gate> createdData) {
682 final Map<InstanceIdentifier<Gate>, ValidationException> errorMap =
683 qosDataValidator.validateOneType(createdData, Validator.Extent.NODE_AND_SUBTREE);
685 // validate all new objects an update operational datastore
686 if (!errorMap.isEmpty()) {
687 // bad data write errors to operational datastore
688 saveErrors(errorMap, createdData);
691 if (createdData.size() > errorMap.size()) {
692 final Map<InstanceIdentifier<Gate>, Gate> goodData =
693 Maps.newHashMapWithExpectedSize(createdData.size() - errorMap.size());
694 for (InstanceIdentifier<Gate> iid : createdData.keySet()) {
695 if (!errorMap.containsKey(iid)) {
696 goodData.put(iid, createdData.get(iid));
699 addNewGates(goodData);
704 private void addNewGates(final Map<InstanceIdentifier<Gate>, Gate> createdGates) {
706 for (InstanceIdentifier<Gate> gateIID : createdGates.keySet()) {
707 final Gate newGate = createdGates.get(gateIID);
709 final String newGatePathStr = makeGatePathString(gateIID);
711 // if a new app comes along add RPC registration
712 final InstanceIdentifier<App> appIID = gateIID.firstIdentifierOf(App.class);
713 // TBD verify if App ID exists first
715 //register appID RPC path
716 logger.info("Registering App Routed RPC Path...");
717 rpcRegistration.registerPath(AppContext.class, appIID);
719 final InstanceIdentifier<Subscriber> subscriberIID = gateIID.firstIdentifierOf(Subscriber.class);
720 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
721 final InetAddress subscriberAddr = getInetAddress(subscriberKey.getSubscriberId());
722 if (subscriberAddr == null) {
723 final String msg = String.format("subscriberId must be a valid ipaddress: %s",
724 subscriberKey.getSubscriberId());
726 saveGateError(gateIID, newGatePathStr, msg);
730 final Ccap ccap = findCcapForSubscriberId(subscriberAddr);
732 final String msg = String.format("Unable to find Ccap for subscriber %s: @ %s",
733 subscriberKey.getSubscriberId(), newGatePathStr);
735 saveGateError(gateIID, newGatePathStr, msg);
739 final PCMMService pcmmService = pcmmServiceMap.get(ccap.getCcapId());
740 if (pcmmService == null) {
742 String.format("Unable to locate PCMM Service for CCAP: %s ; with subscriber: %s", ccap,
743 subscriberKey.getSubscriberId());
745 saveGateError(gateIID, newGatePathStr, msg);
750 // set up gate builder with known fields (and some empty ones)
752 final GateBuilder gateBuilder = new GateBuilder();
753 gateBuilder.setGateId(newGate.getGateId())
754 .setGatePath(newGatePathStr)
755 .setCcapId(ccap.getCcapId())
756 .setTrafficProfile(newGate.getTrafficProfile())
757 .setClassifiers(newGate.getClassifiers())
758 .setGateSpec(newGate.getGateSpec())
759 .setCopsGateState("")
760 .setCopsGateTimeInfo("")
761 .setCopsGateUsageInfo("");
764 // Right now only ServiceClassName traffic Profile is supported. This logic needs to
765 // be updated when the yang traffic-profile is extended to support new types
766 // Override requested Direction using the Ccap configuration information about SCNs and
767 // their configured direction.
769 final ServiceClassName scn = newGate.getTrafficProfile().getServiceClassName();
770 final ServiceFlowDirection scnDirection = findScnOnCcap(scn, ccap);
771 if (scnDirection == null) {
773 String.format("SCN %s not found on CCAP %s for %s", scn, ccap.getCcapId(), newGatePathStr);
775 saveGateError(gateIID, newGatePathStr, msg);
780 // since we may be modifying the contents of the original request GateSpec
781 // to update flow direction (based on the ccap SCN configuration) we need to
782 // rebuild the requested gate spec and replace the existing one in the gate builder
784 final GateSpecBuilder gateSpecBuilder = new GateSpecBuilder();
785 gateSpecBuilder.setDirection(scnDirection);
786 gateSpecBuilder.setDscpTosMask(newGate.getGateSpec().getDscpTosMask());
787 gateSpecBuilder.setDscpTosOverwrite(newGate.getGateSpec().getDscpTosOverwrite());
788 final GateSpec gateSpec = gateSpecBuilder.build();
789 gateBuilder.setGateSpec(gateSpec);
792 // build the gate to be requested
794 gateBuilder.setTimestamp(getNowTimeStamp());
796 final Gate requestGate = gateBuilder.build();
799 // send gate request to Ccap
801 PCMMService.GateSendStatus status =
802 pcmmService.sendGateSet(newGatePathStr, subscriberAddr, requestGate);
803 if (status.didSucceed()) {
804 gateMap.put(newGatePathStr, requestGate);
805 gateCcapMap.put(newGatePathStr, ccap.getCcapId());
808 // inquire as to the status, and implementation info of the requested gate
810 PCMMService.GateSendStatus infoStatus = pcmmService.sendGateInfo(newGatePathStr);
812 if (infoStatus.didSucceed()) {
814 // update builder with info for operational storage
816 gateBuilder.setCopsGateState(
817 infoStatus.getCopsGateState() + "/" + infoStatus.getCopsGateStateReason())
818 .setCopsGateTimeInfo(infoStatus.getCopsGateTimeInfo())
819 .setCopsGateUsageInfo(infoStatus.getCopsGateUsageInfo())
820 .setCopsGateId(status.getCopsGateId());
822 List<String> errors = new ArrayList<>(2);
824 // Keep GateSetErrors
825 if (gateBuilder.getError() != null) {
826 errors.addAll(gateBuilder.getError());
829 errors.add(infoStatus.getMessage());
830 gateBuilder.setError(errors);
834 gateBuilder.setError(Collections.singletonList(status.getMessage()));
837 Gate operationalGate = gateBuilder.build();
839 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
844 private void saveGateError(@Nonnull final InstanceIdentifier<Gate> gateIID, @Nonnull final String gatePathStr,
845 @Nonnull final String error) {
846 checkNotNull(gateIID);
849 final GateBuilder gateBuilder = new GateBuilder();
850 gateBuilder.setGateId(InstanceIdentifier.keyOf(gateIID).getGateId())
851 .setGatePath(gatePathStr)
853 .setCopsGateState("N/A");
855 gateBuilder.setError(Collections.singletonList(error));
857 Gate operationalGate = gateBuilder.build();
859 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIID, operationalGate);
863 protected void handleUpdatedData(final Map<InstanceIdentifier<Gate>, Gate> updatedData,
864 final Map<InstanceIdentifier<Gate>, Gate> originalData) {
865 // TODO actually support updates
867 // update operation not allowed -- restore the original config object and complain
868 for (final Map.Entry<InstanceIdentifier<Gate>, Gate> entry : updatedData.entrySet()) {
869 if (!originalData.containsKey(entry.getKey())) {
870 logger.error("No original data found for supposedly updated data: {}", entry.getValue());
874 // If this notification is coming from our modification ignore it.
875 if (updateQueue.contains(entry.getKey())) {
876 updateQueue.remove(entry.getKey());
880 final Gate originalGate = originalData.get(entry.getKey());
882 // restores the original data
883 updateQueue.add(entry.getKey());
884 mdsalUtils.put(LogicalDatastoreType.CONFIGURATION, entry.getKey(), originalGate);
885 logger.error("Update not permitted {}", entry.getKey());
893 protected void handleRemovedData(final Set<InstanceIdentifier<Gate>> removedPaths,
894 final Map<InstanceIdentifier<Gate>, Gate> originalData) {
896 for (final InstanceIdentifier<Gate> removedGateIID : removedPaths) {
898 mdsalUtils.delete(LogicalDatastoreType.OPERATIONAL, removedGateIID);
900 executor.execute(new SubscriberCleaner(removedGateIID));
902 final String gatePathStr = makeGatePathString(removedGateIID);
904 if (gateMap.containsKey(gatePathStr)) {
905 final Gate thisGate = gateMap.remove(gatePathStr);
906 final String gateId = thisGate.getGateId();
907 final String ccapId = gateCcapMap.remove(gatePathStr);
908 final Ccap thisCcap = ccapMap.get(ccapId);
909 final PCMMService service = pcmmServiceMap.get(thisCcap.getCcapId());
910 if (service != null) {
911 service.sendGateDelete(gatePathStr);
912 logger.info("onDataChanged(): removed QoS gate {} for {}/{}/{}: ", gateId, ccapId, gatePathStr,thisGate);
914 logger.warn("Unable to send to locate PCMMService to send gate delete message with CCAP - "
924 private String makeGatePathString(InstanceIdentifier<Gate> iid) {
925 final InstanceIdentifier<App> appIID = iid.firstIdentifierOf(App.class);
926 final AppKey appKey = InstanceIdentifier.keyOf(appIID);
928 final InstanceIdentifier<Subscriber> subscriberIID = iid.firstIdentifierOf(Subscriber.class);
929 final SubscriberKey subscriberKey = InstanceIdentifier.keyOf(subscriberIID);
931 final GateKey gateKey = InstanceIdentifier.keyOf(iid);
933 return appKey.getAppId() + "/" + subscriberKey.getSubscriberId() + "/" + gateKey.getGateId();
939 public Future<RpcResult<CcapSetConnectionOutput>> ccapSetConnection(CcapSetConnectionInput input) {
940 // TODO refactor this method into smaller parts
942 InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
943 List<String> outputError = new ArrayList<String>();
944 String rpcResponse = null;
945 Boolean inputIsConnected = input.getConnection().isConnected();
946 Boolean effectiveIsConnected = null;
947 String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
948 PCMMService pcmmService = pcmmServiceMap.get(ccapId);
950 if (!inputIsConnected) {
951 // set connected false
952 if (pcmmService.getPcmmPdpSocket()) {
953 outputError.add(ccapId + ": CCAP COPS socket is already closed");
954 effectiveIsConnected = false;
956 //if (!pcmmService.getPcmmCcapClientIsConnected()) {
957 outputError.add(ccapId + ": CCAP client is disconnected with error: "
958 + pcmmService.getPcmmCcapClientConnectErrMsg());
960 pcmmService.ccapClient.disconnect();
961 effectiveIsConnected = false;
964 // set connected true
965 if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
966 outputError.add(ccapId + ": CCAP COPS socket is already open");
967 outputError.add(ccapId + ": CCAP client is connected");
968 effectiveIsConnected = true;
970 if (pcmmService.getPcmmCcapClientIsConnected()) {
971 pcmmService.ccapClient.disconnect();
973 pcmmService.ccapClient.connect();
974 if (pcmmService.getPcmmCcapClientIsConnected()) {
975 effectiveIsConnected = true;
976 outputError.add(ccapId + ": CCAP client is connected");
978 effectiveIsConnected = false;
979 outputError.add(ccapId + ": CCAP client is disconnected with error: "
980 + pcmmService.getPcmmCcapClientConnectErrMsg());
985 DateAndTime connectionDateAndTime = getNowTimeStamp();
986 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.set.connection.output.ccap.ConnectionBuilder
987 connectionRpcOutput =
988 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.set.connection.output.ccap.ConnectionBuilder()
989 .setConnected(effectiveIsConnected)
990 .setError(outputError)
991 .setTimestamp(connectionDateAndTime);
993 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.set.connection.output.CcapBuilder ccapRpcOutput =
994 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.set.connection.output.CcapBuilder().setCcapId(
995 ccapId).setConnection(connectionRpcOutput.build());
998 ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
999 .setError(outputError)
1000 .setTimestamp(connectionDateAndTime);
1002 CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
1005 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
1008 DateAndTime rpcDateAndTime = getNowTimeStamp();
1009 rpcResponse = ccapId + ": CCAP set complete";
1010 CcapSetConnectionOutputBuilder outputBuilder =
1011 new CcapSetConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
1012 .setResponse(rpcResponse)
1013 .setTimestamp(rpcDateAndTime);
1015 return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1021 public Future<RpcResult<CcapPollConnectionOutput>> ccapPollConnection(CcapPollConnectionInput input) {
1022 // TODO refactor this method into smaller parts
1024 InstanceIdentifier<Ccap> ccapIid = (InstanceIdentifier<Ccap>) input.getCcapId();
1025 List<String> outputError = new ArrayList<String>();
1027 String ccapId = input.getCcapId().firstIdentifierOf(Ccap.class).firstKeyOf(Ccap.class).getCcapId();
1028 PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1029 Boolean effectiveIsConnected = true;
1030 String response = null;
1031 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.poll.connection.output.ccap.ConnectionBuilder
1032 connectionRpcOutput =
1033 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.poll.connection.output.ccap.ConnectionBuilder();
1035 if (pcmmService != null) {
1036 if (pcmmService.getPcmmPdpSocket()) {
1037 outputError.add(ccapId + ": CCAP Cops socket is closed");
1038 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1039 outputError.add(ccapId + ": CCAP client is disconnected with error: "
1040 + pcmmService.getPcmmCcapClientConnectErrMsg());
1042 effectiveIsConnected = false;
1044 //outputError.add(String.format(ccapId+": CCAP Cops socket is open"));
1045 if (!pcmmService.getPcmmCcapClientIsConnected()) {
1046 outputError.add(ccapId + ": CCAP client is disconnected with error: "
1047 + pcmmService.getPcmmCcapClientConnectErrMsg());
1048 effectiveIsConnected = false;
1050 outputError.add(ccapId + ": CCAP client is connected");
1053 DateAndTime connectionDateAndTime = getNowTimeStamp();
1056 ConnectionBuilder connectionOps = new ConnectionBuilder().setConnected(effectiveIsConnected)
1057 .setError(outputError)
1058 .setTimestamp(connectionDateAndTime);
1060 CcapBuilder responseCcapBuilder = new CcapBuilder().setCcapId(ccapId).setConnection(connectionOps.build());
1062 connectionRpcOutput =
1063 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.poll.connection.output.ccap.ConnectionBuilder()
1064 .setConnected(effectiveIsConnected)
1065 .setError(outputError)
1066 .setTimestamp(connectionDateAndTime);
1068 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, ccapIid, responseCcapBuilder.build());
1069 response = ccapId + ": CCAP poll complete";
1071 //pcmmService is null, do not poll
1072 response = ccapId + ": CCAP connection null; no poll performed";
1075 DateAndTime rpcDateAndTime = getNowTimeStamp();
1077 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.poll.connection.output.CcapBuilder ccapRpcOutput =
1078 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.ccap.poll.connection.output.CcapBuilder().setCcapId(
1079 ccapId).setConnection(connectionRpcOutput.build());
1081 CcapPollConnectionOutputBuilder outputBuilder =
1082 new CcapPollConnectionOutputBuilder().setCcap(ccapRpcOutput.build())
1083 .setResponse(response)
1084 .setTimestamp(rpcDateAndTime);
1086 return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1091 private App readAppFromOperationalDatastore(InstanceIdentifier<App> appIid) {
1092 Optional<App> optionalApp = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, appIid);
1093 AppBuilder thisAppBuilder = new AppBuilder(optionalApp.get());
1094 App thisApp = thisAppBuilder.build();
1095 logger.info("readAppFromConfigDatastore() retrived App: " + thisApp.getAppId());
1099 private Gate readGateFromOperationalDatastore(InstanceIdentifier<Gate> gateIid) {
1100 Optional<Gate> optionalGate = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, gateIid);
1101 if (optionalGate.isPresent()) {
1102 GateBuilder gateBuilder = new GateBuilder(optionalGate.get());
1103 Gate thisGate = gateBuilder.build();
1110 private Subscriber readSubscriberFromOperationalDatastore(InstanceIdentifier<Subscriber> subscriberIid) {
1111 Optional<Subscriber> optionalSubscriber = mdsalUtils.read(LogicalDatastoreType.OPERATIONAL, subscriberIid);
1112 if (optionalSubscriber.isPresent()) {
1113 SubscriberBuilder subscriberBuilder = new SubscriberBuilder(optionalSubscriber.get());
1114 Subscriber thisSubscriber = subscriberBuilder.build();
1115 return thisSubscriber;
1124 public Future<RpcResult<QosPollGatesOutput>> qosPollGates(QosPollGatesInput input) {
1125 // TODO refactor this method into smaller parts
1127 InstanceIdentifier<App> appIid = (InstanceIdentifier<App>) input.getAppId();
1128 //logger.info("qospollgates appIid : "+appIid.toString());
1129 App app = readAppFromOperationalDatastore(appIid);
1130 //logger.info("qospollgates app : "+app.toString());
1131 AppKey appKey = InstanceIdentifier.keyOf(appIid);
1132 String inputSubscriberId = input.getSubscriberId();
1133 String inputGateId = input.getGateId();
1134 List<String> gateOutputError = Collections.emptyList();
1135 String subscriberId = null;
1136 String gateId = null;
1137 String ccapId = null;
1138 String gatePathStr = null;
1139 String opsCopsGateId = null;
1140 Gate opsGate = null;
1142 String rpcResponse = null;
1144 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.qos.poll.gates.output.GateBuilder gateOutputBuilder =
1145 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.qos.poll.gates.output.GateBuilder();
1147 GateBuilder gateBuilder = new GateBuilder();
1149 if (inputSubscriberId != null) {
1150 if (inputGateId != null) {
1151 //Subscriber Id and Gate Id provided, only one gate to be poolled
1153 //generate the gateiid
1154 InstanceIdentifier<Gate> gateIid = appIid.builder()
1155 .child(Subscribers.class)
1156 .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1158 .child(Gate.class, new GateKey(inputGateId))
1162 opsGate = readGateFromOperationalDatastore(gateIid);
1164 //does the gate exists in the Operational DS?
1165 if (opsGate == null) {
1166 gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1167 rpcResponse = gatePathStr + ": gate does not exist in the system; gate poll not performed";
1169 opsCopsGateId = opsGate.getCopsGateId();
1170 gatePathStr = opsGate.getGatePath();
1172 if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1173 ccapId = findCcapForSubscriberId(getInetAddress(inputSubscriberId)).getCcapId();
1174 PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1175 //is the CCAP socket open?
1176 if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1177 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1178 DateAndTime gateDateAndTime = getNowTimeStamp();
1179 //logger.info("qospollgates Gate Status : GateID/"+status.getCopsGateId());
1180 //logger.info("qospollgates Gate Status : Message/"+status.getMessage());
1181 //logger.info("qospollgates Gate Status : DidSucceed/"+status.didSucceed());
1182 gateOutputError = Collections.singletonList(status.getMessage());
1184 gateOutputBuilder.setGatePath(gatePathStr)
1186 .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1187 .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1188 .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1189 .setCopsGateId(status.getCopsGateId())
1190 .setError(gateOutputError)
1191 .setTimestamp(gateDateAndTime);
1193 gateBuilder.setGateId(inputGateId)
1194 .setGatePath(gatePathStr)
1196 .setCopsGateState(status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1197 .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1198 .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1199 .setCopsGateId(status.getCopsGateId())
1200 .setError(gateOutputError)
1201 .setTimestamp(gateDateAndTime);
1203 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1204 rpcResponse = gatePathStr + ": gate poll complete";
1207 ccapId + ": CCAP socket is down or client disconnected; gate poll not performed";
1210 rpcResponse = gatePathStr + ": gate not active; gate poll not performed";
1214 //inputGateId is null; pool all gates for the subscriber if the sub exists
1216 //generate active subIid
1217 InstanceIdentifier<Subscriber> subIid = appIid.builder()
1218 .child(Subscribers.class)
1219 .child(Subscriber.class, new SubscriberKey(inputSubscriberId))
1221 //does the subscriber provided exists in the Operational Datastore?
1222 Subscriber sub = readSubscriberFromOperationalDatastore(subIid);
1224 //If Subscriber exsits poll all gates for the subscriber
1225 subscriberId = sub.getSubscriberId();
1226 List<Gate> gateList = sub.getGates().getGate();
1227 for (Gate gate : gateList) {
1228 //generate active gateIid
1229 gateId = gate.getGateId();
1230 InstanceIdentifier<Gate> gateIid =
1231 subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1233 opsGate = readGateFromOperationalDatastore(gateIid);
1234 opsCopsGateId = opsGate.getCopsGateId();
1235 //generate active gatePathStr
1236 gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1238 if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1239 ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1240 PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1241 //is the CCAP socket open?
1242 if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1243 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1244 DateAndTime gateDateAndTime = getNowTimeStamp();
1246 gateBuilder.setGateId(gateId)
1247 .setGatePath(gatePathStr)
1250 status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1251 .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1252 .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1253 .setCopsGateId(status.getCopsGateId())
1254 .setError(gateOutputError)
1255 .setTimestamp(gateDateAndTime);
1257 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1260 "qospollgates: {}: CCAP Cops socket is down or client disconnected; gate poll not performed",
1264 //TODO define what happens if a gate is not active.. is nothing ok?
1265 logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1268 rpcResponse = inputSubscriberId + "/: subscriber subtree poll in progress";
1271 inputSubscriberId + "/: subscriber is not defined in the system, gate poll not performed";
1276 // inputSubId is null
1277 if (inputGateId != null) {
1278 gatePathStr = appKey.getAppId() + "/" + inputSubscriberId + "/" + inputGateId;
1279 rpcResponse = gatePathStr + ": Subscriber ID not provided; gate poll not performed";
1281 //poll all gates for the appId
1282 PollAllGatesForApp pollAllGatesForApp = new PollAllGatesForApp(appIid,app);
1283 Thread t = new Thread(pollAllGatesForApp);
1285 rpcResponse = appKey.getAppId() + "/: gate subtree poll in progress";
1289 DateAndTime rpcDateAndTime = getNowTimeStamp();
1291 QosPollGatesOutputBuilder outputBuilder = new QosPollGatesOutputBuilder().setTimestamp(rpcDateAndTime)
1292 .setResponse(rpcResponse)
1293 .setGate(gateOutputBuilder.build());
1294 return Futures.immediateFuture(RpcResultBuilder.success(outputBuilder.build()).build());
1296 private class PollAllGatesForApp implements Runnable {
1298 private InstanceIdentifier <App> appIid;
1301 private PollAllGatesForApp (InstanceIdentifier <App> appIid, App app) {
1303 this.appIid = appIid;
1309 org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.qos.poll.gates.output.GateBuilder gateOutputBuilder =
1310 new org.opendaylight.yang.gen.v1.urn.packetcable.rev161107.qos.poll.gates.output.GateBuilder();
1312 GateBuilder gateBuilder = new GateBuilder();
1315 AppKey appKey = InstanceIdentifier.keyOf(appIid);
1317 Subscribers subs = app.getSubscribers();
1318 logger.info("qospollgates subscribers: " + subs.toString());
1320 List<Subscriber> subList = subs.getSubscriber();
1321 logger.info("qospollgates subList: " + subList.toString());
1323 for (Subscriber sub : subList) {
1324 //generate active subIid
1325 String subscriberId = sub.getSubscriberId();
1326 InstanceIdentifier<Subscriber> subIid = appIid.builder()
1327 .child(Subscribers.class)
1328 .child(Subscriber.class, new SubscriberKey(subscriberId))
1331 List<Gate> gateList = sub.getGates().getGate();
1333 for (Gate gate : gateList) {
1334 //logger.info("qospollgates active gate: "+gate);
1336 //generate active gateIid
1337 String gateId = gate.getGateId();
1338 InstanceIdentifier<Gate> gateIid =
1339 subIid.builder().child(Gates.class).child(Gate.class, new GateKey(gateId)).build();
1342 Gate opsGate = readGateFromOperationalDatastore(gateIid);
1343 String opsCopsGateId = opsGate.getCopsGateId();
1344 //generate active gatePathStr
1345 String gatePathStr = appKey.getAppId() + "/" + subscriberId + "/" + gateId;
1347 if ((!Objects.equals(opsCopsGateId, "")) && (!Objects.equals(opsCopsGateId, null))) {
1348 String ccapId = findCcapForSubscriberId(getInetAddress(subscriberId)).getCcapId();
1349 PCMMService pcmmService = pcmmServiceMap.get(ccapId);
1350 //is the CCAP socket open?
1351 if (!pcmmService.getPcmmPdpSocket() && pcmmService.getPcmmCcapClientIsConnected()) {
1352 PCMMService.GateSendStatus status = pcmmService.sendGateInfo(gatePathStr);
1353 DateAndTime gateDateAndTime = getNowTimeStamp();
1354 List<String> gateOutputError = Collections.singletonList(status.getMessage());
1357 gateBuilder.setGateId(gateId)
1358 .setGatePath(gatePathStr)
1361 status.getCopsGateState() + "/" + status.getCopsGateStateReason())
1362 .setCopsGateTimeInfo(status.getCopsGateTimeInfo())
1363 .setCopsGateUsageInfo(status.getCopsGateUsageInfo())
1364 .setCopsGateId(status.getCopsGateId())
1365 .setError(gateOutputError)
1366 .setTimestamp(gateDateAndTime);
1368 mdsalUtils.put(LogicalDatastoreType.OPERATIONAL, gateIid, gateBuilder.build());
1371 "qospollgates: {}: CCAP socket is down or client disconnected; gate poll not performed",
1375 //TODO define what happens if a gate is not active.. is nothing ok
1376 logger.info("qospollgates: {}: gate not active; gate poll not performed", gatePathStr);
1385 private DateAndTime getNowTimeStamp() {
1386 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
1387 return new DateAndTime(dateFormat.format(new Date()));