blob: eb558416b8e41d7629729d0a526e559ac9f6fa6a [file] [log] [blame]
Brenden Blancoa94bd932015-04-26 00:56:42 -07001/*
2 * =====================================================================
3 * Copyright (c) 2012, PLUMgrid, http://plumgrid.com
4 *
5 * This source is subject to the PLUMgrid License.
6 * All rights reserved.
7 *
8 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
9 * ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
10 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
11 * PARTICULAR PURPOSE.
12 *
13 * PLUMgrid confidential information, delete if you are not the
14 * intended recipient.
15 *
16 * =====================================================================
17 */
18
19#include <set>
20#include <algorithm>
21#include <sstream>
22#include <assert.h>
23#include "exception.h"
24#include "cc/codegen_c.h"
25#include "cc/lexer.h"
26#include "cc/type_helper.h"
27
28namespace ebpf {
29namespace cc {
30
31using std::set;
32using std::for_each;
33using std::pair;
34using std::stringstream;
35
36template <typename... Args>
37void CodegenC::emitln(const char *fmt, Args&&... params) {
38 fprintf(out_, fmt, std::forward<Args>(params)...);
39 fprintf(out_, "\n%*s", indent_ * 2, "");
40}
41void CodegenC::emitln(const char *s) {
42 fprintf(out_, "%s", s);
43 fprintf(out_, "\n%*s", indent_ * 2, "");
44}
45
46template <typename... Args>
47void CodegenC::emit(const char *fmt, Args&&... params) {
48 fprintf(out_, fmt, std::forward<Args>(params)...);
49}
50void CodegenC::emit(const char *s) {
51 fprintf(out_, "%s", s);
52}
53
54template <typename... Args>
55void CodegenC::lnemit(const char *fmt, Args&&... params) {
56 fprintf(out_, "\n%*s", indent_ * 2, "");
57 fprintf(out_, fmt, std::forward<Args>(params)...);
58}
59void CodegenC::lnemit(const char *s) {
60 fprintf(out_, "\n%*s", indent_ * 2, "");
61 fprintf(out_, "%s", s);
62}
63
64void CodegenC::indent() {
65 fprintf(out_, "%*s", indent_ * 2, "");
66}
67
68void CodegenC::emit_comment(Node* n) {
69 // if (!n->text_.empty()) {
70 // emitln("/* %s */", n->text_.c_str());
71 // }
72}
73
74void CodegenC::visit_block_stmt_node(BlockStmtNode* n) {
75
76 ++indent_;
77 emit("{");
78
79 // enter scope
80 auto scope = scopes_->current_var();
81 if (n->scope_) {
82 scopes_->set_current(n->scope_);
83 }
84
85
86 if (!n->stmts_.empty()) {
87 for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) {
88 emitln("");
89 (*it)->accept(this);
90 }
91 }
92 // exit scope
93 scopes_->set_current(scope);
94
95 --indent_;
96 emitln("");
97 emit("}");
98}
99
100void CodegenC::visit_version_stmt_node(VersionStmtNode* n) {
101 uint32_t version;
102 version = MAKE_VERSION(n->major_, n->minor_, n->rev_);
103 emit("static const uint32_t plumlet_version __attribute__"
104 "((section (\".version\"), used)) = 0x%x;\n", version);
105}
106
107void CodegenC::visit_if_stmt_node(IfStmtNode* n) {
108 emit_comment(n);
109 emit("if (");
110 n->cond_->accept(this);
111 emit(") ");
112 n->true_block_->accept(this);
113 if (n->false_block_) {
114 emit(" else ");
115 n->false_block_->accept(this);
116 }
117}
118
119void CodegenC::visit_onvalid_stmt_node(OnValidStmtNode* n) {
120 auto sdecl = static_cast<StructVariableDeclStmtNode*>(n->cond_->decl_);
121 emit_comment(n);
122 // cheat a little not using n->cond_->accept(this) to prevent the dereference
123 emit("if (%s%s) ", sdecl->scope_id(), sdecl->id_->c_str());
124 n->block_->accept(this);
125 if (n->else_block_) {
126 emit(" else ");
127 n->else_block_->accept(this);
128 }
129}
130
131void CodegenC::visit_switch_stmt_node(SwitchStmtNode* n) {
132 emit_comment(n);
133 emit("switch (");
134 n->cond_->accept(this);
135 emit(") ");
136 n->block_->accept(this);
137}
138
139void CodegenC::visit_case_stmt_node(CaseStmtNode* n) {
140 if (n->value_) {
141 emit("case ");
142 n->value_->accept(this);
143 } else {
144 emit("default");
145 }
146 emit(": ");
147 ++indent_;
148 n->block_->accept(this);
149 emitln("");
150 emit("break;");
151 --indent_;
152}
153
154void CodegenC::visit_ident_expr_node(IdentExprNode* n) {
155 if (!n->decl_)
156 throw CompilerException("variable lookup failed: %s", n->name_.c_str());
157 if (n->decl_->storage_type_ == VariableDeclStmtNode::STRUCT_REFERENCE) {
158 if (n->sub_name_.size()) {
159 if (n->bitop_) {
160 // ident is holding a host endian number, don't use dext
161 if (n->flags_[ExprNode::IS_LHS]) {
162 emit("%s%s->%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str());
163 } else {
164 emit("(((%s%s->%s) >> %d) & (((%s)1 << %d) - 1))", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str(),
165 n->bitop_->bit_offset_, bits_to_uint(n->bitop_->bit_width_ + 1), n->bitop_->bit_width_);
166 }
167 } else {
168 if (n->struct_type_->id_->name_ == "_Packet" && n->sub_name_.substr(0, 3) == "arg") {
169 // convert arg1~arg8 into args[0]~args[7] assuming type_check verified the range already
170 auto arg_num = stoi(n->sub_name_.substr(3, 3));
171 if (arg_num < 5) {
172 emit("%s%s->args_lo[%d]", n->decl_->scope_id(), n->c_str(), arg_num - 1);
173 } else {
174 emit("%s%s->args_hi[%d]", n->decl_->scope_id(), n->c_str(), arg_num - 5);
175 }
176 } else {
177 emit("%s%s->%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str());
178 }
179 }
180 } else {
181 emit("*%s%s", n->decl_->scope_id(), n->c_str());
182 }
183 } else {
184 if (n->sub_name_.size()) {
185 emit("%s%s.%s", n->decl_->scope_id(), n->c_str(), n->sub_name_.c_str());
186 } else {
187 if (n->bitop_) {
188 // ident is holding a host endian number, don't use dext
189 if (n->flags_[ExprNode::IS_LHS]) {
190 assert(0);
191 } else {
192 emit("(((%s%s) >> %d) & (((%s)1 << %d) - 1))", n->decl_->scope_id(), n->c_str(),
193 n->bitop_->bit_offset_, bits_to_uint(n->bitop_->bit_width_ + 1), n->bitop_->bit_width_);
194 }
195 } else {
196 emit("%s%s", n->decl_->scope_id(), n->c_str());
197 }
198 }
199 }
200}
201
202void CodegenC::visit_assign_expr_node(AssignExprNode* n) {
203 if (n->bitop_) {
204 n->id_->accept(this);
205 emit(" = (");
206 n->id_->accept(this);
207 emit(" & ~((((%s)1 << %d) - 1) << %d)) | (", bits_to_uint(n->id_->bit_width_),
208 n->bitop_->bit_width_, n->bitop_->bit_offset_);
209 n->rhs_->accept(this);
210 emit(" << %d)", n->bitop_->bit_offset_);
211 } else {
212 if (n->id_->flags_[ExprNode::PROTO]) {
213 auto f = n->id_->struct_type_->field(n->id_->sub_name_);
214 emit("bpf_dins(%s%s + %zu, %zu, %zu, ", n->id_->decl_->scope_id(), n->id_->c_str(),
215 f->bit_offset_ >> 3, f->bit_offset_ & 0x7, f->bit_width_);
216 n->rhs_->accept(this);
217 emit(")");
218 } else {
219 n->id_->accept(this);
220 emit(" = ");
221 n->rhs_->accept(this);
222 }
223 }
224}
225
226void CodegenC::visit_packet_expr_node(PacketExprNode* n) {
227 auto p = proto_scopes_->top_struct()->lookup(n->id_->name_, true);
228 if (p) {
229 auto f = p->field(n->id_->sub_name_);
230 if (f) {
231 size_t bit_offset = f->bit_offset_;
232 size_t bit_width = f->bit_width_;
233 if (n->bitop_) {
234 bit_offset += f->bit_width_ - (n->bitop_->bit_offset_ + n->bitop_->bit_width_);
235 bit_width = std::min(bit_width - n->bitop_->bit_offset_, n->bitop_->bit_width_);
236 }
237 if (n->flags_[ExprNode::IS_LHS])
238 emit("bpf_dins_pkt(pkt, %s + %zu, %zu, %zu, ", n->id_->c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width);
239 else
240 emit("bpf_dext_pkt(pkt, %s + %zu, %zu, %zu)", n->id_->c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width);
241 } else {
242 emit("pkt->start + pkt->offset + %s", n->id_->c_str());
243 }
244 }
245}
246
247void CodegenC::visit_integer_expr_node(IntegerExprNode* n) {
248 emit("%s", n->val_.c_str());
249}
250
251void CodegenC::visit_binop_expr_node(BinopExprNode* n) {
252 n->lhs_->accept(this);
253 switch (n->op_) {
254 case Tok::TCEQ: emit(" == "); break;
255 case Tok::TCNE: emit(" != "); break;
256 case Tok::TXOR: emit(" ^ "); break;
257 case Tok::TAND: emit(" && "); break;
258 case Tok::TOR: emit(" || "); break;
259 case Tok::TMOD: emit("%"); break;
260 case Tok::TCLT: emit(" < "); break;
261 case Tok::TCLE: emit(" <= "); break;
262 case Tok::TCGT: emit(" > "); break;
263 case Tok::TCGE: emit(" >= "); break;
264 case Tok::TPLUS: emit(" + "); break;
265 case Tok::TMINUS: emit(" - "); break;
266 case Tok::TLAND: emit(" & "); break;
267 case Tok::TLOR: emit(" | "); break;
268 default: emit(" ?%d? ", n->op_); break;
269 }
270 n->rhs_->accept(this);
271}
272
273void CodegenC::visit_unop_expr_node(UnopExprNode* n) {
274 const char* s = "";
275 switch (n->op_) {
276 case Tok::TNOT: s = "!"; break;
277 case Tok::TCMPL: s = "~"; break;
278 default: {}
279 }
280 emit("%s", s);
281 n->expr_->accept(this);
282}
283
284void CodegenC::visit_bitop_expr_node(BitopExprNode* n) {
285}
286
287void CodegenC::visit_goto_expr_node(GotoExprNode* n) {
288 if (n->id_->name_ == "DONE") {
289 for (auto ii = free_instructions_.rbegin(); ii != free_instructions_.rend(); ++ii)
290 for (auto jj = ii->rbegin(); jj != ii->rend(); ++jj)
291 emitln("%s;", jj->c_str());
292 emit("goto DONE");
293 return;
294 }
295 string jump_label;
296 // when dealing with multistates, goto statements may be overridden
297 auto rewrite_it = proto_rewrites_.find(n->id_->full_name());
298 auto default_it = proto_rewrites_.find("");
299 if (rewrite_it != proto_rewrites_.end()) {
300 jump_label = rewrite_it->second;
301 } else if (default_it != proto_rewrites_.end()) {
302 jump_label = default_it->second;
303 } else {
304 auto state = scopes_->current_state()->lookup(n->id_->full_name(), false);
305 if (state) {
306 jump_label = state->scoped_name();
307 if (n->is_continue_) {
308 jump_label += "_continue";
309 }
310 } else {
311 state = scopes_->current_state()->lookup("EOP", false);
312 if (state) {
313 jump_label = state->scoped_name();
314 }
315 }
316 }
317 for (auto ii = free_instructions_.rbegin(); ii != free_instructions_.rend(); ++ii)
318 for (auto jj = ii->rbegin(); jj != ii->rend(); ++jj)
319 emitln("%s;", jj->c_str());
320 emit("goto %s", jump_label.c_str());
321}
322
323void CodegenC::emit_table_lookup(MethodCallExprNode* n) {
324 TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_);
325 IdentExprNode* arg0 = static_cast<IdentExprNode*>(n->args_.at(0).get());
326 stringstream free_inst;
327 IdentExprNode* arg1;
328 StructVariableDeclStmtNode* arg1_type;
329
330 emitln("{ if (unlikely(pkt->capture)) {");
331 emitln(" bpf_capture(pkt, BPF_CAP_TABLE_LOOKUP, TABLE_ID_%s, 0);", n->id_->c_str());
332 emitln("} }");
333 emit("%s* %s_key = &", table->key_id()->c_str(), n->id_->c_str());
334 arg0->accept(this);
335 emitln(";");
336 emitln("%s *%s_element = (%s*)",
337 table->leaf_id()->c_str(), n->id_->c_str(), table->leaf_id()->c_str());
338 if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED" ||
339 table->type_id()->name_ == "LPM") {
340 emit(" bpf_table_lookup(pkt, TABLE_ID_%s, %s_key)", n->id_->c_str(), n->id_->c_str());
341 if (n->args_.size() == 2) {
342 arg1 = static_cast<IdentExprNode*>(n->args_.at(1).get());
343 arg1_type = static_cast<StructVariableDeclStmtNode*>(arg1->decl_);
344 if (table->leaf_id()->name_ != arg1_type->struct_id_->name_) {
345 throw CompilerException("lookup pointer type mismatch %s != %s", table->leaf_id()->c_str(),
346 arg1_type->struct_id_->c_str());
347 }
348 emitln(";");
349 // cheat a little not using arg1->accept(this) to prevent the dereference
350 emit("%s%s = %s_element", arg1_type->scope_id(), arg1_type->id_->c_str(), n->id_->c_str());
351 }
352 } else {
353 throw CompilerException("lookup in table type %s unsupported", table->type_id()->c_str());
354 }
355 free_instructions_.back().push_back(free_inst.str());
356}
357
358void CodegenC::emit_table_update(MethodCallExprNode* n) {
359 TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_);
360 IdentExprNode* arg0 = static_cast<IdentExprNode*>(n->args_.at(0).get());
361 IdentExprNode* arg1 = static_cast<IdentExprNode*>(n->args_.at(1).get());
362 IdentExprNode* type0 = table->templates_.at(0).get();
363
364 emit("%s* %s_ukey = &", type0->c_str(), n->id_->c_str());
365 arg0->accept(this);
366 emitln(";");
367 if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") {
368 emit("bpf_table_update(pkt, TABLE_ID_%s, %s_ukey", n->id_->c_str(), n->id_->c_str());
369 emit(", &");
370 arg1->accept(this);
371 emitln(");");
372 } else if (table->type_id()->name_ == "LPM") {
373 }
374}
375
376void CodegenC::emit_table_delete(MethodCallExprNode* n) {
377 TableDeclStmtNode* table = scopes_->top_table()->lookup(n->id_->name_);
378 IdentExprNode* arg0 = static_cast<IdentExprNode*>(n->args_.at(0).get());
379 IdentExprNode* type0 = table->templates_.at(0).get();
380
381 emit("%s* %s_dkey = &", type0->c_str(), n->id_->c_str());
382 arg0->accept(this);
383 emitln(";");
384 if (table->type_id()->name_ == "FIXED_MATCH" || table->type_id()->name_ == "INDEXED") {
385 emit("bpf_table_delete(pkt, TABLE_ID_%s, %s_dkey", n->id_->c_str(), n->id_->c_str());
386 emitln(");");
387 } else if (table->type_id()->name_ == "LPM") {
388 }
389}
390
391void CodegenC::emit_channel_push_generic(MethodCallExprNode* n) {
392 /* computation of orig_length of packet:
393 * orig_lenth = pkt->length - (orig_offset - pkt->offset)
394 * push_header(N) does pkt->length += N; pkt->offset -= N;
395 * pop_header(N) does pg_may_access(N); pkt->length -=N; pkt->offset +=N;
396 *
397 * therefore push_header(); pop_header(); sequence is currently broken, ticket #930
398 */
399 emit("bpf_channel_push_packet(pkt");
400 emit(")");
401}
402
403void CodegenC::emit_channel_push(MethodCallExprNode* n) {
404 IdentExprNode* arg0 = static_cast<IdentExprNode*>(n->args_.at(0).get());
405 StructVariableDeclStmtNode* arg0_type = static_cast<StructVariableDeclStmtNode*>(arg0->decl_);
406 emit("bpf_channel_push_struct(pkt, STRUCTID_%s, &", arg0_type->struct_id_->c_str());
407 arg0->accept(this);
408 emit(", sizeof(");
409 arg0->accept(this);
410 emit("))");
411}
412
413void CodegenC::emit_log(MethodCallExprNode* n) {
414 emitln("{ if (unlikely(pkt->capture)) {");
415 emit(" bpf_capture(pkt, BPF_CAP_LOG, %d, ", n->line_);
416 n->args_[0]->accept(this);
417 emit("); } }");
418}
419
420void CodegenC::emit_packet_forward(MethodCallExprNode* n) {
421 emitln("pkt->arg1 &= ~1;");
422 emit("bpf_forward(pkt, ");
423 n->args_[0]->accept(this);
424 emit(")");
425}
426
427void CodegenC::emit_packet_replicate(MethodCallExprNode*n) {
428 emitln("pkt->arg1 &= ~1;");
429 emit("bpf_replicate(pkt, ");
430 n->args_[0]->accept(this);
431 emit(",", n->id_->c_str());
432 n->args_[1]->accept(this);
433 emit(")");
434}
435
436void CodegenC::emit_packet_clone_forward(MethodCallExprNode* n) {
437 emitln("pkt->arg1 &= ~1;");
438 emit("bpf_clone_forward(pkt, ");
439 n->args_[0]->accept(this);
440 emit(")");
441}
442
443void CodegenC::emit_packet_forward_self(MethodCallExprNode* n) {
444 emit("bpf_forward_self(pkt, ");
445 n->args_[0]->accept(this);
446 emit(")");
447}
448
449void CodegenC::emit_packet_drop(MethodCallExprNode* n) {
450 emit("bpf_drop(pkt)");
451}
452
453void CodegenC::emit_packet_push_header(MethodCallExprNode* n) {
454 emit("if (unlikely(bpf_push_header(pkt, ");
455 n->args_[0]->accept(this);
456 if (n->args_.size() == 1) {
457 emit(", %zu, 0) != 0)) goto ERROR", n->args_[0]->struct_type_->bit_width_ >> 3);
458 } else {
459 emit(", %zu, ", n->args_[0]->struct_type_->bit_width_ >> 3);
460 n->args_[1]->accept(this);
461 emit(") != 0)) goto ERROR");
462 }
463}
464
465void CodegenC::emit_packet_pop_header(MethodCallExprNode* n) {
466 emit("if (unlikely(bpf_pop_header(pkt, ");
467 if (n->args_[0]->typeof_ == ExprNode::STRUCT) {
468 emit("%zu", n->args_[0]->struct_type_->bit_width_ >> 3);
469 } else if (n->args_[0]->typeof_ == ExprNode::INTEGER) {
470 n->args_[0]->accept(this);
471 }
472 emit(", 0/*todo*/) != 0)) goto ERROR");
473}
474
475void CodegenC::emit_packet_push_vlan(MethodCallExprNode* n) {
476 emit("if (unlikely(bpf_push_vlan(pkt, bpf_htons(0x8100/*ETH_P_8021Q*/), ");
477 n->args_[0]->accept(this);
478 emit(") != 0)) goto ERROR");
479}
480
481void CodegenC::emit_packet_pop_vlan(MethodCallExprNode* n) {
482 emit("if (unlikely(bpf_pop_vlan(pkt) != 0)) goto ERROR");
483}
484
485void CodegenC::emit_packet_rewrite_field(MethodCallExprNode* n) {
486 n->args_[0]->accept(this);
487 n->args_[1]->accept(this);
488 emit(")");
489}
490
491void CodegenC::emit_atomic_add(MethodCallExprNode* n) {
492 emit("__sync_fetch_and_add(&");
493 n->args_[0]->accept(this);
494 emit(", ");
495 n->args_[1]->accept(this);
496 emit(")");
497}
498
499void CodegenC::emit_cksum(MethodCallExprNode* n) {
500 if (n->args_[0]->typeof_ == ExprNode::STRUCT) {
501 auto v = n->args_[0]->struct_type_;
502 size_t bit_width = v->bit_width_ >> 3;
503 auto p = proto_scopes_->top_struct()->lookup(v->id_->name_, true);
504 if (p) {
505 /* should we do store_half directly? */
506 if (!n->args_[0]->flags_[ExprNode::PROTO]) {
507 emit("bpf_ntohs(bpf_checksum_pkt(pkt, %s, %zu))", v->id_->c_str(), bit_width);
508 } else {
509 emit("bpf_ntohs(bpf_checksum(");
510 n->args_[0]->accept(this);
511 emit(", %zu))", bit_width);
512 }
513 } else {
514 throw CompilerException("cannot pg_cksum %d", n->args_[0]->typeof_);
515 }
516/** emit("pg_cksum(");
517 n->args_[0]->accept(this);
518 emit(", %zu)", n->args_[0]->struct_type_->bit_width_ >> 3);**/
519 } else {
520 throw CompilerException("cannot pg_cksum %d", n->args_[0]->typeof_);
521 }
522}
523
524void CodegenC::emit_incr_cksum_u16(MethodCallExprNode* n) {
525 if (n->args_.size() == 3) {
526 /* ip checksum */
527 emit("bpf_ntohs(bpf_csum_replace2(bpf_htons(");
528 n->args_[0]->accept(this);
529 emit("), bpf_htons(");
530 n->args_[1]->accept(this);
531 emit("), bpf_htons(");
532 n->args_[2]->accept(this);
533 emit(")))");
534 } else {
535 /* L4 checksum */
536 emit("(");
537 /* part of pseudo header */
538 n->args_[3]->accept(this);
539 emit(" ? ");
540 emit("((pkt->hw_csum == 1) ? ");
541 /* CHECKSUM_PARTIAL update pseudo only */
542 emit("bpf_ntohs(bpf_pseudo_csum_replace2(bpf_htons(");
543 n->args_[0]->accept(this);
544 emit("), bpf_htons(");
545 n->args_[1]->accept(this);
546 emit("), bpf_htons(");
547 n->args_[2]->accept(this);
548 emit(")))");
549 emit(" : ");
550 /* CHECKSUM_NONE update normally */
551 emit("bpf_ntohs(bpf_csum_replace2(bpf_htons(");
552 n->args_[0]->accept(this);
553 emit("), bpf_htons(");
554 n->args_[1]->accept(this);
555 emit("), bpf_htons(");
556 n->args_[2]->accept(this);
557 emit(")))");
558 emit(")");
559 emit(" : ");
560 /* not part of pseudo */
561 emit("((pkt->hw_csum != 1) ? ");
562 /* CHECKSUM_NONE update normally */
563 emit("bpf_ntohs(bpf_csum_replace2(bpf_htons(");
564 n->args_[0]->accept(this);
565 emit("), bpf_htons(");
566 n->args_[1]->accept(this);
567 emit("), bpf_htons(");
568 n->args_[2]->accept(this);
569 emit(")))");
570 emit(" : ");
571 /* CHECKSUM_PARTIAL no-op */
572 n->args_[0]->accept(this);
573 emit("))");
574 }
575}
576
577void CodegenC::emit_incr_cksum_u32(MethodCallExprNode* n) {
578 if (n->args_.size() == 3) {
579 /* ip checksum */
580 emit("bpf_ntohs(bpf_csum_replace4(bpf_htons(");
581 n->args_[0]->accept(this);
582 emit("), bpf_htonl(");
583 n->args_[1]->accept(this);
584 emit("), bpf_htonl(");
585 n->args_[2]->accept(this);
586 emit(")))");
587 } else {
588 /* L4 checksum */
589 emit("(");
590 /* part of pseudo header */
591 n->args_[3]->accept(this);
592 emit(" ? ");
593 emit("((pkt->hw_csum == 1) ? ");
594 /* CHECKSUM_PARTIAL update pseudo only */
595 emit("bpf_ntohs(bpf_pseudo_csum_replace4(bpf_htons(");
596 n->args_[0]->accept(this);
597 emit("), bpf_htonl(");
598 n->args_[1]->accept(this);
599 emit("), bpf_htonl(");
600 n->args_[2]->accept(this);
601 emit(")))");
602 emit(" : ");
603 /* CHECKSUM_NONE update normally */
604 emit("bpf_ntohs(bpf_csum_replace4(bpf_htons(");
605 n->args_[0]->accept(this);
606 emit("), bpf_htonl(");
607 n->args_[1]->accept(this);
608 emit("), bpf_htonl(");
609 n->args_[2]->accept(this);
610 emit(")))");
611 emit(")");
612 emit(" : ");
613 /* not part of pseudo */
614 emit("((pkt->hw_csum != 1) ? ");
615 /* CHECKSUM_NONE updata normally */
616 emit("bpf_ntohs(bpf_csum_replace4(bpf_htons(");
617 n->args_[0]->accept(this);
618 emit("), bpf_htonl(");
619 n->args_[1]->accept(this);
620 emit("), bpf_htonl(");
621 n->args_[2]->accept(this);
622 emit(")))");
623 emit(" : ");
624 /* CHECKSUM_PARTIAL no-op */
625 n->args_[0]->accept(this);
626 emit("))");
627 }
628}
629
630void CodegenC::emit_lb_hash(MethodCallExprNode* n) {
631 emit("pg_lb_hash(");
632 n->args_[0]->accept(this);
633 emit(", ");
634 n->args_[1]->accept(this);
635 emit(")");
636}
637
638void CodegenC::emit_sizeof(MethodCallExprNode* n) {
639 if (n->args_[0]->typeof_ == ExprNode::STRUCT) {
640 if (n->args_[0]->struct_type_->id_->name_ == "_Packet") {
641 emit("PG_SIZEOF(pkt)");
642 } else {
643 emit("%zu", n->args_[0]->struct_type_->bit_width_ >> 3);
644 }
645 } else if (n->args_[0]->typeof_ == ExprNode::INTEGER) {
646 emit("%zu", n->args_[0]->bit_width_ >> 3);
647 }
648}
649
650void CodegenC::emit_get_usec_time(MethodCallExprNode* n) {
651 emit("bpf_get_usec_time()");
652}
653
654void CodegenC::emit_forward_to_vnf(MethodCallExprNode*n) {
655 emitln("pkt->arg1 |= 1;");
656 emit("pkt->arg2 = ");
657 n->args_[0]->accept(this);
658 emitln(";");
659 emit("bpf_forward_to_plum(pkt, ");
660 n->args_[1]->accept(this);
661 emit(")");
662
663}
664
665void CodegenC::emit_forward_to_group(MethodCallExprNode *n) {
666
667 emit("pkt->arg2 = ");
668 n->args_[0]->accept(this);
669 emitln(";");
670 emitln("pkt->arg3 = pkt->plum_id;");
671 emit("bpf_forward_to_plum(pkt, ");
672 emit("1/*TUNNEL_PLUM_ID*/");
673 emit(")");
674
675}
676
677void CodegenC::visit_method_call_expr_node(MethodCallExprNode* n) {
678 free_instructions_.push_back(vector<string>());
679
680 if (!n->stmts_.empty()) {
681 ++indent_;
682 emitln("{");
683 }
684
685 if (n->id_->sub_name_.size()) {
686 if (n->id_->sub_name_ == "lookup") {
687 emit_table_lookup(n);
688 } else if (n->id_->sub_name_ == "update") {
689 emit_table_update(n);
690 } else if (n->id_->sub_name_ == "delete") {
691 emit_table_delete(n);
692 } else if (n->id_->sub_name_ == "replicate" && n->id_->name_ == "pkt") {
693 emit_packet_replicate(n);
694 } else if (n->id_->sub_name_ == "forward" && n->id_->name_ == "pkt") {
695 emit_packet_forward(n);
696 } else if (n->id_->sub_name_ == "forward_self" && n->id_->name_ == "pkt") {
697 emit_packet_forward_self(n);
698 } else if (n->id_->sub_name_ == "push_header" && n->id_->name_ == "pkt") {
699 emit_packet_push_header(n);
700 } else if (n->id_->sub_name_ == "pop_header" && n->id_->name_ == "pkt") {
701 emit_packet_pop_header(n);
702 } else if (n->id_->sub_name_ == "push_vlan" && n->id_->name_ == "pkt") {
703 emit_packet_push_vlan(n);
704 } else if (n->id_->sub_name_ == "pop_vlan" && n->id_->name_ == "pkt") {
705 emit_packet_pop_vlan(n);
706 } else if (n->id_->sub_name_ == "rewrite_field" && n->id_->name_ == "pkt") {
707 emit_packet_rewrite_field(n);
708 } else if (n->id_->sub_name_ == "clone_forward" && n->id_->name_ == "pkt") {
709 emit_packet_clone_forward(n);
710 }
711 } else if (n->id_->name_ == "atomic_add") {
712 emit_atomic_add(n);
713 } else if (n->id_->name_ == "log") {
714 emit_log(n);
715 } else if (n->id_->name_ == "cksum") {
716 emit_cksum(n);
717 } else if (n->id_->name_ == "incr_cksum_u16") {
718 emit_incr_cksum_u16(n);
719 } else if (n->id_->name_ == "incr_cksum_u32") {
720 emit_incr_cksum_u32(n);
721 } else if (n->id_->name_ == "lb_hash") {
722 emit_lb_hash(n);
723 } else if (n->id_->name_ == "sizeof") {
724 emit_sizeof(n);
725 } else if (n->id_->name_ == "get_usec_time") {
726 emit_get_usec_time(n);
727 } else if (n->id_->name_ == "channel_push") {
728 emit_channel_push(n);
729 } else if (n->id_->name_ == "channel_push_generic") {
730 emit_channel_push_generic(n);
731 } else if (n->id_->name_ == "forward_to_vnf") {
732 emit_forward_to_vnf(n);
733 } else if (n->id_->name_ == "forward_to_group") {
734 emit_forward_to_group(n);
735 } else {
736 n->id_->accept(this);
737 emit("(");
738 for (auto it = n->args_.begin(); it != n->args_.end(); ++it) {
739 (*it)->accept(this);
740 if (it + 1 != n->args_.end()) {
741 emit(", ");
742 }
743 }
744 emit(")");
745 }
746 if (!n->stmts_.empty()) {
747 emit(";");
748 for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) {
749 lnemit("");
750 (*it)->accept(this);
751 }
752 for (auto it = free_instructions_.back().rbegin(); it != free_instructions_.back().rend(); ++it) {
753 lnemit("%s;", it->c_str());
754 }
755 --indent_;
756 lnemit("}");
757 }
758 free_instructions_.pop_back();
759}
760
761/// on_match
762void CodegenC::visit_match_decl_stmt_node(MatchDeclStmtNode* n) {
763 if (n->formals_.size() != 2)
764 throw CompilerException("on_match expected 2 arguments, %zu given", n->formals_.size());
765 StructVariableDeclStmtNode* key_n = static_cast<StructVariableDeclStmtNode*>(n->formals_.at(0).get());
766 StructVariableDeclStmtNode* leaf_n = static_cast<StructVariableDeclStmtNode*>(n->formals_.at(1).get());
767 if (!key_n || !leaf_n)
768 throw CompilerException("invalid parameter type");
769 ++indent_;
770 emitln("if (%s_element) {", n->id_->c_str());
771 emitln("%s* %s%s = %s_key;", key_n->struct_id_->c_str(), key_n->scope_id(),
772 key_n->id_->c_str(), n->id_->c_str());
773 emitln("%s* %s%s = %s_element;", leaf_n->struct_id_->c_str(), leaf_n->scope_id(),
774 leaf_n->id_->c_str(), n->id_->c_str());
775 n->block_->accept(this);
776 --indent_;
777 emitln("");
778 emit("}");
779}
780
781/// on_miss
782void CodegenC::visit_miss_decl_stmt_node(MissDeclStmtNode* n) {
783 if (n->formals_.size() != 1)
784 throw CompilerException("on_match expected 1 argument, %zu given", n->formals_.size());
785 StructVariableDeclStmtNode* key_n = static_cast<StructVariableDeclStmtNode*>(n->formals_.at(0).get());
786 ++indent_;
787 emitln("if (!%s_element) {", n->id_->c_str());
788 emitln("%s* %s%s = %s_key;", key_n->struct_id_->c_str(),
789 key_n->scope_id(), key_n->id_->c_str(), n->id_->c_str());
790 n->block_->accept(this);
791 --indent_;
792 emitln("");
793 emit("}");
794}
795
796void CodegenC::visit_failure_decl_stmt_node(FailureDeclStmtNode* n) {
797 if (n->formals_.size() != 1)
798 throw CompilerException("on_failure expected 1 argument, %zu given", n->formals_.size());
799 StructVariableDeclStmtNode* key_n = static_cast<StructVariableDeclStmtNode*>(n->formals_.at(0).get());
800 ++indent_;
801 emitln("/*if ((unsigned long)%s_element >= (unsigned long)-4095) {", n->id_->name_.c_str());
802 emitln("%s* %s%s = %s_key;", key_n->struct_id_->c_str(),
803 key_n->scope_id(), key_n->id_->c_str(), n->id_->c_str());
804 n->block_->accept(this);
805 --indent_;
806 emitln("");
807 emit("}*/");
808}
809
810void CodegenC::visit_expr_stmt_node(ExprStmtNode* n) {
811 emit_comment(n);
812 n->expr_->accept(this);
813 emit(";");
814}
815
816void CodegenC::visit_struct_variable_decl_stmt_node(StructVariableDeclStmtNode* n) {
817 if (n->struct_id_->name_ == "" || n->struct_id_->name_[0] == '_') {
818 return;
819 }
820 emit_comment(n);
821 if (n->struct_id_->scope_name_ == "proto") {
822 auto p = proto_scopes_->top_struct()->lookup(n->struct_id_->name_, true);
823 if (p) {
824 string var = n->scope_id() + n->id_->name_;
825 /* zero initialize array to be filled in with packet header */
826 emit("uint64_t __%s[%zu] = {}; uint8_t *%s = (uint8_t*)__%s;",
827 var.c_str(), ((p->bit_width_ >> 3) + 7) >> 3, var.c_str(), var.c_str());
828 for (auto it = n->init_.begin(); it != n->init_.end(); ++it) {
829 auto asn = static_cast<AssignExprNode*>(it->get());
830 if (auto f = p->field(asn->id_->sub_name_)) {
831 size_t bit_offset = f->bit_offset_;
832 size_t bit_width = f->bit_width_;
833 if (asn->bitop_) {
834 bit_offset += f->bit_width_ - (asn->bitop_->bit_offset_ + asn->bitop_->bit_width_);
835 bit_width = std::min(bit_width - asn->bitop_->bit_offset_, asn->bitop_->bit_width_);
836 }
837 emit(" bpf_dins(%s + %zu, %zu, %zu, ", var.c_str(), bit_offset >> 3, bit_offset & 0x7, bit_width);
838 asn->rhs_->accept(this);
839 emit(");");
840 }
841 }
842 }
843 } else {
844 /* all structs must be initialized with zeros, since they're alocated on stack,
845 * if struct doesn't have gaps between fields, gcc will be smart enough to avoid redundant zeroing */
846 if (n->storage_type_ == VariableDeclStmtNode::STRUCT_REFERENCE) {
847 emit("%s* %s%s = 0;", n->struct_id_->c_str(), n->scope_id(), n->id_->c_str());
848 } else {
849 emit("%s %s%s = {};", n->struct_id_->c_str(), n->scope_id(), n->id_->c_str());
850 if (!n->init_.empty()) {
851 for (auto it = n->init_.begin(); it != n->init_.end(); ++it) {
852 emit(" ");
853 (*it)->accept(this);
854 emit(";");
855 }
856 }
857 }
858 }
859}
860
861void CodegenC::visit_integer_variable_decl_stmt_node(IntegerVariableDeclStmtNode* n) {
862 if (n->id_->name_ == "timer_delay" || n->id_->name_ == "parsed_bytes")
863 return;
864 emit_comment(n);
865 emit("%s %s%s", bits_to_uint(n->bit_width_), n->scope_id(), n->id_->c_str());
866 if (!n->scope_id_.empty())
867 emit(" = 0");
868 if (!n->init_.empty()) {
869 emit("; ");
870 n->init_[0]->accept(this);
871 }
872 emit(";");
873}
874
875void CodegenC::visit_struct_decl_stmt_node(StructDeclStmtNode* n) {
876 emit("typedef struct {\n");
877 ++indent_;
878 for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it) {
879 indent();
880 (*it)->accept(this);
881 emit("\n");
882 }
883 --indent_;
884 indent();
885 emit("} __attribute__((aligned(4))) ");
886 emit("%s", n->id_->c_str());
887}
888
889void CodegenC::visit_parser_state_stmt_node(ParserStateStmtNode* n) {
890 string jump_label = n->scoped_name() + "_continue";
891 emit("%s: {", jump_label.c_str());
892 ++indent_;
893 lnemit("PG_TRACE(%.14s);", jump_label.c_str());
894 if (n->next_state_) {
895 lnemit("");
896 n->next_state_->accept(this);
897 }
898 --indent_;
899 lnemit("}");
900}
901
902void CodegenC::visit_timer_decl_stmt_node(TimerDeclStmtNode* n) {
903 auto scope = scopes_->current_state();
904 scopes_->set_current(n->scope_);
905 n->block_->accept(this);
906 scopes_->set_current(scope);
907}
908void CodegenC::visit_state_decl_stmt_node(StateDeclStmtNode* n) {
909 if (!n->id_) {
910 return;
911 }
912 string jump_label = n->scoped_name();
913 ++indent_;
914 emitln("JUMP_GUARD; %s: {", jump_label.c_str());
915 emitln("PG_TRACE(%.14s);", jump_label.c_str());
916 if (auto p = proto_scopes_->top_struct()->lookup(n->id_->name_, true)) {
917 emitln("%s = parsed_bytes; /* remember the offset of this header */", n->id_->c_str());
918 emitln("parsed_bytes += %zu;", p->bit_width_ >> 3);
919 //emitln("if (!pg_may_access(pkt, parsed_bytes)) goto ERROR; /* pull data from fragments to access this header */");
920 }
921 // collect the protocols used in this state scope and declare them
922 set<string> protos;
923 for (auto it = n->subs_.begin(); it != n->subs_.end(); ++it) {
924 if (!it->scope_) {
925 continue;
926 }
927 auto scope = scopes_->current_state();
928 scopes_->set_current(it->scope_);
929 for (auto it2 = scopes_->current_state()->obegin(); it2 != scopes_->current_state()->oend(); ++it2) {
930 if (proto_scopes_->top_struct()->lookup((*it2)->id_->name_, true)) {
931 protos.insert((*it2)->id_->name_);
932 }
933 for (auto it3 = (*it2)->subs_.begin(); it3 != (*it2)->subs_.end(); ++it3) {
934 if (proto_scopes_->top_struct()->lookup(it3->id_->name_, true)) {
935 protos.insert(it3->id_->name_);
936 }
937 }
938 }
939 scopes_->set_current(scope);
940 }
941 for (auto it = protos.begin(); it != protos.end(); ++it) {
942 emitln("uint32_t %s = 0; /* header offset */", it->c_str());
943 }
944
945 auto it = n->subs_.begin();
946 if (n->subs_.size() == 1 && it->id_->name_ == "") {
947 // this is not a multistate protocol, emit everything and finish
948 auto scope = scopes_->current_state();
949 scopes_->set_current(it->scope_);
950 it->block_->accept(this);
951 if (n->parser_) {
952 emitln("");
953 n->parser_->accept(this);
954 }
955 scopes_->set_current(scope);
956 } else {
957 if (n->parser_) {
958 for (auto it2 = n->subs_.begin(); it2 != n->subs_.end(); ++it2) {
959 proto_rewrites_[it2->id_->full_name()] = n->scoped_name() + "_" + it2->id_->name_;
960 }
961 n->parser_->accept(this);
962 proto_rewrites_.clear();
963 emitln("");
964 }
965 for (; it != n->subs_.end(); ++it) {
966 auto scope = scopes_->current_state();
967 scopes_->set_current(it->scope_);
968
969 string jump_label = n->scoped_name() + "_" + it->id_->name_;
970 ++indent_;
971 emitln("JUMP_GUARD; %s: {", jump_label.c_str());
972 emitln("PG_TRACE(%.14s);", jump_label.c_str());
973 if (auto p = proto_scopes_->top_struct()->lookup(it->id_->name_, true)) {
974 emitln("%s = pkt->offset + parsed_bytes; /* remember the offset of this header */", it->id_->c_str());
975 emitln("parsed_bytes += %zu;", p->bit_width_ >> 3);
976 emitln("if (!pg_may_access(pkt, parsed_bytes)) goto ERROR; /* pull data from fragments to access this header */");
977 }
978 it->block_->accept(this);
979 if (it->parser_) {
980 emitln("");
981 it->parser_->accept(this);
982 }
983 --indent_;
984 emitln("");
985 emitln("}");
986
987 scopes_->set_current(scope);
988 }
989 }
990
991 --indent_;
992 emitln("");
993 emit("}");
994}
995
996void CodegenC::visit_table_decl_stmt_node(TableDeclStmtNode* n) {
997 if (n->table_type_->name_ == "Table"
998 || n->table_type_->name_ == "SharedTable") {
999 if (n->templates_.size() != 4)
1000 throw CompilerException("%s expected 4 arguments, %zu given", n->table_type_->c_str(), n->templates_.size());
1001 const char *key_type = n->key_id()->c_str();
1002 const char *leaf_type = n->leaf_id()->c_str();
1003 char buf[128];
1004 if (n->type_id()->name_ == "FIXED_MATCH" || n->type_id()->name_ == "INDEXED") {
1005 //emitln("struct %s_Element {", n->id_->c_str());
1006 //emitln(" PG_HASH_TABLE_ELEMENT_COMMON");
1007 //emitln(" %s key;", key_type);
1008 //emitln(" %s leaf;", leaf_type);
1009 //emitln("} __attribute__((aligned(8)));");
1010 //emitln("static struct PGHashTable %s;", n->id_->c_str());
1011 //emitln("#define N_BUCKETS_%s %zu", n->id_->c_str(), n->size_);
1012 //emitln("PG_HASH_TABLE_DECL(%d, %s, sizeof(%s), sizeof(struct %s_Element), N_BUCKETS_%s)",
1013 // table_inits_.size(), n->id_->c_str(), key_type, n->id_->c_str(), n->id_->c_str());
1014 emitln("#define TABLE_ID_%s %zd", n->id_->c_str(), table_inits_.size());
1015 snprintf(buf, sizeof(buf), "[%zd] = {%zd, PG_TABLE_HASH, sizeof(%s), sizeof(%s), %zd, 0}, // %s",
1016 table_inits_.size(), table_inits_.size(), key_type, leaf_type, n->size_, n->id_->c_str());
1017 } else if (n->type_id()->name_ == "LPM") {
1018 //emitln("struct %s_Element {", n->id_->c_str());
1019 //emitln(" PG_LPM_TABLE_ELEMENT_COMMON");
1020 //emitln(" %s key;", key_type);
1021 //emitln(" %s leaf;", leaf_type);
1022 //emitln("} __attribute__((aligned(8)));");
1023 //emitln("static struct PGLpmTable %s;", n->id_->c_str());
1024 //emitln("#define N_BUCKETS_%s %zu", n->id_->c_str(), n->size_);
1025 //emitln("PG_LPM_TABLE_DECL(%d, %s, sizeof(%s), sizeof(struct %s_Element), N_BUCKETS_%s, %u)",
1026 // table_inits_.size(), n->id_->c_str(), key_type, n->id_->c_str(), n->id_->c_str(),
1027 // n->key_id()->bit_width_);
1028 emitln("#define TABLE_ID_%s %zd", n->id_->c_str(), table_inits_.size());
1029 snprintf(buf, sizeof(buf), "[%zd] = {%zd, PG_TABLE_LPM, sizeof(%s), sizeof(%s), %zd, %zd}, // %s",
1030 table_inits_.size(), table_inits_.size(), key_type, leaf_type, n->size_,
1031 n->key_id()->bit_width_, n->id_->c_str());
1032 } else {
1033 throw CompilerException("table type \"%s\" unknown", n->type_id()->c_str());
1034 }
1035 //table_inits_.push_back(n->id_->name_);
1036 table_inits_.push_back(buf);
1037 }
1038}
1039
1040int CodegenC::visit(Node* root) {
1041 BlockStmtNode* b = static_cast<BlockStmtNode*>(root);
1042
1043
1044 scopes_->set_current(scopes_->top_state());
1045 scopes_->set_current(scopes_->top_var());
1046
1047 print_header();
1048
1049 b->ver_.accept(this);
1050
1051 for (auto it = scopes_->top_table()->obegin(); it != scopes_->top_table()->oend(); ++it) {
1052 (*it)->accept(this);
1053 emit("\n");
1054 }
1055
1056 print_parser();
1057
1058 print_footer();
1059
1060 return 0;
1061}
1062
1063void CodegenC::print_timer() {
1064 // visit timers
1065 ++indent_;
1066 emitln("PG_PARSE_DECL(timer) {");
1067 emitln("uint32_t timer_delay = 0;");
1068 // visit function scoped variables
1069 for (auto it = scopes_->current_var()->obegin(); it != scopes_->current_var()->oend(); ++it) {
1070 (*it)->accept(this);
1071 emitln("");
1072 }
1073 for (auto it = scopes_->top_timer()->obegin(); it != scopes_->top_timer()->oend(); ++it) {
1074 (*it)->accept(this);
1075 emitln("");
1076 }
1077 ++indent_;
1078 emitln("DONE: {");
1079 emitln("PG_TRACE(DONE);");
1080 emitln("pg_timer_forward(pkt, timer_delay);");
1081 --indent_;
1082 emitln("return;");
1083 emitln("}");
1084
1085 ++indent_;
1086 emitln("ERROR: {");
1087 emitln("PG_TRACE(ERROR);");
1088 emitln("pg_drop(pkt);");
1089 emitln("pg_timer_forward(pkt, timer_delay);");
1090 --indent_;
1091 emitln("return;");
1092 --indent_;
1093 emitln("}");
1094 emitln("}");
1095}
1096
1097void CodegenC::print_parser() {
1098 ++indent_;
1099 emitln("PG_PARSE_DECL(parse) {");
1100 /* emitln("uint8_t *pp;"); */
1101 emitln("uint32_t parsed_bytes = 0;");
1102 emitln("uint16_t orig_offset = 0;/*pkt->offset;*/");
1103
1104 // visit function scoped variables
1105 for (auto it = scopes_->current_var()->obegin(); it != scopes_->current_var()->oend(); ++it) {
1106 (*it)->accept(this);
1107 emitln("");
1108 }
1109
1110 for (auto it = scopes_->current_state()->obegin(); it != scopes_->current_state()->oend(); ++it) {
1111 if (proto_scopes_->top_struct()->lookup((*it)->id_->name_, true)) {
1112 emitln("uint32_t %s = 0; /* header offset */", (*it)->id_->c_str());
1113 }
1114 }
1115
1116 /* emitln("pp = pkt->start + pkt->offset;"); */
1117 emitln("goto s1_INIT;");
1118
1119 // finally, visit the states
1120 for (auto it = scopes_->current_state()->obegin(); it != scopes_->current_state()->oend(); ++it) {
1121 (*it)->accept(this);
1122 emitln("");
1123 }
1124
1125 ++indent_;
1126 emitln("ERROR: {");
1127 emitln("PG_TRACE(ERROR);");
1128 --indent_;
1129 emitln("goto CLEANUP;");
1130 emitln("}");
1131
1132 ++indent_;
1133 emitln("DONE: {");
1134 emitln("PG_TRACE(DONE);");
1135 --indent_;
1136 emitln("goto CLEANUP;");
1137 emitln("}");
1138
1139 ++indent_;
1140 emitln("CLEANUP: {");
1141 --indent_;
1142 emitln("/* cleanup is done by PE */;");
1143 --indent_;
1144 emitln("}");
1145
1146 emitln("}");
1147
1148 //print_timer();
1149}
1150
1151void CodegenC::print_header() {
1152 if (use_pre_header_) {
1153 //emit("%s", PRE_HEADER.c_str());
1154 emitln("");
1155 } else {
1156 emitln("#include <stdint.h>");
1157 emitln("#include \"../dp/linux/filter.h\"");
1158 emitln("#include \"container/pg_api.h\"");
1159 emitln("#include \"container/pg_defs.h\"");
1160 }
1161 emitln("#define JUMP_GUARD goto DONE");
1162 emitln("#define PG_SIZEOF(_pkt) ((int)_pkt->length - (int)pkt->offset + orig_offset)");
1163
1164 int i = 0;
1165 // declare structures
1166 for (auto it = scopes_->top_struct()->obegin(); it != scopes_->top_struct()->oend(); ++it) {
1167 if ((*it)->id_->name_ == "_Packet")
1168 continue;
1169 (*it)->accept(this);
1170 emit(";\n");
1171 emitln("#define STRUCTID_%s %d", (*it)->id_->c_str(), i++);
1172 }
1173 emitln("#define STRUCTID_generic %d", i);
1174}
1175
1176void CodegenC::print_footer() {
1177 //emitln("#define EXPAND_TABLES(E) \\");
1178 emitln("struct bpf_table plum_tables[] = {");
1179 for (auto it = table_inits_.begin(); it != table_inits_.end(); ++it) {
1180 //emit("E(%s) ", it->c_str());
1181 emitln(" %s", it->c_str());
1182 }
1183 emitln(" {0,0,0,0,0,0} // last table marker");
1184 emitln("};");
1185 emitln("");
1186 emitln("PG_INIT");
1187 emitln("PG_CLEANUP");
1188}
1189
1190} // namespace cc
1191} // namespace ebpf