6d7403cd8e6195f94a65cf0000299ca338c241e8
[packetcable.git] / packetcable-provider / src / main / java / org / opendaylight / controller / packetcable / provider / OpendaylightPacketcableProvider.java
1 package org.opendaylight.controller.packetcable.provider;
2
3 import java.util.Collection;
4 import java.util.Iterator;
5 import java.util.List;
6 import java.util.concurrent.ExecutionException;
7 import java.util.concurrent.ExecutorService;
8 import java.util.concurrent.Executors;
9 import java.util.concurrent.Future;
10 import java.util.concurrent.atomic.AtomicReference;
11
12 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
13 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
14 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
15 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
16 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.controller.packetcable.provider.processors.PCMMDataProcessor;
21 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
22 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
23 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RoutedRpcRegistration;
24 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
25 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.action.types.rev131112.action.list.Action;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutputBuilder;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowOutput;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.TrafficProfileBestEffortAttributes;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.TrafficProfileDocsisServiceClassNameAttributes;
39 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.TrafficProfileFlowspecAttributes;
40 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.add.flow.input.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.BestEffortCase;
41 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.add.flow.input.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.DocsisServiceClassNameCase;
42 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.traffic.profile.rev140908.add.flow.input.instructions.instruction.instruction.apply.actions._case.apply.actions.action.action.FlowspecCase;
43 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.transaction.rev131103.TransactionId;
44 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
45 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.instruction.ApplyActionsCase;
46 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.instruction.list.Instruction;
47 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeContextRef;
48 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
49 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
50 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
51 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsAdded;
52 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsAddedBuilder;
53 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsRemoved;
54 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsRemovedBuilder;
55 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsUpdated;
56 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.broker.rev140909.CmtsUpdatedBuilder;
57 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.rev140909.CmtsCapableNode;
58 import org.opendaylight.yang.gen.v1.urn.opendaylight.node.cmts.rev140909.nodes.node.CmtsNode;
59 import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.match.types.rev140909.UdpMatchRangesRpcRemoveFlow;
60 import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.match.types.rev140909.UdpMatchRangesRpcUpdateFlowOriginal;
61 import org.opendaylight.yang.gen.v1.urn.opendaylight.packetcable.match.types.rev140909.UdpMatchRangesRpcUpdateFlowUpdated;
62 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
63 import org.opendaylight.yangtools.concepts.CompositeObjectRegistration.CompositeObjectRegistrationBuilder;
64 import org.opendaylight.yangtools.concepts.ListenerRegistration;
65 import org.opendaylight.yangtools.yang.binding.DataObject;
66 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
67 import org.opendaylight.yangtools.yang.binding.RpcService;
68 import org.opendaylight.yangtools.yang.common.RpcResult;
69 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
70 import org.pcmm.gates.IClassifier;
71 import org.pcmm.gates.ITrafficProfile;
72 import org.slf4j.Logger;
73 import org.slf4j.LoggerFactory;
74
75 import com.google.common.base.Optional;
76 import com.google.common.collect.Lists;
77 import com.google.common.util.concurrent.CheckedFuture;
78 import com.google.common.util.concurrent.FutureCallback;
79 import com.google.common.util.concurrent.Futures;
80
81 @SuppressWarnings("unused")
82 public class OpendaylightPacketcableProvider implements DataChangeListener,
83                 SalFlowService, OpenDaylightPacketCableProviderService,
84                 BindingAwareProvider, AutoCloseable {
85
86         private static final Logger logger = LoggerFactory.getLogger(OpendaylightPacketcableProvider.class);
87         private NotificationProviderService notificationProvider;
88         private DataBroker dataProvider;
89
90         private final ExecutorService executor;
91
92         // The following holds the Future for the current make toast task.
93         // This is used to cancel the current toast.
94         private final AtomicReference<Future<?>> currentConnectionsTasks = new AtomicReference<>();
95         private ProviderContext providerContext;
96         private NotificationProviderService notificationService;
97         private DataBroker dataBroker;
98         private ListenerRegistration<DataChangeListener> listenerRegistration;
99         private List<InstanceIdentifier<?>> cmtsInstances;
100         private PCMMDataProcessor pcmmDataProcessor;
101
102         public OpendaylightPacketcableProvider() {
103                 executor = Executors.newCachedThreadPool();
104                 cmtsInstances = Lists.newArrayList();
105                 pcmmDataProcessor = new PCMMDataProcessor();
106         }
107
108         public void setNotificationProvider(final NotificationProviderService salService) {
109                 this.notificationProvider = salService;
110         }
111
112         public void setDataProvider(final DataBroker salDataProvider) {
113                 this.dataProvider = salDataProvider;
114         }
115
116         /**
117          * Implemented from the AutoCloseable interface.
118          */
119         @Override
120         public void close() throws ExecutionException, InterruptedException {
121                 executor.shutdown();
122                 if (dataProvider != null) {
123                         for (Iterator<InstanceIdentifier<?>> iter = cmtsInstances.iterator(); iter.hasNext();) {
124                                 WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
125                                 tx.delete(LogicalDatastoreType.OPERATIONAL, iter.next());
126                                 Futures.addCallback(tx.submit(), new FutureCallback<Void>() {
127                                         @Override
128                                         public void onSuccess(final Void result) {
129                                                 logger.debug("Delete commit result: " + result);
130                                         }
131
132                                         @Override
133                                         public void onFailure(final Throwable t) {
134                                                 logger.error("Delete operation failed", t);
135                                         }
136                                 });
137                         }
138                 }
139         }
140
141         /**
142          * Implemented from the DataChangeListener interface.
143          */
144         @Override
145         public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
146                 DataObject dataObject = change.getUpdatedSubtree();
147                 logger.debug("OpendaylightPacketcableProvider.onDataChanged() :" + dataObject);
148         }
149
150         public void notifyConsumerOnCmtsAdd(CmtsNode input, TransactionId transactionId) {
151                 CmtsAdded cmtsRemoved = new CmtsAddedBuilder().setAddress(input.getAddress()).setPort(input.getPort()).setTransactionId(transactionId).build();
152                 notificationProvider.publish(cmtsRemoved);
153         }
154
155         public void notifyConsumerOnCmtsRemove(CmtsNode input, TransactionId transactionId) {
156                 CmtsRemoved cmtsRemoved = new CmtsRemovedBuilder().setAddress(input.getAddress()).setPort(input.getPort()).setTransactionId(transactionId).build();
157                 notificationProvider.publish(cmtsRemoved);
158         }
159
160         public void notifyConsumerOnCmtsUpdate(CmtsNode input, TransactionId transactionId) {
161                 CmtsUpdated cmtsRemoved = new CmtsUpdatedBuilder().setAddress(input.getAddress()).setPort(input.getPort()).setTransactionId(transactionId).build();
162                 notificationProvider.publish(cmtsRemoved);
163         }
164
165         @Override
166         public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
167                 Match match = input.getMatch();
168                 CmtsNode cmts = getCmtsNode(input);
169                 if (cmts != null)
170                         cmtsInstances.add(input.getNode().getValue());
171                 IClassifier classifier = buildClassifier(match);
172                 ITrafficProfile trafficProfie = null;
173                 for (Instruction i : input.getInstructions().getInstruction()) {
174                         if (i.getInstruction() instanceof ApplyActionsCase) {
175                                 ApplyActionsCase aac = (ApplyActionsCase) i.getInstruction();
176                                 for (Action a : aac.getApplyActions().getAction()) {
177                                         if (a.getAction() instanceof FlowspecCase) {
178                                                 // not implemented
179                                                 // trafficProfie = buildTrafficProfile(((FlowspecCase)
180                                                 // a.getAction()).getFlowspec());
181                                         } else if (a.getAction() instanceof BestEffortCase) {
182                                                 trafficProfie = buildTrafficProfile(((BestEffortCase) a.getAction()).getBestEffort());
183                                                 break;
184                                         } else if (a.getAction() instanceof DocsisServiceClassNameCase) {
185                                                 trafficProfie = buildTrafficProfile(((DocsisServiceClassNameCase) a.getAction()).getDocsisServiceClassName());
186                                                 break;
187                                         }
188                                 }
189                         }
190                 }
191                 TransactionId transactionId = null;
192                 notifyConsumerOnCmtsAdd(cmts, transactionId);
193                 return Futures.immediateFuture(RpcResultBuilder.success(new AddFlowOutputBuilder().setTransactionId(transactionId).build()).build());
194         }
195
196         @Override
197         public ITrafficProfile buildTrafficProfile(TrafficProfileDocsisServiceClassNameAttributes docsis) {
198                 return pcmmDataProcessor.process(docsis);
199         }
200
201         @Override
202         public ITrafficProfile buildTrafficProfile(TrafficProfileBestEffortAttributes bestEffort) {
203                 return pcmmDataProcessor.process(bestEffort);
204         }
205
206         @Override
207         public ITrafficProfile buildTrafficProfile(TrafficProfileFlowspecAttributes flowSpec) {
208                 return pcmmDataProcessor.process(flowSpec);
209         }
210
211         @Override
212         public IClassifier buildClassifier(Match match) {
213                 return pcmmDataProcessor.process(match);
214         }
215
216         @Override
217         public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
218                 UdpMatchRangesRpcRemoveFlow updRange = input.getMatch().getAugmentation(UdpMatchRangesRpcRemoveFlow.class);
219                 notifyConsumerOnCmtsRemove(getCmtsNode(input), null);
220                 return null;
221         }
222
223         @Override
224         public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
225                 OriginalFlow foo = input.getOriginalFlow();
226                 UdpMatchRangesRpcUpdateFlowOriginal bar = foo.getMatch().getAugmentation(UdpMatchRangesRpcUpdateFlowOriginal.class);
227                 UpdatedFlow updated = input.getUpdatedFlow();
228                 UdpMatchRangesRpcUpdateFlowUpdated updatedRange = updated.getMatch().getAugmentation(UdpMatchRangesRpcUpdateFlowUpdated.class);
229                 notifyConsumerOnCmtsUpdate(getCmtsNode(input), null);
230                 return null;
231         }
232
233         @SuppressWarnings("unchecked")
234         protected CmtsNode getCmtsNode(NodeContextRef input) {
235                 NodeRef nodeRef = input.getNode();
236                 InstanceIdentifier<Node> instanceIdentifier = (InstanceIdentifier<Node>) nodeRef.getValue();
237                 ReadOnlyTransaction rtransaction = dataBroker.newReadOnlyTransaction();
238                 CheckedFuture<Optional<Node>, ReadFailedException> value = rtransaction.read(LogicalDatastoreType.CONFIGURATION, instanceIdentifier);
239                 rtransaction.close();
240                 Optional<Node> opt = null;
241                 try {
242                         opt = value.get();
243                 } catch (Exception e) {
244                         logger.error(e.getMessage());
245                         return null;
246                 }
247                 Node node = opt.get();
248                 CmtsCapableNode cmts = node.getAugmentation(CmtsCapableNode.class);
249                 CmtsNode cmtsNode = cmts.getCmtsNode();
250                 return cmtsNode;
251         }
252
253         @Override
254         public Collection<? extends RpcService> getImplementations() {
255                 // TODO Auto-generated method stub
256                 return null;
257         }
258
259         @Override
260         public Collection<? extends ProviderFunctionality> getFunctionality() {
261                 // TODO Auto-generated method stub
262                 return null;
263         }
264
265         @Override
266         public void onSessionInitiated(ProviderContext session) {
267                 providerContext = session;
268                 notificationService = session.getSALService(NotificationProviderService.class);
269                 dataBroker = session.getSALService(DataBroker.class);
270                 InstanceIdentifier<CmtsNode> listenTo = InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(CmtsCapableNode.class).child(CmtsNode.class);
271                 listenerRegistration = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, listenTo, this, DataChangeScope.BASE);
272         }
273
274         @Override
275         public void onSessionInitialized(ConsumerContext session) {
276                 // Noop
277
278         }
279
280         public void onSessionAdded(/* Whatever you need per CmtsConnection */) {
281                 CompositeObjectRegistrationBuilder<OpendaylightPacketcableProvider> builder = CompositeObjectRegistration.<OpendaylightPacketcableProvider> builderFor(this);
282                 /*
283                  * You will need a routedRpc registration per Cmts... I'm not doing the
284                  * accounting of storing them here, but you will need to so you can
285                  * close them when your provider is closed
286                  */
287                 RoutedRpcRegistration<SalFlowService> registration = providerContext.addRoutedRpcImplementation(SalFlowService.class, this);
288                 /*
289                  * You will need to get your identifier somewhere... this is your
290                  * nodeId. I would recommend adoption a convention like
291                  * "cmts:<ipaddress>" for CmtsCapableNodes
292                  * registration.registerPath(NodeContext.class, getIdentifier());
293                  */
294         }
295
296 }