VPP Object Model (VOM)
[vpp.git] / src / vpp-api / vom / hw.cpp
1 /*
2  * Copyright (c) 2017 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include "vom/hw.hpp"
17 #include "vom/logger.hpp"
18
19 #include <vapi/vpe.api.vapi.hpp>
20
21 namespace VOM {
22 HW::cmd_q::cmd_q()
23   : m_enabled(true)
24   , m_connected(false)
25   , m_conn()
26 {
27 }
28
29 HW::cmd_q::~cmd_q()
30 {
31   m_connected = false;
32
33   if (m_rx_thread && m_rx_thread->joinable()) {
34     m_rx_thread->join();
35   }
36 }
37
38 HW::cmd_q&
39 HW::cmd_q::operator=(const HW::cmd_q& f)
40 {
41   return (*this);
42 }
43
44 /**
45  * Run the connect/dispatch thread.
46  */
47 void
48 HW::cmd_q::rx_run()
49 {
50   while (m_connected) {
51     m_conn.ctx().dispatch();
52   }
53 }
54
55 void
56 HW::cmd_q::enqueue(cmd* c)
57 {
58   std::shared_ptr<cmd> sp(c);
59
60   m_queue.push_back(sp);
61 }
62
63 void
64 HW::cmd_q::enqueue(std::shared_ptr<cmd> c)
65 {
66   m_queue.push_back(c);
67 }
68
69 void
70 HW::cmd_q::enqueue(std::queue<cmd*>& cmds)
71 {
72   while (cmds.size()) {
73     std::shared_ptr<cmd> sp(cmds.front());
74
75     m_queue.push_back(sp);
76     cmds.pop();
77   }
78 }
79
80 void
81 HW::cmd_q::dequeue(cmd* c)
82 {
83   c->retire(m_conn);
84   m_pending.erase(c);
85 }
86
87 void
88 HW::cmd_q::dequeue(std::shared_ptr<cmd> c)
89 {
90   c->retire(m_conn);
91   m_pending.erase(c.get());
92 }
93
94 void
95 HW::cmd_q::connect()
96 {
97   if (m_connected) {
98     m_conn.disconnect();
99   }
100
101   m_connected = false;
102
103   if (m_rx_thread && m_rx_thread->joinable()) {
104     m_rx_thread->join();
105   }
106
107   m_conn.connect();
108
109   m_connected = true;
110   m_rx_thread.reset(new std::thread(&HW::cmd_q::rx_run, this));
111 }
112
113 void
114 HW::cmd_q::enable()
115 {
116   m_enabled = true;
117 }
118
119 void
120 HW::cmd_q::disable()
121 {
122   m_enabled = false;
123 }
124
125 rc_t
126 HW::cmd_q::write()
127 {
128   rc_t rc = rc_t::OK;
129
130   /*
131  * The queue is enabled, Execute each command in the queue.
132  * If one execution fails, abort the rest
133  */
134   auto it = m_queue.begin();
135
136   while (it != m_queue.end()) {
137     std::shared_ptr<cmd> c = *it;
138
139     VOM_LOG(log_level_t::DEBUG) << *c;
140
141     if (m_enabled) {
142       /*
143  * before we issue the command we must move it to the pending
144  * store
145  * ince a async event can be recieved before the command
146  * completes
147  */
148       m_pending[c.get()] = c;
149
150       rc = c->issue(m_conn);
151
152       if (rc_t::INPROGRESS == rc) {
153         /*
154  * this command completes asynchronously
155  * leave the command in the pending store
156  */
157       } else {
158         /*
159  * the command completed, remove from the pending store
160  */
161         m_pending.erase(c.get());
162
163         if (rc_t::OK == rc) {
164           /*
165  * move to the next
166  */
167         } else {
168           /*
169  * barf out without issuing the rest
170  */
171           break;
172         }
173       }
174     } else {
175       /*
176  * The HW is disabled, so set each command as succeeded
177  */
178       c->succeeded();
179     }
180
181     ++it;
182   }
183
184   /*
185  * erase all objects in the queue
186  */
187   m_queue.erase(m_queue.begin(), m_queue.end());
188
189   return (rc);
190 }
191
192 /*
193  * The single Command Queue
194  */
195 HW::cmd_q* HW::m_cmdQ;
196 HW::item<bool> HW::m_poll_state;
197
198 /**
199  * Initialse the connection to VPP
200  */
201 void
202 HW::init(HW::cmd_q* f)
203 {
204   m_cmdQ = f;
205 }
206
207 /**
208  * Initialse the connection to VPP
209  */
210 void
211 HW::init()
212 {
213   m_cmdQ = new cmd_q();
214 }
215
216 void
217 HW::enqueue(cmd* cmd)
218 {
219   m_cmdQ->enqueue(cmd);
220 }
221
222 void
223 HW::enqueue(std::shared_ptr<cmd> cmd)
224 {
225   m_cmdQ->enqueue(cmd);
226 }
227
228 void
229 HW::enqueue(std::queue<cmd*>& cmds)
230 {
231   m_cmdQ->enqueue(cmds);
232 }
233
234 void
235 HW::dequeue(cmd* cmd)
236 {
237   m_cmdQ->dequeue(cmd);
238 }
239
240 void
241 HW::dequeue(std::shared_ptr<cmd> cmd)
242 {
243   m_cmdQ->dequeue(cmd);
244 }
245
246 void
247 HW::connect()
248 {
249   m_cmdQ->connect();
250 }
251
252 void
253 HW::enable()
254 {
255   m_cmdQ->enable();
256 }
257
258 void
259 HW::disable()
260 {
261   m_cmdQ->disable();
262 }
263
264 rc_t
265 HW::write()
266 {
267   return (m_cmdQ->write());
268 }
269
270 bool
271 HW::poll()
272 {
273   std::shared_ptr<cmd> poll(new Poll(m_poll_state));
274
275   HW::enqueue(poll);
276   HW::write();
277
278   return (m_poll_state);
279 }
280
281 template <>
282 std::string
283 HW::item<bool>::to_string() const
284 {
285   std::ostringstream os;
286
287   os << "hw-item:["
288      << "rc:" << item_rc.to_string() << " data:" << item_data << "]";
289   return (os.str());
290 }
291
292 template <>
293 std::string
294 HW::item<unsigned int>::to_string() const
295 {
296   std::ostringstream os;
297
298   os << "hw-item:["
299      << "rc:" << item_rc.to_string() << " data:" << item_data << "]";
300   return (os.str());
301 }
302
303 HW::Poll::Poll(HW::item<bool>& item)
304   : rpc_cmd(item)
305 {
306 }
307
308 rc_t
309 HW::Poll::issue(connection& con)
310 {
311   msg_t req(con.ctx(), std::ref(*this));
312
313   VAPI_CALL(req.execute());
314
315   m_hw_item.set(wait());
316
317   return (rc_t::OK);
318 }
319
320 std::string
321 HW::Poll::to_string() const
322 {
323   std::ostringstream s;
324
325   s << "poll: " << m_hw_item.to_string();
326
327   return (s.str());
328 }
329 }
330
331 /*
332  * fd.io coding-style-patch-verification: ON
333  *
334  * Local Variables:
335  * eval: (c-set-style "mozilla")
336  * End:
337  */