Integrated with SFC to make RPC call.
[groupbasedpolicy.git] / groupbasedpolicy / src / main / java / org / opendaylight / groupbasedpolicy / renderer / ofoverlay / SfcManager.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.groupbasedpolicy.renderer.ofoverlay;
10
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.FutureCallback;
13 import com.google.common.util.concurrent.Futures;
14 import com.google.common.util.concurrent.ListenableFuture;
15
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
23 import org.opendaylight.groupbasedpolicy.resolver.PolicyResolver;
24 import org.opendaylight.sfc.provider.SfcProviderRpc;
25 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopInputBuilder;
26 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.ReadRenderedServicePathFirstHopOutput;
27 import org.opendaylight.yang.gen.v1.urn.cisco.params.xml.ns.yang.sfc.rsp.rev140701.rendered.service.path.first.hop.info.RenderedServicePathFirstHop;
28 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
29 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.common.rev140421.ActionDefinitionId;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.SubjectFeatureDefinitions;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.Tenants;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinition;
34 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.definitions.ActionDefinitionKey;
35 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.subject.feature.instance.ParameterValue;
36 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.Tenant;
37 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.SubjectFeatureInstances;
38 import org.opendaylight.yang.gen.v1.urn.opendaylight.groupbasedpolicy.policy.rev140421.tenants.tenant.subject.feature.instances.ActionInstance;
39 import org.opendaylight.yangtools.concepts.ListenerRegistration;
40 import org.opendaylight.yangtools.yang.binding.DataObject;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.opendaylight.yangtools.yang.common.RpcResult;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 import java.util.concurrent.Future;
47 import java.util.concurrent.ScheduledExecutorService;
48
49 /**
50  * Manage all things SFC
51  *
52  * This is a bit of a place-holder for functionality
53  * that we'll need to add for SFC integration. This
54  * will likely change a lot.
55  *
56  * TODO Move SfcManager out of ofoverlay renderer -- should be something
57  *       that's shared by renderers, not specific to ofoverlay
58  *
59  * @author tbachman
60  */
61 public class SfcManager implements AutoCloseable, DataChangeListener {
62     private static final Logger LOG =
63             LoggerFactory.getLogger(SfcManager.class);
64
65     private final DataBroker dataBroker;
66     // currently unused
67     private final PolicyResolver policyResolver;
68     // currently unused
69     private final RpcProviderRegistry rpcRegistry;
70     private final ScheduledExecutorService executor;
71     private final InstanceIdentifier<ActionInstance> allActionInstancesIid;
72     private final ListenerRegistration<DataChangeListener> actionListener;
73
74     // place-holder - not sure what we'll call it
75     private final String SFC_CHAIN_ACTION = "CHAIN";
76     private final String SFC_CHAIN_NAME = "sfc-chain-name";
77     private final String SFC_RSP_NAME = "rsp-sfc-gbp";
78
79     public SfcManager(DataBroker dataBroker,
80                       PolicyResolver policyResolver,
81                       RpcProviderRegistry rpcRegistry,
82                       ScheduledExecutorService executor) {
83         this.dataBroker = dataBroker;
84         this.policyResolver = policyResolver;
85         this.rpcRegistry = rpcRegistry;
86         this.executor = executor;
87
88         /*
89          * For now, listen to all changes in rules
90          */
91         allActionInstancesIid =
92                 InstanceIdentifier.builder(Tenants.class)
93                     .child(Tenant.class)
94                     .child(SubjectFeatureInstances.class)
95                     .child(ActionInstance.class)
96                     .build();
97         actionListener = dataBroker.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION, 
98                 allActionInstancesIid, this, DataChangeScope.ONE);
99         LOG.debug("SfcManager: Started");
100     }
101
102     @Override
103     public void onDataChanged(
104             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
105
106         for (DataObject dao : change.getCreatedData().values()) {
107             if (dao instanceof ActionInstance) {
108                 ActionInstance ai = (ActionInstance)dao;
109                 LOG.debug("New ActionInstance created");
110                 executor.execute(new MatchActionDefTask(ai));
111             }
112         }
113
114         // TODO: how to handle deletes (comment out for now)
115 //        for (InstanceIdentifier<?> iid : change.getRemovedPaths()) {
116 //            DataObject old = change.getOriginalData().get(iid);
117 //            if (old != null && old instanceof ActionInstance) {
118 //
119 //            }
120 //        }
121
122         for (DataObject dao : change.getUpdatedData().values()) {
123             if (dao instanceof ActionInstance) {
124                 ActionInstance ai = (ActionInstance)dao;
125                 executor.execute(new MatchActionDefTask(ai));
126             }
127         }
128     }
129
130     /**
131      * Private internal class that gets the action definition
132      * referenced by the instance. If the definition has an
133      * action of "chain" (or whatever we decide to use
134      * here), then we need to invoke the SFC API to go
135      * get the chain information, which we'll eventually
136      * use during policy resolution.
137      *
138      * @author tbachman
139      *
140      */
141     private class MatchActionDefTask implements Runnable,
142                      FutureCallback<Optional<ActionDefinition>> {
143         private final ActionInstance actionInstance;
144         private final InstanceIdentifier<ActionDefinition> adIid;
145         private final ActionDefinitionId id;
146
147         public MatchActionDefTask(ActionInstance actionInstance) {
148             this.actionInstance = actionInstance;
149             this.id = actionInstance.getActionDefinitionId();
150
151             adIid = InstanceIdentifier.builder(SubjectFeatureDefinitions.class)
152                                       .child(ActionDefinition.class,
153                                              new ActionDefinitionKey(this.id))
154                                       .build();
155
156         }
157
158         /**
159          * Create read transaction with callback
160          */
161         @Override
162         public void run() {
163             ReadOnlyTransaction rot = dataBroker.newReadOnlyTransaction();
164             ListenableFuture<Optional<ActionDefinition>> dao =
165                     rot.read(LogicalDatastoreType.OPERATIONAL, adIid);
166             Futures.addCallback(dao, this, executor);
167
168         }
169
170         @Override
171         public void onFailure(Throwable arg0) {
172             LOG.error("Failure reading ActionDefinition {}", id.getValue());
173         }
174
175         @Override
176         public void onSuccess(Optional<ActionDefinition> dao) {
177             LOG.debug("Found ActionDefinition {}", id.getValue());
178             if (dao instanceof ActionDefinition) {
179                 ActionDefinition ad = (ActionDefinition)dao;
180                 if (ad.getName().getValue().equals(SFC_CHAIN_ACTION)) {
181                     /*
182                      * We have the state we need:
183                      *  1) it's a "CHAIN" action
184                      *  2) the name is defined in the ActionInstance
185                      */
186                     if (actionInstance.getParameterValue() != null) {
187                         getSfcRsp();
188                     }
189                 }
190             }
191         }
192
193         /**
194          * Go get the RenderedServicePath from SFC
195          *
196          * TBD: what to do with this once we have it - who to
197          * give it to
198          */
199         private void getSfcRsp() {
200             for (ParameterValue pv: actionInstance.getParameterValue()) {
201                 if (pv.getName().getValue().equals(SFC_CHAIN_NAME)) {
202                     // TODO: check for rspFirstHop.getTransportType()
203                     ReadRenderedServicePathFirstHopInputBuilder builder =
204                         new ReadRenderedServicePathFirstHopInputBuilder();
205                     builder.setName(SFC_CHAIN_NAME);
206                     Future<RpcResult<ReadRenderedServicePathFirstHopOutput>> result =
207                         SfcProviderRpc.getSfcProviderRpc().readRenderedServicePathFirstHop(builder.build());
208                     try {
209                         RpcResult<ReadRenderedServicePathFirstHopOutput> output = result.get();
210                         if (output.isSuccessful()) {
211                             RenderedServicePathFirstHop rspFirstHop =
212                                 output.getResult().getRenderedServicePathFirstHop();
213                             IpAddress ip = rspFirstHop.getIp();
214                             PortNumber pn = rspFirstHop.getPort();
215                             // TODO: use NSI, NSP, SPI
216                             //Short nsi = rspFirstHop.getStartingIndex();
217                             //Long nsp = rspFirstHop.getPathId();
218                             //Long spi = rspFirstHop.getSymmetricPathId();
219                         }
220                     } catch (Exception e) {
221                         // TODO: proper exception handling
222                     }
223                 }
224             }
225         }
226
227
228     }
229
230     @Override
231     public void close() throws Exception {
232         if (actionListener != null) actionListener.close();
233
234     }
235 }