ROFL-pipeline  v0.6.0dev
of1x_flow_entry.c
1 #include "of1x_flow_entry.h"
2 
3 #include "../../../platform/likely.h"
4 #include "../../../platform/lock.h"
5 #include "../../../platform/memory.h"
6 #include "../of1x_async_events_hooks.h"
7 
8 #include <assert.h>
9 #include "../of1x_switch.h"
10 #include "of1x_pipeline.h"
11 #include "of1x_flow_table.h"
12 #include "of1x_action.h"
13 #include "of1x_group_table.h"
14 
15 #include "../../../util/logging.h"
16 
17 
18 /*
19 * Intializer and destructor
20 */
21 
23 
25 
26  if( unlikely(entry==NULL) )
27  return NULL;
28 
29  platform_memset(entry,0,sizeof(of1x_flow_entry_t));
30 
31  entry->rwlock = platform_rwlock_init(NULL);
32  if( unlikely(NULL==entry->rwlock) ){
33  platform_free_shared(entry);
34  assert(0);
35  return NULL;
36  }
37 
38  //Init matches
39  __of1x_init_match_group(&entry->matches);
40 
41  //Init instructions
42  __of1x_init_instruction_group(&entry->inst_grp);
43 
44  //init stats
46 
47  //Flags
48  entry->notify_removal = notify_removal;
49 
50  return entry;
51 
52 }
53 
54 
55 //This function is meant to only be used internally
56 rofl_result_t __of1x_destroy_flow_entry_with_reason(of1x_flow_entry_t* entry, of1x_flow_remove_reason_t reason){
57 
58  //wait for any thread which is still using the entry (processing a packet)
59  platform_rwlock_wrlock(entry->rwlock);
60 
61  //destroying timers, if any
63 
64  //Notify flow removed
65  if(entry->notify_removal && (reason != OF1X_FLOW_REMOVE_NO_REASON ) ){
66  //Safety checks
67  if(entry->table && entry->table->pipeline && entry->table->pipeline->sw){
68  __of1x_stats_flow_tid_t consolidated_stats;
69 
70  //Consolidate stats so that users of the pipeline can use counters
71  __of1x_stats_flow_consolidate(&entry->stats, &consolidated_stats);
73  entry->stats.s.counters = consolidated_stats;
74 
75  //Then notify
76  platform_of1x_notify_flow_removed(entry->table->pipeline->sw, reason, entry);
77  }
78  }
79 
80  //destroy stats
82 
83  //Destroy matches group
84  __of1x_destroy_match_group(&entry->matches);
85 
86  //Destroy instructions
87  __of1x_destroy_instruction_group(&entry->inst_grp);
88 
89  platform_rwlock_destroy(entry->rwlock);
90 
91  //Destroy entry itself
92  platform_free_shared(entry);
93 
94  return ROFL_SUCCESS;
95 }
96 
97 //This is the interface to be used when deleting entries used as
98 //a message or not inserted in a table
100  return __of1x_destroy_flow_entry_with_reason(entry, OF1X_FLOW_REMOVE_NO_REASON);
101 }
102 
103 //Adds one or more to the entry
105 
106  __of1x_match_group_push_back(&entry->matches, match);
107 
108  return ROFL_SUCCESS;
109 }
110 
111 rofl_result_t __of1x_update_flow_entry(of1x_flow_entry_t* entry_to_update, of1x_flow_entry_t* mod, bool reset_counts){
112 
113 
114  // let the platform do the necessary updates
115  platform_of1x_modify_entry_hook(entry_to_update, mod, reset_counts);
116 
117  //Lock entry
118  platform_rwlock_wrlock(entry_to_update->rwlock);
119 
120  //Copy instructions
121  __of1x_update_instructions(&entry_to_update->inst_grp, &mod->inst_grp);
122 
123  //Reset counts
124  if(reset_counts){
125  __of1x_stats_flow_reset_counts(entry_to_update);
126  __of1x_reset_last_packet_count_idle_timeout(&entry_to_update->timer_info);
127  }
128 
129  //Update flags from the new modification flowmod
130  entry_to_update->flags = mod->flags;
131 
132  //Unlock
133  platform_rwlock_wrunlock(entry_to_update->rwlock);
134 
135  return ROFL_SUCCESS;
136 }
142 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){
143 
144  of1x_match_t* it_orig, *it_entry;
145 
146  //Check cookie first
147  if(check_cookie && entry->cookie != OF1X_DO_NOT_CHECK_COOKIE && entry->cookie_mask){
148  if( (entry->cookie&entry->cookie_mask) != (original->cookie&entry->cookie_mask) )
149  return false;
150  }
151 
152  //Check priority
153  if(check_priority && ((entry->priority&OF1X_2_BYTE_MASK) != (original->priority&OF1X_2_BYTE_MASK))) //In OF1.0 overlapping ignore wildcard flag
154  return false;
155 
156  //Check if matches are contained. This is expensive.. //FIXME: move this to of1x_match
157  for( it_entry = entry->matches.head; it_entry; it_entry = it_entry->next ){
158  for( it_orig = original->matches.head; it_orig; it_orig = it_orig->next ){
159 
160  //Skip if different types
161  if( it_entry->type != it_orig->type)
162  continue;
163 
164  if( !__of1x_is_submatch( it_entry, it_orig ) && !__of1x_is_submatch( it_orig, it_entry ) )
165  return false;
166  }
167  }
168 
169 
170  //Check out group actions
171  if( out_group != OF1X_GROUP_ANY && (
172  !__of1x_write_actions_has(original->inst_grp.instructions[OF1X_IT_WRITE_ACTIONS].write_actions, OF1X_AT_GROUP, out_group) &&
173  !__of1x_apply_actions_has(original->inst_grp.instructions[OF1X_IT_APPLY_ACTIONS].apply_actions, OF1X_AT_GROUP, out_group)
174  )
175  )
176  return false;
177 
178 
179  //Check out port actions
180  if( out_port != OF1X_PORT_ANY && (
181  !__of1x_write_actions_has(original->inst_grp.instructions[OF1X_IT_WRITE_ACTIONS].write_actions, OF1X_AT_OUTPUT, out_port) &&
182  !__of1x_apply_actions_has(original->inst_grp.instructions[OF1X_IT_APPLY_ACTIONS].apply_actions, OF1X_AT_OUTPUT, out_port)
183  )
184  )
185  return false;
186 
187  return true;
188 }
189 
194 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){
195 
196  of1x_match_t* it_orig, *it_subentry;
197 
198  //Check cookie first
199  if(check_cookie && subentry->cookie != OF1X_DO_NOT_CHECK_COOKIE && subentry->cookie_mask){
200  if( (subentry->cookie&subentry->cookie_mask) != (original->cookie&subentry->cookie_mask) )
201  return false;
202  }
203 
204  //Check priority
205  if(check_priority && (original->priority != subentry->priority))
206  return false;
207 
208  //Check if matches are contained. This is expensive.. //FIXME: move this to of1x_match
209  for( it_subentry = subentry->matches.head; it_subentry; it_subentry = it_subentry->next ){
210  for( it_orig = original->matches.head; it_orig; it_orig = it_orig->next ){
211 
212  //Skip if different types
213  if( it_subentry->type != it_orig->type)
214  continue;
215 
216  if( !__of1x_is_submatch( it_subentry, it_orig ) )
217  return false;
218  }
219  }
220 
221  //Check out group actions
222  if( out_group != OF1X_GROUP_ANY){
223  if(!reverse_out_check && !(__of1x_instruction_has(&original->inst_grp,OF1X_AT_GROUP,out_group)) )
224  return false;
225  else if(reverse_out_check && !(__of1x_instruction_has(&subentry->inst_grp,OF1X_AT_GROUP,out_group)) )
226  return false;
227  }
228 
229  //Check out port actions
230  if( out_port != OF1X_PORT_ANY){
231  if(!reverse_out_check && !(__of1x_instruction_has(&original->inst_grp,OF1X_AT_OUTPUT,out_port)) )
232  return false;
233  else if(reverse_out_check && !(__of1x_instruction_has(&subentry->inst_grp,OF1X_AT_OUTPUT,out_port)) )
234  return false;
235  }
236 
237 
238  return true;
239 }
244 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){
245 
246  of1x_match_t* it_original, *it_entry;
247 
248  //Check cookie first
249  if(check_cookie && entry->cookie != OF1X_DO_NOT_CHECK_COOKIE && entry->cookie_mask){
250  if( (entry->cookie&entry->cookie_mask) != (original->cookie&entry->cookie_mask) )
251  return false;
252  }
253 
254  //Check priority
255  if(entry->priority != original->priority)
256  return false;
257 
258  //Fast Check #matches
259  if(original->matches.num_elements != entry->matches.num_elements)
260  return false;
261 
262  //Matches in-depth check //FIXME: move this to of1x_match
263  for(it_original = original->matches.head, it_entry = entry->matches.head; it_entry != NULL; it_original = it_original->next, it_entry = it_entry->next){
264  if(!__of1x_equal_matches(it_original,it_entry))
265  return false;
266  }
267 
268  //Check out group actions
269  if( out_group != OF1X_GROUP_ANY && (
270  !__of1x_write_actions_has(original->inst_grp.instructions[OF1X_IT_WRITE_ACTIONS].write_actions, OF1X_AT_GROUP, out_group) &&
271  !__of1x_apply_actions_has(original->inst_grp.instructions[OF1X_IT_APPLY_ACTIONS].apply_actions, OF1X_AT_GROUP, out_group)
272  )
273  )
274  return false;
275 
276 
277  //Check out port actions
278  if( out_port != OF1X_PORT_ANY && (
279  !__of1x_write_actions_has(original->inst_grp.instructions[OF1X_IT_WRITE_ACTIONS].write_actions, OF1X_AT_OUTPUT, out_port) &&
280  !__of1x_apply_actions_has(original->inst_grp.instructions[OF1X_IT_APPLY_ACTIONS].apply_actions, OF1X_AT_OUTPUT, out_port)
281  )
282  )
283  return false;
284 
285 
286  return true;
287 }
288 
289 void of1x_dump_flow_entry(of1x_flow_entry_t* entry, bool raw_nbo){
290 
292 
293  //Consolidate stats so that users of the pipeline can use counters
294  __of1x_stats_flow_consolidate(&entry->stats, &c);
295 
296  ROFL_PIPELINE_INFO_NO_PREFIX("Entry (%p), prior. %u, cookie 0x%"PRIx64", pkts.matched %u. Matches:{",entry, entry->priority, entry->cookie, c.packet_count, entry->matches.num_elements);
297 
298  //print matches(all)
299  __of1x_dump_matches(entry->matches.head, raw_nbo);
300  ROFL_PIPELINE_INFO_NO_PREFIX("}\n");
301  __of1x_dump_instructions(entry->inst_grp, raw_nbo);
302 }
303 
307 rofl_result_t __of1x_validate_flow_entry( of1x_flow_entry_t* entry, of1x_pipeline_t* pipeline, unsigned int table_id){
308 
309  of_version_t version = pipeline->sw->of_ver;
310  of1x_flow_table_t* table = &pipeline->tables[table_id];
311 
312  /*
313  * Validate matches
314  */
315  if( entry->matches.head)
316  if( (version < entry->matches.ver_req.min_ver) ||
317  (version > entry->matches.ver_req.max_ver) )
318  return ROFL_FAILURE;
319 
320  //Validate matches
321  if( !bitmap128_check_mask(&entry->matches.match_bm, &table->config.match))
322  return ROFL_FAILURE;
323 
324  //Validate wildcards
325  if( !bitmap128_check_mask(&entry->matches.wildcard_bm, &table->config.wildcards))
326  return ROFL_FAILURE;
327 
328  /*
329  * Validate instructions (and actions)
330  */
331  if(__of1x_validate_instructions(&entry->inst_grp, pipeline, table_id)!=ROFL_SUCCESS)
332  return ROFL_FAILURE;
333 
334  if(version == OF_VERSION_10 && entry->matches.head && !__of10_is_wildcard(&entry->matches))
335  entry->priority |= OF10_NON_WILDCARDED_PRIORITY_FLAG;
336  return ROFL_SUCCESS;
337 }
338 
rofl_result_t __of1x_destroy_timer_entries(struct of1x_flow_entry *entry)
of1x_destroy_timer_entry When a flow entry is removed from the table this function will be called in ...
Definition: of1x_timers.c:335
of1x_flow_entry_t * of1x_init_flow_entry(bool notify_removal)
Create an empty flow entry.
OpenFlow v1.0, 1.2 and 1.3.2 pipeline abstraction.
bool __of1x_instruction_has(of1x_instruction_group_t *inst_grp, of1x_packet_action_type_t type, uint64_t value)
OpenFlow v1.0, 1.2 and 1.3.2 flow table abstraction.
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 __of1x_stats_flow_reset_counts(struct of1x_flow_entry *entry)
of1x_stats_flow_reset_counts
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 of1x_dump_flow_entry(of1x_flow_entry_t *entry, bool raw_nbo)
Dumps the flow entry for debugging purposes.
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.
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.
platform_rwlock_t * platform_rwlock_init(void *params)
Allocates and initializes a rwlock.
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.
OpenFlow v1.0, 1.2 and 1.3.2 actions.
static bool bitmap128_check_mask(bitmap128_t *bitmap, bitmap128_t *mask)
Check whether a bitmap is within a certain mask (bitmap&mask == bitmap)
Definition: bitmap.h:99
void platform_of1x_notify_flow_removed(const of1x_switch_t *sw, of1x_flow_remove_reason_t reason, of1x_flow_entry_t *removed_flow_entry)
Flow removed event notification.
void platform_rwlock_destroy(platform_rwlock_t *rwlock)
Destroys and deallocates a rwlock previously inited by platform_rwlock_init().
void __of1x_destroy_flow_stats(struct of1x_flow_entry *entry)
of1x_stats_flow_destroy basically destroys the mutex
OpenFlow v1.0, 1.2 and 1.3.2 flow entry abstraction.
rofl_result_t of1x_add_match_to_entry(of1x_flow_entry_t *entry, of1x_match_t *match)
Adds a match to the flow_entry.
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
rofl_result_t of1x_destroy_flow_entry(of1x_flow_entry_t *entry)
Destroy the flow entry, including stats, instructions and actions.
OpenFlow v1.0, 1.2 and 1.3.2 pipeline abstraction data structure.
Definition: of1x_pipeline.h:50
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...
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 group table subsystem.
rofl_result_t __of1x_validate_flow_entry(of1x_flow_entry_t *entry, struct of1x_pipeline *pipeline, unsigned int table_id)
Check if the entry(matches, actions and instructions is valid for insertion)