Skip to content

Commit

Permalink
Merge branch 'master' into patch-1
Browse files Browse the repository at this point in the history
  • Loading branch information
Qasim Sarfraz committed May 13, 2016
2 parents f712dca + a67ef8a commit b263926
Show file tree
Hide file tree
Showing 10 changed files with 455 additions and 3 deletions.
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples)

add_subdirectory(networking)
add_subdirectory(tracing)
add_subdirectory(lua)
4 changes: 4 additions & 0 deletions examples/lua/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
file(GLOB C_FILES *.c)
file(GLOB LUA_FILES *.lua)
install(FILES ${C_FILES} DESTINATION share/bcc/examples/lua)
install(PROGRAMS ${LUA_FILES} DESTINATION share/bcc/examples/lua)
2 changes: 2 additions & 0 deletions examples/networking/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ install(PROGRAMS ${EXAMPLE_PROGRAMS} DESTINATION share/bcc/examples/networking)
add_subdirectory(distributed_bridge)
add_subdirectory(neighbor_sharing)
add_subdirectory(vlan_learning)
add_subdirectory(tunnel_monitor)
add_subdirectory(http_filter)
105 changes: 105 additions & 0 deletions examples/networking/dns_matching/dns_matching.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* dns_matching.c Drop DNS packets requesting DNS name contained in hash map
* For Linux, uses BCC, eBPF. See .py file.
*
* Copyright (c) 2016 Rudi Floren.
* 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.
*
* 11-May-2016 Rudi Floren Created this.
*/

#include <uapi/linux/bpf.h>
#include <uapi/linux/if_ether.h>
#include <uapi/linux/if_packet.h>
#include <uapi/linux/ip.h>
#include <uapi/linux/in.h>
#include <uapi/linux/udp.h>
#include <bcc/proto.h>

#define ETH_LEN 14

struct dns_hdr_t
{
uint16_t id;
uint16_t flags;
uint16_t qdcount;
uint16_t ancount;
uint16_t nscount;
uint16_t arcount;
} BPF_PACKET_HEADER;


struct dns_query_flags_t
{
uint16_t qtype;
uint16_t qclass;
} BPF_PACKET_HEADER;

struct dns_char_t
{
char c;
} BPF_PACKET_HEADER;

struct Key {
unsigned char p[32];
};

struct Leaf {
// Not really needed in this example
unsigned char p[4];
};

BPF_TABLE("hash", struct Key, struct Leaf, cache, 128);

int dns_matching(struct __sk_buff *skb)
{
u8 *cursor = 0;
struct Key key = {};
// Check of ethernet/IP frame.
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
if(ethernet->type == ETH_P_IP) {

// Check for UDP.
struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
u16 hlen_bytes = ip->hlen << 2;
if(ip->nextp == IPPROTO_UDP) {

// Check for Port 53, DNS packet.
struct udp_t *udp = cursor_advance(cursor, sizeof(*udp));
if(udp->dport == 53){

// Our Cursor + the length of our udp packet - size of the udp header
// - the two 16bit values for QTYPE and QCLASS.
u8 *sentinel = cursor + udp->length - sizeof(*udp) - 4;

struct dns_hdr_t *dns_hdr = cursor_advance(cursor, sizeof(*dns_hdr));

// Do nothing if packet is not a request.
if((dns_hdr->flags >>15) != 0) {
// Exit if this packet is not a request.
return -1;
}

u16 i = 0;
struct dns_char_t *c;
// This unroll worked not in latest BCC version.
for(u8 j = 0; i<255;i++){
if (cursor == sentinel) goto end; c = cursor_advance(cursor, 1); key.p[i++] = c->c;
}
end:
{}

struct Leaf * lookup_leaf = cache.lookup(&key);

// If DNS name is contained in our map, drop packet.
if(lookup_leaf) {
return 0;
}
}
}
}

return -1;
}
57 changes: 57 additions & 0 deletions examples/networking/dns_matching/dns_matching.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/python

from __future__ import print_function
from bcc import BPF
from ctypes import *

import sys
import socket
import os
import struct


def encode_dns(name):
size = 32
if len(name) > 253:
raise Exception("DNS Name too long.")
b = bytearray(size)
i = 0;
elements = name.split(".")
for element in elements:
b[i] = struct.pack("!B", len(element))
i += 1
for j in range(0, len(element)):
b[i] = element[j]
i += 1


return (c_ubyte * size).from_buffer(b)



# initialize BPF - load source code from http-parse-simple.c
bpf = BPF(src_file = "dns_matching.c", debug=0)
# print(bpf.dump_func("dns_test"))

#load eBPF program http_filter of type SOCKET_FILTER into the kernel eBPF vm
#more info about eBPF program types
#http:https://man7.org/linux/man-pages/man2/bpf.2.html
function_dns_matching = bpf.load_func("dns_matching", BPF.SOCKET_FILTER)


#create raw socket, bind it to eth0
#attach bpf program to socket created
BPF.attach_raw_socket(function_dns_matching, "eth1")

# Get the table.
cache = bpf.get_table("cache")

# Create first entry for foo.bar
key = cache.Key()
key.p = encode_dns("foo.bar")

leaf = cache.Leaf()
leaf.p = (c_ubyte * 4).from_buffer(bytearray(4))
cache[key] = leaf

