1*387f9dfdSAndroid Build Coastguard Worker // Copyright (c) PLUMgrid, Inc.
2*387f9dfdSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License")
3*387f9dfdSAndroid Build Coastguard Worker #include <bcc/proto.h>
4*387f9dfdSAndroid Build Coastguard Worker
5*387f9dfdSAndroid Build Coastguard Worker #define _memcpy __builtin_memcpy
6*387f9dfdSAndroid Build Coastguard Worker
7*387f9dfdSAndroid Build Coastguard Worker // meta data passed between bpf programs
8*387f9dfdSAndroid Build Coastguard Worker typedef struct bpf_metadata {
9*387f9dfdSAndroid Build Coastguard Worker u32 prog_id;
10*387f9dfdSAndroid Build Coastguard Worker u32 rx_port_id;
11*387f9dfdSAndroid Build Coastguard Worker } bpf_metadata_t;
12*387f9dfdSAndroid Build Coastguard Worker
13*387f9dfdSAndroid Build Coastguard Worker typedef struct bpf_dest {
14*387f9dfdSAndroid Build Coastguard Worker u32 prog_id;
15*387f9dfdSAndroid Build Coastguard Worker u32 port_id;
16*387f9dfdSAndroid Build Coastguard Worker } bpf_dest_t;
17*387f9dfdSAndroid Build Coastguard Worker
18*387f9dfdSAndroid Build Coastguard Worker // use u64 to represent eth_addr.
19*387f9dfdSAndroid Build Coastguard Worker // maintain the structure though to indicate the semantics
20*387f9dfdSAndroid Build Coastguard Worker typedef struct eth_addr {
21*387f9dfdSAndroid Build Coastguard Worker u64 addr;
22*387f9dfdSAndroid Build Coastguard Worker } eth_addr_t;
23*387f9dfdSAndroid Build Coastguard Worker
24*387f9dfdSAndroid Build Coastguard Worker // Program table definitions for tail calls
25*387f9dfdSAndroid Build Coastguard Worker BPF_PROG_ARRAY(jump, 16);
26*387f9dfdSAndroid Build Coastguard Worker
27*387f9dfdSAndroid Build Coastguard Worker // physical endpoint manager (pem) tables which connects to boeht bridge 1 and bridge 2
28*387f9dfdSAndroid Build Coastguard Worker // <port_id, bpf_dest>
29*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(pem_dest, bpf_dest_t, 256);
30*387f9dfdSAndroid Build Coastguard Worker // <port_id, ifindex>
31*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(pem_port, u32, 256);
32*387f9dfdSAndroid Build Coastguard Worker // <ifindex, port_id>
33*387f9dfdSAndroid Build Coastguard Worker BPF_HASH(pem_ifindex, u32, u32, 256);
34*387f9dfdSAndroid Build Coastguard Worker // <0, tx2vm_pkts>
35*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(pem_stats, u32, 1);
36*387f9dfdSAndroid Build Coastguard Worker
37*387f9dfdSAndroid Build Coastguard Worker // bridge 1 (br1) tables
38*387f9dfdSAndroid Build Coastguard Worker // <port_id, bpf_dest>
39*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(br1_dest, bpf_dest_t, 256);
40*387f9dfdSAndroid Build Coastguard Worker // <eth_addr, port_id>
41*387f9dfdSAndroid Build Coastguard Worker BPF_HASH(br1_mac, eth_addr_t, u32, 256);
42*387f9dfdSAndroid Build Coastguard Worker // <0, rtr_ifindex>
43*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(br1_rtr, u32, 1);
44*387f9dfdSAndroid Build Coastguard Worker // <mac, ifindex>
45*387f9dfdSAndroid Build Coastguard Worker BPF_HASH(br1_mac_ifindex, eth_addr_t, u32, 1);
46*387f9dfdSAndroid Build Coastguard Worker
47*387f9dfdSAndroid Build Coastguard Worker // bridge 2 (br2) tables
48*387f9dfdSAndroid Build Coastguard Worker // <port_id, bpf_dest>
49*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(br2_dest, bpf_dest_t, 256);
50*387f9dfdSAndroid Build Coastguard Worker // <eth_addr, port_id>
51*387f9dfdSAndroid Build Coastguard Worker BPF_HASH(br2_mac, eth_addr_t, u32, 256);
52*387f9dfdSAndroid Build Coastguard Worker // <0, rtr_ifindex>
53*387f9dfdSAndroid Build Coastguard Worker BPF_ARRAY(br2_rtr, u32, 1);
54*387f9dfdSAndroid Build Coastguard Worker // <mac, ifindex>
55*387f9dfdSAndroid Build Coastguard Worker BPF_HASH(br2_mac_ifindex, eth_addr_t, u32, 1);
56*387f9dfdSAndroid Build Coastguard Worker
pem(struct __sk_buff * skb)57*387f9dfdSAndroid Build Coastguard Worker int pem(struct __sk_buff *skb) {
58*387f9dfdSAndroid Build Coastguard Worker bpf_metadata_t meta = {};
59*387f9dfdSAndroid Build Coastguard Worker u32 ifindex;
60*387f9dfdSAndroid Build Coastguard Worker u32 *tx_port_id_p;
61*387f9dfdSAndroid Build Coastguard Worker u32 tx_port_id;
62*387f9dfdSAndroid Build Coastguard Worker u32 rx_port;
63*387f9dfdSAndroid Build Coastguard Worker u32 *ifindex_p;
64*387f9dfdSAndroid Build Coastguard Worker bpf_dest_t *dest_p;
65*387f9dfdSAndroid Build Coastguard Worker
66*387f9dfdSAndroid Build Coastguard Worker // pem does not look at packet data
67*387f9dfdSAndroid Build Coastguard Worker if (skb->tc_index == 0) {
68*387f9dfdSAndroid Build Coastguard Worker skb->tc_index = 1;
69*387f9dfdSAndroid Build Coastguard Worker skb->cb[0] = skb->cb[1] = 0;
70*387f9dfdSAndroid Build Coastguard Worker meta.prog_id = meta.rx_port_id = 0;
71*387f9dfdSAndroid Build Coastguard Worker } else {
72*387f9dfdSAndroid Build Coastguard Worker meta.prog_id = skb->cb[0];
73*387f9dfdSAndroid Build Coastguard Worker asm volatile("" ::: "memory");
74*387f9dfdSAndroid Build Coastguard Worker meta.rx_port_id = skb->cb[1];
75*387f9dfdSAndroid Build Coastguard Worker }
76*387f9dfdSAndroid Build Coastguard Worker if (!meta.prog_id) {
77*387f9dfdSAndroid Build Coastguard Worker /* from external */
78*387f9dfdSAndroid Build Coastguard Worker ifindex = skb->ingress_ifindex;
79*387f9dfdSAndroid Build Coastguard Worker tx_port_id_p = pem_ifindex.lookup(&ifindex);
80*387f9dfdSAndroid Build Coastguard Worker if (tx_port_id_p) {
81*387f9dfdSAndroid Build Coastguard Worker tx_port_id = *tx_port_id_p;
82*387f9dfdSAndroid Build Coastguard Worker dest_p = pem_dest.lookup(&tx_port_id);
83*387f9dfdSAndroid Build Coastguard Worker if (dest_p) {
84*387f9dfdSAndroid Build Coastguard Worker skb->cb[0] = dest_p->prog_id;
85*387f9dfdSAndroid Build Coastguard Worker skb->cb[1] = dest_p->port_id;
86*387f9dfdSAndroid Build Coastguard Worker jump.call(skb, dest_p->prog_id);
87*387f9dfdSAndroid Build Coastguard Worker }
88*387f9dfdSAndroid Build Coastguard Worker }
89*387f9dfdSAndroid Build Coastguard Worker } else {
90*387f9dfdSAndroid Build Coastguard Worker /* from internal */
91*387f9dfdSAndroid Build Coastguard Worker rx_port = meta.rx_port_id;
92*387f9dfdSAndroid Build Coastguard Worker ifindex_p = pem_port.lookup(&rx_port);
93*387f9dfdSAndroid Build Coastguard Worker if (ifindex_p) {
94*387f9dfdSAndroid Build Coastguard Worker #if 1
95*387f9dfdSAndroid Build Coastguard Worker /* accumulate stats, may hurt performance slightly */
96*387f9dfdSAndroid Build Coastguard Worker u32 index = 0;
97*387f9dfdSAndroid Build Coastguard Worker u32 *value = pem_stats.lookup(&index);
98*387f9dfdSAndroid Build Coastguard Worker if (value)
99*387f9dfdSAndroid Build Coastguard Worker lock_xadd(value, 1);
100*387f9dfdSAndroid Build Coastguard Worker #endif
101*387f9dfdSAndroid Build Coastguard Worker bpf_clone_redirect(skb, *ifindex_p, 0);
102*387f9dfdSAndroid Build Coastguard Worker }
103*387f9dfdSAndroid Build Coastguard Worker }
104*387f9dfdSAndroid Build Coastguard Worker
105*387f9dfdSAndroid Build Coastguard Worker return 1;
106*387f9dfdSAndroid Build Coastguard Worker }
107*387f9dfdSAndroid Build Coastguard Worker
br_common(struct __sk_buff * skb,int which_br)108*387f9dfdSAndroid Build Coastguard Worker static int br_common(struct __sk_buff *skb, int which_br) {
109*387f9dfdSAndroid Build Coastguard Worker u8 *cursor = 0;
110*387f9dfdSAndroid Build Coastguard Worker u16 proto;
111*387f9dfdSAndroid Build Coastguard Worker u16 arpop;
112*387f9dfdSAndroid Build Coastguard Worker eth_addr_t dmac;
113*387f9dfdSAndroid Build Coastguard Worker u8 *mac_p;
114*387f9dfdSAndroid Build Coastguard Worker u32 dip;
115*387f9dfdSAndroid Build Coastguard Worker u32 *tx_port_id_p;
116*387f9dfdSAndroid Build Coastguard Worker u32 tx_port_id;
117*387f9dfdSAndroid Build Coastguard Worker bpf_dest_t *dest_p;
118*387f9dfdSAndroid Build Coastguard Worker u32 index, *rtrif_p;
119*387f9dfdSAndroid Build Coastguard Worker
120*387f9dfdSAndroid Build Coastguard Worker struct ethernet_t *ethernet = cursor_advance(cursor, sizeof(*ethernet));
121*387f9dfdSAndroid Build Coastguard Worker /* handle ethernet packet header */
122*387f9dfdSAndroid Build Coastguard Worker {
123*387f9dfdSAndroid Build Coastguard Worker dmac.addr = ethernet->dst;
124*387f9dfdSAndroid Build Coastguard Worker /* skb->tc_index may be preserved across router namespace if router simply rewrite packet
125*387f9dfdSAndroid Build Coastguard Worker * and send it back.
126*387f9dfdSAndroid Build Coastguard Worker */
127*387f9dfdSAndroid Build Coastguard Worker if (skb->tc_index == 1) {
128*387f9dfdSAndroid Build Coastguard Worker /* packet from pem, send to the router, set tc_index to 2 */
129*387f9dfdSAndroid Build Coastguard Worker skb->tc_index = 2;
130*387f9dfdSAndroid Build Coastguard Worker if (dmac.addr == 0xffffffffffffULL) {
131*387f9dfdSAndroid Build Coastguard Worker index = 0;
132*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
133*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br1_rtr.lookup(&index);
134*387f9dfdSAndroid Build Coastguard Worker else
135*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br2_rtr.lookup(&index);
136*387f9dfdSAndroid Build Coastguard Worker if (rtrif_p)
137*387f9dfdSAndroid Build Coastguard Worker bpf_clone_redirect(skb, *rtrif_p, 0);
138*387f9dfdSAndroid Build Coastguard Worker } else {
139*387f9dfdSAndroid Build Coastguard Worker /* the dmac address should match the router's */
140*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
141*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br1_mac_ifindex.lookup(&dmac);
142*387f9dfdSAndroid Build Coastguard Worker else
143*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br2_mac_ifindex.lookup(&dmac);
144*387f9dfdSAndroid Build Coastguard Worker if (rtrif_p)
145*387f9dfdSAndroid Build Coastguard Worker bpf_clone_redirect(skb, *rtrif_p, 0);
146*387f9dfdSAndroid Build Coastguard Worker }
147*387f9dfdSAndroid Build Coastguard Worker return 1;
148*387f9dfdSAndroid Build Coastguard Worker }
149*387f9dfdSAndroid Build Coastguard Worker
150*387f9dfdSAndroid Build Coastguard Worker /* set the tc_index to 1 so pem knows it is from internal */
151*387f9dfdSAndroid Build Coastguard Worker skb->tc_index = 1;
152*387f9dfdSAndroid Build Coastguard Worker switch (ethernet->type) {
153*387f9dfdSAndroid Build Coastguard Worker case ETH_P_IP: goto ip;
154*387f9dfdSAndroid Build Coastguard Worker case ETH_P_ARP: goto arp;
155*387f9dfdSAndroid Build Coastguard Worker case ETH_P_8021Q: goto dot1q;
156*387f9dfdSAndroid Build Coastguard Worker default: goto EOP;
157*387f9dfdSAndroid Build Coastguard Worker }
158*387f9dfdSAndroid Build Coastguard Worker }
159*387f9dfdSAndroid Build Coastguard Worker
160*387f9dfdSAndroid Build Coastguard Worker dot1q: {
161*387f9dfdSAndroid Build Coastguard Worker struct dot1q_t *dot1q = cursor_advance(cursor, sizeof(*dot1q));
162*387f9dfdSAndroid Build Coastguard Worker switch(dot1q->type) {
163*387f9dfdSAndroid Build Coastguard Worker case ETH_P_IP: goto ip;
164*387f9dfdSAndroid Build Coastguard Worker case ETH_P_ARP: goto arp;
165*387f9dfdSAndroid Build Coastguard Worker default: goto EOP;
166*387f9dfdSAndroid Build Coastguard Worker }
167*387f9dfdSAndroid Build Coastguard Worker }
168*387f9dfdSAndroid Build Coastguard Worker
169*387f9dfdSAndroid Build Coastguard Worker arp: {
170*387f9dfdSAndroid Build Coastguard Worker struct arp_t *arp = cursor_advance(cursor, sizeof(*arp));
171*387f9dfdSAndroid Build Coastguard Worker /* mac learning */
172*387f9dfdSAndroid Build Coastguard Worker arpop = arp->oper;
173*387f9dfdSAndroid Build Coastguard Worker if (arpop == 2) {
174*387f9dfdSAndroid Build Coastguard Worker index = 0;
175*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
176*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br1_rtr.lookup(&index);
177*387f9dfdSAndroid Build Coastguard Worker else
178*387f9dfdSAndroid Build Coastguard Worker rtrif_p = br2_rtr.lookup(&index);
179*387f9dfdSAndroid Build Coastguard Worker if (rtrif_p) {
180*387f9dfdSAndroid Build Coastguard Worker __u32 ifindex = *rtrif_p;
181*387f9dfdSAndroid Build Coastguard Worker eth_addr_t smac;
182*387f9dfdSAndroid Build Coastguard Worker
183*387f9dfdSAndroid Build Coastguard Worker smac.addr = ethernet->src;
184*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
185*387f9dfdSAndroid Build Coastguard Worker br1_mac_ifindex.update(&smac, &ifindex);
186*387f9dfdSAndroid Build Coastguard Worker else
187*387f9dfdSAndroid Build Coastguard Worker br2_mac_ifindex.update(&smac, &ifindex);
188*387f9dfdSAndroid Build Coastguard Worker }
189*387f9dfdSAndroid Build Coastguard Worker }
190*387f9dfdSAndroid Build Coastguard Worker goto xmit;
191*387f9dfdSAndroid Build Coastguard Worker }
192*387f9dfdSAndroid Build Coastguard Worker
193*387f9dfdSAndroid Build Coastguard Worker ip: {
194*387f9dfdSAndroid Build Coastguard Worker struct ip_t *ip = cursor_advance(cursor, sizeof(*ip));
195*387f9dfdSAndroid Build Coastguard Worker goto xmit;
196*387f9dfdSAndroid Build Coastguard Worker }
197*387f9dfdSAndroid Build Coastguard Worker
198*387f9dfdSAndroid Build Coastguard Worker xmit:
199*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
200*387f9dfdSAndroid Build Coastguard Worker tx_port_id_p = br1_mac.lookup(&dmac);
201*387f9dfdSAndroid Build Coastguard Worker else
202*387f9dfdSAndroid Build Coastguard Worker tx_port_id_p = br2_mac.lookup(&dmac);
203*387f9dfdSAndroid Build Coastguard Worker if (tx_port_id_p) {
204*387f9dfdSAndroid Build Coastguard Worker tx_port_id = *tx_port_id_p;
205*387f9dfdSAndroid Build Coastguard Worker if (which_br == 1)
206*387f9dfdSAndroid Build Coastguard Worker dest_p = br1_dest.lookup(&tx_port_id);
207*387f9dfdSAndroid Build Coastguard Worker else
208*387f9dfdSAndroid Build Coastguard Worker dest_p = br2_dest.lookup(&tx_port_id);
209*387f9dfdSAndroid Build Coastguard Worker if (dest_p) {
210*387f9dfdSAndroid Build Coastguard Worker skb->cb[0] = dest_p->prog_id;
211*387f9dfdSAndroid Build Coastguard Worker skb->cb[1] = dest_p->port_id;
212*387f9dfdSAndroid Build Coastguard Worker jump.call(skb, dest_p->prog_id);
213*387f9dfdSAndroid Build Coastguard Worker }
214*387f9dfdSAndroid Build Coastguard Worker }
215*387f9dfdSAndroid Build Coastguard Worker
216*387f9dfdSAndroid Build Coastguard Worker EOP:
217*387f9dfdSAndroid Build Coastguard Worker return 1;
218*387f9dfdSAndroid Build Coastguard Worker }
219*387f9dfdSAndroid Build Coastguard Worker
br1(struct __sk_buff * skb)220*387f9dfdSAndroid Build Coastguard Worker int br1(struct __sk_buff *skb) {
221*387f9dfdSAndroid Build Coastguard Worker return br_common(skb, 1);
222*387f9dfdSAndroid Build Coastguard Worker }
223*387f9dfdSAndroid Build Coastguard Worker
br2(struct __sk_buff * skb)224*387f9dfdSAndroid Build Coastguard Worker int br2(struct __sk_buff *skb) {
225*387f9dfdSAndroid Build Coastguard Worker return br_common(skb, 2);
226*387f9dfdSAndroid Build Coastguard Worker }
227