blob: 53225f9b192e9df5ed9f044bc2b8a2be32ad0fbe [file] [log] [blame]
Neale Ranns812ed392017-10-16 04:20:13 -07001/*
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#ifndef __VOM_INTERFACE_H__
17#define __VOM_INTERFACE_H__
18
Neale Ranns812ed392017-10-16 04:20:13 -070019#include "vom/enum_base.hpp"
Neale Ranns812ed392017-10-16 04:20:13 -070020#include "vom/hw.hpp"
21#include "vom/inspect.hpp"
22#include "vom/object_base.hpp"
23#include "vom/om.hpp"
24#include "vom/prefix.hpp"
25#include "vom/route_domain.hpp"
26#include "vom/rpc_cmd.hpp"
27#include "vom/singular_db.hpp"
28
Neale Ranns812ed392017-10-16 04:20:13 -070029namespace VOM {
30/**
Neale Ranns9ef1c0a2017-11-03 04:39:05 -070031 * Forward declaration of the stats and events command
32 */
33namespace interface_cmds {
Neale Ranns9ef1c0a2017-11-03 04:39:05 -070034class events_cmd;
35};
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +010036class stat_reader;
Neale Ranns9ef1c0a2017-11-03 04:39:05 -070037
38/**
Neale Ranns812ed392017-10-16 04:20:13 -070039 * A representation of an interface in VPP
40 */
41class interface : public object_base
42{
43public:
Neale Ranns871dc422018-03-29 01:28:09 -070044 struct stats_type_t : public enum_base<stats_type_t>
45 {
46 const static stats_type_t DETAILED;
47 const static stats_type_t NORMAL;
48
49 private:
50 stats_type_t(int v, const std::string& s);
51 };
52
Neale Ranns812ed392017-10-16 04:20:13 -070053 /**
54 * The key for interface's key
55 */
Neale Rannsfd920602017-11-23 12:15:00 -080056 typedef std::string key_t;
Neale Ranns812ed392017-10-16 04:20:13 -070057
58 /**
59 * The iterator type
60 */
61 typedef singular_db<const std::string, interface>::const_iterator
62 const_iterator_t;
63
64 /**
65 * An interface type
66 */
67 struct type_t : enum_base<type_t>
68 {
69 /**
Andrey "Zed" Zaikin701625b2018-04-18 17:07:07 +030070 * Unknown type
Neale Ranns812ed392017-10-16 04:20:13 -070071 */
72 const static type_t UNKNOWN;
73 /**
74 * A brideged Virtual interface (aka SVI or IRB)
75 */
76 const static type_t BVI;
77 /**
78 * VXLAN interface
79 */
80 const static type_t VXLAN;
81 /**
82 * Ethernet interface type
83 */
84 const static type_t ETHERNET;
85 /**
86 * AF-Packet interface type
87 */
88 const static type_t AFPACKET;
89 /**
90 * loopback interface type
91 */
92 const static type_t LOOPBACK;
93 /**
94 * Local interface type (specific to VPP)
95 */
96 const static type_t LOCAL;
Neale Ranns812ed392017-10-16 04:20:13 -070097
98 /**
Mohsin Kazmi9aca7b52018-07-04 15:17:01 +020099 * TAPv2 interface type
100 */
101 const static type_t TAPV2;
102
103 /**
Neale Ranns4ef42262018-02-20 08:10:44 -0800104 * vhost-user interface type
105 */
106 const static type_t VHOST;
107
108 /**
Mohsin Kazmied76ee22018-03-02 12:31:37 +0100109 * bond interface type
110 */
111 const static type_t BOND;
112
113 /**
Neale Ranns208c29a2018-04-11 08:08:30 -0700114 * pipe-parent type
115 */
116 const static type_t PIPE;
117
118 /**
119 * pipe-end type
120 */
121 const static type_t PIPE_END;
122
123 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700124 * Convert VPP's name of the interface to a type
125 */
126 static type_t from_string(const std::string& str);
127
128 private:
129 /**
130 * Private constructor taking the value and the string name
131 */
132 type_t(int v, const std::string& s);
133 };
134
135 /**
136 * The admin state of the interface
137 */
138 struct admin_state_t : enum_base<admin_state_t>
139 {
140 /**
141 * Admin DOWN state
142 */
143 const static admin_state_t DOWN;
144 /**
145 * Admin UP state
146 */
147 const static admin_state_t UP;
148
149 /**
150 * Convert VPP's numerical value to enum type
151 */
152 static admin_state_t from_int(uint8_t val);
153
154 private:
155 /**
156 * Private constructor taking the value and the string name
157 */
158 admin_state_t(int v, const std::string& s);
159 };
160
161 /**
162 * The oper state of the interface
163 */
164 struct oper_state_t : enum_base<oper_state_t>
165 {
166 /**
167 * Operational DOWN state
168 */
169 const static oper_state_t DOWN;
170 /**
171 * Operational UP state
172 */
173 const static oper_state_t UP;
174
175 /**
176 * Convert VPP's numerical value to enum type
177 */
178 static oper_state_t from_int(uint8_t val);
179
180 private:
181 /**
182 * Private constructor taking the value and the string name
183 */
184 oper_state_t(int v, const std::string& s);
185 };
186
187 /**
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100188 * stats_t:
189 */
190 struct stats_t
191 {
192 counter_t m_rx;
193 counter_t m_tx;
194 counter_t m_rx_unicast;
195 counter_t m_tx_unicast;
196 counter_t m_rx_multicast;
197 counter_t m_tx_multicast;
198 counter_t m_rx_broadcast;
199 counter_t m_tx_broadcast;
Neale Rannsd8cf40b2018-12-23 06:38:39 -0800200 counter_t m_drop;
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100201 };
202
203 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700204 * Construct a new object matching the desried state
205 */
Neale Ranns4ef42262018-02-20 08:10:44 -0800206 interface(const std::string& name,
207 type_t type,
208 admin_state_t state,
209 const std::string& tag = "");
Neale Ranns812ed392017-10-16 04:20:13 -0700210 /**
211 * Construct a new object matching the desried state mapped
212 * to a specific route_domain
213 */
214 interface(const std::string& name,
215 type_t type,
216 admin_state_t state,
Neale Ranns4ef42262018-02-20 08:10:44 -0800217 const route_domain& rd,
218 const std::string& tag = "");
Neale Ranns812ed392017-10-16 04:20:13 -0700219 /**
220 * Destructor
221 */
222 virtual ~interface();
223
224 /**
225 * Copy Constructor
226 */
227 interface(const interface& o);
228
229 static const_iterator_t cbegin();
230 static const_iterator_t cend();
231
232 /**
233 * Return the matching'singular' of the interface
234 */
235 std::shared_ptr<interface> singular() const;
236
237 /**
238 * convert to string format for debug purposes
239 */
240 virtual std::string to_string(void) const;
241
242 /**
243 * Return VPP's handle to this object
244 */
245 const handle_t& handle() const;
246
247 /**
248 * Return the interface type
249 */
250 const type_t& type() const;
251
252 /**
253 * Return the interface type
254 */
255 const std::string& name() const;
256
257 /**
258 * Return the interface type
259 */
Neale Rannsfd920602017-11-23 12:15:00 -0800260 const key_t& key() const;
Neale Ranns812ed392017-10-16 04:20:13 -0700261
262 /**
263 * Return the L2 Address
264 */
265 const l2_address_t& l2_address() const;
266
267 /**
Mohsin Kazmi17da0c02019-06-25 14:55:46 +0200268 * Return the admin state
269 */
270 const admin_state_t& admin_state() const;
271
272 /**
Neale Ranns4ef42262018-02-20 08:10:44 -0800273 * Set the admin state of the interface
Neale Ranns7752cb62019-02-19 01:41:59 -0800274 *
275 * N.B. All set function change only the attibute of the object on whcih
276 * they act, they do not make changes in VPP
Neale Ranns4ef42262018-02-20 08:10:44 -0800277 */
278 void set(const admin_state_t& state);
279
280 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700281 * Set the L2 Address
282 */
283 void set(const l2_address_t& addr);
284
285 /**
286 * Set the operational state of the interface, as reported by VPP
287 */
288 void set(const oper_state_t& state);
289
290 /**
Neale Ranns4ef42262018-02-20 08:10:44 -0800291 * Set the tag to the interface
292 */
293 void set(const std::string& tag);
294
295 /**
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100296 * Get the interface stats
297 */
298 const stats_t& get_stats(void) const;
299
300 /**
Neale Rannsfd920602017-11-23 12:15:00 -0800301 * Comparison operator - only used for UT
302 */
303 virtual bool operator==(const interface& i) const;
304
305 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700306 * A base class for interface Create commands
307 */
308 template <typename MSG>
Neale Ranns208c29a2018-04-11 08:08:30 -0700309 class create_cmd : public rpc_cmd<HW::item<handle_t>, MSG>
Neale Ranns812ed392017-10-16 04:20:13 -0700310 {
311 public:
312 create_cmd(HW::item<handle_t>& item, const std::string& name)
Neale Ranns208c29a2018-04-11 08:08:30 -0700313 : rpc_cmd<HW::item<handle_t>, MSG>(item)
Neale Ranns812ed392017-10-16 04:20:13 -0700314 , m_name(name)
315 {
316 }
317
318 /**
319 * Destructor
320 */
321 virtual ~create_cmd() = default;
322
323 /**
324 * Comparison operator - only used for UT
325 */
326 virtual bool operator==(const create_cmd& o) const
327 {
328 return (m_name == o.m_name);
329 }
330
331 /**
332 * Indicate the succeeded, when the HW Q is disabled.
333 */
334 void succeeded()
335 {
Neale Ranns208c29a2018-04-11 08:08:30 -0700336 rpc_cmd<HW::item<handle_t>, MSG>::succeeded();
Neale Ranns812ed392017-10-16 04:20:13 -0700337 interface::add(m_name, this->item());
338 }
339
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700340 /**
341 * add the created interface to the DB
342 */
343 void insert_interface() { interface::add(m_name, this->item()); }
344
Neale Ranns812ed392017-10-16 04:20:13 -0700345 virtual vapi_error_e operator()(MSG& reply)
346 {
347 int sw_if_index = reply.get_response().get_payload().sw_if_index;
348 int retval = reply.get_response().get_payload().retval;
349
Neale Ranns8e1cc462018-11-28 09:51:40 -0800350 VOM_LOG(log_level_t::DEBUG) << this->to_string() << " res:" << retval
351 << " sw-if-index:" << sw_if_index;
Neale Ranns812ed392017-10-16 04:20:13 -0700352
353 rc_t rc = rc_t::from_vpp_retval(retval);
354 handle_t handle = handle_t::INVALID;
355
356 if (rc_t::OK == rc) {
357 handle = sw_if_index;
358 }
359
Neale Ranns208c29a2018-04-11 08:08:30 -0700360 this->fulfill(HW::item<handle_t>(handle, rc));
Neale Ranns812ed392017-10-16 04:20:13 -0700361
362 return (VAPI_OK);
363 }
364
365 protected:
366 /**
367 * The name of the interface to be created
368 */
369 const std::string& m_name;
370 };
371
372 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700373 * Base class for intterface Delete commands
374 */
375 template <typename MSG>
Neale Ranns208c29a2018-04-11 08:08:30 -0700376 class delete_cmd : public rpc_cmd<HW::item<handle_t>, MSG>
Neale Ranns812ed392017-10-16 04:20:13 -0700377 {
378 public:
379 delete_cmd(HW::item<handle_t>& item, const std::string& name)
Neale Ranns208c29a2018-04-11 08:08:30 -0700380 : rpc_cmd<HW::item<handle_t>, MSG>(item)
Neale Ranns812ed392017-10-16 04:20:13 -0700381 , m_name(name)
382 {
383 }
384
385 delete_cmd(HW::item<handle_t>& item)
Neale Ranns208c29a2018-04-11 08:08:30 -0700386 : rpc_cmd<HW::item<handle_t>, MSG>(item)
Neale Ranns812ed392017-10-16 04:20:13 -0700387 , m_name()
388 {
389 }
390
391 /**
392 * Destructor
393 */
394 virtual ~delete_cmd() = default;
395
396 /**
397 * Comparison operator - only used for UT
398 */
399 virtual bool operator==(const delete_cmd& o) const
400 {
401 return (this->m_hw_item == o.m_hw_item);
402 }
403
404 /**
405 * Indicate the succeeded, when the HW Q is disabled.
406 */
407 void succeeded() {}
408
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700409 /**
Mohsin Kazmi3a758b02018-02-27 14:05:15 +0100410 * remove the deleted interface from the DB
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700411 */
412 void remove_interface() { interface::remove(this->item()); }
413
Neale Ranns812ed392017-10-16 04:20:13 -0700414 protected:
415 /**
416 * The name of the interface to be created
417 */
418 const std::string m_name;
419 };
420
Neale Ranns7e9affb2018-12-05 04:34:27 -0800421 struct event
422 {
423 event(const interface& itf, const interface::oper_state_t& state)
424 : itf(itf)
425 , state(state)
426 {
427 }
428
429 const interface& itf;
430 interface::oper_state_t state;
431 };
432
Neale Ranns812ed392017-10-16 04:20:13 -0700433 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700434 * A class that listens to interface Events
435 */
436 class event_listener
437 {
438 public:
439 /**
440 * Default Constructor
441 */
442 event_listener();
443
444 /**
445 * Virtual function called on the listener when the command has data
446 * ready to process
447 */
Neale Ranns7e9affb2018-12-05 04:34:27 -0800448 virtual void handle_interface_event(std::vector<event> es) = 0;
Neale Ranns812ed392017-10-16 04:20:13 -0700449
450 /**
451 * Return the HW::item representing the status
452 */
453 HW::item<bool>& status();
454
455 protected:
456 /**
457 * The status of the subscription
458 */
459 HW::item<bool> m_status;
460 };
461
462 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700463 * A class that listens to interface Stats
464 */
465 class stat_listener
466 {
467 public:
468 /**
469 * Default Constructor
470 */
471 stat_listener();
472
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100473 virtual ~stat_listener() = default;
474
Neale Ranns812ed392017-10-16 04:20:13 -0700475 /**
476 * Virtual function called on the listener when the command has data
477 * ready to process
478 */
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100479 virtual void handle_interface_stat(const interface&) = 0;
Neale Ranns812ed392017-10-16 04:20:13 -0700480
481 /**
482 * Return the HW::item representing the status
483 */
484 HW::item<bool>& status();
485
486 protected:
487 /**
488 * The status of the subscription
489 */
490 HW::item<bool> m_status;
491 };
492
493 /**
Neale Rannsfd920602017-11-23 12:15:00 -0800494 * The the singular instance of the interface in the DB by handle
Neale Ranns812ed392017-10-16 04:20:13 -0700495 */
496 static std::shared_ptr<interface> find(const handle_t& h);
497
498 /**
Neale Rannsfd920602017-11-23 12:15:00 -0800499 * The the singular instance of the interface in the DB by key
Neale Ranns812ed392017-10-16 04:20:13 -0700500 */
Neale Rannsfd920602017-11-23 12:15:00 -0800501 static std::shared_ptr<interface> find(const key_t& k);
Neale Ranns812ed392017-10-16 04:20:13 -0700502
503 /**
504 * Dump all interfaces into the stream provided
505 */
506 static void dump(std::ostream& os);
507
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100508 /**
509 * Enable stats for this interface
510 */
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100511 void enable_stats(stat_listener* el,
Neale Ranns871dc422018-03-29 01:28:09 -0700512 const stats_type_t& st = stats_type_t::NORMAL);
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100513
Neale Ranns7e9affb2018-12-05 04:34:27 -0800514 /**
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100515 * Disable stats for this interface
516 */
517 void disable_stats();
518
519 /**
Neale Ranns7e9affb2018-12-05 04:34:27 -0800520 * Enable the reception of events of all interfaces
521 */
522 static void enable_events(interface::event_listener& el);
523
524 /**
525 * disable the reception of events of all interfaces
526 */
527 static void disable_events();
528
Neale Ranns812ed392017-10-16 04:20:13 -0700529protected:
530 /**
Neale Rannsa2ee0292017-11-28 22:29:13 -0800531 * Set the handle of an interface object. Only called by the interface
532 * factory during the populate
Neale Ranns812ed392017-10-16 04:20:13 -0700533 */
Neale Rannsa2ee0292017-11-28 22:29:13 -0800534 void set(const handle_t& handle);
Neale Ranns9ef1c0a2017-11-03 04:39:05 -0700535 friend class interface_factory;
Neale Ranns208c29a2018-04-11 08:08:30 -0700536 friend class pipe;
Neale Ranns812ed392017-10-16 04:20:13 -0700537 /**
538 * The SW interface handle VPP has asigned to the interface
539 */
540 HW::item<handle_t> m_hdl;
541
542 /**
543 * Return the matching 'singular' of the interface
544 */
545 virtual std::shared_ptr<interface> singular_i() const;
546
547 /**
548 * release/remove an interface form the singular store
549 */
550 void release();
551
552 /**
553 * Virtual functions to construct an interface create commands.
554 * Overridden in derived classes like the sub_interface
555 */
556 virtual std::queue<cmd*>& mk_create_cmd(std::queue<cmd*>& cmds);
557
558 /**
559 * Virtual functions to construct an interface delete commands.
560 * Overridden in derived classes like the sub_interface
561 */
562 virtual std::queue<cmd*>& mk_delete_cmd(std::queue<cmd*>& cmds);
563
564 /**
565 * Sweep/reap the object if still stale
566 */
567 virtual void sweep(void);
568
569 /**
570 * A map of all interfaces key against the interface's name
571 */
Neale Rannsfd920602017-11-23 12:15:00 -0800572 static singular_db<key_t, interface> m_db;
Neale Ranns812ed392017-10-16 04:20:13 -0700573
574 /**
575 * Add an interface to the DB keyed on handle
576 */
Neale Rannsfd920602017-11-23 12:15:00 -0800577 static void add(const key_t& name, const HW::item<handle_t>& item);
Neale Ranns812ed392017-10-16 04:20:13 -0700578
579 /**
580 * remove an interface from the DB keyed on handle
581 */
582 static void remove(const HW::item<handle_t>& item);
583
584private:
585 /**
586 * Class definition for listeners to OM events
587 */
588 class event_handler : public OM::listener, public inspect::command_handler
589 {
590 public:
591 event_handler();
592 virtual ~event_handler() = default;
593
594 /**
595 * Handle a populate event
596 */
597 void handle_populate(const client_db::key_t& key);
598
599 /**
600 * Handle a replay event
601 */
602 void handle_replay();
603
604 /**
605 * Show the object in the Singular DB
606 */
607 void show(std::ostream& os);
608
609 /**
610 * Get the sortable Id of the listener
611 */
612 dependency_t order() const;
613 };
614
615 static event_handler m_evh;
616
617 /**
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100618 * friend with stat_reader
619 */
620 friend stat_reader;
621
622 /**
623 * publish stats
624 */
625 void publish_stats();
626
627 /**
628 * Set the interface stat
629 */
Neale Rannsa8ac77f2018-12-19 02:34:59 -0800630 void set(const counter_t& count, const std::string& stat_type);
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100631
632 /**
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100633 * enable the interface stats in the singular instance
634 */
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100635 void enable_stats_i(stat_listener* el, const stats_type_t& st);
636
637 /**
638 * disable the interface stats in the singular instance
639 */
640 void disable_stats_i();
Mohsin Kazmi5a4f96a2017-11-20 10:23:47 +0100641
642 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700643 * Commit the acculmulated changes into VPP. i.e. to a 'HW" write.
644 */
645 void update(const interface& obj);
646
647 /*
Neale Ranns263f9552017-11-15 02:52:13 -0800648 * return the interface's handle in the singular instance
649 */
650 const handle_t& handle_i() const;
651
652 /*
Neale Ranns812ed392017-10-16 04:20:13 -0700653 * It's the OM class that calls singular()
654 */
655 friend class OM;
656
657 /**
658 * It's the singular_db class that calls replay()
659 */
Neale Rannsfd920602017-11-23 12:15:00 -0800660 friend class singular_db<key_t, interface>;
Neale Ranns812ed392017-10-16 04:20:13 -0700661
662 /**
663 * The interfaces name
664 */
665 const std::string m_name;
666
667 /**
668 * The interface type. clearly this cannot be changed
669 * once the interface has been created.
670 */
671 const type_t m_type;
672
673 /**
674 * shared pointer to the routeDoamin the interface is in.
Neale Ranns352ea0c2017-11-14 11:04:28 -0800675 * NULL is not mapped - i.e. in the default table
Neale Ranns812ed392017-10-16 04:20:13 -0700676 */
Neale Ranns352ea0c2017-11-14 11:04:28 -0800677 std::shared_ptr<route_domain> m_rd;
Neale Ranns812ed392017-10-16 04:20:13 -0700678
679 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700680 * The state of the interface
681 */
682 HW::item<admin_state_t> m_state;
683
684 /**
685 * HW state of the VPP table mapping
686 */
687 HW::item<route::table_id_t> m_table_id;
688
689 /**
690 * HW state of the L2 address
691 */
692 HW::item<l2_address_t> m_l2_address;
693
694 /**
Neale Ranns871dc422018-03-29 01:28:09 -0700695 * The state of the detailed stats collection
696 */
697 HW::item<stats_type_t> m_stats_type;
698
699 /**
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100700 * Interface stats
701 */
702 stats_t m_stats;
703
704 /**
705 * reference to stat listener
706 */
707 stat_listener* m_listener;
708
709 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700710 * Operational state of the interface
711 */
712 oper_state_t m_oper;
713
714 /**
Neale Ranns4ef42262018-02-20 08:10:44 -0800715 * tag of the interface
716 */
717 std::string m_tag;
718
719 /**
Neale Ranns812ed392017-10-16 04:20:13 -0700720 * A map of all interfaces keyed against VPP's handle
721 */
722 static std::map<handle_t, std::weak_ptr<interface>> m_hdl_db;
723
724 /**
725 * replay the object to create it in hardware
726 */
727 virtual void replay(void);
728
729 /**
730 * Create commands are firends so they can add interfaces to the
731 * handle store.
732 */
733 template <typename MSG>
734 friend class create_cmd;
735
736 /**
737 * Create commands are firends so they can remove interfaces from the
738 * handle store.
739 */
740 template <typename MSG>
741 friend class delete_cmd;
Neale Ranns7e9affb2018-12-05 04:34:27 -0800742
743 static std::shared_ptr<interface_cmds::events_cmd> m_events_cmd;
Neale Ranns812ed392017-10-16 04:20:13 -0700744};
Mohsin Kazmi51edc3a2018-11-21 19:00:46 +0100745
746/**
747 * stream insertion operator for interface stats
748 */
749std::ostream& operator<<(std::ostream& os, const interface::stats_t& stats);
Neale Ranns812ed392017-10-16 04:20:13 -0700750};
751/*
Damjan Marion8c1afb52020-10-16 15:28:47 +0200752 * fd.io coding-style-patch-verification: OFF
Neale Ranns812ed392017-10-16 04:20:13 -0700753 *
754 * Local Variables:
755 * eval: (c-set-style "mozilla")
756 * End:
757 */
758#endif