Skip to content

Commit

Permalink
Convert to using pyroute2 for tc
Browse files Browse the repository at this point in the history
* Remove libbpf.c netlink
* Requires pyroute2 from source
 git clone https://github.com/svinota/pyroute2.git;
          cd pyroute2; sudo make install

Update: Remove references to mnl

Signed-off-by: Brenden Blanco <[email protected]>
  • Loading branch information
Brenden Blanco committed Jun 5, 2015
1 parent 7249bea commit bb7200c
Show file tree
Hide file tree
Showing 15 changed files with 80 additions and 128 deletions.
1 change: 0 additions & 1 deletion scripts/bpf_demo.ks.erb
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ bc
kexec-tools
cmake
clang
libmnl-devel
libstdc++-static
python-netaddr
%end
Expand Down
12 changes: 0 additions & 12 deletions src/bpf.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,6 @@
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, ct.c_uint]
Expand Down Expand Up @@ -163,16 +161,6 @@ def attach_raw_socket(fn, dev):
% (dev, errstr))
fn.sock = sock

@staticmethod
def attach_classifier(fn, ifname, prio=10, classid=1):
with open("/sys/class/net/%s/ifindex" % ifname) as f:
ifindex = int(f.read())
if not isinstance(fn, BPF.Function):
raise Exception("arg 1 must be of type BPF.Function")
res = lib.bpf_attach_filter(fn.fd, fn.name.encode("ascii"), ifindex, prio, classid)
if res < 0:
raise Exception("Failed to filter with BPF")

