ROFL-pipeline  v0.6.0dev
ternary_fields.c
1 #include "ternary_fields.h"
2 
3 #include <assert.h>
4 
5 #include "../platform/memory.h"
6 #include <rofl/datapath/pipeline/common/ternary_fields.h>
7 
8 /*
9 * Initializers
10 */
11 inline utern_t* __init_utern8(uint8_t value, uint8_t mask){
12  utern_t* tern = (utern_t*)platform_malloc_shared(sizeof(utern_t));
13 
14  if(!tern)
15  return NULL;
16 
17  tern->type = UTERN8_T;
18  tern->value.u8 = value;
19  tern->mask.u8 = mask;
20  return (utern_t*)tern;
21 }
22 inline utern_t* __init_utern16(uint16_t value, uint16_t mask){
23  utern_t* tern = (utern_t*)platform_malloc_shared(sizeof(utern_t));
24 
25  if(!tern)
26  return NULL;
27 
28  tern->type = UTERN16_T;
29  tern->value.u16 = value;
30  tern->mask.u16 = mask;
31  return (utern_t*)tern;
32 }
33 inline utern_t* __init_utern32(uint32_t value, uint32_t mask){
34  utern_t* tern = (utern_t*)platform_malloc_shared(sizeof(utern_t));
35 
36  if(!tern)
37  return NULL;
38 
39  tern->type = UTERN32_T;
40  tern->value.u32 = value;
41  tern->mask.u32 = mask;
42  return (utern_t*)tern;
43 }
44 inline utern_t* __init_utern64(uint64_t value, uint64_t mask){
45  utern_t* tern = (utern_t*)platform_malloc_shared(sizeof(utern_t));
46 
47  if(!tern)
48  return NULL;
49 
50  tern->type = UTERN64_T;
51  tern->value.u64 = value;
52  tern->mask.u64 = mask;
53  return (utern_t*)tern;
54 }
55 inline utern_t* __init_utern128(uint128__t value, uint128__t mask){ //uint128_t funny!
56  utern_t* tern = (utern_t*)platform_malloc_shared(sizeof(utern_t));
57 
58  if(!tern)
59  return NULL;
60 
61  tern->type = UTERN128_T;
62  tern->value.u128 = value;
63  tern->mask.u128 = mask;
64  return (utern_t*)tern;
65 }
66 
67 /*
68 * Single destructor
69 */
70 rofl_result_t __destroy_utern(utern_t* utern){
71  platform_free_shared(utern);
72  //FIXME: maybe check returning value
73  return ROFL_SUCCESS;
74 }
75 
76 
77 
78 
79 /*
80 * Contained
81 */
82 //Extensive tern is a more generic (with a less restrictive mask or equal) to tern
83 inline bool __utern_is_contained(const utern_t* extensive_tern, const utern_t* tern){
84 
85  switch(extensive_tern->type){
86 
87  case UTERN8_T:
88  //if(((extensive_tern->mask.u8 ^ tern->mask.u8) & extensive_tern->mask.u8) > 0)
89  // return false;
90  return (extensive_tern->value.u8 & extensive_tern->mask.u8) == (tern->value.u8 & extensive_tern->mask.u8);
91  break;
92  case UTERN16_T:
93  //if(((extensive_tern->mask.u16 ^ tern->mask.u16) & extensive_tern->mask.u16) > 0)
94  // return false;
95  return (extensive_tern->value.u16 & extensive_tern->mask.u16) == (tern->value.u16 & extensive_tern->mask.u16);
96  break;
97  case UTERN32_T:
98  //if(((extensive_tern->mask.u32 ^ tern->mask.u32) & extensive_tern->mask.u32) > 0)
99  // return false;
100  return (extensive_tern->value.u32 & extensive_tern->mask.u32) == (tern->value.u32 & extensive_tern->mask.u32);
101  break;
102  case UTERN64_T:
103  if(((extensive_tern->mask.u64 ^ tern->mask.u64) & extensive_tern->mask.u64) > 0)
104  return false;
105  return (extensive_tern->value.u64 & extensive_tern->mask.u64) == (tern->value.u64 & extensive_tern->mask.u64);
106  break;
107  case UTERN128_T:
108 #if 0
109  if((((extensive_tern->mask.low ^ tern->mask.low) & extensive_tern->mask.low) > 0 ) ||
110  (((extensive_tern->mask.high ^ tern->mask.high) & extensive_tern->mask.high) > 0 ) )
111  return false;
112  return ( (extensive_tern->value.low & extensive_tern->mask.low) == (tern->value.low & extensive_tern->mask.low) &&
113  (extensive_tern->value.high & extensive_tern->mask.high) == (tern->value.high & extensive_tern->mask.high) );
114 #endif
115 
116  //if( (( (UINT128__T_LO(extensive_tern->mask.u128) ^ UINT128__T_LO(tern->mask.u128)) & UINT128__T_LO(extensive_tern->mask.u128) ) > 0 ) ||
117  // (( (UINT128__T_HI(extensive_tern->mask.u128) ^ UINT128__T_HI(tern->mask.u128)) & UINT128__T_HI(extensive_tern->mask.u128) ) > 0 ) )
118  // return false;
119  return ( (UINT128__T_LO(extensive_tern->value.u128) & UINT128__T_LO(extensive_tern->mask.u128)) == (UINT128__T_LO(tern->value.u128) & UINT128__T_LO(extensive_tern->mask.u128)) ) &&
120  ((UINT128__T_HI(extensive_tern->value.u128) & UINT128__T_HI(extensive_tern->mask.u128)) == (UINT128__T_HI(tern->value.u128) & UINT128__T_HI(extensive_tern->mask.u128)) );
121 
122  break;
123  default:
124  assert(0); //we should never reach this point
125  return false;
126  }
127 }
128 
129 /*
130 * Check if two ternary values are equal
131 */
132 inline bool __utern_equals(const utern_t* tern1, const utern_t* tern2){
133  switch(tern1->type) {
134 
135  case UTERN8_T:
136  return (tern1->value.u8 == tern2->value.u8) && (tern1->mask.u8 == tern2->mask.u8);
137  break;
138  case UTERN16_T:
139  return (tern1->value.u16 == tern2->value.u16) && (tern1->mask.u16 == tern2->mask.u16);
140  break;
141  case UTERN32_T:
142  return (tern1->value.u32 == tern2->value.u32) && (tern1->mask.u32 == tern2->mask.u32);
143  break;
144  case UTERN64_T:
145  return (tern1->value.u64 == tern2->value.u64) && (tern1->mask.u64 == tern2->mask.u64);
146  break;
147  case UTERN128_T:
148  return (UINT128__T_LO(tern1->value.u128) == UINT128__T_LO(tern2->value.u128)) && (UINT128__T_LO(tern1->mask.u128) == UINT128__T_LO(tern2->mask.u128)) &&
149  (UINT128__T_HI(tern1->value.u128) == UINT128__T_HI(tern2->value.u128)) && (UINT128__T_HI(tern1->mask.u128) == UINT128__T_HI(tern2->mask.u128));
150  break;
151  default:
152  assert(0); // we should never reach this point
153  return false;
154  }
155 }
156 
157 //Ternary alike functions. Tern2 MUST always have more restrictive mask
158 inline utern_t* __utern_get_alike(const utern_t tern1, const utern_t tern2){
159  //TODO: there might be more efficient impl. maybe erasing 1s in diff... but dunno
160 
161  wrap_uint_t diff, new_mask;
162 
163  switch(tern1.type){
164  case UTERN8_T:
165 
166  diff.u8 = ~(
167  (tern1.value.u8 & tern1.mask.u8)
168  ^
169  (tern2.value.u8 & tern2.mask.u8)
170  );
171  //erase right 1.
172  for(new_mask.u8=0xFF;new_mask.u8;new_mask.u8=new_mask.u8<<1)
173  if((diff.u8&new_mask.u8) == new_mask.u8) break;
174 
175  if(tern1.mask.u8 < new_mask.u8 || tern2.mask.u8 < new_mask.u8 )
176  return NULL;
177 
178  if(new_mask.u8)
179  return __init_utern8(tern1.value.u8,new_mask.u8);
180 
181  return NULL;
182 
183  break;
184 
185  case UTERN16_T:
186 
187  diff.u16 = ~(
188  (tern1.value.u16 & tern1.mask.u16)
189  ^
190  (tern2.value.u16 & tern2.mask.u16)
191  );
192  //erase right 1.
193  for(new_mask.u16=0xFFFF;new_mask.u16;new_mask.u16=new_mask.u16<<1)
194  if((diff.u16&new_mask.u16) == new_mask.u16) break;
195 
196  if(tern1.mask.u16 < new_mask.u16 || tern2.mask.u16 < new_mask.u16 )
197  return NULL;
198 
199  if(new_mask.u16)
200  return __init_utern16(tern1.value.u16,new_mask.u16);
201 
202  return NULL;
203 
204  break;
205 
206  case UTERN32_T:
207 
208  diff.u32 = ~(
209  (tern1.value.u32 & tern1.mask.u32)
210  ^
211  (tern2.value.u32 & tern2.mask.u32)
212  );
213  //erase right 1.
214  for(new_mask.u32=0xFFFFFFFF;new_mask.u32;new_mask.u32=new_mask.u32<<1)
215  if((diff.u32&new_mask.u32) == new_mask.u32) break;
216 
217  if(tern1.mask.u32 < new_mask.u32 || tern2.mask.u32 < new_mask.u32 )
218  return NULL;
219 
220  if(new_mask.u32)
221  return __init_utern32(tern1.value.u32,new_mask.u32);
222 
223  return NULL;
224 
225  break;
226 
227  case UTERN64_T:
228 
229  diff.u64 = ~(
230  (tern1.value.u64 & tern1.mask.u64)
231  ^
232  (tern2.value.u64 & tern2.mask.u64)
233  );
234  //erase right 1.
235  for(new_mask.u64=0xFFFFFFFFFFFFFFFFULL;new_mask.u64;new_mask.u64=new_mask.u64<<1)
236  if((diff.u64&new_mask.u64) == new_mask.u64) break;
237 
238  //FIXME assert unlikely
239  //FIXME this condition happens also when two values are different in the non masked part.
240  //in this case we sould return the utern as it is now.
241  if(tern1.mask.u64 < new_mask.u64 || tern2.mask.u64 < new_mask.u64 )
242  return NULL;
243 
244  if(new_mask.u64)
245  return __init_utern64(tern1.value.u64,new_mask.u64);
246 
247  return NULL;
248 
249  break;
250 
251  case UTERN128_T:
252 
253  UINT128__T_LO(diff.u128) = ~( (UINT128__T_LO(tern1.value.u128) & UINT128__T_LO(tern1.mask.u128)) ^ (UINT128__T_LO(tern2.value.u128) & UINT128__T_LO(tern2.mask.u128)) );
254  UINT128__T_HI(diff.u128) = ~( (UINT128__T_HI(tern1.value.u128) & UINT128__T_HI(tern1.mask.u128)) ^ (UINT128__T_HI(tern2.value.u128) & UINT128__T_HI(tern2.mask.u128)) );
255 
256  //We first look for the common mask in the lower part
257  for(UINT128__T_LO(new_mask.u128)=0xFFFFFFFFFFFFFFFFULL;UINT128__T_LO(new_mask.u128);UINT128__T_LO(new_mask.u128)=UINT128__T_LO(new_mask.u128)<<1)
258  if((UINT128__T_LO(diff.u128)&UINT128__T_LO(new_mask.u128)) == UINT128__T_LO(new_mask.u128)) break;
259 
260  if( (UINT128__T_LO(tern1.mask.u128) < UINT128__T_LO(new_mask.u128) || UINT128__T_LO(tern2.mask.u128) < UINT128__T_LO(new_mask.u128)) && UINT128__T_HI(diff.u128) == 0xffffffffffffffffULL )
261  return NULL;
262 
263  if( UINT128__T_LO(new_mask.u128) && UINT128__T_HI(diff.u128) == 0xffffffffffffffffULL ){
264  UINT128__T_HI(new_mask.u128) = 0xffffffffffffffffULL;
265  return __init_utern128(tern1.value.u128,new_mask.u128);
266  }
267 
268  //Now we look for it in the higher part
269  for(UINT128__T_HI(new_mask.u128)=0xFFFFFFFFFFFFFFFFULL;UINT128__T_HI(new_mask.u128);UINT128__T_HI(new_mask.u128)=UINT128__T_HI(new_mask.u128)<<1)
270  if((UINT128__T_HI(diff.u128)&UINT128__T_HI(new_mask.u128)) == UINT128__T_HI(new_mask.u128)) break;
271 
272  if(UINT128__T_HI(tern1.mask.u128)<UINT128__T_HI(new_mask.u128) || UINT128__T_HI(tern2.mask.u128) < UINT128__T_HI(new_mask.u128) )
273  return NULL;
274 
275  if(UINT128__T_HI(new_mask.u128)){
276  UINT128__T_LO(new_mask.u128)=0x0000000000000000;
277  return __init_utern128(tern1.value.u128,new_mask.u128);
278  }
279 
280  return NULL;
281 
282  break;
283 
284  default:
285  assert(0); // we should never reach this point
286  return NULL;
287  }
288  return NULL;
289 }
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().