diff --git a/src/program/lisp/lisp.lua b/src/program/lisp/lisp.lua deleted file mode 100644 index 75d2ab83c9..0000000000 --- a/src/program/lisp/lisp.lua +++ /dev/null @@ -1,41 +0,0 @@ -module(..., package.seeall) - ---LISP controller mock-up program for testing. - -local ffi = require("ffi") -local S = require("syscall") - -CONTROL_SOCK = "/var/tmp/ctrl.socket" -CONTROL_DATA = [[ -[5] 08:00:27:7f:05:37 fd80:1::1,fd80:1::2 -[7] 4a:86:5c:50:33:5a fd80:2::1 -[2] 00:16:3e:01:01:02 fd80:3::1 -]] - -local function sleep(s) - ffi.C.usleep(s * 10^6) -end - -function run (args) - - local sock = assert(S.socket("unix", "stream, nonblock")) - local sa = S.t.sockaddr_un(CONTROL_SOCK) - ::retry:: - local ok, err = sock:connect(sa) - if not ok then - if err.CONNREFUSED or err.AGAIN then - sleep(1) - print'retrying...' - goto retry - end - assert(nil, err) - end - print'connected' - - while assert(S.select({writefds = {sock}}, 0)).count == 1 do - print'sending...' - assert(S.write(sock, CONTROL_DATA, #CONTROL_DATA)) - sleep(1) - end - -end diff --git a/src/program/lisper/README.inc b/src/program/lisper/README.inc deleted file mode 100644 index 2dc24b4b3d..0000000000 --- a/src/program/lisper/README.inc +++ /dev/null @@ -1,18 +0,0 @@ -Usage: lisper --control SOCK --punt-interface IF --network-device IPv6 - - -c SOCK, --control SOCK Control socket - -p IF, --punt-interface IF Punt interface - -n IF, --network-device IF Network device - -i IPv6, --local-ip IPv6 Local IP address - -m MAC, --local-mac MAC Local MAC address - -N IPv6, --next-hop IPv6 Next hop address - -h, --help Print usage information - -Snabb Switch extension to support interfacing with an external control plane -for establishing L2TPv3 tunnels. The extension is suitable for use with -an external LISP (RFC 6830) controller. - -Examples: - - snabb lisper --control ctrl.socket --punt-interface veth0 \ - --network-device 01:00.0 --local-ip 10.0.0.1 --local-mac deadbeefdeadbeef diff --git a/src/program/lisper/README.inc b/src/program/lisper/README.inc new file mode 120000 index 0000000000..100b93820a --- /dev/null +++ b/src/program/lisper/README.inc @@ -0,0 +1 @@ +README \ No newline at end of file diff --git a/src/program/lisper/dev-env/l2tp.app1 b/src/program/lisper/dev-env/l2tp.app1 new file mode 100755 index 0000000000..319423cb17 --- /dev/null +++ b/src/program/lisper/dev-env/l2tp.app1 @@ -0,0 +1,6 @@ +ip netns exec app1 ./l2tp.lua t0 e0 \ + aa:aa:aa:aa:aa:01 \ + aa:aa:aa:aa:aa:02 \ + fd80:0001:0000:0000:0000:0000:0000:0002 \ + fd80:0002:0000:0000:0000:0000:0000:0002 \ + 00001234 00004321 diff --git a/src/program/lisper/dev-env/l2tp.app2 b/src/program/lisper/dev-env/l2tp.app2 new file mode 100755 index 0000000000..8605534a34 --- /dev/null +++ b/src/program/lisper/dev-env/l2tp.app2 @@ -0,0 +1,6 @@ +ip netns exec app2 ./l2tp.lua t0 e0 \ + aa:aa:aa:aa:aa:02 \ + aa:aa:aa:aa:aa:01 \ + fd80:0002:0000:0000:0000:0000:0000:0002 \ + fd80:0001:0000:0000:0000:0000:0000:0002 \ + 00004321 00001234 diff --git a/src/program/lisper/dev-env/l2tp.lua b/src/program/lisper/dev-env/l2tp.lua new file mode 100644 index 0000000000..c11db893fd --- /dev/null +++ b/src/program/lisper/dev-env/l2tp.lua @@ -0,0 +1,166 @@ +#!/usr/bin/env luajit + +--L2TP IP-over-IPv6 tunnelling program for testing. + +local ffi = require'ffi' +local S = require'syscall' +local C = ffi.C +local htons = require'syscall.helpers'.htons + +local DEBUG = true + +local function assert(v, ...) + if v then return v, ... end + error(tostring((...)), 2) +end + +local function hex(s) + return (s:gsub('(.)(.?)', function(c1, c2) + return c2 and + string.format('%02x%02x ', c1:byte(), c2:byte()) or + string.format('%02x ', c1:byte()) + end)) +end + +local digits = {} +for i=0,9 do digits[string.char(('0'):byte()+i)] = i end +for i=0,5 do digits[string.char(('a'):byte()+i)] = 10+i end +for i=0,5 do digits[string.char(('A'):byte()+i)] = 10+i end +local function parsehex(s) + return (s:gsub('[%s%:%.]*(%x)(%x)[%s%:%.]*', function(hi, lo) + local hi = digits[hi] + local lo = digits[lo] + return string.char(lo + hi * 16) + end)) +end + +local function open_tap(name) + local fd = assert(S.open('/dev/net/tun', 'rdwr, nonblock')) + local ifr = S.t.ifreq{flags = 'tap, no_pi', name = name} + assert(fd:ioctl('tunsetiff', ifr)) + return fd +end + +local function open_raw(name) + local fd = assert(S.socket('packet', 'raw, nonblock', htons(S.c.ETH_P.all))) + local ifr = S.t.ifreq{name = name} + assert(S.ioctl(fd, 'siocgifindex', ifr)) + assert(S.bind(fd, S.t.sockaddr_ll{ + ifindex = ifr.ivalue, + protocol = 'all'})) + return fd +end + +local function can_read(...) + return assert(S.select({readfds = {...}}, 0)).count == 1 +end + +local function can_write(...) + return assert(S.select({writefds = {...}}, 0)).count == 1 +end + +local mtu = 1500 +local buf = ffi.new('uint8_t[?]', mtu) +local function read(fd) + local len = assert(S.read(fd, buf, mtu)) + return ffi.string(buf, len) +end + +local function write(fd, s, len) + assert(S.write(fd, s, len or #s)) +end + +local function close(fd) + S.close(fd) +end + +local tapname, ethname, smac, dmac, sip, dip, sid, did = ... +if not (tapname and ethname and smac and dmac and sip and dip and sid and did) then + print('Usage: '..arg[0]..' TAP ETH SMAC DMAC SIP DIP SID DID') + os.exit(1) +end +smac = parsehex(smac) +dmac = parsehex(dmac) +sip = parsehex(sip) +dip = parsehex(dip) +sid = parsehex(sid) +did = parsehex(did) + +local tap = open_tap(tapname) +local raw = open_raw(ethname) + +print('tap ', tapname) +print('raw ', ethname) +print('smac ', hex(smac)) +print('dmac ', hex(dmac)) +print('sip ', hex(sip)) +print('dip ', hex(dip)) +print('sid ', hex(sid)) +print('did ', hex(did)) + +local function decap_l2tp(s) + local dmac = s:sub(1, 6) + local smac = s:sub(1+6, 1+6+6-1) + local sip = s:sub(23, 23+16-1) + local dip = s:sub(23+16, 23+16+16-1) + local sid = s:sub(55, 55+4-1) + local payload = s:sub(63) + return smac, dmac, sip, dip, sid, payload +end + +local function encap_l2tp(smac, dmac, sip, dip, did, payload) + local l2tp = did..'\0\0\0\0' + local len = #payload + #l2tp + local len = string.char(bit.rshift(len, 8)) .. string.char(bit.band(len, 0xff)) + local ipv6_proto = '\115' --l2tp + local maxhops = '\64' + local ipv6 = '\x60\0\0\0'..len..ipv6_proto..maxhops..sip..dip + local eth_proto = '\x86\xdd' --ipv6 + local eth = dmac..smac..eth_proto + return eth..ipv6..l2tp..payload +end + +while true do + if can_read(tap, raw) then + if can_read(raw) then + local s = read(raw) + local smac1, dmac1, sip1, dip1, did1, payload = decap_l2tp(s) + local accept = + smac1 == dmac + and dmac1 == smac + and dip1 == sip + and sip1 == dip + and did1 == sid + if DEBUG then + print('read ', accept and 'accepted' or 'rejected') + print(' smac ', hex(smac1)) + print(' dmac ', hex(dmac1)) + print(' sip ', hex(sip1)) + print(' dip ', hex(dip1)) + print(' did ', hex(did1)) + print(' # ', #payload) + end + if accept then + write(tap, payload) + end + end + if can_read(tap) then + local payload = read(tap) + local s = encap_l2tp(smac, dmac, sip, dip, did, payload) + if DEBUG then + print('write') + print(' smac ', hex(smac)) + print(' dmac ', hex(dmac)) + print(' sip ', hex(sip)) + print(' dip ', hex(dip)) + print(' did ', hex(did)) + print(' # ', #payload) + print(hex(s)) + end + write(raw, s) + end + end +end + +tap:close() +raw:close() diff --git a/src/program/lisper/dev-env/lisp.lua b/src/program/lisper/dev-env/lisp.lua new file mode 100755 index 0000000000..c4d1a9e50d --- /dev/null +++ b/src/program/lisper/dev-env/lisp.lua @@ -0,0 +1,35 @@ +#!/usr/bin/env luajit + +--LISP controller mock-up program for testing. + +local ffi = require("ffi") +local S = require("syscall") + +CONTROL_SOCK = "/var/tmp/ctrl.socket" +CONTROL_DATA = [[ +[5] 08:00:27:7f:05:37 fd80:1::1,fd80:1::2 +[7] 4a:86:5c:50:33:5a fd80:2::1 +[2] 00:16:3e:01:01:02 fd80:3::1 +]] + +local sock = assert(S.socket("unix", "stream, nonblock")) +local sa = S.t.sockaddr_un(CONTROL_SOCK) + +::retry:: +local ok, err = sock:connect(sa) +if not ok then + if err.CONNREFUSED or err.AGAIN then + S.sleep(1) + print'retrying...' + goto retry + end + assert(nil, err) +end +print'connected' + +while assert(S.select({writefds = {sock}}, 0)).count == 1 do + print'sending...' + assert(S.write(sock, CONTROL_DATA, #CONTROL_DATA)) + S.sleep(1) +end + diff --git a/src/program/lisper/dev-env/net-bringup b/src/program/lisper/dev-env/net-bringup new file mode 100755 index 0000000000..2ed5cc9ef0 --- /dev/null +++ b/src/program/lisper/dev-env/net-bringup @@ -0,0 +1,79 @@ +#!/bin/bash + +# This creates a virtual network of 3 machines in 3 different subnets +# connected to a router. Besides that, app1 and app2 machines create +# two static l2tp tunnels which connect _to the same endpoint_ in the +# lisp machine where lisper responds back. + +bringup() { +ip netns add r2 +ip netns add app1 +ip netns add app2 +ip netns add lisp + +ip link add netns app1 e0 address aa:aa:aa:aa:aa:01 type veth peer name e1 netns r2 +ip link add netns app2 e0 address aa:aa:aa:aa:aa:02 type veth peer name e2 netns r2 +ip link add netns lisp e0 address aa:aa:aa:aa:aa:04 type veth peer name e4 netns r2 + +ip netns exec r2 ip addr add fd80:1::1/56 dev e1 +ip netns exec r2 ip addr add fd80:2::1/56 dev e2 +ip netns exec r2 ip addr add fd80:4::1/56 dev e4 + +ip netns exec app1 ip addr add fd80:1::2/56 dev e0 +ip netns exec app2 ip addr add fd80:2::2/56 dev e0 +ip netns exec lisp ip addr add fd80:4::2/56 dev e0 + +ip netns exec app1 ip -6 route add default via fd80:1::1 +ip netns exec app2 ip -6 route add default via fd80:2::1 +ip netns exec lisp ip -6 route add default via fd80:4::1 + +ip netns exec app1 ip link set e0 up +ip netns exec app2 ip link set e0 up +ip netns exec lisp ip link set e0 up + +ip netns exec r2 sysctl -wq net.ipv6.conf.all.forwarding=1 + +ip netns exec r2 ip link set e1 up +ip netns exec r2 ip link set e2 up +ip netns exec r2 ip link set e4 up + +if false; then +# NOTE: l2tp ip-over-ipv6 encapsulation doesn't work with namespaces. +# Hence we're using our own little Lua script which does the same thing in userspace. +modprobe l2tp_ip6 +modprobe l2tp_eth +modprobe l2tp_core +modprobe l2tp_netlink +ip netns exec app1 ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 encap ip local fd80:1::2 remote fd80:4::2 +ip netns exec app2 ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 encap ip local fd80:2::2 remote fd80:4::2 +ip netns exec app1 ip l2tp add session name t0 tunnel_id 1 session_id 4660 peer_session_id 17185 +ip netns exec app2 ip l2tp add session name t0 tunnel_id 1 session_id 4660 peer_session_id 17185 +ip netns exec app1 ip link set t0 up +ip netns exec app2 ip link set t0 up +ip netns exec lisp ip l2tp add tunnel tunnel_id 1 peer_tunnel_id 1 encap ip local fd80:4::2 remote fd80:1::2 +ip netns exec lisp ip l2tp add session name t0 tunnel_id 1 session_id 17185 peer_session_id 4660 +ip netns exec lisp ip link set t0 up +else +./l2tp.app1 & +echo $! > l2tp.app1.pid +./l2tp.app2 & +echo $! > l2tp.app2.pid +sleep 0.2 +ip netns exec app1 ifconfig t0 10.0.0.1/24 up +ip netns exec app2 ifconfig t0 10.0.0.2/24 up +fi +} + + +teardown() { +kill -9 `cat l2tp.app1.pid`; rm l2tp.app1.pid +kill -9 `cat l2tp.app2.pid`; rm l2tp.app2.pid +ip netns del r2 +ip netns del app1 +ip netns del app2 +ip netns del lisp +} + + +action=$1; [ "$action" ] || action=bringup +$action diff --git a/src/program/lisper/dev-env/net-teardown b/src/program/lisper/dev-env/net-teardown new file mode 100755 index 0000000000..547f93750a --- /dev/null +++ b/src/program/lisper/dev-env/net-teardown @@ -0,0 +1 @@ +./net-bringup teardown diff --git a/src/program/lisper/dev-env/syscall b/src/program/lisper/dev-env/syscall new file mode 120000 index 0000000000..f70e116022 --- /dev/null +++ b/src/program/lisper/dev-env/syscall @@ -0,0 +1 @@ +../../../syscall \ No newline at end of file diff --git a/src/program/lisper/dev-env/syscall.lua b/src/program/lisper/dev-env/syscall.lua new file mode 120000 index 0000000000..0845186512 --- /dev/null +++ b/src/program/lisper/dev-env/syscall.lua @@ -0,0 +1 @@ +../../../syscall.lua \ No newline at end of file