Commit 540d45a0 authored by Yonghong Song's avatar Yonghong Song

simply vlan_learning example with newer vlan_push/pop helpers

Signed-off-by: default avatarYonghong Song <yhs@plumgrid.com>
parent c366fcf2
......@@ -5,6 +5,8 @@
struct ifindex_leaf_t {
int out_ifindex;
int vlan_tci; // populated by phys2virt and used by virt2phys
int vlan_proto; // populated by phys2virt and used by virt2phys
u64 tx_pkts;
u64 tx_bytes;
};
......@@ -16,6 +18,9 @@ BPF_TABLE("hash", int, struct ifindex_leaf_t, egress, 4096);
BPF_TABLE("hash", u64, struct ifindex_leaf_t, ingress, 4096);
int handle_phys2virt(struct __sk_buff *skb) {
// only handle vlan packets
if (!skb->vlan_present)
return 1;
u8 *cursor = 0;
ethernet: {
struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
......@@ -31,6 +36,13 @@ int handle_phys2virt(struct __sk_buff *skb) {
// relearn when mac moves ifindex
if (out_leaf->out_ifindex != skb->ifindex)
out_leaf->out_ifindex = skb->ifindex;
// relearn when vlan_tci/vlan_proto changes
if (out_leaf->vlan_tci != skb->vlan_tci)
out_leaf->vlan_tci = skb->vlan_tci;
if (out_leaf->vlan_proto != skb->vlan_proto)
out_leaf->vlan_proto = skb->vlan_proto;
// pop the vlan header and send to the destination
bpf_skb_vlan_pop(skb);
bpf_clone_redirect(skb, leaf->out_ifindex, 0);
}
}
......@@ -46,6 +58,7 @@ int handle_virt2phys(struct __sk_buff *skb) {
if (leaf) {
lock_xadd(&leaf->tx_pkts, 1);
lock_xadd(&leaf->tx_bytes, skb->len);
bpf_skb_vlan_push(skb, leaf->vlan_proto, leaf->vlan_tci);
bpf_clone_redirect(skb, leaf->out_ifindex, 0);
}
}
......
......@@ -14,14 +14,14 @@
# overlapping IP spaces and the traffic will still work.
# | bpf program |
# cli0 --| | |----\ /--|-- worker0 |
# cli1 --| trunk | |----->-handle_p2v(pkt)-> /---|-- worker1 |
# cli2 --|=======|=|----/ /----|-- worker2 |
# ... --| | |---/ <-handle_v2p(pkt)-<-----|-- ... |
# cliN --| | |--/ \----|-- workerM |
# | | ^ ^ |
# phys | vlan veth |
# switch | subinterface |
# cli0 --| | /--|-- worker0 |
# cli1 --| trunk | +->--->-handle_p2v(pkt)-> /---|-- worker1 |
# cli2 --|=======|=+ /----|-- worker2 |
# ... --| | +-<---<-handle_v2p(pkt)-<-----|-- ... |
# cliN --| | \----|-- workerM |
# | | ^ |
# phys | veth |
# switch | |
from bpf import BPF
from builtins import input
......@@ -63,22 +63,12 @@ class VlanSimulation(Simulation):
v.up()
self.ipdb.interfaces.eth0b.up().commit()
# connect the trunk to the bridge
with self.ipdb.create(ifname="br100", kind="bridge") as br100:
br100.add_port(self.ipdb.interfaces.eth0b)
br100.up()
# for each vlan, create a subinterface on the eth...most of these will be
# unused, but still listening and waiting for a client to send traffic on
for i in range(2, 2 + num_vlans):
with self.ipdb.create(ifname="eth0a.%d" % i, kind="vlan",
link=ipdb.interfaces.eth0a, vlan_id=i) as v:
v.up()
v = self.ipdb.interfaces["eth0a.%d" % i]
# add the bpf program for demuxing phys2virt packets
ipr.tc("add", "ingress", v["index"], "ffff:")
ipr.tc("add-filter", "bpf", v["index"], ":1", fd=phys_fn.fd,
name=phys_fn.name, parent="ffff:", action="drop", classid=1)
# eth0a will be hooked to clients with vlan interfaces
# add the bpf program to eth0b for demuxing phys2virt packets
v = self.ipdb.interfaces["eth0b"]
ipr.tc("add", "ingress", v["index"], "ffff:")
ipr.tc("add-filter", "bpf", v["index"], ":1", fd=phys_fn.fd,
name=phys_fn.name, parent="ffff:", action="drop", classid=1)
# allocate vlans randomly
available_vlans = [i for i in range(2, 2 + num_vlans)]
......@@ -93,15 +83,15 @@ class VlanSimulation(Simulation):
# assign this client to the given worker
idx = self.ipdb.interfaces["worker%da" % i]["index"]
mac = int(macaddr.replace(":", ""), 16)
ingress[ingress.Key(mac)] = ingress.Leaf(idx, 0, 0)
ingress[ingress.Key(mac)] = ingress.Leaf(idx, 0, 0, 0, 0)
# test traffic with curl loop
cmd = ["bash", "-c",
"for i in {1..8}; do curl 172.16.1.5 -o /dev/null; sleep 1; done"]
br_ifc = self.ipdb.create(ifname="br100.%d" % i, kind="vlan",
link=br100,
vlan_id=available_vlans.pop(0)).commit()
(out_ifc, in_ifc) = self._create_ns("client%d" % i, in_ifc=br_ifc,
client_ifc = self.ipdb.create(ifname="eth0a.%d" % i, kind="vlan",
link=self.ipdb.interfaces["eth0a"],
vlan_id=available_vlans.pop(0)).commit()
(out_ifc, in_ifc) = self._create_ns("client%d" % i, in_ifc=client_ifc,
ipaddr="172.16.1.100/24",
macaddr=macaddr, cmd=cmd)[1:3]
......@@ -123,6 +113,5 @@ try:
print(" tx pkts = %u, tx bytes = %u" % (v[2], v[3]))
finally:
if "eth0a" in ipdb.interfaces: ipdb.interfaces.eth0a.remove().commit()
if "br100" in ipdb.interfaces: ipdb.interfaces.br100.remove().commit()
if "sim" in locals(): sim.release()
ipdb.release()
......@@ -249,6 +249,15 @@ enum bpf_func_id {
* Return: 0 on success
*/
BPF_FUNC_get_current_comm,
/**
* bpf_get_cgroup_classid(skb) - retrieve a proc's classid
* @skb: pointer to skb
* Return: classid if != 0
*/
BPF_FUNC_get_cgroup_classid,
BPF_FUNC_skb_vlan_push, /* bpf_skb_vlan_push(skb, vlan_proto, vlan_tci) */
BPF_FUNC_skb_vlan_pop, /* bpf_skb_vlan_pop(skb) */
__BPF_FUNC_MAX_ID,
};
......
......@@ -74,6 +74,12 @@ static u64 (*bpf_get_current_uid_gid)(void) =
(void *) BPF_FUNC_get_current_uid_gid;
static int (*bpf_get_current_comm)(void *buf, int buf_size) =
(void *) BPF_FUNC_get_current_comm;
static u64 (*bpf_get_cgroup_classid)(void *ctx) =
(void *) BPF_FUNC_get_cgroup_classid;
static u64 (*bpf_skb_vlan_push)(void *ctx, u16 proto, u16 vlan_tci) =
(void *) BPF_FUNC_skb_vlan_push;
static u64 (*bpf_skb_vlan_pop)(void *ctx) =
(void *) BPF_FUNC_skb_vlan_pop;
static void bpf_tail_call_(u64 map_fd, void *ctx, int index) {
((void (*)(void *, u64, int))BPF_FUNC_tail_call)(ctx, map_fd, index);
}
......
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