• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2
3# Copyright (c) Barefoot Networks, Inc.
4# Licensed under the Apache License, Version 2.0 (the "License")
5
6# Compiler from P4 to EBPF
7# (See http://www.slideshare.net/PLUMgrid/ebpf-and-linux-networking).
8# This compiler in fact generates a C source file
9# which can be compiled to EBPF using the LLVM compiler
10# with the ebpf target.
11#
12# Main entry point.
13
14import argparse
15import os
16import traceback
17import sys
18import target
19from p4_hlir.main import HLIR
20from ebpfProgram import EbpfProgram
21from compilationException import *
22from programSerializer import ProgramSerializer
23
24
25def get_parser():
26    parser = argparse.ArgumentParser(description='p4toEbpf arguments')
27    parser.add_argument('source', metavar='source', type=str,
28                        help='a P4 source file to compile')
29    parser.add_argument('-g', dest='generated', default="router",
30                        help="kind of output produced: filter or router")
31    parser.add_argument('-o', dest='output_file', default="output.c",
32                        help="generated C file name")
33    return parser
34
35
36def process(input_args):
37    parser = get_parser()
38    args, unparsed_args = parser.parse_known_args(input_args)
39
40    has_remaining_args = False
41    preprocessor_args = []
42    for a in unparsed_args:
43        if a[:2] == "-D" or a[:2] == "-I" or a[:2] == "-U":
44            input_args.remove(a)
45            preprocessor_args.append(a)
46        else:
47            has_remaining_args = True
48
49    # trigger error
50    if has_remaining_args:
51        parser.parse_args(input_args)
52
53    if args.generated == "router":
54        isRouter = True
55    elif args.generated == "filter":
56        isRouter = False
57    else:
58        print("-g should be one of 'filter' or 'router'")
59
60    print("*** Compiling ", args.source)
61    return compileP4(args.source, args.output_file, isRouter, preprocessor_args)
62
63
64class CompileResult(object):
65    def __init__(self, kind, error):
66        self.kind = kind
67        self.error = error
68
69    def __str__(self):
70        if self.kind == "OK":
71            return "Compilation successful"
72        else:
73            return "Compilation failed with error: " + self.error
74
75
76def compileP4(inputFile, gen_file, isRouter, preprocessor_args):
77    h = HLIR(inputFile)
78
79    for parg in preprocessor_args:
80        h.add_preprocessor_args(parg)
81    if not h.build():
82        return CompileResult("HLIR", "Error while building HLIR")
83
84    try:
85        basename = os.path.basename(inputFile)
86        basename = os.path.splitext(basename)[0]
87
88        config = target.BccConfig()
89        e = EbpfProgram(basename, h, isRouter, config)
90        serializer = ProgramSerializer()
91        e.toC(serializer)
92        f = open(gen_file, 'w')
93        f.write(serializer.toString())
94        return CompileResult("OK", "")
95    except CompilationException, e:
96        prefix = ""
97        if e.isBug:
98            prefix = "### Compiler bug: "
99        return CompileResult("bug", prefix + e.show())
100    except NotSupportedException, e:
101        return CompileResult("not supported", e.show())
102    except:
103        return CompileResult("exception", traceback.format_exc())
104
105
106# main entry point
107if __name__ == "__main__":
108    result = process(sys.argv[1:])
109    if result.kind != "OK":
110        print(str(result))
111