bpf.trace_print()
4 changes: 4 additions & 0 deletions examples/networking/http_filter/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(FILES http-parse-complete.c http-parse-simple.c README.md)
set(PROGRAMS http-parse-complete.py http-parse-simple.py)
install(FILES ${FILES} DESTINATION share/bcc/examples/networking/http_filter)
install(PROGRAMS ${PROGRAMS} DESTINATION share/bcc/examples/networking/http_filter)
4 changes: 4 additions & 0 deletions examples/networking/tunnel_monitor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
set(FILES README.md chord.png monitor.c simulation.py vxlan.jpg)
set(PROGRAMS main.py monitor.py setup.sh traffic.sh)
install(FILES ${FILES} DESTINATION share/bcc/examples/networking/tunnel_monitor)
install(PROGRAMS ${PROGRAMS} DESTINATION share/bcc/examples/networking/tunnel_monitor)
6 changes: 3 additions & 3 deletions src/lua/src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
#include <string.h>
#include <unistd.h>

#include <luajit-2.0/lauxlib.h>
#include <luajit-2.0/lua.h>
#include <luajit-2.0/lualib.h>
#include "lauxlib.h"
#include "lua.h"
#include "lualib.h"

static lua_State *globalL = NULL;
static const char *progname = NULL;
Expand Down
183 changes: 183 additions & 0 deletions tools/biosnoop.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
#!/usr/bin/env bcc-lua
--[[
Copyright 2016 GitHub, Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http:https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--]]

local program = [[
#include <uapi/linux/ptrace.h>
#include <linux/blkdev.h>
struct val_t {
u32 pid;
char name[TASK_COMM_LEN];
};
struct data_t {
u32 pid;
u64 rwflag;
u64 delta;
u64 sector;
u64 len;
u64 ts;
char disk_name[DISK_NAME_LEN];
char name[TASK_COMM_LEN];
};
BPF_HASH(start, struct request *);
BPF_HASH(infobyreq, struct request *, struct val_t);
BPF_PERF_OUTPUT(events);
// cache PID and comm by-req
int trace_pid_start(struct pt_regs *ctx, struct request *req)
{
struct val_t val = {};
if (bpf_get_current_comm(&val.name, sizeof(val.name)) == 0) {
val.pid = bpf_get_current_pid_tgid();
infobyreq.update(&req, &val);
}
return 0;
}
// time block I/O
int trace_req_start(struct pt_regs *ctx, struct request *req)
{
u64 ts;
ts = bpf_ktime_get_ns();
start.update(&req, &ts);
return 0;
}
// output
int trace_req_completion(struct pt_regs *ctx, struct request *req)
{
u64 *tsp, delta;
u32 *pidp = 0;
struct val_t *valp;
struct data_t data ={};
u64 ts;
// fetch timestamp and calculate delta
tsp = start.lookup(&req);
if (tsp == 0) {
// missed tracing issue
return 0;
}
ts = bpf_ktime_get_ns();
data.delta = ts - *tsp;
data.ts = ts / 1000;
valp = infobyreq.lookup(&req);
if (valp == 0) {
data.len = req->__data_len;
strcpy(data.name,"?");
} else {
data.pid = valp->pid;
data.len = req->__data_len;
data.sector = req->__sector;
bpf_probe_read(&data.name, sizeof(data.name), valp->name);
bpf_probe_read(&data.disk_name, sizeof(data.disk_name),
req->rq_disk->disk_name);
}
if (req->cmd_flags & REQ_WRITE) {
data.rwflag=1;
} else {
data.rwflag=0;
}
events.perf_submit(ctx,&data,sizeof(data));
start.delete(&req);
infobyreq.delete(&req);
return 0;
}
]]

local ffi = require("ffi")

return function(BPF, utils)
local bpf = BPF:new{text=program}

bpf:attach_kprobe{event="blk_account_io_start", fn_name="trace_pid_start"}
bpf:attach_kprobe{event="blk_start_request", fn_name="trace_req_start"}
bpf:attach_kprobe{event="blk_mq_start_request", fn_name="trace_req_start"}
bpf:attach_kprobe{event="blk_account_io_completion",
fn_name="trace_req_completion"}

print("%-14s %-14s %-6s %-7s %-2s %-9s %-7s %7s" % {"TIME(s)", "COMM", "PID",
"DISK", "T", "SECTOR", "BYTES", "LAT(ms)"})

local rwflg = ""
local start_ts = 0
local prev_ts = 0
local delta = 0

local function print_event(cpu, event)
local val = -1
local event_pid = event.pid
local event_delta = tonumber(event.delta)
local event_sector = tonumber(event.sector)
local event_len = tonumber(event.len)
local event_ts = tonumber(event.ts)
local event_disk_name = ffi.string(event.disk_name)
local event_name = ffi.string(event.name)

if event.rwflag == 1 then
rwflg = "W"
end

if event.rwflag == 0 then
rwflg = "R"
end

if not event_name:match("%?") then
val = event_sector
end

if start_ts == 0 then
prev_ts = start_ts
end

if start_ts == 1 then
delta = delta + (event_ts - prev_ts)
end

print("%-14.9f %-14.14s %-6s %-7s %-2s %-9s %-7s %7.2f" % {
delta / 1000000, event_name, event_pid, event_disk_name, rwflg, val,
event_len, event_delta / 1000000})

prev_ts = event_ts
start_ts = 1
end

local TASK_COMM_LEN = 16 -- linux/sched.h
local DISK_NAME_LEN = 32 -- linux/genhd.h

bpf:get_table("events"):open_perf_buffer(print_event, [[
struct {
uint32_t pid;
uint64_t rwflag;
uint64_t delta;
uint64_t sector;
uint64_t len;
uint64_t ts;
char disk_name[%d];
char name[%d];
}
]] % {DISK_NAME_LEN, TASK_COMM_LEN})
bpf:kprobe_poll_loop()
end
Loading

0 comments on commit b263926

Please sign in to comment.