-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlpm-dir-24-8.gh
322 lines (275 loc) · 9.1 KB
/
lpm-dir-24-8.gh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
#ifndef __LPM_DIR_24_8_GH_INCLUDED__
#define __LPM_DIR_24_8_GH_INCLUDED__
#include <bitops.gh>
#include "stdex.gh"
inductive lpm_rule = rule(Z, int, int); //ipv4, prefixlen, route
inductive dir_24_8 = tables(list<option<pair<bool, Z> > >,
list<option<Z> >, int); //last is for lpm_long_index
fixpoint Z Z_of_int(int x, nat length) {
return Z_of_bits(Zsign(false), snd(bits_of_int(x, length)));
}
fixpoint lpm_rule init_rule(int ipv4, int prefixlen, int route) {
return rule(Z_of_int(ipv4, N32), prefixlen, route);
}
fixpoint int rule_ipv4(lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route): return int_of_Z(ipv4);
}
}
fixpoint int rule_prefixlen(lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route): return prefixlen;
}
}
fixpoint int rule_route(lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route): return route;
}
}
fixpoint list<option<pair<bool, Z> > > dir_lpm24(dir_24_8 dir) {
switch(dir) {
case tables(lpm_24, lpm_long, lpm_long_index): return lpm_24;
}
}
fixpoint list<option<Z> > dir_lpm_long(dir_24_8 dir) {
switch(dir) {
case tables(lpm_24, lpm_long, lpm_long_index): return lpm_long;
}
}
fixpoint int dir_lpm_long_index(dir_24_8 dir) {
switch(dir) {
case tables(lpm_24, lpm_long, lpm_long_index): return lpm_long_index;
}
}
fixpoint int rule_24_get_value(Z entry) {
return int_of_Z(Z_and(entry, Z_of_int(0x7FFF, N16)));
}
// INDEX COMPUTING FUNCTIONS
fixpoint int index24_from_ipv4(Z ipv4) {
return int_of_Z(Z_shiftright(ipv4, N8));
}
fixpoint int indexlong_from_ipv4(Z ipv4, int index) {
return index * 256 + int_of_Z(Z_and(ipv4, Z_of_int(0xFF, N8)));
}
//Assuming that prefixlen <= 32
fixpoint int compute_rule_size(int prefixlen) {
return prefixlen < 25 ?
pow_nat(2, nat_of_int(24 - prefixlen))
:
pow_nat(2, nat_of_int(32 - prefixlen));
}
fixpoint Z mask_rec(int mask_length, nat total_length) {
switch(total_length) {
case zero: return Zsign(false);
case succ(n):
return int_of_nat(total_length) ==
mask_length ?
Zdigit(mask_rec(mask_length-1, n), true)
:
Zdigit(mask_rec(mask_length, n), false);
}
}
fixpoint Z mask32_from_prefixlen(int prefixlen) {
return mask_rec(prefixlen, N32);
}
fixpoint int compute_starting_index_24(lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route):
return index24_from_ipv4(Z_and(ipv4, mask32_from_prefixlen(prefixlen)));
}
}
fixpoint int compute_starting_index_long(lpm_rule rule, int base_index) {
switch(rule) {
case rule(ipv4, prefixlen, value):
return base_index * 256 +
(int_of_Z(Z_and(Z_and(ipv4, mask32_from_prefixlen(prefixlen)),
Z_of_int(0xFF, N8))));
}
}
fixpoint bool is_new_index_needed(option<pair<bool, Z> > entry) {
switch(entry) {
case none: return true;
case some(p): return
switch(p) {
case pair(f,v): return !f;
};
}
}
fixpoint int extract24_value(option<pair<bool, Z> > entry) {
switch(entry) {
case none: return 0xFFFF;
case some(p): return int_of_Z(snd(p));
}
}
//Entry is on 16 bits
fixpoint bool extract_flag(int entry) {
return (entry >> 15) == 1;
}
fixpoint int set_flag(int entry) {
return entry | 0x8000;
}
fixpoint option<pair<bool, Z> > set_flag_entry(option<pair<bool, Z> > entry) {
switch(entry) {
case none: return none;
case some(p): return
switch(p) {
case pair(b,z): return some(pair(true, z));
};
}
}
//The output value does not contain the flag
fixpoint int extract_value(int entry) {
return entry & 0x7FFF;
}
// LOOKUP FUNCTIONS
fixpoint option<pair<bool, Z> > lookup_lpm_24(int index, dir_24_8 dir) {
switch(dir) {
case(tables(lpm_24, lpm_long, long_index)): return nth(index, lpm_24);
}
}
fixpoint option<Z> lookup_lpm_long(int index, dir_24_8 dir) {
switch(dir) {
case(tables(lpm_24, lpm_long, long_index)): return nth(index, lpm_long);
}
}
fixpoint int lpm_dir_24_8_lookup(Z ipv4, dir_24_8 dir) {
switch(dir) {
case tables(lpm_24, lpm_long, index_long): return
switch(lookup_lpm_24(index24_from_ipv4(ipv4), dir)) {
case none: return 0xFFFF;
case some(p): return
switch(p) {
case pair(f, v): return
f ?
switch(lookup_lpm_long(indexlong_from_ipv4(ipv4, int_of_Z(v)),
dir))
{
case none: return 0xFFFF;
case some(vl): return int_of_Z(vl);
}
:
int_of_Z(v);
};
};
}
}
// ADD ROUTE FUNCTIONS
fixpoint list<t> update_n<t>(list<t> lst, int start, nat count, t x) {
switch(count) {
case zero: return lst;
case succ(n): return update_n(update(start, x, lst),
start+1, n, x);
}
}
lemma_auto(length(update_n(lst, start, count, x))) void update_n_length<t>(list<t> lst, int start, nat count, t x)
requires true;
ensures length(lst) == length(update_n(lst, start, count, x));
{
switch(count) {
case zero:
case succ(n):
list<t> updated = update(start, x, lst);
length_update(start, x, lst);
update_n_length(updated, start+1, n, x);
}
}
fixpoint list<option<pair<bool, Z> > > insert_route_24(list<option<pair<bool, Z> > > lpm_24,
lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route):
return update_n(lpm_24, compute_starting_index_24(rule),
nat_of_int(compute_rule_size(prefixlen)),
some(pair(false, Z_of_int(route, N16))));
}
}
fixpoint list<option<Z> > insert_route_long(list<option<Z> > lpm_long,
lpm_rule rule, int base_index) {
switch(rule) {
case rule(ipv4, prefixlen, route):
return update_n(lpm_long,
compute_starting_index_long(rule, base_index),
nat_of_int(compute_rule_size(prefixlen)),
some(Z_of_int(route, N16)));
}
}
fixpoint dir_24_8 insert_lpm_24(dir_24_8 dir, lpm_rule rule) {
switch(dir) {
case tables(lpm_24, lpm_long, long_index):
return tables(insert_route_24(lpm_24, rule), lpm_long, long_index);
}
}
fixpoint dir_24_8 insert_lpm_long(dir_24_8 dir, lpm_rule rule) {
switch(dir) {
case tables(lpm_24, lpm_long, long_index): return
switch(rule) {
case rule(ipv4, prefixlen, route): return
//Check whether a new index_long is needed
is_new_index_needed(lookup_lpm_24(index24_from_ipv4(ipv4), dir)) ?
//Check for available index, if not -> no change
long_index == 256 ?
tables(lpm_24, lpm_long, long_index)
:
//Update the value in lpm_24 and lpm_long
tables(update_n(lpm_24, compute_starting_index_24(rule),
N1, some(pair(true, Z_of_int(long_index, N16)))),
insert_route_long(lpm_long, rule, long_index),
long_index + 1)
:
//No need to update the value in lpm_24, only in tlb_long
tables(lpm_24,
insert_route_long(lpm_long, rule,
extract24_value(lookup_lpm_24(index24_from_ipv4(ipv4),
dir))),
long_index);
};
}
}
fixpoint dir_24_8 add_rule(dir_24_8 dir, lpm_rule rule) {
switch(rule) {
case rule(ipv4, prefixlen, route):
return prefixlen < 25 ?
insert_lpm_24(dir, rule)
:
insert_lpm_long(dir, rule);
}
}
// STRUCTURE BUILDING FUNCTIONS
fixpoint option<pair<bool, Z> > entry_24_mapping(int entry) {
return entry == 0xFFFF ?
none
:
some(pair(extract_flag(entry), Z_of_int(extract_value(entry), N16)));
}
fixpoint option<Z> entry_long_mapping(int entry) {
return entry == 0xFFFF ? none : some(Z_of_int(entry, N16));
}
fixpoint dir_24_8 build_tables(list<int> t_24, list<int> t_long,
int long_index) {
return tables(map(entry_24_mapping, t_24),
map(entry_long_mapping, t_long), long_index);
}
fixpoint dir_24_8 dir_init() {
return tables(repeat_n(nat_of_int(16777216), none),
repeat_n(nat_of_int(65536), none), 0);
}
// This function must be called only when the option is known not to be none
fixpoint pair<bool, Z> get_someOption24(option<pair<bool, Z> > o) {
switch(o) {
case none: return pair(false, Zsign(false));//should never happen
case some(p): return p;
}
}
fixpoint bool valid_entry24(int entry) {
return entry == 0xFFFF ?
true
:
(extract_flag(entry) ?
(0x8000 <= entry && entry <= 0x80FF) &&
(0 <= extract_value(entry) && extract_value(entry) <= 0xFF)
:
(0 <= entry && entry <= 0x7FFF));
}
fixpoint bool valid_entry_long(int entry) {
return entry == 0xFFFF ? true : 0 <= entry && entry <= 0x7FFF;
}
#endif//__LPM_DIR_24_8_GH_INCLUDED__