ROFL-pipeline  v0.6.0dev
of1x_l2hash_ma.c
1 #include "of1x_l2hash_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 "../loop/of1x_loop_ma.h"
17 
18 #define L2HASH_DESCRIPTION "The l2hash 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 
20 
21 //
22 // Constructors and destructors
23 //
24 rofl_result_t of1x_init_l2hash(struct of1x_flow_table *const table){
25 
26  //Allocate memory for the hash table
27  table->matching_aux[0] = (void*)platform_malloc_shared(sizeof(l2hash_state_t));
28  //Cleanup everything
29  memset(table->matching_aux[0], 0, sizeof(l2hash_state_t));
30 
31  //Matches and wildcards support
32  bitmap128_clean(&table->config.match);
33  bitmap128_set(&table->config.match, OF1X_MATCH_ETH_DST);
34  bitmap128_set(&table->config.match, OF1X_MATCH_VLAN_VID);
35 
36  bitmap128_clean(&table->config.wildcards);
37 
38  return ROFL_SUCCESS;
39 }
40 
41 
42 static void l2hash_destroy_ht(l2hash_ht_table_t* ht){
43  unsigned int i;
44  l2hash_ht_bucket_t *bucket, *next_bucket;
45 
46  if(ht->num_of_entries)
47  return;
48 
49  //Loop over tables and de
50  for(i=0;i<L2HASH_MAX_ENTRIES;i++){
51  if(ht->table[i].num_of_buckets){
52  bucket = ht->table[i].bucket_list;
53  while(bucket){
54  next_bucket = bucket->next;
55  platform_free_shared(bucket);
56  bucket = next_bucket;
57  }
58  }
59  }
60 }
61 
62 //Add&Remove routine
63 void l2hash_ht_add_bucket(l2hash_ht_table_t* ht, uint16_t hash, l2hash_ht_bucket_t* bucket){
64  l2hash_ht_entry_t* ht_e = &ht->table[hash];
66 
67  //Insertion priority
68  uint32_t priority = bucket->entry->priority;
69 
70  //Assign HT entry to the buck
71  bucket->ht_entry = ht_e;
72 
73  if(ht_e->bucket_list){
74  it = ht_e->bucket_list;
75  //Find the postion
76  while(it){
77  if(it->entry->priority <= priority)
78  break;
79  it = it->next;
80  }
81 
82  //Assign first the next and previous on our node
83  bucket->next = it;
84  bucket->prev = it->prev;
85  it->prev = bucket;
86 
87  //Add before it
88  if(it->prev)
89  it->prev->next = bucket;
90  else
91  ht_e->bucket_list = bucket;
92  }else{
93  //Put in the head and continue
94  ht_e->bucket_list = bucket;
95  bucket->next = bucket->prev = NULL;
96  }
97 
98  ht_e->num_of_buckets++;
99 }
100 
101 void l2hash_ht_remove_bucket(l2hash_ht_bucket_t* bucket){
102 
103  //Recover the entry from the bucket
104  l2hash_ht_entry_t* ht_e = bucket->ht_entry;
105 
106  //Adjust prev and next pointers
107  if(bucket->next)
108  bucket->next->prev = bucket->prev;
109 
110  if(bucket->prev){
111  bucket->prev->next = bucket->next;
112  }else{
113  ht_e->bucket_list = bucket->next;
114  }
115 
116  ht_e->num_of_buckets--;
117 }
118 
119 
120 //
121 // L2 hash table state
122 //
123 rofl_result_t of1x_destroy_l2hash(struct of1x_flow_table *const table){
124 
125  l2hash_destroy_ht(&((struct l2hash_state*)table->matching_aux[0])->vlan);
126  l2hash_destroy_ht(&((struct l2hash_state*)table->matching_aux[0])->no_vlan);
128 
129  return ROFL_FAILURE;
130 }
131 
132 //
133 //Hooks
134 //
135 void of1x_add_hook_l2hash(of1x_flow_entry_t *const entry){
136 
137  uint16_t hash;
138  of1x_match_t *vlan=NULL, *eth_dst=NULL, *match;
139  l2hash_entry_ps_t* ps;
140  l2hash_ht_bucket_t* bucket;
141  l2hash_state_t* state = (l2hash_state_t*)entry->table->matching_aux[0];
142 
143  for(match = entry->matches.head;match;){
144  of1x_match_t *next = match->next;
145 
146  if(match->type == OF1X_MATCH_VLAN_VID){
147  vlan = match;
148  }else if(match->type == OF1X_MATCH_ETH_DST){
149  eth_dst=match;
150  }
151  match = next;
152  }
153 
154  if(unlikely(eth_dst == NULL)){
155  assert(0);
156  return;//ROFL_FAILURE;
157  }
158 
159  //allocate flow entry additional state
162 
163  //Check for allocations
164  if(unlikely(ps == NULL) || unlikely(bucket == NULL)){
165  assert(0);
166  return;// ROFL_FAILURE;
167  }
168 
169  //That could not happen
170  assert( bitmap128_is_bit_set(&entry->matches.match_bm, OF1X_MATCH_VLAN_VID) == (vlan != NULL) );
171 
172 
173  //Assign common stuff of the bucket
174  bucket->entry = entry;
175 
176  if(vlan){
177  //VLAN
178  l2hash_vlan_key_t key;
179  key.vid = vlan->__tern->value.u16 & vlan->__tern->mask.u16;
180  key.eth_dst = eth_dst->__tern->value.u64 & eth_dst->__tern->mask.u64;
181  //calculate hash
182  hash = l2hash_ht_hash96((const char*)&key, sizeof(l2hash_vlan_key_t));
183  //Fill in ps
184  ps->has_vlan = false;
185 
186  //Fill-in bucket
187  bucket->eth_dst = key.eth_dst;
188  bucket->vid = key.vid;
189 
190  //Add to the bucket list
191  l2hash_ht_add_bucket(&state->vlan, hash, bucket);
192 
193  //Increase the number of entries
194  state->vlan.num_of_entries++;
195  }else{
196  //NO-VLAN
198  key.eth_dst = eth_dst->__tern->value.u64 & eth_dst->__tern->mask.u64;
199  //calculate hash
200  hash = l2hash_ht_hash64((const char*)&key, sizeof(l2hash_novlan_key_t));
201 
202  //Fill in ps
203  ps->has_vlan = false;
204 
205  //Fill-in bucket
206  bucket->eth_dst = key.eth_dst;
207 
208  //Add to the bucket list
209  l2hash_ht_add_bucket(&state->no_vlan, hash, bucket);
210 
211  //Increase the number of entries
212  state->no_vlan.num_of_entries++;
213  }
214 
215  //Store ps to entry
216  ps->bucket = bucket;
217  entry->platform_state = (void*)ps;
218 }
219 void of1x_modify_hook_l2hash(of1x_flow_entry_t *const entry){
220  //We don't care
221 }
222 void of1x_remove_hook_l2hash(of1x_flow_entry_t *const entry){
223 
224  l2hash_state_t* state = (l2hash_state_t*)entry->table->matching_aux[0];
225 
226  if(unlikely(entry->platform_state == NULL)){
227  assert(0);
228  return;
229  }
230 
231  l2hash_entry_ps_t* ps = (l2hash_entry_ps_t*)entry->platform_state;
232 
233  //Perform the remove
234  l2hash_ht_remove_bucket(ps->bucket);
235 
236  if(ps->has_vlan){
237  state->vlan.num_of_entries--;
238  }else{
239  state->no_vlan.num_of_entries--;
240  }
241 
242  platform_free_shared(entry->platform_state);
243  entry->platform_state = NULL;
244 }
245 
246 //
247 // Main routines
248 //
249 
250 
251 /* Conveniently wraps call with mutex. */
252 rofl_of1x_fm_result_t of1x_add_flow_entry_l2hash(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, bool check_overlap, bool reset_counts){
253  //Call loop with the right hooks
254  return __of1x_add_flow_entry_loop(table, entry, check_overlap, reset_counts, of1x_add_hook_l2hash);
255 }
256 
257 rofl_result_t of1x_modify_flow_entry_l2hash(of1x_flow_table_t *const table, of1x_flow_entry_t *const entry, const enum of1x_flow_removal_strictness strict, bool reset_counts){
258  //Call loop with the right hooks
259  return __of1x_modify_flow_entry_loop(table, entry, strict, reset_counts, of1x_add_hook_l2hash, of1x_modify_hook_l2hash);
260 }
261 
262 rofl_result_t of1x_remove_flow_entry_l2hash(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){
263  //Call loop with the right hooks
264  return __of1x_remove_flow_entry_loop(table, entry, specific_entry, strict, out_port, out_group, reason, mutex_acquired, of1x_remove_hook_l2hash);
265 }
266 
267 //Define the matching algorithm struct
268 OF1X_REGISTER_MATCHING_ALGORITHM(l2hash) = {
269  //Init and destroy hooks
270  .init_hook = of1x_init_l2hash,
271  .destroy_hook = of1x_destroy_l2hash,
272 
273  //Flow mods
274  .add_flow_entry_hook = of1x_add_flow_entry_l2hash,
275  .modify_flow_entry_hook = of1x_modify_flow_entry_l2hash,
276  .remove_flow_entry_hook = of1x_remove_flow_entry_l2hash,
277 
278  //Stats
279  .get_flow_stats_hook = of1x_get_flow_stats_loop,
280  .get_flow_aggregate_stats_hook = of1x_get_flow_aggregate_stats_loop,
281 
282  //Find group related entries
283  .find_entry_using_group_hook = of1x_find_entry_using_group_loop,
284 
285  //Dumping
286  .dump_hook = NULL,
287  .description = L2HASH_DESCRIPTION,
288 };
289 
290 //Hash T
291 uint16_t l2hash_ht_T[L2HASH_MAX_ENTRIES] = {
292  // 256 values 0-255 in any (random) order suffices
293  98, 6, 85,150, 36, 23,112,164,135,207,169, 5, 26, 64,165,219, // 1
294 
295  61, 20, 68, 89,130, 63, 52,102, 24,229,132,245, 80,216,195,115, // 2
296 
297  90,168,156,203,177,120, 2,190,188, 7,100,185,174,243,162, 10, // 3
298 
299  237, 18,253,225, 8,208,172,244,255,126,101, 79,145,235,228,121, // 4
300 
301  123,251, 67,250,161, 0,107, 97,241,111,181, 82,249, 33, 69, 55, // 5
302 
303  59,153, 29, 9,213,167, 84, 93, 30, 46, 94, 75,151,114, 73,222, // 6
304 
305  197, 96,210, 45, 16,227,248,202, 51,152,252,125, 81,206,215,186, // 7
306 
307  39,158,178,187,131,136, 1, 49, 50, 17,141, 91, 47,129, 60, 99, // 8
308 
309  154, 35, 86,171,105, 34, 38,200,147, 58, 77,118,173,246, 76,254, // 9
310 
311  133,232,196,144,198,124, 53, 4,108, 74,223,234,134,230,157,139, // 10
312 
313  189,205,199,128,176, 19,211,236,127,192,231, 70,233, 88,146, 44, // 11
314 
315  183,201, 22, 83, 13,214,116,109,159, 32, 95,226,140,220, 57, 12, // 12
316 
317  221, 31,209,182,143, 92,149,184,148, 62,113, 65, 37, 27,106,166, // 13
318 
319  3, 14,204, 72, 21, 41, 56, 66, 28,193, 40,217, 25, 54,179,117, // 14
320 
321  238, 87,240,155,180,170,242,212,191,163, 78,218,137,194,175,110, // 15
322 
323  43,119,224, 71,122,142, 42,160,104, 48,247,103, 15, 11,138,239 // 16
324 
325  //TODO: the rest are 0
326 };
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)
static void bitmap128_clean(bitmap128_t *bitmap)
Set bitmap to 0.
Definition: bitmap.h:29
OpenFlow v1.0, 1.2 and 1.3.2 flow table abstraction.
of1x_flow_removal_strictness
Flow removal operations strictness.
static bool bitmap128_is_bit_set(const bitmap128_t *bitmap, unsigned int pos)
Check if bit is set in the 128bit bitmap.
Definition: bitmap.h:45
matching_auxiliary_t * matching_aux[2]
Place-holder to allow matching algorithms keep its own state.
enum rofl_of1x_fm_result rofl_of1x_fm_result_t
Extended flowmod return codes.
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...
void platform_free_shared(void *data)
Frees a chunk of dynamic memory previously allocated with platform_malloc_shared().
static void bitmap128_set(bitmap128_t *bitmap, unsigned int pos)
Set a bit in the 128bit bitmap.
Definition: bitmap.h:55