first proposal of integration plugin - library
[openflowplugin.git] / openflowplugin / src / main / java / org / opendaylight / openflowplugin / openflow / md / core / ConnectionConductorImpl.java
1 /**
2  * Copyright (c) 2013 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.openflowplugin.openflow.md.core;
10
11 import java.util.List;
12 import java.util.concurrent.Future;
13 import java.util.concurrent.LinkedBlockingQueue;
14 import java.util.concurrent.TimeUnit;
15
16 import org.opendaylight.openflowjava.protocol.api.connection.ConnectionAdapter;
17 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoReplyInputBuilder;
18 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.EchoRequestMessage;
19 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ErrorMessage;
20 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.ExperimenterMessage;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.FlowRemovedMessage;
22 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesInputBuilder;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.GetFeaturesOutput;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloInputBuilder;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.HelloMessage;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartReplyMessage;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.MultipartRequestMessage;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.OpenflowProtocolListener;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PacketInMessage;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.protocol.rev130731.PortStatusMessage;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.DisconnectEvent;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.system.rev130927.SystemNotificationsListener;
33 import org.opendaylight.yangtools.yang.common.RpcResult;
34 import org.slf4j.Logger;
35 import org.slf4j.LoggerFactory;
36
37 import com.google.common.collect.Lists;
38
39 /**
40  * @author mirehak
41  */
42 public class ConnectionConductorImpl implements OpenflowProtocolListener,
43         SystemNotificationsListener, ConnectionConductor {
44
45     private static final Logger LOG = LoggerFactory
46             .getLogger(ConnectionConductorImpl.class);
47
48     private LinkedBlockingQueue<Exception> errorQueue = new LinkedBlockingQueue<>();
49
50     private final ConnectionAdapter connectionAdapter;
51     private final List<Short> versionOrder;
52     private ConnectionConductor.CONDUCTOR_STATE conductorState;
53     private Short version;
54
55     private GetFeaturesOutput features;
56
57     /**
58      * @param connectionAdapter
59      */
60     public ConnectionConductorImpl(ConnectionAdapter connectionAdapter) {
61         this.connectionAdapter = connectionAdapter;
62         conductorState = CONDUCTOR_STATE.HANDSHAKING;
63         versionOrder = Lists.newArrayList((short) 0x04, (short) 0x01);
64         new Thread(new ErrorQueueHandler(errorQueue)).start();
65     }
66
67     @Override
68     public void init() {
69         connectionAdapter.setMessageListener(this);
70         connectionAdapter.setSystemListener(this);
71     }
72
73     @Override
74     public void onEchoRequestMessage(EchoRequestMessage arg0) {
75         LOG.debug("echo request received: " + arg0.getXid());
76         EchoReplyInputBuilder builder = new EchoReplyInputBuilder();
77         builder.setVersion(arg0.getVersion());
78         builder.setXid(arg0.getXid());
79         builder.setData(arg0.getData());
80
81         connectionAdapter.echoReply(builder.build());
82     }
83
84     @Override
85     public void onErrorMessage(ErrorMessage errorMessage) {
86         // TODO Auto-generated method stub
87         LOG.debug("error received, type: " + errorMessage.getType()
88                 + "; code: " + errorMessage.getCode());
89     }
90
91     @Override
92     public void onExperimenterMessage(ExperimenterMessage experimenterMessage) {
93         // TODO Auto-generated method stub
94         LOG.debug("experimenter received, type: "
95                 + experimenterMessage.getExpType());
96     }
97
98     @Override
99     public void onFlowRemovedMessage(FlowRemovedMessage arg0) {
100         // TODO Auto-generated method stub
101     }
102
103     @Override
104     public void onHelloMessage(HelloMessage hello) {
105         // do handshake
106         LOG.info("handshake STARTED");
107         checkState(CONDUCTOR_STATE.HANDSHAKING);
108
109         Short remoteVersion = hello.getVersion();
110         short proposedVersion;
111         try {
112             proposedVersion = proposeVersion(remoteVersion);
113         } catch (Exception e) {
114             handleException(e);
115             throw e;
116         }
117         HelloInputBuilder helloBuilder = new HelloInputBuilder();
118         helloBuilder.setVersion(proposedVersion).setXid(hello.getXid());
119         LOG.debug("sending helloReply");
120         connectionAdapter.hello(helloBuilder.build());
121
122         if (proposedVersion != remoteVersion) {
123             // need to wait for another hello
124         } else {
125             // sent version is equal to remote --> version is negotiated
126             version = proposedVersion;
127             LOG.debug("version set: " + proposedVersion);
128
129             // request features
130             GetFeaturesInputBuilder featuresBuilder = new GetFeaturesInputBuilder();
131             featuresBuilder.setVersion(version).setXid(hello.getXid());
132             Future<RpcResult<GetFeaturesOutput>> featuresFuture = connectionAdapter
133                     .getFeatures(featuresBuilder.build());
134             LOG.debug("waiting for features");
135             RpcResult<GetFeaturesOutput> rpcFeatures;
136             try {
137                 rpcFeatures = featuresFuture.get(getMaxTimeout(),
138                         TimeUnit.MILLISECONDS);
139                 LOG.debug("obtained features: datapathId="
140                         + rpcFeatures.getResult().getDatapathId());
141                 conductorState = CONDUCTOR_STATE.WORKING;
142                 this.features = rpcFeatures.getResult();
143                 LOG.info("handshake SETTLED");
144             } catch (Exception e) {
145                 handleException(e);
146             }
147         }
148     }
149
150     /**
151      * @return rpc-response timeout in [ms]
152      */
153     private long getMaxTimeout() {
154         // TODO:: get from configuration
155         return 2000;
156     }
157
158     /**
159      * @param e
160      */
161     private void handleException(Exception e) {
162         try {
163             errorQueue.put(e);
164         } catch (InterruptedException e1) {
165             LOG.error(e1.getMessage(), e1);
166         }
167     }
168
169     @Override
170     public void onMultipartReplyMessage(MultipartReplyMessage arg0) {
171         // TODO Auto-generated method stub
172     }
173
174     @Override
175     public void onMultipartRequestMessage(MultipartRequestMessage arg0) {
176         // TODO Auto-generated method stub
177     }
178
179     @Override
180     public void onPacketInMessage(PacketInMessage arg0) {
181         // TODO Auto-generated method stub
182     }
183
184     @Override
185     public void onPortStatusMessage(PortStatusMessage arg0) {
186         // TODO Auto-generated method stub
187     }
188
189     /**
190      * @param conductorState
191      *            the connectionState to set
192      */
193     @Override
194     public void setConductorState(CONDUCTOR_STATE conductorState) {
195         this.conductorState = conductorState;
196     }
197
198     @Override
199     public CONDUCTOR_STATE getConductorState() {
200         return conductorState;
201     }
202
203     /**
204      * @param handshaking
205      */
206     private void checkState(CONDUCTOR_STATE expectedState) {
207         if (!conductorState.equals(expectedState)) {
208             throw new IllegalStateException("Expected state: " + expectedState
209                     + ", actual state:" + conductorState);
210         }
211     }
212
213     @Override
214     public void onDisconnectEvent(DisconnectEvent arg0) {
215         // TODO Auto-generated method stub
216     }
217
218     protected short proposeVersion(short remoteVersion) {
219         Short proposal = null;
220         for (short offer : versionOrder) {
221             if (offer <= remoteVersion) {
222                 proposal = offer;
223                 break;
224             }
225         }
226         if (proposal == null) {
227             throw new IllegalArgumentException("unsupported version: "
228                     + remoteVersion);
229         }
230         return proposal;
231     }
232
233     @Override
234     public Short getVersion() {
235         return version;
236     }
237
238     @Override
239     public GetFeaturesOutput getFeatures() {
240         return features;
241     }
242 }