Commit a94bd931 authored by Brenden Blanco's avatar Brenden Blanco

Initial commit

llvm-jit based parser and loader
parents
cmake_minimum_required(VERSION 2.8.7)
project(bpf-tools)
find_package(BISON)
find_package(FLEX)
find_package(LLVM REQUIRED CONFIG)
find_program(XXD xxd)
if (${XXD} STREQUAL "XXD-NOTFOUND")
message(FATAL_ERROR "program xxd not found, install vim-common")
endif()
find_program(CLANG clang)
if (${CLANG} STREQUAL "CLANG-NOTFOUND")
message(FATAL_ERROR "program clang not found, install clang with bpf support")
endif()
set(CMAKE_C_FLAGS "-Wall")
set(CMAKE_CXX_FLAGS "-std=c++11 -Wall")
add_subdirectory(jit)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto -fno-rtti")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/compat/include)
add_subdirectory(src)
/* Copyright (c) 2011-2014 PLUMgrid, http://plumgrid.com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public
* License as published by the Free Software Foundation.
*/
#ifndef _UAPI__LINUX_BPF_H__
#define _UAPI__LINUX_BPF_H__
#include <linux/types.h>
#include <linux/bpf_common.h>
/* Extended instruction set based on top of classic BPF */
/* instruction classes */
#define BPF_ALU64 0x07 /* alu mode in double word width */
/* ld/ldx fields */
#define BPF_DW 0x18 /* double word */
#define BPF_XADD 0xc0 /* exclusive add */
/* alu/jmp fields */
#define BPF_MOV 0xb0 /* mov reg to reg */
#define BPF_ARSH 0xc0 /* sign extending arithmetic shift right */
/* change endianness of a register */
#define BPF_END 0xd0 /* flags for endianness conversion: */
#define BPF_TO_LE 0x00 /* convert to little-endian */
#define BPF_TO_BE 0x08 /* convert to big-endian */
#define BPF_FROM_LE BPF_TO_LE
#define BPF_FROM_BE BPF_TO_BE
#define BPF_JNE 0x50 /* jump != */
#define BPF_JSGT 0x60 /* SGT is signed '>', GT in x86 */
#define BPF_JSGE 0x70 /* SGE is signed '>=', GE in x86 */
#define BPF_CALL 0x80 /* function call */
#define BPF_EXIT 0x90 /* function return */
/* Register numbers */
enum {
BPF_REG_0 = 0,
BPF_REG_1,
BPF_REG_2,
BPF_REG_3,
BPF_REG_4,
BPF_REG_5,
BPF_REG_6,
BPF_REG_7,
BPF_REG_8,
BPF_REG_9,
BPF_REG_10,
__MAX_BPF_REG,
};
/* BPF has 10 general purpose 64-bit registers and stack frame. */
#define MAX_BPF_REG __MAX_BPF_REG
struct bpf_insn {
__u8 code; /* opcode */
__u8 dst_reg:4; /* dest register */
__u8 src_reg:4; /* source register */
__s16 off; /* signed offset */
__s32 imm; /* signed immediate constant */
};
/* BPF syscall commands */
enum bpf_cmd {
/* create a map with given type and attributes
* fd = bpf(BPF_MAP_CREATE, union bpf_attr *, u32 size)
* returns fd or negative error
* map is deleted when fd is closed
*/
BPF_MAP_CREATE,
/* lookup key in a given map
* err = bpf(BPF_MAP_LOOKUP_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->value
* returns zero and stores found elem into value
* or negative error
*/
BPF_MAP_LOOKUP_ELEM,
/* create or update key/value pair in a given map
* err = bpf(BPF_MAP_UPDATE_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->value, attr->flags
* returns zero or negative error
*/
BPF_MAP_UPDATE_ELEM,
/* find and delete elem by key in a given map
* err = bpf(BPF_MAP_DELETE_ELEM, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key
* returns zero or negative error
*/
BPF_MAP_DELETE_ELEM,
/* lookup key in a given map and return next key
* err = bpf(BPF_MAP_GET_NEXT_KEY, union bpf_attr *attr, u32 size)
* Using attr->map_fd, attr->key, attr->next_key
* returns zero and stores next key or negative error
*/
BPF_MAP_GET_NEXT_KEY,
/* verify and load eBPF program
* prog_fd = bpf(BPF_PROG_LOAD, union bpf_attr *attr, u32 size)
* Using attr->prog_type, attr->insns, attr->license
* returns fd or negative error
*/
BPF_PROG_LOAD,
};
enum bpf_map_type {
BPF_MAP_TYPE_UNSPEC,
BPF_MAP_TYPE_HASH,
BPF_MAP_TYPE_ARRAY,
};
enum bpf_prog_type {
BPF_PROG_TYPE_UNSPEC,
BPF_PROG_TYPE_SOCKET_FILTER,
BPF_PROG_TYPE_SCHED_CLS,
BPF_PROG_TYPE_SCHED_ACT,
};
#define BPF_PSEUDO_MAP_FD 1
/* flags for BPF_MAP_UPDATE_ELEM command */
#define BPF_ANY 0 /* create new element or update existing */
#define BPF_NOEXIST 1 /* create new element if it didn't exist */
#define BPF_EXIST 2 /* update existing element */
union bpf_attr {
struct { /* anonymous struct used by BPF_MAP_CREATE command */
__u32 map_type; /* one of enum bpf_map_type */
__u32 key_size; /* size of key in bytes */
__u32 value_size; /* size of value in bytes */
__u32 max_entries; /* max number of entries in a map */
};
struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
__u32 map_fd;
__aligned_u64 key;
union {
__aligned_u64 value;
__aligned_u64 next_key;
};
__u64 flags;
};
struct { /* anonymous struct used by BPF_PROG_LOAD command */
__u32 prog_type; /* one of enum bpf_prog_type */
__u32 insn_cnt;
__aligned_u64 insns;
__aligned_u64 license;
__u32 log_level; /* verbosity level of verifier */
__u32 log_size; /* size of user buffer */
__aligned_u64 log_buf; /* user supplied buffer */
};
} __attribute__((aligned(8)));
/* integer value in 'imm' field of BPF_CALL instruction selects which helper
* function eBPF program intends to call
*/
enum bpf_func_id {
BPF_FUNC_unspec,
BPF_FUNC_map_lookup_elem, /* void *map_lookup_elem(&map, &key) */
BPF_FUNC_map_update_elem, /* int map_update_elem(&map, &key, &value, flags) */
BPF_FUNC_map_delete_elem, /* int map_delete_elem(&map, &key) */
BPF_FUNC_get_prandom_u32, /* u32 prandom_u32(void) */
BPF_FUNC_get_smp_processor_id, /* u32 raw_smp_processor_id(void) */
/**
* skb_store_bytes(skb, offset, from, len, flags) - store bytes into packet
* @skb: pointer to skb
* @offset: offset within packet from skb->data
* @from: pointer where to copy bytes from
* @len: number of bytes to store into packet
* @flags: bit 0 - if true, recompute skb->csum
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_skb_store_bytes,
/**
* l3_csum_replace(skb, offset, from, to, flags) - recompute IP checksum
* @skb: pointer to skb
* @offset: offset within packet where IP checksum is located
* @from: old value of header field
* @to: new value of header field
* @flags: bits 0-3 - size of header field
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_l3_csum_replace,
/**
* l4_csum_replace(skb, offset, from, to, flags) - recompute TCP/UDP checksum
* @skb: pointer to skb
* @offset: offset within packet where TCP/UDP checksum is located
* @from: old value of header field
* @to: new value of header field
* @flags: bits 0-3 - size of header field
* bit 4 - is pseudo header
* other bits - reserved
* Return: 0 on success
*/
BPF_FUNC_l4_csum_replace,
__BPF_FUNC_MAX_ID,
};
/* user accessible mirror of in-kernel sk_buff.
* new fields can only be added to the end of this structure
*/
struct __sk_buff {
__u32 len;
__u32 pkt_type;
__u32 mark;
__u32 queue_mapping;
__u32 protocol;
__u32 vlan_present;
__u32 vlan_tci;
__u32 vlan_proto;
__u32 priority;
};
#endif /* _UAPI__LINUX_BPF_H__ */
#ifndef __LINUX_BPF_COMMON_H__
#define __LINUX_BPF_COMMON_H__
/* Instruction classes */
#define BPF_CLASS(code) ((code) & 0x07)
#define BPF_LD 0x00
#define BPF_LDX 0x01
#define BPF_ST 0x02
#define BPF_STX 0x03
#define BPF_ALU 0x04
#define BPF_JMP 0x05
#define BPF_RET 0x06
#define BPF_MISC 0x07
/* ld/ldx fields */
#define BPF_SIZE(code) ((code) & 0x18)
#define BPF_W 0x00
#define BPF_H 0x08
#define BPF_B 0x10
#define BPF_MODE(code) ((code) & 0xe0)
#define BPF_IMM 0x00
#define BPF_ABS 0x20
#define BPF_IND 0x40
#define BPF_MEM 0x60
#define BPF_LEN 0x80
#define BPF_MSH 0xa0
/* alu/jmp fields */
#define BPF_OP(code) ((code) & 0xf0)
#define BPF_ADD 0x00
#define BPF_SUB 0x10
#define BPF_MUL 0x20
#define BPF_DIV 0x30
#define BPF_OR 0x40
#define BPF_AND 0x50
#define BPF_LSH 0x60
#define BPF_RSH 0x70
#define BPF_NEG 0x80
#define BPF_MOD 0x90
#define BPF_XOR 0xa0
#define BPF_JA 0x00
#define BPF_JEQ 0x10
#define BPF_JGT 0x20
#define BPF_JGE 0x30
#define BPF_JSET 0x40
#define BPF_SRC(code) ((code) & 0x08)
#define BPF_K 0x00
#define BPF_X 0x08
#ifndef BPF_MAXINSNS
#define BPF_MAXINSNS 4096
#endif
#endif /* __LINUX_BPF_COMMON_H__ */
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_CURRENT_BINARY_DIR})
add_subdirectory(cc)
import ctypes as ct
import os
import pyroute2 as pr
lib = ct.cdll.LoadLibrary("libbpfprog.so")
lib.bpf_program_create.restype = ct.c_void_p
lib.bpf_program_create.argtypes = [ct.c_char_p, ct.c_char_p, ct.c_uint]
lib.bpf_program_destroy.restype = None
lib.bpf_program_destroy.argtypes = [ct.c_void_p]
lib.bpf_program_start.restype = ct.c_void_p
lib.bpf_program_start.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_program_size.restype = ct.c_size_t
lib.bpf_program_size.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_program_license.restype = ct.c_char_p
lib.bpf_program_license.argtypes = [ct.c_void_p]
lib.bpf_program_table_fd.restype = ct.c_int
lib.bpf_program_table_fd.argtypes = [ct.c_void_p, ct.c_char_p]
lib.bpf_get_next_key.restype = ct.c_int
lib.bpf_get_next_key.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p]
lib.bpf_lookup_elem.restype = ct.c_int
lib.bpf_lookup_elem.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p]
lib.bpf_update_elem.restype = ct.c_int
lib.bpf_update_elem.argtypes = [ct.c_int, ct.c_void_p, ct.c_void_p,
ct.c_ulonglong]
lib.bpf_delete_elem.restype = ct.c_int
lib.bpf_delete_elem.argtypes = [ct.c_int, ct.c_void_p]
lib.bpf_open_raw_sock.restype = ct.c_int
lib.bpf_open_raw_sock.argtypes = [ct.c_char_p]
lib.bpf_attach_socket.restype = ct.c_int
lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int]
lib.bpf_attach_filter.restype = ct.c_int
lib.bpf_attach_filter.argtypes = [ct.c_int, ct.c_char_p, ct.c_uint, ct.c_ubyte, ct.c_uint]
lib.bpf_prog_load.restype = ct.c_int
lib.bpf_prog_load.argtypes = [ct.c_int, ct.c_void_p, ct.c_size_t,
ct.c_char_p]
class BPF(object):
BPF_PROG_TYPE_SOCKET_FILTER = 1
BPF_PROG_TYPE_SCHED_CLS = 2
BPF_PROG_TYPE_SCHED_ACT = 3
def __init__(self, name, dp_file, dph_file,
prog_type=BPF_PROG_TYPE_SOCKET_FILTER,
debug=0):
self.debug = debug
self.name = name
self.prog = lib.bpf_program_create(dp_file.encode("ascii"),
dph_file.encode("ascii"), self.debug)
if self.prog == ct.c_void_p(None):
raise Exception("Failed to compile BPF program %s" % dp_file)
if lib.bpf_program_start(self.prog,
self.name.encode("ascii")) == ct.c_void_p(None):
raise Exception("Unknown program %s" % self.name)
self.fd = lib.bpf_prog_load(prog_type,
lib.bpf_program_start(self.prog, self.name.encode("ascii")),
lib.bpf_program_size(self.prog, self.name.encode("ascii")),
lib.bpf_program_license(self.prog))
if self.fd < 0:
print((ct.c_char * 65536).in_dll(lib, "bpf_log_buf").value)
#print(ct.c_char_p.in_dll(lib, "bpf_log_buf").value)
raise Exception("Failed to load BPF program %s" % dp_file)
class Table(object):
def __init__(self, bpf, map_fd, keytype, leaftype):
self.bpf = bpf
self.map_fd = map_fd
self.keytype = keytype
self.leaftype = leaftype
def get(self, key):
key_p = ct.pointer(key)
leaf = self.leaftype()
leaf_p = ct.pointer(leaf)
res = lib.bpf_lookup_elem(self.map_fd,
ct.cast(key_p, ct.c_void_p),
ct.cast(leaf_p, ct.c_void_p))
if res < 0:
raise Exception("Could not lookup in table")
return leaf
def put(self, key, leaf, flags=0):
key_p = ct.pointer(key)
leaf_p = ct.pointer(leaf)
res = lib.bpf_update_elem(self.map_fd,
ct.cast(key_p, ct.c_void_p),
ct.cast(leaf_p, ct.c_void_p), flags)
if res < 0:
raise Exception("Could not update table")
class Iter(object):
def __init__(self, table, keytype):
self.keytype = keytype
self.table = table
self.key = keytype()
def __iter__(self):
return self
def __next__(self):
return self.next()
def next(self):
self.key = self.table.next(self.key)
return self.key
def iter(self):
return BPF.Table.Iter(self, self.keytype)
def next(self, key):
next_key = self.keytype()
next_key_p = ct.pointer(next_key)
key_p = ct.pointer(key)
res = lib.bpf_get_next_key(self.map_fd,
ct.cast(key_p, ct.c_void_p),
ct.cast(next_key_p, ct.c_void_p))
if res < 0:
raise StopIteration()
return next_key
def table(self, name, keytype, leaftype):
map_fd = lib.bpf_program_table_fd(self.prog,
ct.c_char_p(name.encode("ascii")))
if map_fd < 0:
raise Exception("Failed to find BPF Table %s" % name)
return BPF.Table(self, map_fd, keytype, leaftype)
def attach(self, dev):
self.sock = lib.bpf_open_raw_sock(dev.encode("ascii"))
if self.sock < 0:
errstr = os.strerror(ct.get_errno())
raise Exception("Failed to open raw device %s: %s" % (dev, errstr))
res = lib.bpf_attach_socket(self.sock, self.fd)
if res < 0:
errstr = os.strerror(ct.get_errno())
raise Exception("Failed to attach BPF to device %s: %s"
% (dev, errstr))
def attach_filter(self, ifindex, prio, classid):
res = lib.bpf_attach_filter(self.fd, self.name.encode("ascii"), ifindex, prio, classid)
if res < 0:
raise Exception("Failed to filter with BPF")
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${LLVM_INCLUDE_DIRS})
add_definitions(${LLVM_DEFINITIONS})
BISON_TARGET(Parser parser.yy ${CMAKE_CURRENT_BINARY_DIR}/parser.yy.cc COMPILE_FLAGS "-o parser.yy.cc -v --debug")
FLEX_TARGET(Lexer lexer.ll ${CMAKE_CURRENT_BINARY_DIR}/lexer.ll.cc COMPILE_FLAGS "--c++ --o lexer.ll.cc")
ADD_FLEX_BISON_DEPENDENCY(Lexer Parser)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bitops.bc
COMMAND ${CLANG}
ARGS -O3 -emit-llvm -S -o bitops.bc -I${CMAKE_SOURCE_DIR}/jit/compat/include
-c ${CMAKE_CURRENT_SOURCE_DIR}/bitops.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/bitops.c
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating bitops IR")
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/bitops.h
COMMAND ${XXD} ARGS -i bitops.bc bitops.h
DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bitops.bc
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating bitops.h")
add_custom_target(bitops DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/bitops.h)
set(CMAKE_SHARED_LINKER_FLAGS "-static-libstdc++ -Wl,--exclude-libs=ALL")
add_library(bpfprog SHARED bpf_common.cc bpf_program.cc codegen_llvm.cc
node.cc parser.cc printer.cc type_check.cc libbpf.c
${BISON_Parser_OUTPUTS} ${FLEX_Lexer_OUTPUTS} ${CMAKE_CURRENT_BINARY_DIR}/bitops.h)
# BPF is still experimental otherwise it should be available
#llvm_map_components_to_libnames(llvm_libs bpf mcjit irreader passes)
llvm_map_components_to_libnames(llvm_libs mcjit irreader passes)
# Link against LLVM libraries
target_link_libraries(bpfprog ${llvm_libs} LLVMBPFCodeGen mnl)
/*
* ====================================================================
* Copyright (c) 2012-2013, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* ====================================================================
*/
#include <stdint.h>
#include "linux/bpf.h"
#include "bpf_helpers.h"
#define assert(v)
static inline uint16_t bpf_ntohs(uint16_t val) {
/* will be recognized by gcc into rotate insn and eventually rolw 8 */
return (val << 8) | (val >> 8);
}
static inline uint32_t bpf_ntohl(uint32_t val) {
/* gcc will use bswapsi2 insn */
return __builtin_bswap32(val);
}
static inline uint64_t bpf_ntohll(uint64_t val) {
/* gcc will use bswapdi2 insn */
return __builtin_bswap64(val);
}
static inline unsigned __int128 bpf_ntoh128(unsigned __int128 val) {
return (((unsigned __int128)bpf_ntohll(val) << 64) | (uint64_t)bpf_ntohll(val >> 64));
}
static inline uint16_t bpf_htons(uint16_t val) {
return bpf_ntohs(val);
}
static inline uint32_t bpf_htonl(uint32_t val) {
return bpf_ntohl(val);
}
static inline uint64_t bpf_htonll(uint64_t val) {
return bpf_ntohll(val);
}
static inline unsigned __int128 bpf_hton128(unsigned __int128 val) {
return bpf_ntoh128(val);
}
static inline uint64_t load_dword(void *skb, uint64_t off) {
return ((uint64_t)load_word(skb, off) << 4) | load_word(skb, off + 4);
}
void bpf_store_byte(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.byte");
void bpf_store_half(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.half");
void bpf_store_word(void *skb, uint64_t off, uint64_t val) asm("llvm.bpf.store.word");
static inline void bpf_store_dword(void *skb, uint64_t off, uint64_t val) {
bpf_store_word(skb, off, (uint32_t)val);
bpf_store_word(skb, off + 4, val >> 32);
}
#define MASK(_n) ((_n) < 64 ? (1ull << (_n)) - 1 : ((uint64_t)-1LL))
#define MASK128(_n) ((_n) < 128 ? ((unsigned __int128)1 << (_n)) - 1 : ((unsigned __int128)-1))
struct _skbuff;
struct bpf_context;
//static inline __attribute__((always_inline))
SEC("helpers")
uint64_t bpf_dext_pkt(void *pkt, uint64_t off, uint64_t bofs, uint64_t bsz) {
if (bofs == 0 && bsz == 8) {
return load_byte(pkt, off);
} else if (bofs + bsz <= 8) {
return load_byte(pkt, off) >> (8 - (bofs + bsz)) & MASK(bsz);
} else if (bofs == 0 && bsz == 16) {
return load_half(pkt, off);
} else if (bofs + bsz <= 16) {
return load_half(pkt, off) >> (16 - (bofs + bsz)) & MASK(bsz);
} else if (bofs == 0 && bsz == 32) {
return load_word(pkt, off);
} else if (bofs + bsz <= 32) {
return load_word(pkt, off) >> (32 - (bofs + bsz)) & MASK(bsz);
} else if (bofs + bsz <= 64) {
return bpf_ntohll(load_dword(pkt, off)) >> (64 - (bofs + bsz)) & MASK(bsz);
} else {
assert(0);
}
return 0;
}
//static inline __attribute__((always_inline))
SEC("helpers")
void bpf_dins_pkt(void *pkt, uint64_t off, uint64_t bofs, uint64_t bsz, uint64_t val) {
// The load_xxx function does a bswap before returning the short/word/dword,
// so the value in register will always be host endian. However, the bytes
// written back need to be in network order.
if (bofs == 0 && bsz == 8) {
bpf_skb_store_bytes(pkt, off, &val, 1, 0);
} else if (bofs + bsz <= 8) {
uint8_t v = load_byte(pkt, off);
v &= ~(MASK(bsz) << (8 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (8 - (bofs + bsz)));
bpf_skb_store_bytes(pkt, off, &v, 1, 0);
} else if (bofs == 0 && bsz == 16) {
uint16_t v = bpf_htons(val);
bpf_skb_store_bytes(pkt, off, &v, 2, 0);
} else if (bofs + bsz <= 16) {
uint16_t v = load_half(pkt, off);
v &= ~(MASK(bsz) << (16 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (16 - (bofs + bsz)));
v = bpf_htons(v);
bpf_skb_store_bytes(pkt, off, &v, 2, 0);
} else if (bofs == 0 && bsz == 32) {
uint32_t v = bpf_htonl(val);
bpf_skb_store_bytes(pkt, off, &v, 4, 0);
} else if (bofs + bsz <= 32) {
uint32_t v = load_word(pkt, off);
v &= ~(MASK(bsz) << (32 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (32 - (bofs + bsz)));
v = bpf_htonl(v);
bpf_skb_store_bytes(pkt, off, &v, 4, 0);
} else if (bofs == 0 && bsz == 64) {
uint64_t v = bpf_htonll(val);
bpf_skb_store_bytes(pkt, off, &v, 8, 0);
} else if (bofs + bsz <= 64) {
uint64_t v = load_dword(pkt, off);
v &= ~(MASK(bsz) << (64 - (bofs + bsz)));
v |= ((val & MASK(bsz)) << (64 - (bofs + bsz)));
v = bpf_htonll(v);
bpf_skb_store_bytes(pkt, off, &v, 8, 0);
} else if (bofs + bsz <= 128) {
assert(0);
//bpf_store_16bytes(pkt, off, bpf_hton128(~(MASK128(bsz) << (128 - (bofs + bsz)))),
// bpf_hton128((val & MASK128(bsz)) << (128 - (bofs + bsz))));
} else {
assert(0);
}
}
SEC("helpers")
void * bpf_map_lookup_elem_(uintptr_t map, void *key) {
return bpf_map_lookup_elem((void *)map, key);
}
SEC("helpers")
int bpf_map_update_elem_(uintptr_t map, void *key, void *value, uint64_t flags) {
return bpf_map_update_elem((void *)map, key, value, flags);
}
SEC("helpers")
int bpf_map_delete_elem_(uintptr_t map, void *key) {
return bpf_map_delete_elem((void *)map, key);
}
SEC("helpers")
int bpf_skb_store_bytes_(void *ctx, uint64_t off, void *from, uint64_t len, uint64_t flags) {
return bpf_skb_store_bytes(ctx, off, from, len, flags);
}
SEC("helpers")
int bpf_l3_csum_replace_(void *ctx, uint64_t off, uint64_t from, uint64_t to, uint64_t flags) {
switch (flags & 0xf) {
case 2:
return bpf_l3_csum_replace(ctx, off, bpf_htons(from), bpf_htons(to), flags);
case 4:
return bpf_l3_csum_replace(ctx, off, bpf_htonl(from), bpf_htonl(to), flags);
case 8:
return bpf_l3_csum_replace(ctx, off, bpf_htonll(from), bpf_htonll(to), flags);
default:
{}
}
return bpf_l3_csum_replace(ctx, off, from, to, flags);
}
SEC("helpers")
int bpf_l4_csum_replace_(void *ctx, uint64_t off, uint64_t from, uint64_t to, uint64_t flags) {
switch (flags & 0xf) {
case 2:
return bpf_l4_csum_replace(ctx, off, bpf_htons(from), bpf_htons(to), flags);
case 4:
return bpf_l4_csum_replace(ctx, off, bpf_htonl(from), bpf_htonl(to), flags);
case 8:
return bpf_l4_csum_replace(ctx, off, bpf_htonll(from), bpf_htonll(to), flags);
default:
{}
}
return bpf_l4_csum_replace(ctx, off, from, to, flags);
}
#undef assert
#include "cc/bpf_program.h"
#include "cc/bpf_common.h"
extern "C" {
void * bpf_program_create(const char *filename, const char *proto_filename, unsigned flags) {
auto prog = new ebpf::BPFProgram(flags);
if (prog->load(filename, proto_filename) != 0) {
delete prog;
return nullptr;
}
return prog;
}
void bpf_program_destroy(void *program) {
auto prog = static_cast<ebpf::BPFProgram *>(program);
if (!prog) return;
delete prog;
}
void * bpf_program_start(void *program, const char *name) {
auto prog = static_cast<ebpf::BPFProgram *>(program);
if (!prog) return nullptr;
return prog->start(name);
}
size_t bpf_program_size(void *program, const char *name) {
auto prog = static_cast<ebpf::BPFProgram *>(program);
if (!prog) return 0;
return prog->size(name);
}
char * bpf_program_license(void *program) {
auto prog = static_cast<ebpf::BPFProgram *>(program);
if (!prog) return nullptr;
return prog->license();
}
int bpf_program_table_fd(void *program, const char *table_name) {
auto prog = static_cast<ebpf::BPFProgram *>(program);
if (!prog) return -1;
return prog->table_fd(table_name);
}
}
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
void * bpf_program_create(const char *filename, const char *proto_filename, unsigned flags);
void bpf_program_destroy(void *program);
void * bpf_program_start(void *program, const char *name);
size_t bpf_program_size(void *program, const char *name);
char * bpf_program_license(void *program);
int bpf_program_table_fd(void *program, const char *table_name);
#ifdef __cplusplus
}
#endif
#ifndef __BPF_HELPERS_H
#define __BPF_HELPERS_H
/* helper macro to place programs, maps, license in
* different sections in elf_bpf file. Section names
* are interpreted by elf_bpf loader
*/
#define SEC(NAME) __attribute__((section(NAME), used))
/* helper functions called from eBPF programs written in C */
static void *(*bpf_map_lookup_elem)(void *map, void *key) =
(void *) BPF_FUNC_map_lookup_elem;
static int (*bpf_map_update_elem)(void *map, void *key, void *value,
unsigned long long flags) =
(void *) BPF_FUNC_map_update_elem;
static int (*bpf_map_delete_elem)(void *map, void *key) =
(void *) BPF_FUNC_map_delete_elem;
/* llvm builtin functions that eBPF C program may use to
* emit BPF_LD_ABS and BPF_LD_IND instructions
*/
struct sk_buff;
unsigned long long load_byte(void *skb,
unsigned long long off) asm("llvm.bpf.load.byte");
unsigned long long load_half(void *skb,
unsigned long long off) asm("llvm.bpf.load.half");
unsigned long long load_word(void *skb,
unsigned long long off) asm("llvm.bpf.load.word");
/* a helper structure used by eBPF C program
* to describe map attributes to elf_bpf loader
*/
struct bpf_map_def {
unsigned int type;
unsigned int key_size;
unsigned int value_size;
unsigned int max_entries;
};
static int (*bpf_skb_store_bytes)(void *ctx, unsigned long long off, void *from,
unsigned long long len, unsigned long long flags) =
(void *) BPF_FUNC_skb_store_bytes;
static int (*bpf_l3_csum_replace)(void *ctx, unsigned long long off, unsigned long long from,
unsigned long long to, unsigned long long flags) =
(void *) BPF_FUNC_l3_csum_replace;
static int (*bpf_l4_csum_replace)(void *ctx, unsigned long long off, unsigned long long from,
unsigned long long to, unsigned long long flags) =
(void *) BPF_FUNC_l4_csum_replace;
#endif
// Generated by llvm2cpp - DO NOT MODIFY!
#include <algorithm>
#include <map>
#include <string>
#include <llvm/ADT/STLExtras.h>
#include <llvm/ExecutionEngine/MCJIT.h>
#include <llvm/ExecutionEngine/SectionMemoryManager.h>
#include <llvm/IRReader/IRReader.h>
#include <llvm/IR/IRPrintingPasses.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Verifier.h>
#include <llvm/Object/ObjectFile.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Transforms/IPO.h>
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
#include "exception.h"
#include "parser.h"
#include "type_check.h"
#include "codegen_llvm.h"
#include "bpf_program.h"
namespace ebpf {
using std::get;
using std::make_tuple;
using std::map;
using std::move;
using std::string;
using std::tuple;
using std::unique_ptr;
using namespace llvm;
// Snooping class to remember the sections as the JIT creates them
class MyMemoryManager : public SectionMemoryManager {
public:
explicit MyMemoryManager(map<string, tuple<uint8_t *, uintptr_t>> *sections)
: sections_(sections) {
}
virtual ~MyMemoryManager() {}
uint8_t *allocateCodeSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID,
StringRef SectionName) override {
uint8_t *Addr = SectionMemoryManager::allocateCodeSection(Size, Alignment, SectionID, SectionName);
//printf("allocateCodeSection: %s Addr %p Size %ld Alignment %d SectionID %d\n",
// SectionName.str().c_str(), (void *)Addr, Size, Alignment, SectionID);
(*sections_)[SectionName.str()] = make_tuple(Addr, Size);
return Addr;
}
uint8_t *allocateDataSection(uintptr_t Size, unsigned Alignment,
unsigned SectionID, StringRef SectionName,
bool isReadOnly) override {
uint8_t *Addr = SectionMemoryManager::allocateDataSection(Size, Alignment, SectionID, SectionName, isReadOnly);
//printf("allocateDataSection: %s Addr %p Size %ld Alignment %d SectionID %d RO %d\n",
// SectionName.str().c_str(), (void *)Addr, Size, Alignment, SectionID, isReadOnly);
(*sections_)[SectionName.str()] = make_tuple(Addr, Size);
return Addr;
}
map<string, tuple<uint8_t *, uintptr_t>> *sections_;
};
BPFProgram::BPFProgram(unsigned flags)
: flags_(flags) {
LLVMInitializeBPFTarget();
LLVMInitializeBPFTargetMC();
LLVMInitializeBPFTargetInfo();
LLVMInitializeBPFAsmPrinter();
LLVMLinkInMCJIT(); /* call empty function to force linking of MCJIT */
}
BPFProgram::~BPFProgram() {
engine_.reset();
LLVMShutdown();
}
int BPFProgram::parse() {
int rc;
proto_parser_ = make_unique<ebpf::cc::Parser>(proto_filename_);
rc = proto_parser_->parse();
if (rc) return rc;
parser_ = make_unique<ebpf::cc::Parser>(filename_);
rc = parser_->parse();
if (rc) return rc;
//ebpf::cc::Printer printer(stderr);
//printer.visit(parser_->root_node_);
ebpf::cc::TypeCheck type_check(parser_->scopes_.get(), proto_parser_->scopes_.get(), parser_->pragmas_);
auto ret = type_check.visit(parser_->root_node_);
if (get<0>(ret) != 0 || get<1>(ret).size()) {
fprintf(stderr, "Type error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str());
exit(1);
}
codegen_ = ebpf::make_unique<ebpf::cc::CodegenLLVM>(mod_, parser_->scopes_.get(),
proto_parser_->scopes_.get(),
/*use_pre_header*/false,
parser_->pragma("name"));
ret = codegen_->visit(parser_->root_node_);
if (get<0>(ret) != 0 || get<1>(ret).size()) {
fprintf(stderr, "Codegen error @line=%d: %s\n", get<0>(ret), get<1>(ret).c_str());
return get<0>(ret);
}
return 0;
}
string BPFProgram::load_helper() const {
// generated from bitops.cc -> bitops.bc -> hexdump -> bitops.h
#include "cc/bitops.h"
return string((const char *)bitops_bc, bitops_bc_len);
}
// Load in a pre-built list of functions into the initial Module object, then
// build an ExecutionEngine.
int BPFProgram::init_engine() {
SMDiagnostic diag;
string helper = load_helper();
MemoryBufferRef helper_mem(helper, "helper");
unique_ptr<Module> mod = parseIR(helper_mem, diag, getGlobalContext());
if (!mod) {
diag.print("bitops", errs());
exit(1);
}
mod_ = mod.get();
mod_->setDataLayout("e-m:e-i64:64-f80:128-n8:16:32:64-S128");
mod_->setTargetTriple("bpf");
for (auto fn = mod_->getFunctionList().begin(); fn != mod_->getFunctionList().end(); ++fn)
fn->addFnAttr(Attribute::AlwaysInline);
string err;
engine_ = unique_ptr<ExecutionEngine>(EngineBuilder(move(mod))
.setErrorStr(&err)
.setMCJITMemoryManager(make_unique<MyMemoryManager>(&sections_))
.setMArch("bpf")
.create());
if (!engine_) {
fprintf(stderr, "Could not create ExecutionEngine: %s\n", err.c_str());
return -1;
}
return 0;
}
void BPFProgram::dump_ir() {
legacy::PassManager PM;
PM.add(createPrintModulePass(outs()));
PM.run(*mod_);
}
int BPFProgram::finalize() {
if (verifyModule(*mod_, &errs())) {
if (flags_ & 1)
dump_ir();
return -1;
}
legacy::PassManager PM;
PassManagerBuilder PMB;
PMB.OptLevel = 3;
PM.add(createFunctionInliningPass());
PM.add(createAlwaysInlinerPass());
PMB.populateModulePassManager(PM);
if (flags_ & 1)
PM.add(createPrintModulePass(outs()));
PM.run(*mod_);
engine_->finalizeObject();
return 0;
}
uint8_t * BPFProgram::start(const string &name) const {
auto section = sections_.find(name);
if (section == sections_.end())
return nullptr;
return get<0>(section->second);
}
size_t BPFProgram::size(const string &name) const {
auto section = sections_.find(name);
if (section == sections_.end())
return 0;
return get<1>(section->second);
}
char * BPFProgram::license() const {
auto section = sections_.find("license");
if (section == sections_.end())
return nullptr;
return (char *)get<0>(section->second);
}
int BPFProgram::table_fd(const string &name) const {
return codegen_->get_table_fd(name);
}
int BPFProgram::load(const string &filename, const string &proto_filename) {
if (!sections_.empty()) {
fprintf(stderr, "Program already initialized\n");
return -1;
}
filename_ = filename;
proto_filename_ = proto_filename;
if (int rc = init_engine())
return rc;
if (int rc = parse())
return rc;
if (int rc = finalize())
return rc;
return 0;
}
} // namespace ebpf
/*
* ====================================================================
* Copyright (c) 2015, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* ====================================================================
*/
#pragma once
#include <stdint.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace llvm {
class ExecutionEngine;
class Module;
}
namespace ebpf {
namespace cc {
class CodegenLLVM;
class Parser;
}
class BPFProgram {
private:
int init_engine();
int parse();
int finalize();
void dump_ir();
std::string load_helper() const;
public:
BPFProgram(unsigned flags);
~BPFProgram();
int load(const std::string &filename, const std::string &proto_filename);
uint8_t * start(const std::string &name) const;
size_t size(const std::string &name) const;
int table_fd(const std::string &name) const;
char * license() const;
private:
unsigned flags_; // 0x1 for printing
std::string filename_;
std::string proto_filename_;
std::unique_ptr<llvm::ExecutionEngine> engine_;
llvm::Module *mod_;
std::unique_ptr<ebpf::cc::Parser> parser_;
std::unique_ptr<ebpf::cc::Parser> proto_parser_;
std::unique_ptr<ebpf::cc::CodegenLLVM> codegen_;
std::map<std::string, std::tuple<uint8_t *, uintptr_t>> sections_;
};
} // namespace ebpf
This diff is collapsed.
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#pragma once
#include <stdio.h>
#include <vector>
#include <string>
#include <set>
#include "cc/node.h"
#include "cc/scope.h"
namespace ebpf {
namespace cc {
using std::vector;
using std::string;
using std::set;
class CodegenC : public Visitor {
public:
CodegenC(FILE* out, Scopes::Ptr scopes, Scopes::Ptr proto_scopes, bool use_pre_header)
: out_(out), indent_(0), tmp_reg_index_(0), scopes_(scopes),
proto_scopes_(proto_scopes), use_pre_header_(use_pre_header) {}
#define VISIT(type, func) virtual void visit_##func(type* n);
EXPAND_NODES(VISIT)
#undef VISIT
virtual int visit(Node* n);
void emit_table_lookup(MethodCallExprNode* n);
void emit_table_update(MethodCallExprNode* n);
void emit_table_delete(MethodCallExprNode* n);
void emit_channel_push(MethodCallExprNode* n);
void emit_channel_push_generic(MethodCallExprNode* n);
void emit_log(MethodCallExprNode* n);
void emit_packet_forward(MethodCallExprNode* n);
void emit_packet_replicate(MethodCallExprNode* n);
void emit_packet_clone_forward(MethodCallExprNode* n);
void emit_packet_forward_self(MethodCallExprNode* n);
void emit_packet_drop(MethodCallExprNode* n);
void emit_packet_broadcast(MethodCallExprNode* n);
void emit_packet_multicast(MethodCallExprNode* n);
void emit_packet_push_header(MethodCallExprNode* n);
void emit_packet_pop_header(MethodCallExprNode* n);
void emit_packet_push_vlan(MethodCallExprNode* n);
void emit_packet_pop_vlan(MethodCallExprNode* n);
void emit_packet_rewrite_field(MethodCallExprNode* n);
void emit_atomic_add(MethodCallExprNode* n);
void emit_cksum(MethodCallExprNode* n);
void emit_incr_cksum_u16(MethodCallExprNode* n);
void emit_incr_cksum_u32(MethodCallExprNode* n);
void emit_lb_hash(MethodCallExprNode* n);
void emit_sizeof(MethodCallExprNode* n);
void emit_get_usec_time(MethodCallExprNode* n);
void emit_forward_to_vnf(MethodCallExprNode* n);
void emit_forward_to_group(MethodCallExprNode* n);
void print_parser();
void print_timer();
void print_header();
void print_footer();
private:
void indent();
template <typename... Args> void emitln(const char *fmt, Args&&... params);
template <typename... Args> void lnemit(const char *fmt, Args&&... params);
template <typename... Args> void emit(const char *fmt, Args&&... params);
void emitln(const char *s);
void lnemit(const char *s);
void emit(const char *s);
void emit_comment(Node* n);
FILE* out_;
int indent_;
int tmp_reg_index_;
Scopes::Ptr scopes_;
Scopes::Ptr proto_scopes_;
bool use_pre_header_;
vector<vector<string> > free_instructions_;
vector<string> table_inits_;
map<string, string> proto_rewrites_;
};
} // namespace cc
} // namespace ebpf
This diff is collapsed.
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#pragma once
#include <stdio.h>
#include <vector>
#include <string>
#include <set>
#include "cc/node.h"
#include "cc/scope.h"
namespace llvm {
class AllocaInst;
class BasicBlock;
class BranchInst;
class Constant;
class Instruction;
class IRBuilderBase;
class LLVMContext;
class Module;
class StructType;
class SwitchInst;
}
namespace ebpf {
namespace cc {
class BlockStack;
class SwitchStack;
using std::vector;
using std::string;
using std::set;
class CodegenLLVM : public Visitor {
friend class BlockStack;
friend class SwitchStack;
public:
CodegenLLVM(llvm::Module *mod, Scopes *scopes, Scopes *proto_scopes,
bool use_pre_header, const std::string &section);
virtual ~CodegenLLVM();
#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n);
EXPAND_NODES(VISIT)
#undef VISIT
virtual STATUS_RETURN visit(Node* n);
int get_table_fd(const std::string &name) const;
private:
STATUS_RETURN emit_short_circuit_and(BinopExprNode* n);
STATUS_RETURN emit_short_circuit_or(BinopExprNode* n);
STATUS_RETURN emit_table_lookup(MethodCallExprNode* n);
STATUS_RETURN emit_table_update(MethodCallExprNode* n);
STATUS_RETURN emit_table_delete(MethodCallExprNode* n);
STATUS_RETURN emit_channel_push(MethodCallExprNode* n);
STATUS_RETURN emit_channel_push_generic(MethodCallExprNode* n);
STATUS_RETURN emit_log(MethodCallExprNode* n);
STATUS_RETURN emit_packet_forward(MethodCallExprNode* n);
STATUS_RETURN emit_packet_replicate(MethodCallExprNode* n);
STATUS_RETURN emit_packet_clone_forward(MethodCallExprNode* n);
STATUS_RETURN emit_packet_forward_self(MethodCallExprNode* n);
STATUS_RETURN emit_packet_drop(MethodCallExprNode* n);
STATUS_RETURN emit_packet_broadcast(MethodCallExprNode* n);
STATUS_RETURN emit_packet_multicast(MethodCallExprNode* n);
STATUS_RETURN emit_packet_push_header(MethodCallExprNode* n);
STATUS_RETURN emit_packet_pop_header(MethodCallExprNode* n);
STATUS_RETURN emit_packet_push_vlan(MethodCallExprNode* n);
STATUS_RETURN emit_packet_pop_vlan(MethodCallExprNode* n);
STATUS_RETURN emit_packet_rewrite_field(MethodCallExprNode* n);
STATUS_RETURN emit_atomic_add(MethodCallExprNode* n);
STATUS_RETURN emit_cksum(MethodCallExprNode* n);
STATUS_RETURN emit_incr_cksum(MethodCallExprNode* n, size_t sz = 0);
STATUS_RETURN emit_lb_hash(MethodCallExprNode* n);
STATUS_RETURN emit_sizeof(MethodCallExprNode* n);
STATUS_RETURN emit_get_usec_time(MethodCallExprNode* n);
STATUS_RETURN emit_forward_to_vnf(MethodCallExprNode* n);
STATUS_RETURN emit_forward_to_group(MethodCallExprNode* n);
STATUS_RETURN print_parser();
STATUS_RETURN print_timer();
STATUS_RETURN print_header();
void indent();
llvm::LLVMContext & ctx() const;
llvm::Constant * const_int(uint64_t val, unsigned bits = 64, bool is_signed = false);
llvm::Value * pop_expr();
llvm::BasicBlock * resolve_label(const string &label);
StatusTuple lookup_var(Node *n, const std::string &name, Scopes::VarScope *scope,
VariableDeclStmtNode **decl, llvm::Value **mem) const;
template <typename... Args> void emitln(const char *fmt, Args&&... params);
template <typename... Args> void lnemit(const char *fmt, Args&&... params);
template <typename... Args> void emit(const char *fmt, Args&&... params);
void emitln(const char *s);
void lnemit(const char *s);
void emit(const char *s);
void emit_comment(Node* n);
FILE* out_;
llvm::Module* mod_;
llvm::IRBuilderBase *b_;
int indent_;
int tmp_reg_index_;
Scopes *scopes_;
Scopes *proto_scopes_;
bool use_pre_header_;
std::string section_;
vector<vector<string> > free_instructions_;
vector<string> table_inits_;
map<string, string> proto_rewrites_;
map<TableDeclStmtNode *, llvm::GlobalVariable *> tables_;
map<TableDeclStmtNode *, int> table_fds_;
map<VariableDeclStmtNode *, llvm::Value *> vars_;
map<StructDeclStmtNode *, llvm::StructType *> structs_;
map<string, llvm::BasicBlock *> labels_;
llvm::BasicBlock *entry_bb_;
llvm::SwitchInst *cur_switch_;
llvm::Value *expr_;
llvm::AllocaInst *retval_;
};
} // namespace cc
} // namespace ebpf
/*
* ====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* ====================================================================
*/
#pragma once
#include <exception>
#include <string>
#include <tuple>
#include <cstring>
#include <cerrno>
#include <cstdlib>
#undef NDEBUG
namespace ebpf {
class Exception : public std::exception {
public:
virtual ~Exception() throw() {}
};
class StringException : public Exception {
public:
StringException() : errstr_("unknown") {}
virtual ~StringException() throw() {}
explicit StringException(const std::string& s) : errstr_(s) {}
explicit StringException(const char* s) : errstr_(s) {}
template <typename... Args>
StringException(const char* s, Args... args) {
char x[1024];
snprintf(x, sizeof(x), s, args...);
errstr_.assign(x);
}
virtual const char* what() const throw() {
return errstr_.c_str();
}
protected:
std::string errstr_;
};
class ErrnoException : public StringException {
public:
ErrnoException() : StringException(strerror(errno)) {}
explicit ErrnoException(const std::string& s) : StringException(s + ": " + strerror(errno)) {}
explicit ErrnoException(const std::string& s, int err) : StringException(s + ": " + strerror(err)) {}
};
class SystemException : public StringException {
public:
explicit SystemException(int status) {
if (status == -1) {
errstr_.assign("command not found");
} else {
errstr_.assign("command exited with ");
errstr_ += std::to_string(WEXITSTATUS(status));
}
}
SystemException(int status, const std::string& s) {
if (status == -1) {
errstr_.assign("command not found");
} else {
errstr_.assign("command exited with ");
errstr_ += std::to_string(WEXITSTATUS(status));
}
errstr_ += "; " + s + ": " + strerror(errno);
}
};
class CompilerException : public StringException {
public:
explicit CompilerException(const std::string& s) : StringException(s) {}
template <typename... Args>
CompilerException(const char* s, Args... args) : StringException(s, args...) {}
};
class WatermarkException : public Exception {
public:
WatermarkException() {}
virtual const char* what() const throw() {
return "Reached High Watermark";
}
};
class TerminateException : public Exception {
public:
TerminateException() {}
virtual const char* what() const throw() {
return "Terminated";
}
};
class StatusException : public Exception {
public:
explicit StatusException(int st, const std::string &msg) : st_(st), msg_(msg) {}
virtual const char* what() const throw() {
return msg_.c_str();
}
int status() const { return st_; }
const std::string & message() { return msg_; }
protected:
int st_;
std::string msg_;
};
template <typename... Args>
std::tuple<int, std::string> mkstatus(int ret, const char *fmt, Args... args) {
char buf[1024];
snprintf(buf, sizeof(buf), fmt, args...);
return std::make_tuple(ret, std::string(buf));
}
static inline std::tuple<int, std::string> mkstatus(int ret, const char *msg) {
return std::make_tuple(ret, std::string(msg));
}
static inline std::tuple<int, std::string> mkstatus(int ret) {
return std::make_tuple(ret, std::string());
}
#define TRYT(CMD) \
do { \
int __status = (CMD); \
if (__status != 0) { \
throw StatusException(__status); \
} \
} while (0)
#define TRY2T(CMD) \
do { \
std::tuple<int, std::string> __stp = (CMD); \
if (std::get<0>(__stp) != 0) { \
throw StatusException(std::get<0>(__stp)); \
} \
} while (0)
#define TRY(CMD) \
do { \
int __status = (CMD); \
if (__status != 0) { \
return __status; \
} \
} while (0)
#define TRY2(CMD) \
do { \
std::tuple<int, std::string> __stp = (CMD); \
if (std::get<0>(__stp) != 0) { \
return __stp; \
} \
} while (0)
} // namespace ebpf
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#pragma once
#ifndef yyFlexLexerOnce
#undef yyFlexLexer
#define yyFlexLexer ebpfccFlexLexer
#include <FlexLexer.h>
#endif
#undef YY_DECL
#define YY_DECL int ebpf::cc::Lexer::yylex()
#include <iostream> // NOLINT
#include <list>
#include "cc/parser.yy.hh"
namespace ebpf {
namespace cc {
typedef BisonParser::token::yytokentype Tok;
class Lexer : public yyFlexLexer {
public:
explicit Lexer(std::istream* in)
: yyFlexLexer(in), prev_tok_(Tok::TSEMI), lines_({""}), yylval_(NULL), yylloc_(NULL) {
if (!in || !*in)
fprintf(stderr, "Unable to open input stream\n");
}
int yylex(BisonParser::semantic_type *lval, BisonParser::location_type *lloc) {
yylval_ = lval;
yylloc_ = lloc;
return yylex();
}
std::string text(const BisonParser::location_type& loc) const {
return text(loc.begin, loc.end);
}
std::string text(const position& begin, const position& end) const {
std::string result;
for (size_t i = begin.line; i <= end.line; ++i) {
if (i == begin.line && i == end.line) {
result += lines_.at(i - 1).substr(begin.column - 1, end.column - begin.column);
} else if (i == begin.line && i < end.line) {
result += lines_.at(i - 1).substr(begin.column - 1);
} else if (i > begin.line && i == end.line) {
result += lines_.at(i - 1).substr(0, end.column);
} else if (i > begin.line && i == end.line) {
result += lines_.at(i - 1);
}
}
return result;
}
private:
// true if a semicolon should be replaced here
bool next_line() {
lines_.push_back("");
yylloc_->lines();
yylloc_->step();
switch (prev_tok_) {
case Tok::TIDENTIFIER:
case Tok::TINTEGER:
case Tok::THEXINTEGER:
case Tok::TRBRACE:
case Tok::TRPAREN:
case Tok::TRBRACK:
case Tok::TTRUE:
case Tok::TFALSE:
return true;
default:
break;
}
return false;
}
Tok save(Tok tok, bool ignore_text = false) {
if (!ignore_text) {
save_text();
}
switch (tok) {
case Tok::TIDENTIFIER:
case Tok::TINTEGER:
case Tok::THEXINTEGER:
yylval_->string = new std::string(yytext, yyleng);
break;
default:
yylval_->token = tok;
}
prev_tok_ = tok;
return tok;
}
/*
std::string * alloc_string(const char *c, size_t len) {
strings_.push_back(std::unique_ptr<std::string>(new std::string(c, len)));
return strings_.back().get();
}
std::string * alloc_string(const std::string &s) {
strings_.push_back(std::unique_ptr<std::string>(new std::string(s)));
return strings_.back().get();
}
*/
void save_text() {
lines_.back().append(yytext, yyleng);
yylloc_->columns(yyleng);
}
int yylex();
Tok prev_tok_;
std::vector<std::string> lines_;
//std::list<std::unique_ptr<std::string>> strings_;
BisonParser::semantic_type *yylval_;
BisonParser::location_type *yylloc_;
};
} // namespace cc
} // namespace ebpf
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
%{
#include "cc/lexer.h"
%}
%option yylineno nodefault yyclass="Lexer" noyywrap c++ prefix="ebpfcc"
%option never-interactive
%{
#include <string>
#include "cc/parser.yy.hh"
std::string tmp_str_cc;
%}
%x STRING_
%%
\' {BEGIN STRING_;}
<STRING_>\' { BEGIN 0;
yylval_->string = new std::string(tmp_str_cc);
tmp_str_cc = "";
return Tok::TSTRING;
}
<STRING_>. {tmp_str_cc += *yytext; }
<STRING_>\n {tmp_str_cc += "\n"; }
[ \t]+ { save_text(); }
\n { if (next_line()) { return save(Tok::TSEMI, true); } }
"//".*\n { if (next_line()) { return save(Tok::TSEMI, true); } }
^"#" return save(Tok::TPRAGMA);
"=" return save(Tok::TEQUAL);
"==" return save(Tok::TCEQ);
"!=" return save(Tok::TCNE);
"<" return save(Tok::TCLT);
"<=" return save(Tok::TCLE);
">" return save(Tok::TCGT);
">=" return save(Tok::TCGE);
"(" return save(Tok::TLPAREN);
")" return save(Tok::TRPAREN);
"{" return save(Tok::TLBRACE);
"}" return save(Tok::TRBRACE);
"[" return save(Tok::TLBRACK);
"]" return save(Tok::TRBRACK);
"." return save(Tok::TDOT);
"," return save(Tok::TCOMMA);
"+" return save(Tok::TPLUS);
"-" return save(Tok::TMINUS);
"*" return save(Tok::TMUL);
"/" return save(Tok::TDIV);
"%" return save(Tok::TMOD);
"^" return save(Tok::TXOR);
"$" return save(Tok::TDOLLAR);
"!" return save(Tok::TNOT);
"~" return save(Tok::TCMPL);
":" return save(Tok::TCOLON);
"::" return save(Tok::TSCOPE);
";" return save(Tok::TSEMI);
"&&" return save(Tok::TAND);
"||" return save(Tok::TOR);
"&" return save(Tok::TLAND);
"|" return save(Tok::TLOR);
"@" return save(Tok::TAT);
"const" return save(Tok::TCONST);
"struct" return save(Tok::TSTRUCT);
"var" return save(Tok::TVAR);
"state" return save(Tok::TSTATE);
"timer" return save(Tok::TTIMER);
"goto" return save(Tok::TGOTO);
"continue" return save(Tok::TCONTINUE);
"next" return save(Tok::TNEXT);
"on_match" return save(Tok::TMATCH);
"on_miss" return save(Tok::TMISS);
"on_failure" return save(Tok::TFAILURE);
"on_valid" return save(Tok::TVALID);
"true" return save(Tok::TTRUE);
"false" return save(Tok::TFALSE);
"if" return save(Tok::TIF);
"else" return save(Tok::TELSE);
"switch" return save(Tok::TSWITCH);
"case" return save(Tok::TCASE);
"return" return save(Tok::TRETURN);
[a-zA-Z][a-zA-Z0-9_]* return save(Tok::TIDENTIFIER);
[0-9]+ return save(Tok::TINTEGER);
0x[0-9a-fA-F]+ return save(Tok::THEXINTEGER);
. printf("Unknown token\n"); yyterminate();
%%
/* eBPF mini library */
#include <stdlib.h>
#include <stdio.h>
#include <linux/unistd.h>
#include <unistd.h>
#include <string.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/bpf.h>
#include <errno.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <linux/if_packet.h>
#include <linux/pkt_sched.h>
#include <arpa/inet.h>
#include <libmnl/libmnl.h>
#include "libbpf.h"
static __u64 ptr_to_u64(void *ptr)
{
return (__u64) (unsigned long) ptr;
}
int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, int max_entries)
{
union bpf_attr attr = {
.map_type = map_type,
.key_size = key_size,
.value_size = value_size,
.max_entries = max_entries
};
return syscall(__NR_bpf, BPF_MAP_CREATE, &attr, sizeof(attr));
}
int bpf_update_elem(int fd, void *key, void *value, unsigned long long flags)
{
union bpf_attr attr = {
.map_fd = fd,
.key = ptr_to_u64(key),
.value = ptr_to_u64(value),
.flags = flags,
};
return syscall(__NR_bpf, BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr));
}
int bpf_lookup_elem(int fd, void *key, void *value)
{
union bpf_attr attr = {
.map_fd = fd,
.key = ptr_to_u64(key),
.value = ptr_to_u64(value),
};
return syscall(__NR_bpf, BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr));
}
int bpf_delete_elem(int fd, void *key)
{
union bpf_attr attr = {
.map_fd = fd,
.key = ptr_to_u64(key),
};
return syscall(__NR_bpf, BPF_MAP_DELETE_ELEM, &attr, sizeof(attr));
}
int bpf_get_next_key(int fd, void *key, void *next_key)
{
union bpf_attr attr = {
.map_fd = fd,
.key = ptr_to_u64(key),
.next_key = ptr_to_u64(next_key),
};
return syscall(__NR_bpf, BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr));
}
#define ROUND_UP(x, n) (((x) + (n) - 1u) & ~((n) - 1u))
char bpf_log_buf[LOG_BUF_SIZE];
int bpf_prog_load(enum bpf_prog_type prog_type,
const struct bpf_insn *insns, int prog_len,
const char *license)
{
union bpf_attr attr = {
.prog_type = prog_type,
.insns = ptr_to_u64((void *) insns),
.insn_cnt = prog_len / sizeof(struct bpf_insn),
.license = ptr_to_u64((void *) license),
.log_buf = ptr_to_u64(bpf_log_buf),
.log_size = LOG_BUF_SIZE,
.log_level = 1,
};
bpf_log_buf[0] = 0;
return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr));
}
int bpf_open_raw_sock(const char *name)
{
struct sockaddr_ll sll;
int sock;
sock = socket(PF_PACKET, SOCK_RAW | SOCK_NONBLOCK | SOCK_CLOEXEC, htons(ETH_P_ALL));
if (sock < 0) {
printf("cannot create raw socket\n");
return -1;
}
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_ifindex = if_nametoindex(name);
sll.sll_protocol = htons(ETH_P_ALL);
if (bind(sock, (struct sockaddr *)&sll, sizeof(sll)) < 0) {
printf("bind to %s: %s\n", name, strerror(errno));
close(sock);
return -1;
}
return sock;
}
int bpf_attach_socket(int sock, int prog) {
return setsockopt(sock, SOL_SOCKET, 50 /*SO_ATTACH_BPF*/, &prog, sizeof(prog));
}
static int cb(const struct nlmsghdr *nlh, void *data) {
struct nlmsgerr *err;
if (nlh->nlmsg_type == NLMSG_ERROR) {
err = mnl_nlmsg_get_payload(nlh);
if (err->error != 0) {
fprintf(stderr, "bpf tc netlink command failed (%d): %s\n",
err->error, strerror(-1 * err->error));
return -1;
} else {
return 0;
}
} else {
return -1;
}
}
int bpf_attach_filter(int progfd, const char *prog_name, uint32_t ifindex, uint8_t prio, uint32_t classid)
{
int rc = -1;
char buf[1024];
struct nlmsghdr *nlh;
struct tcmsg *tc;
struct nlattr *opt;
struct mnl_socket *nl = NULL;
unsigned int portid;
ssize_t bytes;
int seq = getpid();
memset(buf, 0, sizeof(buf));
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = RTM_NEWTFILTER;
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK | NLM_F_EXCL;
nlh->nlmsg_seq = seq;
tc = mnl_nlmsg_put_extra_header(nlh, sizeof(*tc));
tc->tcm_family = AF_UNSPEC;
tc->tcm_info = TC_H_MAKE(prio << 16, htons(ETH_P_ALL));
tc->tcm_ifindex = ifindex;
mnl_attr_put_strz(nlh, TCA_KIND, "bpf");
opt = mnl_attr_nest_start(nlh, TCA_OPTIONS);
mnl_attr_put_u32(nlh, 6 /*TCA_BPF_FD*/, progfd);
mnl_attr_put_strz(nlh, 7 /*TCP_BPF_NAME*/, prog_name);
mnl_attr_put_u32(nlh, 3 /*TCA_BPF_CLASSID*/, classid);
mnl_attr_nest_end(nlh, opt);
nl = mnl_socket_open(NETLINK_ROUTE);
if (!nl || (uintptr_t)nl == (uintptr_t)-1) {
perror("mnl_socket_open");
goto cleanup;
}
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
goto cleanup;
}
portid = mnl_socket_get_portid(nl);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
perror("mnl_socket_sendto");
goto cleanup;
}
if ((bytes = mnl_socket_recvfrom(nl, buf, sizeof(buf))) < 0) {
perror("mnl_socket_recvfrom");
goto cleanup;
}
if (mnl_cb_run(buf, bytes, seq, portid, cb, NULL) < 0) {
perror("mnl_cb_run");
goto cleanup;
}
rc = 0;
cleanup:
if (nl && (uintptr_t)nl != (uintptr_t)-1)
if (mnl_socket_close(nl) < 0)
perror("mnl_socket_close");
return rc;
}
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#include <stdio.h>
#include <vector>
#include <string>
#include "cc/node.h"
namespace ebpf {
namespace cc {
#define ACCEPT(type, func) \
STATUS_RETURN type::accept(Visitor* v) { return v->visit_##func(this); }
EXPAND_NODES(ACCEPT)
#undef ACCEPT
VariableDeclStmtNode* StructDeclStmtNode::field(const string& name) const {
for (auto it = stmts_.begin(); it != stmts_.end(); ++it) {
if ((*it)->id_->name_ == name) {
return it->get();
}
}
return NULL;
}
int StructDeclStmtNode::indexof(const string& name) const {
int i = 0;
for (auto it = stmts_.begin(); it != stmts_.end(); ++it, ++i) {
if ((*it)->id_->name_ == name) {
return i;
}
}
return -1;
}
} // namespace cc
} // namespace ebpf
This diff is collapsed.
This diff is collapsed.
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#pragma once
#include <fstream> // NOLINT
#include "cc/node.h"
#include "cc/lexer.h"
#include "cc/scope.h"
namespace ebpf {
namespace cc {
using std::string;
using std::pair;
class Parser {
public:
explicit Parser(const string& infile)
: root_node_(NULL), scopes_(new Scopes), in_(infile), lexer(&in_), parser(lexer, *this) {
// parser.set_debug_level(1);
}
~Parser() { delete root_node_; }
int parse() {
return parser.parse();
}
VariableDeclStmtNode* variable_add(VariableDeclStmtNode* decl);
VariableDeclStmtNode* variable_add(VariableDeclStmtNode* decl, ExprNode* init_expr);
StructVariableDeclStmtNode* variable_add(StructVariableDeclStmtNode* decl, ExprNodeList* args, bool is_kv);
StmtNode* state_add(Scopes::StateScope* scope, IdentExprNode* id1, BlockStmtNode* body);
StmtNode* timer_add(Scopes::StateScope* scope, BlockStmtNode* body);
StmtNode* state_add(Scopes::StateScope* scope, IdentExprNode* id1, IdentExprNode* id2, BlockStmtNode* body);
StmtNode* table_add(IdentExprNode* type, IdentExprNodeList* templates, IdentExprNode* id, string* size);
StmtNode* struct_add(IdentExprNode* type, FormalList* formals);
StmtNode* result_add(int token, IdentExprNode* id, FormalList* formals, BlockStmtNode* body);
bool variable_exists(VariableDeclStmtNode* decl, bool search_local = true);
bool table_exists(TableDeclStmtNode* decl, bool search_local = true);
void add_pragma(const std::string& pr, const std::string& v) { pragmas_[pr] = v; }
void set_loc(Node *n, const BisonParser::location_type &loc) const;
std::string pragma(const std::string &name) const;
Node* root_node_;
Scopes::Ptr scopes_;
std::map<std::string, std::string> pragmas_;
private:
std::ifstream in_;
Lexer lexer;
BisonParser parser;
};
} // namespace cc
} // namespace ebpf
This diff is collapsed.
This diff is collapsed.
/*
* ====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* ====================================================================
*/
#pragma once
#include <stdio.h>
#include "cc/node.h"
namespace ebpf {
namespace cc {
class Printer : public Visitor {
public:
explicit Printer(FILE* out) : out_(out), indent_(0) {}
void print_indent();
#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n);
EXPAND_NODES(VISIT)
#undef VISIT
private:
FILE* out_;
int indent_;
};
} // namespace cc
} // namespace ebpf
This diff is collapsed.
This diff is collapsed.
/*
* =====================================================================
* Copyright (c) 2012, PLUMgrid, http://plumgrid.com
*
* This source is subject to the PLUMgrid License.
* All rights reserved.
*
* THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF
* ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
* PARTICULAR PURPOSE.
*
* PLUMgrid confidential information, delete if you are not the
* intended recipient.
*
* =====================================================================
*/
#pragma once
#include <vector>
#include <string>
#include "cc/node.h"
#include "cc/scope.h"
namespace ebpf {
namespace cc {
class TypeCheck : public Visitor {
public:
TypeCheck(Scopes *scopes, Scopes *proto_scopes, const std::map<std::string, std::string>& pragmas)
: scopes_(scopes), proto_scopes_(proto_scopes), pragmas_(pragmas) {}
virtual STATUS_RETURN visit(Node* n);
STATUS_RETURN expect_method_arg(MethodCallExprNode* n, size_t num, size_t num_def_args);
STATUS_RETURN check_lookup_method(MethodCallExprNode* n);
STATUS_RETURN check_update_method(MethodCallExprNode* n);
STATUS_RETURN check_delete_method(MethodCallExprNode* n);
#define VISIT(type, func) virtual STATUS_RETURN visit_##func(type* n);
EXPAND_NODES(VISIT)
#undef VISIT
private:
Scopes *scopes_;
Scopes *proto_scopes_;
vector<string> errors_;
const std::map<std::string, std::string> &pragmas_;
};
} // namespace cc
} // namespace ebpf
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env python
import sys
from src.bpf import BPF
prog = BPF(sys.argv[1], sys.argv[2], sys.argv[3],
prog_type=int(sys.argv[4]), debug=int(sys.argv[5]))
This diff is collapsed.
@1.0.0
#packed 'true'
struct ethernet {
dst:48
src:48
type:16
}
state ethernet {
switch $ethernet.type {
case * {
goto EOP
}
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment