Click
Loading...
Searching...
No Matches
loadbalancer.hh
1// -*- c-basic-offset: 4 -*-
2#ifndef CLICK_LB_HH
3#define CLICK_LB_HH
4
5#include <click/ipflowid.hh>
6#include <algorithm>
7#include <random>
8#include <iterator>
9#if HAVE_DPDK
10#include <click/dpdk_glue.hh>
11#endif
12#include <click/hashtable.hh>
13#include <click/ipflowid.hh>
14#include <click/tcphelper.hh>
15#include <click/straccum.hh>
16#include <click/args.hh>
17#include <click/timer.hh>
18#include <click/algorithm.hh>
19
20template <typename T>
21class LoadBalancer { public:
22
23 LoadBalancer() : _current(0), _dsts(), _weights_helper(), _mode_case(round_robin) {
24 modetrans.find_insert("rr",round_robin);
25 modetrans.find_insert("hash",direct_hash);
26 modetrans.find_insert("chash",direct_chash);
27 modetrans.find_insert("hash_ip",direct_hash_ip);
28#if HAVE_DPDK
29 modetrans.find_insert("hash_crc",direct_hash_crc);
30#endif
31 modetrans.find_insert("hash_agg",direct_hash_agg);
32 modetrans.find_insert("cst_hash_agg",constant_hash_agg);
33 modetrans.find_insert("wrr",weighted_round_robin);
34 modetrans.find_insert("awrr",auto_weighted_round_robin);
35 modetrans.find_insert("least",least_load);
36 modetrans.find_insert("pow2",pow2);
37 modetrans.find_insert("table",table);
38 lsttrans.find_insert("conn",connections);
39 lsttrans.find_insert("packets",packets);
40 lsttrans.find_insert("bytes",bytes);
41 lsttrans.find_insert("cpu",cpu);
42#if __cplusplus > 201402L
43 std::random_device rd;
44 _gen= std::mt19937(rd());
45#endif
46 }
47
48 enum LBMode {
49 round_robin,
50 weighted_round_robin,
51 auto_weighted_round_robin,
52 pow2,
53 constant_hash_agg,
54 direct_hash,
55 direct_chash,
56 direct_hash_crc,
57 direct_hash_agg,
58 direct_hash_ip,
59 least_load,
60 table
61
62 };
63
64 static bool isLoadBased(LBMode mode) {
65 return mode == pow2 || mode == least_load || mode == weighted_round_robin || mode == auto_weighted_round_robin || mode == table;
66 }
67
68 // Metric to use when the LB technique is load-based
69 enum LSTMode {
70 connections,
71 packets,
72 bytes,
73 cpu
74 };
75
76 typedef atomic_uint64_t load_type_t;
77
78 struct MachineLoad {
79 MachineLoad() {
80 connection_load = 0;
81 cpu_load = 0;
82 raw_cpu_load = 0;
83 packets_load = 0;
84 bytes_load = 0;
85 }
86 load_type_t connection_load;
87 load_type_t packets_load;
88 load_type_t bytes_load;
89 uint64_t cpu_load;
90 uint64_t raw_cpu_load;
91 } CLICK_CACHE_ALIGN;
92
93protected:
96 per_thread<int> _current;
97 Vector <T> _dsts;
99 LBMode _mode_case;
100 LSTMode _lst_case;
101 Vector <MachineLoad, CLICK_CACHE_LINE_SIZE> _loads;
102 Vector <unsigned> _selector;
103 Vector <unsigned> _cst_hash;
104 Vector <unsigned> _spares;
105 bool _track_load;
106 bool _force_track_load;
107 int _awrr_interval;
108 float _alpha;
109 bool _autoscale;
110#if __cplusplus > 201402L
111 std::mt19937 _gen;
112#endif
113
114 uint64_t get_load_metric(int idx) {
115 return get_load_metric(idx, _lst_case);
116 }
117
118 uint64_t get_load_metric(int idx,LSTMode metric) {
119 MachineLoad& l = _loads[idx];
120 switch(metric) {
121 case connections: {
122 return l.connection_load;
123 }
124 case bytes: {
125 return l.bytes_load;
126 }
127 case packets: {
128 return l.packets_load;
129 }
130 case cpu: {
131 return l.cpu_load;
132 }
133 default:
134 assert(false);
135 }
136 }
137
138 int hash_4tuple(const Packet* p, int n) {
139 const unsigned char *data = p->data();
140 int o = 26, l = 12;
141 int h;
142 if ((int)p->length() < o + l)
143 h = 0;
144 else {
145 int d = 0;
146 for (int i = o; i < o + l; i++)
147 d += data[i];
148 if (n == 2 || n == 4 || n == 8)
149 h = (d ^ (d>>4)) & (n-1);
150 else
151 h = (d % n);
152 }
153 return h;
154 }
155
156 inline void track_load(Packet*p, int b) {
157 if (_track_load) {
158 if (TCPHelper::isSyn(p))
159 _loads[b].connection_load++;
160 else if (TCPHelper::isFin(p) || TCPHelper::isRst(p))
161 _loads[b].connection_load--;
162
163 _loads[b].packets_load++;
164 _loads[b].bytes_load += p->length();
165 }
166 }
167
168 /* Builds the constant hashing map
169 */
170 void build_hash_ring() {
171 Vector<unsigned> new_hash;
172 new_hash.resize(_cst_hash.size(), -1);
173 int fac = ((new_hash.size() - 1) / _selector.size()) + 1;
174 for (int j = 0; j < fac; j++) {
175 for (int i = 0; i < _selector.size(); i++) {
176 int server_place = cantor(_selector[i], j) % new_hash.size();
177 new_hash[server_place] = _selector[i];
178 }
179
180 }
181 int cur = _selector[0];
182 for (int i = 0; i < new_hash.size(); i++) {
183 if (new_hash[i] == - 1) {
184 new_hash[i] = cur;
185 } else
186 cur = new_hash[i];
187 }
188 _cst_hash.swap(new_hash);
189 }
190
191 static void atc(Timer *timer, void *user_data) {
192 LoadBalancer* lb = (LoadBalancer*)user_data;
193 uint64_t metric_tot = 0;
194 for (int i = 0; i < lb->_loads.size(); i++) {
195 metric_tot += lb->get_load_metric(i);
196 }
197 uint64_t avg = metric_tot / lb->_dsts.size();
198
199 Vector<unsigned> new_weight;
200 for (int i = 0; i < lb->_dsts.size(); i++) {
201 float l = lb->get_load_metric(i);
212 float buckets;
213 if (l == 0) {
214 buckets = 30;
215 } else {
216 buckets = 10 * avg / ((1 - lb->_alpha) * l + lb->_alpha*avg);
217 if (buckets > 30) buckets = 30;
218 else if (buckets < 2) buckets = 2;
219 }
220 new_weight.push_back((unsigned)buckets);
221 // click_chatter("%d load %f, %d buck",i,l,(unsigned)buckets);
222 }
223 lb->set_weights(new_weight.data());
224 timer->reschedule_after_msec(lb->_awrr_interval);
225 }
226
227 int hash_ip(const Packet* p, int n) {
228 const unsigned char *data = p->data();
229 int o = 26, l = 8;
230 int h;
231 if ((int)p->length() < o + l)
232 h = 0;
233 else {
234 int d = 0;
235 for (int i = o; i < o + l; i++)
236 d += data[i];
237 if (n == 2 || n == 4 || n == 8)
238 h = (d ^ (d>>4)) & (n-1);
239 else
240 h = (d % n);
241 }
242 return h;
243 }
244
245
246 // Parse common LB parameters
247 int parseLb(Vector<String> &conf, Element* lb, ErrorHandler* errh) {
248 String lb_mode;
249 String lst_mode;
250 int awrr_timer;
251 double alpha;
252 bool autoscale;
253 bool has_cst_buckets;
254 int cst_buckets;
255 int nserver;
256 bool force_track_load;
257 int ret = Args(lb, errh).bind(conf)
258 .read_or_set("LB_MODE", lb_mode,"rr")
259 .read_or_set("LST_MODE",lst_mode,"conn")
260 .read_or_set("AWRR_TIME",awrr_timer, 100)
261 .read_or_set("AUTOSCALE", autoscale, false)
262 .read_or_set("FORCE_TRACK_LOAD", force_track_load, false)
263 .read_or_set("NSERVER", nserver, 0)
264 .read("CST_BUCKETS", cst_buckets).read_status(has_cst_buckets)
265 .read_or_set("AWRR_ALPHA", alpha, 0).consume();
266
267 if (ret < 0)
268 return -1;
269
270 _alpha = alpha;
271 _autoscale = autoscale;
272 _force_track_load = force_track_load;
273 if (has_cst_buckets) {
274 _cst_hash.resize(cst_buckets, -1);
275 }
276
277 set_mode(lb_mode, lst_mode, lb, awrr_timer, nserver);
278
279 return ret;
280 }
281
282 void add_server() {
283 if (_spares.size() == 0) {
284 click_chatter("No server to add!");
285 return;
286 }
287 int spare = _spares.front();
288 _spares.pop_front();
289
290 int id = click_random() % _selector.size();
291 Vector<unsigned> news;
292 news.reserve(_dsts.size());
293 for (int i = 0; i < _selector.size(); i++) {
294 if (i == id) {
295 news.push_back(spare);
296 }
297 news.push_back(_selector[i]);
298 }
299 _selector.swap(news);
300 if (_mode_case == constant_hash_agg) {
301 build_hash_ring();
302 }
303 }
304
305 void remove_server() {
306 if (_selector.size() == 0) {
307 click_chatter("No server to remove!");
308 return;
309 }
310
311 int id = click_random() % _selector.size();
312 int removed = _selector[id];
313 Vector<unsigned> news;
314 news.reserve(_dsts.size());
315 for (int i = 0; i < _selector.size(); i++) {
316 if (i == id) {
317 continue;
318 }
319 news.push_back(_selector[i]);
320 }
321 _spares.push_back(removed);
322 _selector.swap(news);
323 if (_mode_case == constant_hash_agg) {
324 build_hash_ring();
325 }
326 }
327
328 enum {
329 h_load,h_load_raw,h_nb_total_servers,h_nb_active_servers,h_load_conn,h_load_packets,h_load_bytes,h_add_server,h_remove_server,h_lb_max
330 };
331
332
333 int lb_handler(int op, String &data, void *r_thunk, void* w_thunk, ErrorHandler *errh) {
334
335 LoadBalancer *cs = this;
336 if (op == Handler::f_read) {
337 switch((uintptr_t) r_thunk) {
338 case h_load: {
339 StringAccum acc;
340 if (data) {
341 int i = atoi(data.c_str());
342 if (cs->_loads.size() <= i) {
343 acc << "unknown";
344 } else {
345 acc << cs->_loads[i].cpu_load ;
346 }
347 } else {
348 for (int i = 0; i < cs->_dsts.size(); i ++) {
349 if (cs->_loads.size() <= i) {
350 acc << "unknown";
351 } else {
352 acc << cs->_loads[i].cpu_load ;
353 }
354 acc << (i == cs->_dsts.size() -1?"":" ");
355 }
356 }
357 data = acc.take_string();
358 return 0;
359 }
360 }
361 } else {
362 switch((uintptr_t)w_thunk) {
363 case h_load_raw:
364 case h_load:
365 {
366 String s(data);
367 //click_chatter("Input %s", s.c_str());
368 while (s.length() > 0) {
369 int ntoken = s.find_left(',');
370 if (ntoken < 0)
371 ntoken = s.length() - 1;
372 int pos = s.find_left(':');
373 int server_id = atoi(s.substring(0,pos).c_str());
374 int server_load = atoi(s.substring(pos + 1, ntoken).c_str());
375 //click_chatter("%d is %d",server_id, server_load);
376 if (cs->_loads.size() <= server_id) {
377 click_chatter("Invalid server id %d", server_id);
378 return 1;
379 }
380 if ((uintptr_t)w_thunk == h_load_raw) {
381 cs->_loads[server_id].cpu_load = server_load - cs->_loads[server_id].raw_cpu_load;
382 cs->_loads[server_id].raw_cpu_load = server_load;
383 } else
384 cs->_loads[server_id].cpu_load = server_load;
385// click_chatter("Server %d load %d", server_id, cs->_loads[server_id].cpu_load);
386 s = s.substring(ntoken + 1);
387 }
388
389 return 0;
390 }
391 if (cs->_autoscale)
392 cs->checkload();
393 return 0;
394 }
395 }
396 return -1;
397 }
398
399
400 int lb_write_handler(
401 const String &input, void *thunk, ErrorHandler *errh) {
402 LoadBalancer *cs = this;
403 switch((uintptr_t) thunk) {
404 case h_add_server: {
405 add_server();
406 break;
407 }
408 case h_remove_server: {
409 remove_server();
410 break;
411 }
412 }
413 return -1;
414 }
415
416 String
417 lb_read_handler(void *thunk) {
418 LoadBalancer *cs = this;
419
420 switch((uintptr_t) thunk) {
421 case h_nb_active_servers: {
422 return String(cs->_selector.size());
423 }
424 case h_nb_total_servers: {
425 return String(cs->_dsts.size());
426 }
427
428 case h_load_conn: {
429 StringAccum acc;
430 for (int i = 0; i < cs->_dsts.size(); i ++) {
431 acc << cs->get_load_metric(i,connections) << (i == cs->_dsts.size() -1?"":" ");
432 }
433 return acc.take_string();}
434 case h_load_packets:{
435 StringAccum acc;
436 for (int i = 0; i < cs->_dsts.size(); i ++) {
437 acc << cs->get_load_metric(i,packets) << (i == cs->_dsts.size() -1?"":" ");
438 }
439 return acc.take_string();}
440 case h_load_bytes:{
441 StringAccum acc;
442 for (int i = 0; i <cs-> _dsts.size(); i ++) {
443 acc << cs->get_load_metric(i,bytes) << (i == cs->_dsts.size() -1?"":" ");
444 }
445 return acc.take_string();}
446 default:
447 return "<none>";
448 }
449 }
450
451 void checkload() {
452 double tot = 0;
453 for (int i = 0; i < _selector.size(); i++) {
454 tot += _loads[_selector[i]].cpu_load;
455 }
456 double avg = tot / _loads.size();
457 if (avg > 80 && _spares.size() > 0) {
458 click_chatter("Load is %f, adding a server", avg);
459 add_server();
460 } else if (avg < 40 && _selector.size() > 1) {
461 remove_server();
462 click_chatter("Load is %f, removing a server", avg);
463 }
464
465 }
466
467 template <class C>
468 void add_lb_handlers(Element* _e) {
469 C* e = (C*)_e;
470 e->set_handler("load", Handler::f_read | Handler::f_read_param | Handler::f_write, e->handler, h_load, h_load);
471 e->set_handler("load_raw", Handler::f_write, e->handler, h_load_raw, h_load_raw);
472 e->add_read_handler("nb_active_servers", e->read_handler, h_nb_active_servers);
473 e->add_read_handler("nb_total_servers", e->read_handler, h_nb_total_servers);
474 e->add_read_handler("load_conn", e->read_handler, h_load_conn);
475 e->add_read_handler("load_bytes", e->read_handler, h_load_bytes);
476 e->add_read_handler("load_packets", e->read_handler, h_load_packets);
477 e->add_write_handler("remove_server", e->write_handler, h_remove_server);
478 e->add_write_handler("add_server", e->write_handler, h_add_server);
479 }
480
481 void set_mode(String mode, String metric="cpu", Element* owner=0,int awrr_timer_interval = -1, int nserver = 0) {
482 auto item = modetrans.find(mode);
483 _mode_case = item.value();
484 if (_mode_case == weighted_round_robin || _mode_case == auto_weighted_round_robin || _mode_case == table) {
485 auto &wh = _weights_helper.write_begin();
486 wh.resize(_dsts.size());
487 for(int i=0; i<_dsts.size(); i++) {
488 wh[i] = i;
489 }
490 _weights_helper.write_commit();
491 }
492
493 _lst_case = lsttrans.find(metric).value();
494 _track_load = ((isLoadBased(_mode_case)) && _lst_case != cpu) || _force_track_load;
495
496 if (_mode_case == auto_weighted_round_robin) {
497 Timer* awrr_timer = new Timer(atc, this);
498 awrr_timer->initialize(owner, false);
499 _awrr_interval = awrr_timer_interval;
500 awrr_timer->schedule_after(Timestamp::make_msec(_awrr_interval));
501 }
502
503 if (nserver == 0) {
504 if (_autoscale) {
505 nserver=1;
506 } else {
507 nserver= _dsts.size();
508 }
509 }
510
511 if (_mode_case == round_robin ||_mode_case == weighted_round_robin || _mode_case == auto_weighted_round_robin) {
512 int p = nserver / _current.weight();
513 if (p == 0)
514 p = 1;
515 for (int i = 0; i < _current.weight(); i++) {
516 _current.get_value(i) = (i * p) % nserver;
517 }
518 }
519 _spares.reserve(_dsts.size());
520 _selector.reserve(_dsts.size());
521 for (int i = nserver; i < _dsts.size(); i++)
522 _spares.push_back(i);
523 for (int i = 0; i < nserver; i++)
524 _selector.push_back(i);
525
526 if (_mode_case == constant_hash_agg) {
527 if (_cst_hash.size() == 0)
528 _cst_hash.resize(_dsts.size() * 100);
529 build_hash_ring();
530 }
531
532 _loads.resize(_dsts.size());
533 CLICK_ASSERT_ALIGNED(_loads.data());
534
535 }
536
537 void set_weights(unsigned weigths_value[]) {
538 Vector<unsigned> weights_helper;
539 for(int i=0; i<_dsts.size(); i++) {
540 for (unsigned j=0; j<weigths_value[i]; j++) {
541 weights_helper.push_back(i);
542 }
543 }
544#if __cplusplus > 201402L
545 std::shuffle(weights_helper.begin(), weights_helper.end(), _gen);
546#else
547 std::random_shuffle(weights_helper.begin(), weights_helper.end());
548#endif
549 auto& v = _weights_helper.write_begin();
550 v = weights_helper;
551 _weights_helper.write_commit();
552 }
553
554 inline int pick_server(const Packet* p) {
555 switch(_mode_case) {
556 case round_robin: {
557 int b = _selector.unchecked_at((*_current)++);
558 if ((unsigned)*_current == (unsigned)_selector.size()) {
559 *_current = 0;
560 }
561 return b;
562 }
563#if HAVE_DPDK
564 case direct_hash_crc: {
565 IPFlow5ID srv = IPFlow5ID(p);
566 unsigned server_val = ipv4_hash_crc(&srv, sizeof(srv), 0);
567 server_val = ((server_val >> 16) ^ (server_val & 65535)) % _selector.size();
568 return _selector.unchecked_at(server_val);
569 }
570#endif
571 case direct_hash_agg: {
572 unsigned server_val = AGGREGATE_ANNO(p);
573 server_val = ((server_val >> 16) ^ (server_val & 65535)) % _selector.size();
574 return _selector.unchecked_at(server_val);
575 }
576 case direct_hash_ip: {
577 unsigned server_val = hash_ip(p, _selector.size());
578 return _selector.unchecked_at(server_val);
579 }
580 case direct_hash: {
581 unsigned server_val = IPFlowID(p, false).hashcode();
582 server_val = ((server_val >> 16) ^ (server_val & 65535)) % _selector.size();
583 return _selector.unchecked_at(server_val);
584 }
585 case constant_hash_agg: {
586 unsigned server_val = AGGREGATE_ANNO(p);
587 server_val = ((server_val >> 16) ^ (server_val & 65535)) % _cst_hash.size();
588 return _cst_hash.unchecked_at(server_val);
589 }
590 case auto_weighted_round_robin:
591 case weighted_round_robin: {
592 //click_chatter("weighted Round Robin mode");
593 auto & wh = _weights_helper.read_begin();
594 int b = (*_current)++;
595 if (*_current >= wh.size())
596 *_current = 0;
597 if (b >= wh.size()) //Upon WR change, this may be over the new limit
598 b = 0;
599
600 int server = wh.unchecked_at(b);
601 _weights_helper.read_end();
602 return server;
603 }
604 case least_load: {
605 //click_chatter("Least loaded mode");
606 std::function<bool(MachineLoad,MachineLoad)> comp;
607
608 switch(_lst_case) {
609 case connections: {
610 comp = [&](MachineLoad m,MachineLoad n)-> bool {return m.connection_load<n.connection_load;};
611 break;
612 }
613 case bytes: {
614 comp = [&](MachineLoad m,MachineLoad n)-> bool {return m.bytes_load<n.bytes_load;};
615 break;
616 }
617 case packets: {
618 comp = [&](MachineLoad m,MachineLoad n)-> bool {return m.packets_load<n.packets_load;};
619 break;
620 }
621 case cpu: {
622 comp = [&](MachineLoad m,MachineLoad n)-> bool {return m.cpu_load<n.cpu_load;};
623 break;
624 /*Vector <uint64_t> load_dic;
625 for (int i=0;i<_dsts.size();i++){
626 dic.find_insert(_loads[i].cpu_load,i);
627 load_dic.push_back(_loads[i].cpu_load);
628 }
629 std::make_heap (load_dic.begin(), load_dic.end());
630 std::sort_heap(load_dic.begin(), load_dic.end());
631 return dic.find(load_dic.front()).value();*/
632 }
633 default:
634 assert(false);
635 break;
636 }
637 auto result = std::min_element(std::begin(_loads), std::end(_loads),comp);
638 int sid = std::distance(std::begin(_loads), result);
639 //click_chatter("%s\n--> %d",a.c_str(), sid);
640 return sid;
641 }
642 case pow2: {
643 //click_chatter("Power of 2 mode");
644 int a = _selector.unchecked_at(click_random() % _selector.size());
645 int b = _selector.unchecked_at(click_random() % _selector.size());
646 switch(_lst_case) {
647 case connections: {
648 return (_loads[a].connection_load > _loads[b].connection_load?b:a);
649 }
650 case bytes: {
651 return (_loads[a].bytes_load > _loads[b].bytes_load?b:a);
652 }
653 case packets: {
654 return (_loads[a].packets_load > _loads[b].packets_load?b:a);
655 }
656 case cpu: {
657 int ret = (_loads[a].cpu_load > _loads[b].cpu_load?b:a);
658 //click_chatter("A %d B %d -> %d",a ,b, ret);
659 return ret;
660 }
661 default:
662 assert(false);
663 }
664 return -1; //unreachable
665 }
666 case direct_chash: {
667 return hash_4tuple(p, _selector.size());
668 }
669 case table: {
670
671 auto & wh = _weights_helper.read_begin();
672 int hash = hash_4tuple(p, wh.size());
673 auto r = wh[hash];
674 _weights_helper.read_end();
675 return r;
676 }
677 default: {
678 //click_chatter("No mode set, go to bucket 0");
679 return 0;
680 break;
681 }
682 } //switch _lb_mode
683 }
684};
685
686#endif
Argument parser class.
Definition args.hh:249
Args & read_or_set(const char *keyword, T &x, const V &default_value)
Read an argument using the default parser, or set it to a default value if the argument is was not su...
Definition args.hh:403
Args & read(const char *keyword, T &x)
Read an argument using its type's default parser.
Definition args.hh:371
bool read_status() const
Return true iff the last read request succeeded.
Definition args.hh:739
Args & bind(Vector< String > &conf)
Bind this parser's arguments to conf.
Definition args.cc:171
Base class for Click elements.
Definition element.hh:42
Error reporting class.
Definition error.hh:90
@ f_read
Handler supports read operations.
Definition handler.hh:22
@ f_read_param
Read handler takes parameters.
Definition handler.hh:24
@ f_write
Handler supports write operations.
Definition handler.hh:23
Hash table template.
Definition hashtable.hh:570
const_iterator find(key_const_reference key) const
Return an iterator for the element with key key, if any.
Definition hashtable.hh:693
A network packet.
Definition packet.hh:68
const unsigned char * data() const
Return the packet's data pointer.
Definition packet.hh:1207
uint32_t length() const
Return the packet's length.
Definition packet.hh:1276
Efficiently build up Strings from pieces.
Definition straccum.hh:28
String take_string()
Return a String object with this StringAccum's contents.
Definition straccum.cc:211
A string of characters.
Definition string.hh:22
const char * c_str() const
Null-terminate the string.
Definition string.hh:519
static bool isSyn(Packet *packet)
Indicate whether a packet is a SYN packet.
Definition tcphelper.hh:444
static bool isRst(Packet *packet)
Indicate whether a packet is a RST packet.
Definition tcphelper.hh:454
static bool isFin(Packet *packet)
Indicate whether a packet is a FIN packet.
Definition tcphelper.hh:449
Triggers execution at a given time.
Definition timer.hh:14
void schedule_after(const Timestamp &delta)
Schedule the timer to fire delta time in the future.
Definition timer.cc:310
void initialize(Element *owner, bool quiet=false)
Initialize the timer.
Definition timer.cc:238
void reschedule_after_msec(uint32_t delta_msec)
Schedule the timer to fire delta_msec milliseconds after its previous expiry.
Definition timer.hh:280
static Timestamp make_msec(seconds_type sec, uint32_t msec)
Return a timestamp representing sec seconds plus msec milliseconds.
Definition timestamp.hh:332
Vector template.
Definition vector.hh:111
T * data()
Return a pointer to the vector's data.
Definition vector.hh:376
T & front()
Return a reference to the first element.
Definition vector.hh:321
bool reserve(size_type n)
Reserve space for at least n more elements.
Definition vector.hh:487
void pop_front()
Remove the first element.
Definition vector.hh:434
iterator end()
Return an iterator for the end of the vector.
Definition vector.hh:266
iterator begin()
Return an iterator for the first element in the vector.
Definition vector.hh:253
void resize(size_type n, value_argument_type v=T())
Resize the vector to contain n elements.
Definition vector.hh:390
void swap(Vector< T, ALIGNMENT > &x)
Swap the contents of this vector and x.
Definition vector.hh:493
T & unchecked_at(size_type i)
Return a reference to the ith element.
Definition vector.hh:350
size_type size() const
Return the number of elements.
Definition vector.hh:231
void push_back(value_argument_type v)
Append element v.
Definition vector.hh:399
A 64-bit integer with support for atomic operations.
Definition atomic.hh:137
Definition sync.hh:57
unsigned weight() const
Definition sync.hh:203
T & get_value(int i) const
Definition sync.hh:190
Definition multithread.hh:284
Click's hash table container template.
Click's StringAccum class, used to construct Strings efficiently from pieces.
Support for Timer, which triggers execution at a given time.