| #!/usr/bin/env bcc-lua | |
| --[[ | |
| Copyright 2016 Marek Vavrusa <mvavrusa@cloudflare.com> | |
| 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://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. | |
| ]] | |
| -- Simple parsing example of TCP/HTTP that counts frequency of types of requests | |
| -- and shows more complicated pattern matching constructions and slices. | |
| -- Rewrite of a BCC example: | |
| -- https://github.com/iovisor/bcc/blob/master/examples/networking/http_filter/http-parse-simple.c | |
| local ffi = require("ffi") | |
| local bpf = require("bpf") | |
| local S = require("syscall") | |
| -- Shared part of the program | |
| local map = bpf.map('hash', 64) | |
| -- Kernel-space part of the program | |
| local prog = bpf.socket('lo', function (skb) | |
| -- Only ingress so we don't count twice on loopback | |
| if skb.ingress_ifindex == 0 then return end | |
| local data = pkt.ip.tcp.data -- Get TCP protocol dissector | |
| -- Continue only if we have 7 bytes of TCP data | |
| if data + 7 > skb.len then return end | |
| -- Fetch 4 bytes of TCP data and compare | |
| local h = data(0, 4) | |
| if h == 'HTTP' or h == 'GET ' or | |
| h == 'POST' or h == 'PUT ' or | |
| h == 'HEAD' or h == 'DELE' then | |
| -- If hash key doesn't exist, create it | |
| -- otherwise increment counter | |
| local v = map[h] | |
| if not v then map[h] = 1 | |
| else xadd(map[h], 1) | |
| end | |
| end | |
| end) | |
| -- User-space part of the program | |
| for _ = 1, 10 do | |
| local strkey = ffi.new('uint32_t [1]') | |
| local s = '' | |
| for k,v in map.pairs,map,0 do | |
| strkey[0] = bpf.ntoh(k) | |
| s = s..string.format('%s %d ', ffi.string(strkey, 4):match '^%s*(.-)%s*$', tonumber(v)) | |
| end | |
| if #s > 0 then print(s..'messages') end | |
| S.sleep(1) | |
| end |