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