@staticmethod
def attach_kprobe(fn, event, pid=-1, cpu=0, group_fd=-1):
if not isinstance(fn, BPF.Function):
Expand Down
2 changes: 1 addition & 1 deletion src/cc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ set(clang_libs ${libclangFrontend} ${libclangSerialization} ${libclangDriver} ${
${libclangAST} ${libclangLex} ${libclangBasic})

# Link against LLVM libraries
target_link_libraries(bpfprog ${clang_libs} ${llvm_libs} LLVMBPFCodeGen mnl)
target_link_libraries(bpfprog ${clang_libs} ${llvm_libs} LLVMBPFCodeGen)
2 changes: 1 addition & 1 deletion src/cc/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ bool BTypeVisitor::VisitImplicitCastExpr(ImplicitCastExpr *E) {
uint64_t ofs = C.getFieldOffset(F);
uint64_t sz = F->isBitField() ? F->getBitWidthValue(C) : C.getTypeSize(F->getType());
string base = rewriter_.getRewrittenText(SourceRange(Base->getLocStart(), Base->getLocEnd()));
string text = "bpf_dext_pkt(skb, (u64)" + base + "+" + to_string(ofs >> 3)
string text = "bpf_dext_pkt(skb, _parse_base + (u64)" + base + "+" + to_string(ofs >> 3)
+ ", " + to_string(ofs & 0x7) + ", " + to_string(sz) + ")";
rewriter_.ReplaceText(SourceRange(E->getLocStart(), E->getLocEnd()), text);
}
Expand Down
3 changes: 3 additions & 0 deletions src/cc/bpf_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
#define __BPF_HELPERS_H

#include <linux/bpf.h>
#include <linux/filter.h>
#include <linux/if_packet.h>
#include <linux/version.h>

/* helper macro to place programs, maps, license in
Expand Down Expand Up @@ -30,6 +32,7 @@ struct _name##_table_t _name
BPF_EXPORT(name) int _##name(struct __sk_buff *skb)
#define BEGIN(next) \
u64 _parse_cursor = 0; \
u64 _parse_base = skb->pkt_type == PACKET_OUTGOING ? 0 : BPF_LL_OFF; \
goto next

#define PROTO(name) \
Expand Down
8 changes: 4 additions & 4 deletions src/cc/codegen_llvm.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1024,7 +1024,7 @@ StatusTuple CodegenLLVM::visit_integer_variable_decl_stmt_node(IntegerVariableDe

StatusTuple CodegenLLVM::visit_struct_decl_stmt_node(StructDeclStmtNode *n) {
++indent_;
StructType *struct_type = StructType::create(ctx(), "struct." + n->id_->name_);
StructType *struct_type = StructType::create(ctx(), "_struct." + n->id_->name_);
vector<Type *> fields;
for (auto it = n->stmts_.begin(); it != n->stmts_.end(); ++it)
fields.push_back(B.getIntNTy((*it)->bit_width_));
Expand Down Expand Up @@ -1089,9 +1089,9 @@ StatusTuple CodegenLLVM::visit_table_decl_stmt_node(TableDeclStmtNode *n) {
else
return mkstatus_(n, "Table type %s not implemented", n->type_id()->name_.c_str());

StructType *decl_struct = mod_->getTypeByName("struct." + n->id_->name_);
StructType *decl_struct = mod_->getTypeByName("_struct." + n->id_->name_);
if (!decl_struct)
decl_struct = StructType::create(ctx(), "struct." + n->id_->name_);
decl_struct = StructType::create(ctx(), "_struct." + n->id_->name_);
if (decl_struct->isOpaque())
decl_struct->setBody(std::vector<Type *>({Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx()),
Type::getInt32Ty(ctx()), Type::getInt32Ty(ctx())}),
Expand Down Expand Up @@ -1156,7 +1156,7 @@ StatusTuple CodegenLLVM::visit_func_decl_stmt_node(FuncDeclStmtNode *n) {
StructType *stype;
//TRY2(lookup_struct_type(formal, &stype));
auto var = (StructVariableDeclStmtNode *)formal;
stype = mod_->getTypeByName("struct." + var->struct_id_->name_);
stype = mod_->getTypeByName("_struct." + var->struct_id_->name_);
if (!stype) return mkstatus_(n, "could not find type %s", var->struct_id_->c_str());
formals.push_back(PointerType::getUnqual(stype));
} else {
Expand Down
85 changes: 2 additions & 83 deletions src/cc/libbpf.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <libmnl/libmnl.h>
#include <linux/bpf.h>
#include <linux/if_packet.h>
#include <linux/pkt_cls.h>
Expand All @@ -12,9 +11,11 @@
#include <linux/version.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>

#include "libbpf.h"

Expand Down Expand Up @@ -135,88 +136,6 @@ 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, TCA_BPF_FD, progfd);
mnl_attr_put_strz(nlh, TCA_BPF_NAME, prog_name);
mnl_attr_put_u32(nlh, 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;
}

static int bpf_attach_tracing_event(int progfd, const char *event_path, pid_t pid, int cpu, int group_fd)
{
int efd = -1, rc = -1, pfd = -1;
Expand Down
12 changes: 12 additions & 0 deletions src/cc/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ struct dot1q_t {
u16 type;
} __attribute__((packed));

struct arp_t {
u16 htype;
u16 ptype;
u8 hlen;
u8 plen;
u16 oper;
u64 sha:48;
u64 spa:32;
u64 tha:48;
u32 tpa;
} __attribute__((packed));

struct ip_t {
u8 ver:4; // byte 0
u8 hlen:4;
Expand Down
2 changes: 0 additions & 2 deletions src/libbpf.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
const struct bpf_insn *insns, int insn_len,
const char *license, unsigned kern_version);
int bpf_attach_socket(int sockfd, int progfd);
int bpf_attach_filter(int progfd, const char *prog_name, uint32_t ifindex,
uint8_t prio, uint32_t classid);

/* create RAW socket and bind to interface 'name' */
int bpf_open_raw_sock(const char *name);
Expand Down
4 changes: 2 additions & 2 deletions tests/cc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ add_test(NAME py_test_stat1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_stat1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.b proto.b)
add_test(NAME py_test_stat1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_stat1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_stat1.py test_stat1.c)
add_test(NAME py_test_xlate1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_xlate1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.b proto.b)
#add_test(NAME py_test_xlate1_b WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
# COMMAND ${TEST_WRAPPER} py_xlate1_b namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.b proto.b)
add_test(NAME py_test_xlate1_c WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND ${TEST_WRAPPER} py_xlate1_c namespace ${CMAKE_CURRENT_SOURCE_DIR}/test_xlate1.py test_xlate1.c)
add_test(NAME py_test_call1 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
Expand Down
8 changes: 4 additions & 4 deletions tests/cc/test_call1.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ int parse_ether(struct __sk_buff *skb) {
case 0x0806: jump.call(skb, S_ARP);
}
jump.call(skb, S_EOP);
return 0;
return 1;
}

BPF_EXPORT(parse_arp)
Expand All @@ -37,7 +37,7 @@ int parse_arp(struct __sk_buff *skb) {
if (leaf) (*leaf)++;

jump.call(skb, S_EOP);
return 0;
return 1;
}

BPF_EXPORT(parse_ip)
Expand All @@ -50,13 +50,13 @@ int parse_ip(struct __sk_buff *skb) {
if (leaf) (*leaf)++;

jump.call(skb, S_EOP);
return 0;
return 1;
}

BPF_EXPORT(eop)
int eop(struct __sk_buff *skb) {
int key = S_EOP;
u64 *leaf = stats.lookup(&key);
if (leaf) (*leaf)++;
return 0;
return 1;
}
7 changes: 6 additions & 1 deletion tests/cc/test_call1.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from ctypes import c_ushort, c_int, c_ulonglong
from netaddr import IPAddress
from bpf import BPF
from pyroute2 import IPRoute
from socket import socket, AF_INET, SOCK_DGRAM
import sys
from time import sleep
Expand All @@ -22,7 +23,10 @@ def setUp(self):
arp_fn = b.load_func("parse_arp", BPF.SCHED_CLS)
ip_fn = b.load_func("parse_ip", BPF.SCHED_CLS)
eop_fn = b.load_func("eop", BPF.SCHED_CLS)
BPF.attach_classifier(ether_fn, "eth0")
ip = IPRoute()
ifindex = ip.link_lookup(ifname="eth0")[0]
ip.tc("add-filter", "bpf", ifindex, ":1", fd=ether_fn.fd,
name=ether_fn.name, parent="0:", action="ok", classid=1)
self.jump = b.get_table("jump", c_int, c_int)
self.jump.update(c_int(S_ARP), c_int(arp_fn.fd))
self.jump.update(c_int(S_IP), c_int(ip_fn.fd))
Expand All @@ -32,6 +36,7 @@ def setUp(self):
def test_jumps(self):
udp = socket(AF_INET, SOCK_DGRAM)
udp.sendto(b"a" * 10, ("172.16.1.1", 5000))
udp.close()
self.assertGreater(self.stats.lookup(c_int(S_IP)).value, 0)
self.assertGreater(self.stats.lookup(c_int(S_ARP)).value, 0)
self.assertGreater(self.stats.lookup(c_int(S_EOP)).value, 1)
Expand Down
23 changes: 19 additions & 4 deletions tests/cc/test_xlate1.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,47 @@ struct IPKey {
struct IPLeaf {
u32 xdip;
u32 xsip;
u64 xlated_pkts;
u64 ip_xlated_pkts;
u64 arp_xlated_pkts;
};
BPF_TABLE("hash", struct IPKey, struct IPLeaf, xlate, 1024);

BPF_EXPORT(on_packet)
int on_packet(struct __sk_buff *skb) {
BEGIN(ethernet);

u32 orig_dip = 0;
u32 orig_sip = 0;
struct IPLeaf *xleaf;

BEGIN(ethernet);
PROTO(ethernet) {
switch (ethernet->type) {
case 0x0800: goto ip;
case 0x0806: goto arp;
case 0x8100: goto dot1q;
}
goto EOP;
}

PROTO(dot1q) {
switch (dot1q->type) {
case 0x0806: goto arp;
case 0x0800: goto ip;
}
goto EOP;
}
PROTO(arp) {
orig_dip = arp->tpa;
orig_sip = arp->spa;
struct IPKey key = {.dip=orig_dip, .sip=orig_sip};
xleaf = xlate.lookup(&key);
if (xleaf) {
arp->tpa = xleaf->xdip;
arp->spa = xleaf->xsip;
lock_xadd(&xleaf->arp_xlated_pkts, 1);
}
goto EOP;
}

PROTO(ip) {
orig_dip = ip->dst;
Expand All @@ -44,7 +59,7 @@ int on_packet(struct __sk_buff *skb) {
incr_cksum_l3(&ip->hchecksum, orig_dip, xleaf->xdip);
ip->src = xleaf->xsip;
incr_cksum_l3(&ip->hchecksum, orig_sip, xleaf->xsip);
lock_xadd(&xleaf->xlated_pkts, 1);
lock_xadd(&xleaf->ip_xlated_pkts, 1);
}
switch (ip->nextp) {
case 6: goto tcp;
Expand All @@ -70,5 +85,5 @@ int on_packet(struct __sk_buff *skb) {
}

EOP:
return 0;
return 1;
}
Loading

0 comments on commit bb7200c

Please sign in to comment.