ROFL-pipeline  v0.6.0dev
of1x_loop_ma.c
1 #include "of1x_loop_ma.h"
2 
3 #include <stdlib.h>
4 #include <assert.h>
5 #include "../../of1x_pipeline.h"
6 #include "../../of1x_flow_table.h"
7 #include "../../of1x_flow_entry.h"
8 #include "../../of1x_match.h"
9 #include "../../of1x_group_table.h"
10 #include "../../of1x_instruction.h"
11 #include "../../../of1x_async_events_hooks.h"
12 #include "../../../../../platform/lock.h"
13 #include "../../../../../platform/likely.h"
14 #include "../../../../../platform/memory.h"
15 #include "../matching_algorithms.h"
16 #include "../../../../../util/logging.h"
17 
18 #define LOOP_DESCRIPTION "The loop algorithm searches the list of entries by its priority order. On the worst case the performance is o(N) with the number of entries"
19 
34 //Nice trace
35 void of1x_remove_flow_entry_table_trace( of1x_flow_entry_t *const entry, of1x_flow_entry_t *const it, of1x_flow_remove_reason_t reason){
36  switch(reason){
37  case OF1X_FLOW_REMOVE_DELETE:
38  ROFL_PIPELINE_DEBUG("[flowmod-remove(%p)] Existing entry (%p) will be removed\n", entry, it);
39  break;
40  case OF1X_FLOW_REMOVE_IDLE_TIMEOUT:
41  ROFL_PIPELINE_DEBUG("[flowmod-remove] Removing entry(%p) due to IDLE timeout\n", it);
42  break;
43  case OF1X_FLOW_REMOVE_HARD_TIMEOUT:
44  ROFL_PIPELINE_DEBUG("[flowmod-remove] Removing entry(%p) due to HARD timeout\n", it);
45  break;
46  case OF1X_FLOW_REMOVE_GROUP_DELETE:
47  ROFL_PIPELINE_DEBUG("[flowmod-remove] Removing entry(%p) due to GROUP delete\n", it);
48  break;
49  default:
50  break;
51  }
52 
53 }
54 
58 static of1x_flow_entry_t* of1x_flow_table_loop_check_overlapping(of1x_flow_entry_t *const start_entry, of1x_flow_entry_t* entry, bool check_cookie, uint32_t out_port, uint32_t out_group){
59 
60  of1x_flow_entry_t* it; //Just for code clarity
61 
62  //Empty table
63  if( !start_entry )
64  return NULL;
65 
66  for(it=start_entry; it != NULL; it=it->next){
67  if( __of1x_flow_entry_check_overlap(it, entry, true, check_cookie, out_port, out_group) )
68  return it;
69  }
70  return NULL;
71 }
72 
76 static of1x_flow_entry_t* of1x_flow_table_loop_check_identical(of1x_flow_entry_t *const start_entry, of1x_flow_entry_t* entry, uint32_t out_port, uint32_t out_group, bool check_cookie){
77 
78  of1x_flow_entry_t* it; //Just for code clarity
79 
80  //Empty table
81  if(!start_entry)
82  return NULL;
83 
84  for(it=start_entry; it != NULL; it=it->next){
85  if( __of1x_flow_entry_check_equal(it, entry, out_port, out_group, check_cookie) )
86  return it;
87  }
88  return NULL;
89 }
90 
91 
92 /*
93 *
94 * Removal of specific entry
95 * Warning pointer to the entry MUST be a valid pointer. Some rudimentary checking are made, such checking linked list correct state,
96 * and table pointer, but no further checkings are done (including lookup in the table linked list)
97 *
98 */
99 static rofl_result_t of1x_remove_flow_entry_table_specific_imp(of1x_flow_table_t *const table, of1x_flow_entry_t *const specific_entry, of1x_flow_remove_reason_t reason, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
100 
101  if( unlikely(table->num_of_entries == 0) )
102  return ROFL_FAILURE;
103 
104  //Safety checks
105  if(unlikely(specific_entry->table != table))
106  return ROFL_FAILURE;
107  if(specific_entry->prev && unlikely(specific_entry->prev->next != specific_entry))
108  return ROFL_FAILURE;
109  if(specific_entry->next && unlikely(specific_entry->next->prev != specific_entry))
110  return ROFL_FAILURE;
111 
112  //Prevent readers to jump in
113  platform_rwlock_wrlock(table->rwlock);
114 
115 #ifdef DEBUG
116  of1x_remove_flow_entry_table_trace(NULL, specific_entry, reason);
117 #endif
118 
119  if(!specific_entry->prev){
120  //First table entry
121  if(specific_entry->next)
122  specific_entry->next->prev = NULL;
123  table->entries = specific_entry->next;
124 
125  }else{
126  specific_entry->prev->next = specific_entry->next;
127  if(specific_entry->next)
128  specific_entry->next->prev = specific_entry->prev;
129  }
130  table->num_of_entries--;
131 
132  //Green light to readers and other writers
133  platform_rwlock_wrunlock(table->rwlock);
134 
135  // let the platform do the necessary cleanup
136  if(ma_hook_ptr)
137  (*ma_hook_ptr)(specific_entry);
138  platform_of1x_remove_entry_hook(specific_entry);
139 
140  //Destroy entry
141 #ifdef ROFL_PIPELINE_LOCKLESS
142  tid_wait_all_not_present(&table->tid_presence_mask);
143 #endif
144  return __of1x_destroy_flow_entry_with_reason(specific_entry, reason);
145 }
146 
147 /*
148 * Adds flow_entry to the main table. This function is NOT thread safe, and mutual exclusion should be
149 * acquired BEFORE this function being called, using table->mutex var.
150 */
151 rofl_of1x_fm_result_t of1x_add_flow_entry_table_imp(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, bool check_overlap, bool reset_counts, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
152  of1x_flow_entry_t *it, *prev, *existing=NULL;
153 
154  if(unlikely(table->num_of_entries == OF1X_MAX_NUMBER_OF_TABLE_ENTRIES)){
155  return ROFL_OF1X_FM_FAILURE;
156  }
157 
158  if(!table->entries){
159  //No rule yet
160  entry->prev = NULL;
161  entry->next = NULL;
162  table->entries = entry;
163  //Point entry table to us
164  entry->table = table;
165 
166  table->num_of_entries++;
167 
168  // let the platform do the necessary add operations
169  if(ma_hook_ptr)
170  (*ma_hook_ptr)(entry);
172 
173  return ROFL_OF1X_FM_SUCCESS;
174  }
175 
176  //Check overlapping
177  if(check_overlap && of1x_flow_table_loop_check_overlapping(table->entries, entry, false, OF1X_PORT_ANY, OF1X_GROUP_ANY)) //Why spec is saying not to match cookie only in flow_mod add??
178  return ROFL_OF1X_FM_OVERLAP;
179 
180  //Look for existing entries (only if check_overlap is false)
181  if(!check_overlap)
182  existing = of1x_flow_table_loop_check_identical(table->entries, entry, OF1X_PORT_ANY, OF1X_GROUP_ANY, false); //According to spec do NOT check cookie
183 
184  if(existing){
185  ROFL_PIPELINE_DEBUG("[flowmod-add(%p)] Existing entry(%p) will be replaced by (%p)\n", entry, existing, entry);
186 
187  //There was already an entry. Update it..
188  if(!reset_counts){
189  ROFL_PIPELINE_DEBUG("[flowmod-add(%p)] Getting counters from (%p)\n", entry, existing);
190  __of1x_stats_copy_flow_stats(&existing->stats, &entry->stats);
191  }
192 
193  //Let it add normally...
194  }
195 
196  //Look for appropiate position in the table
197  for(it=table->entries,prev=NULL; it!=NULL;prev=it,it=it->next){
198 // if(it->num_of_matches<= entry->num_of_matches || ( it->num_of_matches<= entry->num_of_matches && it->priority<entry->priority ) ){ //HITS|PRIORITY
199  if(it->priority < entry->priority || (it->priority == entry->priority && it->matches.num_elements <= entry->matches.num_elements) ){ //PRIORITY|HITS
200  //Insert
201  if(prev == NULL){
202  //Set current entry
203  entry->prev = NULL;
204  entry->next = it;
205 
206  //Prevent readers to jump in
207  platform_rwlock_wrlock(table->rwlock);
208 
209  //Place in the head
210  it->prev = entry;
211  table->entries = entry;
212  }else{
213  //Set current entry
214  entry->prev = prev;
215  entry->next = prev->next;
216 
217  //Prevent readers to jump in
218  platform_rwlock_wrlock(table->rwlock);
219 
220  //Add to n+1 if not tail
221  if(prev->next)
222  prev->next->prev = entry;
223  //Fix prev
224  prev->next = entry;
225 
226  }
227  //Unlock mutexes
228  platform_rwlock_wrunlock(table->rwlock);
229 
230  //Increment the number of entries in the table (safe since we have the mutex acquired)
231  table->num_of_entries++;
232 
233  //Point entry table to us
234  entry->table = table;
235 
236  //Delete old entry
237  if(existing){
238  ROFL_PIPELINE_DEBUG("[flowmod-add(%p)] Removing old entry (%p)\n", entry, existing);
239 #ifdef ROFL_PIPELINE_LOCKLESS
240  tid_wait_all_not_present(&table->tid_presence_mask);
241 #endif
242 
243  if(of1x_remove_flow_entry_table_specific_imp(table,existing, OF1X_FLOW_REMOVE_NO_REASON, ma_hook_ptr) != ROFL_SUCCESS){
244  assert(0);
245  }
246  }
247 
248  // let the platform do the necessary add operations
249  if(ma_hook_ptr)
250  (*ma_hook_ptr)(entry);
252 
253  return ROFL_OF1X_FM_SUCCESS;
254  }
255  }
256 
257  if(!table->entries){
258  //There are no entries in the table
259  entry->next = entry->prev = NULL;
260  }else{
261  //Last item
262  entry->next = NULL;
263  entry->prev = prev;
264  }
265 
266  //Point entry table to us
267  entry->table = table;
268 
269  //Prevent readers to jump in
270  platform_rwlock_wrlock(table->rwlock);
271 
272  if(!table->entries){
273  //No entries
274  table->entries = entry;
275  }else{
276  //Last
277  prev->next = entry;
278  }
279 
280  //Unlock mutexes
281  platform_rwlock_wrunlock(table->rwlock);
282 
283  //Increment the number of entries in the table (safe since we have the mutex acquired)
284  table->num_of_entries++;
285 
286  //Delete old entry
287  if(existing){
288  ROFL_PIPELINE_DEBUG("[flowmod-add(%p)] Removing old entry (%p)\n", entry, existing);
289 #ifdef ROFL_PIPELINE_LOCKLESS
290  tid_wait_all_not_present(&table->tid_presence_mask);
291 #endif
292 
293  if(unlikely(of1x_remove_flow_entry_table_specific_imp(table,existing, OF1X_FLOW_REMOVE_NO_REASON, ma_hook_ptr) != ROFL_SUCCESS)){
294  assert(0);
295  }
296  }
297 
298  // let the platform do the necessary add operations
299  if(ma_hook_ptr)
300  (*ma_hook_ptr)(entry);
302 
303  return ROFL_OF1X_FM_SUCCESS;
304 }
305 
306 /*
307 *
308 * ENTRY removal for non-specific entries. It will remove the FIRST matching entry. This function assumes that match order of table_entry and entry are THE SAME. If not
309 * the result is undefined.
310 *
311 * This function shall NOT be used if there is some prior knowledge by the lookup algorithm before (specially a pointer to the entry), as it is inherently VERY innefficient
312 */
313 
314 static rofl_result_t of1x_remove_flow_entry_table_non_specific_imp(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, const enum of1x_flow_removal_strictness strict, uint32_t out_port, uint32_t out_group, of1x_flow_remove_reason_t reason, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
315 
316  int deleted=0;
317  of1x_flow_entry_t *it, *it_next;
318  of_version_t ver = table->pipeline->sw->of_ver;
319 
320  if(table->num_of_entries == 0)
321  return ROFL_SUCCESS; //according to spec
322 
323  //Loop over all the table entries
324  for(it=table->entries; it; it=it_next){
325 
326  //Save next item
327  it_next = it->next;
328 
329  if( strict == STRICT ){
330  //Strict make sure they are equal
331  if( __of1x_flow_entry_check_equal(it, entry, out_port, out_group, true && (ver != OF_VERSION_10)) ){
332 #ifdef DEBUG
333  of1x_remove_flow_entry_table_trace(entry, it, reason);
334 #endif
335  if(of1x_remove_flow_entry_table_specific_imp(table, it, reason, ma_hook_ptr) != ROFL_SUCCESS){
336  assert(0); //This should never happen
337  return ROFL_FAILURE;
338  }
339  deleted++;
340  break;
341  }
342  }else{
343  if( __of1x_flow_entry_check_contained(it, entry, strict, true && (ver != OF_VERSION_10), out_port, out_group,false) ){
344 #ifdef DEBUG
345  of1x_remove_flow_entry_table_trace(entry, it, reason);
346 #endif
347  if(of1x_remove_flow_entry_table_specific_imp(table, it, reason, ma_hook_ptr) != ROFL_SUCCESS){
348  assert(0); //This should never happen
349  return ROFL_FAILURE;
350  }
351  deleted++;
352  }
353  }
354  }
355 
356  //Even if no deletions are performed return SUCCESS
357  //if(deleted == 0)
358  // return ROFL_FAILURE;
359 
360  return ROFL_SUCCESS;
361 }
362 
363 
364 /*
365 * Removes flow_entry to the main table. This function is NOT thread safe, and mutual exclusion should be
366 * acquired BEFORE this function being called, using table->mutex var.
367 *
368 * specific_entry: the exact pointer (as per stored in the table) of the entry
369 * entry: entry containing the exact same matches (including masks) as the entry to be deleted but instance may be different
370 *
371 * specific_entry and entry set both to non-NULL values is strictly forbbiden
372 *
373 * In both cases table entry is deatached from the table but NOT DESTROYED. The duty of destroying entry is for the matching alg.
374 *
375 */
376 
377 static inline rofl_result_t of1x_remove_flow_entry_table_imp(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, of1x_flow_entry_t *const specific_entry, uint32_t out_port, uint32_t out_group, of1x_flow_remove_reason_t reason, const enum of1x_flow_removal_strictness strict, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
378 
379  if( unlikely( (entry&&specific_entry) ) || unlikely( (!entry && !specific_entry) ) )
380  return ROFL_FAILURE;
381 
382  if(entry)
383  return of1x_remove_flow_entry_table_non_specific_imp(table, entry, strict, out_port, out_group, reason, ma_hook_ptr);
384  else
385  return of1x_remove_flow_entry_table_specific_imp(table, specific_entry, reason, ma_hook_ptr);
386 }
387 
388 /* Conveniently wraps call with mutex. */
389 rofl_of1x_fm_result_t __of1x_add_flow_entry_loop(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, bool check_overlap, bool reset_counts, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
390 
391  rofl_of1x_fm_result_t return_value;
392 
393  //Allow single add/remove operation over the table
394  platform_mutex_lock(table->mutex);
395 
396  return_value = of1x_add_flow_entry_table_imp(table, entry, check_overlap, reset_counts, ma_hook_ptr);
397 
398  //Green light to other threads
399  platform_mutex_unlock(table->mutex);
400 
401  return return_value;
402 }
403 rofl_of1x_fm_result_t of1x_add_flow_entry_loop(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, bool check_overlap, bool reset_counts){
404  return __of1x_add_flow_entry_loop(table, entry, check_overlap, reset_counts, NULL);
405 }
406 
407 rofl_result_t __of1x_modify_flow_entry_loop(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, const enum of1x_flow_removal_strictness strict, bool reset_counts, void (*ma_add_hook_ptr)(of1x_flow_entry_t*), void (*ma_modify_hook_ptr)(of1x_flow_entry_t*)){
408 
409  int moded=0;
410  of1x_flow_entry_t *it;
411 
412  //Allow single add/remove operation over the table
413  platform_mutex_lock(table->mutex);
414 
415  //Loop over all the table entries
416  for(it=table->entries; it; it=it->next){
417 
418  if( strict == STRICT ){
419  //Strict make sure they are equal
420  if( __of1x_flow_entry_check_equal(it, entry, OF1X_PORT_ANY, OF1X_GROUP_ANY, true) ){
421 
422  //Modify hook
423  if(ma_modify_hook_ptr)
424  (*ma_modify_hook_ptr)(entry);
425 
426  //Call platform
427  platform_of1x_modify_entry_hook(it, entry, reset_counts);
428 
429  ROFL_PIPELINE_DEBUG("[flowmod-modify(%p)] Existing entry (%p) will be updated with (%p)\n", entry, it, entry);
430 
431  if(__of1x_update_flow_entry(it, entry, reset_counts) != ROFL_SUCCESS)
432  return ROFL_FAILURE;
433  moded++;
434  break;
435  }
436  }else{
437  if( __of1x_flow_entry_check_contained(it, entry, strict, true, OF1X_PORT_ANY, OF1X_GROUP_ANY,false) ){
438 
439  //Modify hook
440  if(ma_modify_hook_ptr)
441  (*ma_modify_hook_ptr)(entry);
442 
443  //Call platform
444  platform_of1x_modify_entry_hook(it, entry, reset_counts);
445 
446  ROFL_PIPELINE_DEBUG("[flowmod-modify(%p)] Existing entry (%p) will be updated with (%p)\n", entry, it, entry);
447 
448  if(__of1x_update_flow_entry(it, entry, reset_counts) != ROFL_SUCCESS)
449  return ROFL_FAILURE;
450  moded++;
451  }
452  }
453  }
454 
455  platform_mutex_unlock(table->mutex);
456 
457  //According to spec
458  if(moded == 0){
459  //TODO: remove cast
460  return (rofl_result_t)__of1x_add_flow_entry_loop(table, entry, false, reset_counts, ma_add_hook_ptr);
461  }
462 
463  ROFL_PIPELINE_DEBUG("[flowmod-modify(%p)] Deleting modifying flowmod \n", entry);
464 
465  //Delete the original flowmod (modify one)
466  of1x_destroy_flow_entry(entry);
467 
468  return ROFL_SUCCESS;
469 }
470 
471 rofl_result_t of1x_modify_flow_entry_loop(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, const enum of1x_flow_removal_strictness strict, bool reset_counts){
472  return __of1x_modify_flow_entry_loop(table, entry, strict, reset_counts, NULL, NULL);
473 
474 }
475 
476 rofl_result_t __of1x_remove_flow_entry_loop(of1x_flow_table_t *const table , of1x_flow_entry_t *const entry, of1x_flow_entry_t *const specific_entry, const enum of1x_flow_removal_strictness strict, uint32_t out_port, uint32_t out_group, of1x_flow_remove_reason_t reason, of1x_mutex_acquisition_required_t mutex_acquired, void (*ma_hook_ptr)(of1x_flow_entry_t*)){
477 
478  rofl_result_t result;
479 
480  //Allow single add/remove operation over the table
481  if(!mutex_acquired){
482  platform_mutex_lock(table->mutex);
483  }
484 
485  result = of1x_remove_flow_entry_table_imp(table, entry, specific_entry, out_port, out_group,reason, strict, ma_hook_ptr);
486 
487  //Green light to other threads
488  if(!mutex_acquired){
489  platform_mutex_unlock(table->mutex);
490  }
491 
492  return result;
493 }
494 
495 rofl_result_t of1x_remove_flow_entry_loop(of1x_flow_table_t *const table , of1x_flow_entry_t *const entry, of1x_flow_entry_t *const specific_entry, const enum of1x_flow_removal_strictness strict, uint32_t out_port, uint32_t out_group, of1x_flow_remove_reason_t reason, of1x_mutex_acquisition_required_t mutex_acquired){
496  return __of1x_remove_flow_entry_loop(table, entry, specific_entry, strict, out_port, out_group, reason, mutex_acquired, NULL);
497 }
498 
499 /*
500 *
501 * Statistics
502 *
503 */
504 rofl_result_t of1x_get_flow_stats_loop(struct of1x_flow_table *const table,
505  uint64_t cookie,
506  uint64_t cookie_mask,
507  uint32_t out_port,
508  uint32_t out_group,
509  of1x_match_group_t *const matches,
510  of1x_stats_flow_msg_t* msg){
511 
512  of1x_flow_entry_t* entry, flow_stats_entry;
513  of1x_stats_single_flow_msg_t* flow_stats;
514  bool check_cookie = (table->pipeline->sw->of_ver != OF_VERSION_10);
515 
516  if( unlikely(msg==NULL) || unlikely(table==NULL) )
517  return ROFL_FAILURE;
518 
519  //Create a flow_stats_entry
520  platform_memset(&flow_stats_entry,0,sizeof(of1x_flow_entry_t));
521  flow_stats_entry.matches = *matches;
522  flow_stats_entry.cookie = cookie;
523  flow_stats_entry.cookie_mask = cookie_mask;
524  check_cookie = ( table->pipeline->sw->of_ver != OF_VERSION_10 ); //Ignore cookie in OF1.0
525 
526  //Mark table as being read
527  platform_rwlock_rdlock(table->rwlock);
528 
529 
530  //Loop over the table and calculate stats
531  for(entry = table->entries; entry!=NULL; entry = entry->next){
532 
533  //Check if is contained
534  if(__of1x_flow_entry_check_contained(&flow_stats_entry, entry, false, check_cookie, out_port, out_group, true)){
535 
536  // update statistics from platform
538 
539  //Create a new single flow entry and fillin
540  flow_stats = __of1x_init_stats_single_flow_msg(entry);
541 
542  if(!flow_stats)
543  return ROFL_FAILURE;
544 
545  //Push this stat to the msg
546  __of1x_push_single_flow_stats_to_msg(msg, flow_stats);
547  }
548 
549  }
550 
551  //Release the table
552  platform_rwlock_rdunlock(table->rwlock);
553 
554  return ROFL_SUCCESS;
555 }
556 
557 rofl_result_t of1x_get_flow_aggregate_stats_loop(struct of1x_flow_table *const table,
558  uint64_t cookie,
559  uint64_t cookie_mask,
560  uint32_t out_port,
561  uint32_t out_group,
562  of1x_match_group_t *const matches,
564 
565  bool check_cookie;
566  of1x_flow_entry_t* entry, flow_stats_entry;
567 
568  if( unlikely(msg==NULL) || unlikely(table==NULL) )
569  return ROFL_FAILURE;
570 
571  //Flow stats entry for easy comparison
572  platform_memset(&flow_stats_entry,0,sizeof(of1x_flow_entry_t));
573  flow_stats_entry.matches = *matches;
574  flow_stats_entry.cookie = cookie;
575  flow_stats_entry.cookie_mask = cookie_mask;
576  check_cookie = ( table->pipeline->sw->of_ver != OF_VERSION_10 ); //Ignore cookie in OF1.0
577 
578  //Mark table as being read
579  platform_rwlock_rdlock(table->rwlock);
580 
581  //Loop over the table and calculate stats
582  for(entry = table->entries; entry!=NULL; entry = entry->next){
583 
584  //Check if is contained
585  if(__of1x_flow_entry_check_contained(&flow_stats_entry, entry, false, check_cookie, out_port, out_group,true)){
586 
587  //Consolidate stats
589  __of1x_stats_flow_consolidate(&entry->stats, &c);
590 
591  msg->packet_count += c.packet_count;
592  msg->byte_count += c.byte_count;
593  msg->flow_count++;
594  }
595 
596  }
597 
598  //Release the table
599  platform_rwlock_rdunlock(table->rwlock);
600 
601  return ROFL_SUCCESS;
602 }
603 
604 /* Group related FLOW entry lookup */
605 of1x_flow_entry_t* of1x_find_entry_using_group_loop(of1x_flow_table_t *const table, const unsigned int group_id){
606 
607  of1x_match_t* it;
608  of1x_flow_entry_t *entry;
609 
610  //Prevent writers to change structure during matching
611  platform_rwlock_rdlock(table->rwlock);
612 
613  //Find an entry that refers to the group with group_id
614  for(entry = table->entries;entry!=NULL;entry = entry->next){
615 
616  bool has_group = false;
617 
618  for( it=entry->matches.head; it; it=it->next ){
619  if(__of1x_instructions_contain_group(entry, group_id)){
620  has_group = true;
621  break;
622  }
623  }
624 
625  if(has_group){
626  //Green light for writers
627  platform_rwlock_rdunlock(table->rwlock);
628  return entry;
629  }
630  }
631 
632  //No match
633  //Green light for writers
634  platform_rwlock_rdunlock(table->rwlock);
635  return NULL;
636 }
637 
638 rofl_result_t of1x_destroy_loop(struct of1x_flow_table *const table){
639 
640  of1x_flow_entry_t *entry, *next;
641 
642  //Destroy all entries
643  for(entry = table->entries; entry; entry = next){
644  next = entry->next;
645  __of1x_destroy_flow_entry_with_reason(entry, OF1X_FLOW_REMOVE_NO_REASON);
646  }
647 
648  table->entries = NULL;
649 
650  return ROFL_SUCCESS;
651 }
652 
653 //Define the matching algorithm struct
654 OF1X_REGISTER_MATCHING_ALGORITHM(loop) = {
655  //Init and destroy hooks
656  .init_hook = NULL,
657  .destroy_hook = of1x_destroy_loop,
658 
659  //Flow mods
660  .add_flow_entry_hook = of1x_add_flow_entry_loop,
661  .modify_flow_entry_hook = of1x_modify_flow_entry_loop,
662  .remove_flow_entry_hook = of1x_remove_flow_entry_loop,
663 
664  //Stats
665  .get_flow_stats_hook = of1x_get_flow_stats_loop,
666  .get_flow_aggregate_stats_hook = of1x_get_flow_aggregate_stats_loop,
667 
668  //Find group related entries
669  .find_entry_using_group_hook = of1x_find_entry_using_group_loop,
670 
671  //Dumping
672  .dump_hook = NULL,
673  .description = LOOP_DESCRIPTION,
674 };
675 
676 
677 //Register matching algorithm
678 //WARNING! Name (first parameter) must be the folder name!!!
679 //OF1X_REGISTER_MATCHING_ALGORITHM(loop, of1x_loop);
void plaftorm_of1x_add_entry_hook(of1x_flow_entry_t *new_entry)
It can be used by hardware or other software (non rofl-pipeline) pipelines, to install the new entry...
void platform_rwlock_rdlock(platform_rwlock_t *rwlock)
Performs a read-lock over the platform_rwlock_t mutex platform_mutex_init().
void platform_mutex_lock(platform_mutex_t *mutex)
Locks the platform_mutex_t mutex.
void platform_rwlock_rdunlock(platform_rwlock_t *rwlock)
Performs a read-unlock over the platform_rwlock_t mutex platform_mutex_init().
OpenFlow v1.0, 1.2 and 1.3.2 flow entry structure.
enum of1x_flow_remove_reason of1x_flow_remove_reason_t
Flow remove reasons (enum ofp_flow_removed_reason)
void platform_mutex_unlock(platform_mutex_t *mutex)
Unlocks the platform_mutex_t mutex.
void platform_of1x_modify_entry_hook(of1x_flow_entry_t *old_entry, of1x_flow_entry_t *mod, int reset_count)
It can be used by hardware or other software (non rofl-pipeline) pipelines, to modify an entry (singl...
void platform_rwlock_wrlock(platform_rwlock_t *rwlock)
Performs a write-lock over the platform_rwlock_t mutex platform_mutex_init().
void * platform_memset(void *src, int c, size_t length)
Sets 'c' to the whole chunk of memory.
OpenFlow v1.0, 1.2 and 1.3.2 flow table abstraction.
of1x_flow_removal_strictness
Flow removal operations strictness.
Single flow entry stats message.
void platform_rwlock_wrunlock(platform_rwlock_t *rwlock)
Performs a write-unlock over the platform_rwlock_t mutex platform_mutex_init().
bool __of1x_flow_entry_check_contained(of1x_flow_entry_t *const original, of1x_flow_entry_t *const subentry, bool check_priority, bool check_cookie, uint32_t out_port, uint32_t out_group, bool reverse_out_check)
Checks whether an entry is contained in the other.
bool __of1x_flow_entry_check_overlap(of1x_flow_entry_t *const original, of1x_flow_entry_t *const entry, bool check_priority, bool check_cookie, uint32_t out_port, uint32_t out_group)
Checks whether two entries overlap overlapping.
void platform_of1x_remove_entry_hook(of1x_flow_entry_t *entry)
It can be used by hardware or other software (non rofl-pipeline) pipelines, to remove an entry (singl...
Linked list containing all the individual flow stats.
enum rofl_of1x_fm_result rofl_of1x_fm_result_t
Extended flowmod return codes.
of1x_flow_entry_t * entries
This pointer may or may not be used depending on the matching algorithm.
void platform_of1x_update_stats_hook(of1x_flow_entry_t *entry)
It can be used by hardware or other software (non rofl-pipeline) pipelines, to update the stats of an...
rofl_result_t of1x_destroy_flow_entry(of1x_flow_entry_t *entry)
Destroy the flow entry, including stats, instructions and actions.
Aggregated flow stats message.
bool __of1x_flow_entry_check_equal(of1x_flow_entry_t *const original, of1x_flow_entry_t *const entry, uint32_t out_port, uint32_t out_group, bool check_cookie)
Checks if entry is identical to another one out_port and out_grouap are ALWAYS checked against origin...