ROFL-pipeline  v0.6.0dev
of1x_statistics.c
1 #include "of1x_statistics.h"
2 
3 #include <assert.h>
4 #include "of1x_pipeline.h"
5 #include "of1x_flow_table.h"
6 #include "of1x_flow_entry.h"
7 #include "of1x_instruction.h"
8 #include "of1x_timers.h"
9 #include "of1x_group_table.h"
10 #include "../../../platform/memory.h"
11 #include "../../../platform/likely.h"
12 #include "../../../platform/timing.h"
13 #include "../../../platform/atomic_operations.h"
14 #include "../../../util/time.h"
15 
24 //Flow Statistics functions
30 {
31  memset(&entry->stats, 0, sizeof(of1x_stats_flow_t));
32 
33  struct timeval now;
35  entry->stats.initial_time = now;
36 
37  entry->stats.mutex = platform_mutex_init(NULL);
38 
39  return;
40 }
41 
47 {
48  platform_mutex_destroy(entry->stats.mutex);
49 }
50 
51 
52 /*
53 * Msg aggregate flow stats
54 */
55 of1x_stats_flow_aggregate_msg_t* __of1x_init_stats_flow_aggregate_msg(){
56 
58 
59  //Init counters
60  if(likely(msg!=NULL))
61  platform_memset(msg,0,sizeof(*msg));
62 
63  return msg;
64 }
66 
67  if(likely(msg!=NULL))
69 }
70 
71 /*
72 * Msg flow stats
73 */
74 of1x_stats_single_flow_msg_t* __of1x_init_stats_single_flow_msg(of1x_flow_entry_t* entry){
75 
77  __of1x_stats_flow_tid_t consolidated_stats;
78 
79  if(!entry)
80  return NULL;
81 
83 
84  if(unlikely(msg==NULL))
85  return NULL;
86 
88 
89  if(unlikely(msg->inst_grp==NULL)){
91  return NULL;
92  }
93 
94  //Fill static values
95  if(entry->table)
96  msg->table_id = entry->table->number;
97  msg->priority = entry->priority;
98  msg->cookie = entry->cookie;
99  msg->idle_timeout = entry->timer_info.idle_timeout;
100  msg->hard_timeout = entry->timer_info.hard_timeout;
101  msg->flags = entry->flags;
102 
103  //Aggregate stats
104  __of1x_stats_flow_consolidate(&entry->stats, &consolidated_stats);
105  msg->byte_count = consolidated_stats.byte_count;
106  msg->packet_count = consolidated_stats.packet_count;
107 
108  //Get durations
109  of1x_stats_flow_get_duration(entry, &msg->duration_sec, &msg->duration_nsec);
110 
111  //Copy matches
112  //TODO: deprecate this in favour of group_matches
113  msg->matches = __of1x_copy_matches(entry->matches.head);
114 
115  //Copy instructions
116  __of1x_copy_instruction_group(&entry->inst_grp,msg->inst_grp);
117 
118  return msg;
119 }
120 void __of1x_destroy_stats_single_flow_msg(of1x_stats_single_flow_msg_t* msg){
121 
122  of1x_match_t* match;
123 
124  if(unlikely(msg==NULL))
125  return;
126 
127  //TODO: deprecate this in favour of group_matches
128  match = msg->matches;
129  while(match){
130  of1x_match_t *next = match->next;
131  of1x_destroy_match(match);
132  match = next;
133  }
134 
135  //Destroy instructions
136  __of1x_destroy_instruction_group(msg->inst_grp);
137 
138 
139  platform_free_shared(msg->inst_grp);
141 }
142 
143 of1x_stats_flow_msg_t* __of1x_init_stats_flow_msg(){
144 
146 
147  //Init counters
148  if(likely(msg!=NULL))
149  platform_memset(msg,0,sizeof(*msg));
150 
151  return msg;
152 }
154 
155  of1x_stats_single_flow_msg_t* item, *next_item;
156 
157  for(item=msg->flows_head; item; item = next_item){
158  next_item = item->next;
159  __of1x_destroy_stats_single_flow_msg(item);
160  }
161 
162  //If there are single flow messages delete them
163 
164  if(msg)
166 }
167 
168 //Push to stats_flow_msg
169 void __of1x_push_single_flow_stats_to_msg(of1x_stats_flow_msg_t* msg, of1x_stats_single_flow_msg_t* sfs){
170 
171  if(unlikely(msg==NULL))
172  return;
173 
174  if(!msg->flows_head)
175  msg->flows_head = sfs;
176  else
177  msg->flows_tail->next = sfs;
178 
179  msg->flows_tail = sfs;
180  sfs->next = NULL;
181  msg->num_of_entries++;
182 }
183 
188  memset(&entry->stats.s,0,sizeof(union __of1x_stats_flow_tids));
189 }
190 
194 void of1x_stats_flow_get_duration(struct of1x_flow_entry * entry, uint32_t* sec, uint32_t* nsec){
195 
196  struct timeval now, diff;
197 
198  platform_gettimeofday(&now);
199 
200  TIMERSUB(&now, &entry->stats.initial_time, &diff);
201  *sec = diff.tv_sec;
202 
203  *nsec = ( (diff.tv_usec*1000)&0xFFFFFFFF00000000ULL )>>32;
204 }
205 
206 //Table Statistics functions
211 
212  memset(&table->stats, 0, sizeof(of1x_stats_table_t));
213 
214  //Stats mutex
215  table->stats.mutex = platform_mutex_init(NULL);
216 }
217 
222 
223  platform_mutex_destroy(table->stats.mutex);
224 }
225 //NOTE this functions add too much overhead!
226 
227 
228 void __of1x_init_group_stats(of1x_stats_group_t *group_stats){
229 
230  memset(group_stats, 0, sizeof(of1x_stats_group_t));
231 
232  //NOTE bucket stats are initialized when the group is created, before being attached to the list
233  group_stats->mutex = platform_mutex_init(NULL);
234 }
235 
236 void __of1x_destroy_group_stats(of1x_stats_group_t* group_stats){
237  platform_mutex_destroy(group_stats->mutex);
238 }
239 
240 
241 void __of1x_stats_group_inc_reference(of1x_stats_group_t *gr_stats){
242  platform_atomic_inc32(&gr_stats->ref_count, gr_stats->mutex);
243 }
244 
245 void __of1x_stats_group_dec_reference(of1x_stats_group_t *gr_stats){
246  platform_atomic_dec32(&gr_stats->ref_count, gr_stats->mutex);
247 }
248 
249 of1x_stats_group_msg_t* __of1x_init_stats_group_msg(unsigned int num_buckets){
250 
252  if(likely(msg!=NULL)){
253  msg->bucket_stats = (of1x_stats_bucket_t*) platform_malloc_shared(sizeof(of1x_stats_bucket_t) * num_buckets);
254  if(msg->bucket_stats)
255  return msg;
256  else
257  {
259  return NULL;
260  }
261  }
262  else
263  return NULL;
264 }
265 
267  of1x_stats_group_msg_t* next, *it;
268 
269  for(it=msg;it;it=next){
270  next=it->next;
271  platform_free_shared(it->bucket_stats);
273  }
274 }
275 
276 of1x_stats_group_msg_t* __of1x_get_group_single_stats(of1x_group_t* group){
277  of1x_bucket_t *bu_it;
278  of1x_stats_group_msg_t* msg = __of1x_init_stats_group_msg(group->bc_list->num_of_buckets);
279 
280  //Consolidate
282  __of1x_stats_group_consolidate(&group->stats, &c);
283 
284  msg->group_id = group->id;
285  msg->ref_count = group->stats.ref_count;
286  msg->packet_count = c.packet_count;
287  msg->byte_count = c.byte_count;
288  msg->num_of_buckets = group->bc_list->num_of_buckets;
289  msg->next = NULL;
290 
291  //collect statistics from buckets
292  int i=0;
293  for(bu_it=group->bc_list->head;bu_it;bu_it=bu_it->next,i++){
294  //Consolidate
296  __of1x_stats_bucket_consolidate(&bu_it->stats, &cc);
297 
298  msg->bucket_stats[i].byte_count = cc.byte_count;
299  msg->bucket_stats[i].packet_count = cc.packet_count;
300  }
301  return msg;
302 }
303 
305  of1x_group_t* group=NULL;
306  of1x_stats_group_msg_t *msg=NULL, *last=NULL, *head=NULL;
307 
308  if( id == OF1X_GROUP_ALL ){
309 
310  for(group=pipeline->groups->head;group;group=group->next){
311  if(group == NULL)
312  return NULL;
313 
314  msg = __of1x_get_group_single_stats(group);
315  if(last)
316  last->next = msg;
317  if(!head)
318  head=msg;
319 
320  last = msg;
321  }
322  } else{
323  //find the group
324  group = __of1x_group_search(pipeline->groups, id);
325  if(group == NULL)
326  return NULL;
327 
328  head = __of1x_get_group_single_stats(group);
329  }
330 
331  return head;
332 }
333 
334 void __of1x_destroy_bucket_desc_stats(of1x_stats_bucket_desc_msg_t* bucket){
335  of1x_destroy_action_group(bucket->actions);
336  platform_free_shared(bucket);
337 }
338 
340  of1x_stats_group_desc_msg_t *group_it, *next_gr;
341  of1x_stats_bucket_desc_msg_t* bucket_it, *next_bu;
342 
343  for(group_it=msg; group_it; group_it=next_gr){
344  next_gr = group_it->next;
345 
346  //destroy buckets
347  for(bucket_it = group_it->bucket; bucket_it; bucket_it=next_bu){
348  next_bu = bucket_it->next;
349  __of1x_destroy_bucket_desc_stats(bucket_it);
350  }
351 
352  //destroy message
353  platform_free_shared(group_it);
354  }
355 }
356 
357 of1x_stats_bucket_desc_msg_t *__of1x_init_bucket_desc_stats(of1x_bucket_t *bucket){
358  of1x_stats_bucket_desc_msg_t *desc_bucket;
359 
360  desc_bucket = platform_malloc_shared( sizeof(of1x_stats_bucket_desc_msg_t) );
361  if ( desc_bucket == NULL ){
362  return NULL;
363  }
364  desc_bucket->group = bucket->group;
365  desc_bucket->weight = bucket->weight;
366  desc_bucket->port = bucket->port;
367  //copy actions
368  desc_bucket->actions = __of1x_copy_action_group(bucket->actions);
369  desc_bucket->next = NULL;
370 
371  return desc_bucket;
372 }
373 
374 of1x_stats_group_desc_msg_t *__of1x_init_group_desc_single_stats(of1x_group_t* group){
375  of1x_bucket_t *bu_it = NULL;
376  of1x_stats_bucket_desc_msg_t *bu_desc=NULL, *head=NULL, *last=NULL;
378 
379  if ( msg==NULL )
380  return NULL;
381 
382  msg->group_id = group->id;
383  msg->type = group->type;
384  msg->next = NULL;
385 
386  for( bu_it = group->bc_list->head; bu_it; bu_it=bu_it->next){
387  bu_desc = __of1x_init_bucket_desc_stats(bu_it);
388  if(bu_desc == NULL){
390  return NULL;
391  }
392 
393  if(last)
394  last->next = bu_desc;
395  if(!head)
396  head=bu_desc;
397 
398  last = bu_desc;
399  }
400 
401  msg->bucket = head;
402 
403  return msg;
404 }
405 
407  of1x_group_t* group;
408  of1x_stats_group_desc_msg_t *msg=NULL, *last=NULL, *head=NULL;
409 
410  for(group=pipeline->groups->head;group;group=group->next){
411  msg = __of1x_init_group_desc_single_stats(group);
412 
413  if (msg == NULL){
414  if(head) of1x_destroy_group_desc_stats(head);
415  return NULL;
416  }
417 
418  if(last)
419  last->next = msg;
420  if(!head)
421  head=msg;
422 
423  last = msg;
424  }
425  return head;
426 }
427 
428 void __of1x_init_bucket_stats(__of1x_stats_bucket_t *bc_stats){
429 
430  memset(bc_stats, 0, sizeof(__of1x_stats_bucket_t));
431 
432  bc_stats->mutex = platform_mutex_init(NULL);
433 }
434 
435 void __of1x_destroy_buckets_stats(__of1x_stats_bucket_t *bc_stats){
436  platform_mutex_destroy(bc_stats->mutex);
437 }
438 
439 
440 /*
441 * External interfaces
442 */
443 
444 of1x_stats_flow_msg_t* of1x_get_flow_stats(struct of1x_pipeline* pipeline, uint8_t table_id, uint32_t cookie, uint32_t cookie_mask, uint32_t out_port, uint32_t out_group, struct of1x_match_group *const matches){
445 
446  uint32_t i,tid_start, tid_end;
448 
449  //Verify table_id
450  if(table_id >= pipeline->num_of_tables && table_id != OF1X_FLOW_TABLE_ALL)
451  return NULL;
452 
453  //Create the message
454  msg = __of1x_init_stats_flow_msg();
455  if(unlikely(msg==NULL))
456  return NULL;
457 
458  //Set the tables to go through
459  if(table_id == OF1X_FLOW_TABLE_ALL){
460  tid_start = 0;
461  tid_end = pipeline->num_of_tables;
462  }else{
463  tid_start = table_id;
464  tid_end = table_id+1;
465  }
466 
467  for(i=tid_start;i<tid_end;i++){
468  if(of1x_matching_algorithms[pipeline->tables[i].matching_algorithm].get_flow_stats_hook(&pipeline->tables[i], cookie, cookie_mask, out_port, out_group, matches, msg) != ROFL_SUCCESS){
470  return NULL;
471  }
472  }
473 
474  return msg;
475 }
476 of1x_stats_flow_aggregate_msg_t* of1x_get_flow_aggregate_stats(struct of1x_pipeline* pipeline, uint8_t table_id, uint32_t cookie, uint32_t cookie_mask, uint32_t out_port, uint32_t out_group, struct of1x_match_group *const matches){
477 
478  uint32_t i, tid_start, tid_end;
480 
481  //Verify table_id
482  if(table_id >= pipeline->num_of_tables && table_id != OF1X_FLOW_TABLE_ALL)
483  return NULL;
484 
485  //Create the message
486  msg = __of1x_init_stats_flow_aggregate_msg();
487 
488  if(unlikely(msg==NULL))
489  return NULL;
490 
491  //Set the tables to go through
492  if(table_id == OF1X_FLOW_TABLE_ALL){
493  tid_start = 0;
494  tid_end = pipeline->num_of_tables;
495  }else{
496  tid_start = table_id;
497  tid_end = table_id+1;
498  }
499 
500  for(i=tid_start;i<tid_end;i++){
501  if(of1x_matching_algorithms[pipeline->tables[i].matching_algorithm].get_flow_aggregate_stats_hook(&pipeline->tables[i], cookie, cookie_mask, out_port, out_group, matches, msg) != ROFL_SUCCESS){
503  return NULL;
504  }
505  }
506 
507  return msg;
508 }
509 
OpenFlow v1.0, 1.2 and 1.3.2 pipeline abstraction.
of1x_stats_flow_aggregate_msg_t * of1x_get_flow_aggregate_stats(struct of1x_pipeline *pipeline, uint8_t table_id, uint32_t cookie, uint32_t cookie_mask, uint32_t out_port, uint32_t out_group, struct of1x_match_group *const matches)
Retrieves aggregated flow stats.
OpenFlow v1.0, 1.2 and 1.3.2 flow table abstraction.
ROFL_BEGIN_DECLS int platform_gettimeofday(struct timeval *tval)
Gets the system time.
Group structure definition.
OpenFlow v1.0, 1.2 and 1.3.2 flow entry structure.
void platform_atomic_dec32(uint32_t *counter, platform_mutex_t *mutex)
Performs an atomic decrement of the counter (32 bit type).
Group bucket.
rofl_result_t(* get_flow_stats_hook)(struct of1x_flow_table *const table, uint64_t cookie, uint64_t cookie_mask, uint32_t out_port, uint32_t out_group, of1x_match_group_t *const matches, of1x_stats_flow_msg_t *msg)
Retrieves flow stats according to spec The operation MUST comply with the behaviour defined in the Op...
void __of1x_stats_flow_reset_counts(struct of1x_flow_entry *entry)
of1x_stats_flow_reset_counts
ROFL_BEGIN_DECLS platform_mutex_t * platform_mutex_init(void *params)
Allocates and initializes a mutex.
OpenFlow v1.X instructions.
void * platform_memset(void *src, int c, size_t length)
Sets 'c' to the whole chunk of memory.
of1x_stats_group_msg_t * of1x_get_group_stats(of1x_pipeline_t *pipeline, uint32_t id)
Retrieves the statistics of a groupReturns a structure with the statistics that needs to be freed by ...
OpenFlow v1.0, 1.2 and 1.3.2 flow table abstraction.
void of1x_destroy_action_group(of1x_action_group_t *group)
Destroy an action group.
Definition: of1x_action.c:480
Single flow entry stats message.
void of1x_destroy_match(of1x_match_t *match)
Destroys whichever match previously created using of1x_init_match_*()
Definition: of1x_match.c:1687
rofl_result_t(* get_flow_aggregate_stats_hook)(struct of1x_flow_table *const table, uint64_t cookie, uint64_t cookie_mask, uint32_t out_port, uint32_t out_group, of1x_match_group_t *const matches, of1x_stats_flow_aggregate_msg_t *msg)
Retrieves aggregate flow stats according to spec The operation MUST comply with the behaviour defined...
OpenFlow v1.0, 1.2 and 1.3.2 timers subsystem.
of1x_stats_flow_msg_t * of1x_get_flow_stats(struct of1x_pipeline *pipeline, uint8_t table_id, uint32_t cookie, uint32_t cookie_mask, uint32_t out_port, uint32_t out_group, struct of1x_match_group *const matches)
Retrieves individual flow stats.
Linked list containing all the individual flow stats.
void of1x_destroy_stats_flow_aggregate_msg(of1x_stats_flow_aggregate_msg_t *msg)
Destroy aggreagated flow_stats message.
void __of1x_stats_table_destroy(struct of1x_flow_table *table)
Destroys table statistics state.
void platform_mutex_destroy(platform_mutex_t *mutex)
Destroys and deallocates a mutex previously inited by platform_mutex_init().
void __of1x_destroy_flow_stats(struct of1x_flow_entry *entry)
of1x_stats_flow_destroy basically destroys the mutex
void __of1x_stats_table_init(struct of1x_flow_table *table)
Initializes table statistics state.
void of1x_destroy_stats_flow_msg(of1x_stats_flow_msg_t *msg)
Destroy a flow_stats message.
of1x_stats_group_desc_msg_t * of1x_get_group_desc_stats(of1x_pipeline_t *pipeline)
Retrieves a copy of the group and bucket structure.
OpenFlow v1.0, 1.2 and 1.3.2 flow entry abstraction.
void of1x_stats_flow_get_duration(struct of1x_flow_entry *entry, uint32_t *sec, uint32_t *nsec)
of1x_stats_flow_get_duration()
void * platform_malloc_shared(size_t length)
Allocates a chunk of dynamic memory of size length, which must be accessible (R/W) for all the thread...
ROFL_BEGIN_DECLS void __of1x_init_flow_stats(struct of1x_flow_entry *entry)
operations in statistics.c
OpenFlow v1.0, 1.2 and 1.3.2 pipeline abstraction data structure.
Definition: of1x_pipeline.h:50
void platform_atomic_inc32(uint32_t *counter, platform_mutex_t *mutex)
Performs an atomic increment to the counter (32 bit type).
Aggregated flow stats message.
void platform_free_shared(void *data)
Frees a chunk of dynamic memory previously allocated with platform_malloc_shared().
OpenFlow v1.0, 1.2 and 1.3.2 statistics subsystem.
void of1x_destroy_stats_group_msg(of1x_stats_group_msg_t *msg)
Frees memory of statistics messageNeeds to be called after retrieving the statistics of the groups...
of1x_group_t * __of1x_group_search(of1x_group_table_t *gt, uint32_t id)
Searches in the table for an entry with a specific id returns pointer if found or NULL if not...
OpenFlow v1.0, 1.2 and 1.3.2 group table subsystem.
void of1x_destroy_group_desc_stats(of1x_stats_group_desc_msg_t *msg)
Frees the memory for a of1x_stats_group_desc_msg_t structure.