0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016 #include <stddef.h>
0017 #include <stdbool.h>
0018 #include <string.h>
0019 #include <linux/bpf.h>
0020 #include <linux/if_ether.h>
0021 #include <linux/if_vlan.h>
0022 #include <linux/in.h>
0023 #include <linux/pkt_cls.h>
0024
0025 #include <bpf/bpf_helpers.h>
0026 #include <bpf/bpf_endian.h>
0027
0028
0029
0030
0031
0032
0033
0034 struct _vlan_hdr {
0035 __be16 h_vlan_TCI;
0036 __be16 h_vlan_encapsulated_proto;
0037 };
0038 #define VLAN_PRIO_MASK 0xe000
0039 #define VLAN_PRIO_SHIFT 13
0040 #define VLAN_CFI_MASK 0x1000
0041 #define VLAN_TAG_PRESENT VLAN_CFI_MASK
0042 #define VLAN_VID_MASK 0x0fff
0043 #define VLAN_N_VID 4096
0044
0045 struct parse_pkt {
0046 __u16 l3_proto;
0047 __u16 l3_offset;
0048 __u16 vlan_outer;
0049 __u16 vlan_inner;
0050 __u8 vlan_outer_offset;
0051 __u8 vlan_inner_offset;
0052 };
0053
0054 char _license[] SEC("license") = "GPL";
0055
0056 static __always_inline
0057 bool parse_eth_frame(struct ethhdr *eth, void *data_end, struct parse_pkt *pkt)
0058 {
0059 __u16 eth_type;
0060 __u8 offset;
0061
0062 offset = sizeof(*eth);
0063
0064 if ((void *)eth + offset + (2*sizeof(struct _vlan_hdr)) > data_end)
0065 return false;
0066
0067 eth_type = eth->h_proto;
0068
0069
0070 if (eth_type == bpf_htons(ETH_P_8021Q)
0071 || eth_type == bpf_htons(ETH_P_8021AD)) {
0072 struct _vlan_hdr *vlan_hdr;
0073
0074 vlan_hdr = (void *)eth + offset;
0075 pkt->vlan_outer_offset = offset;
0076 pkt->vlan_outer = bpf_ntohs(vlan_hdr->h_vlan_TCI)
0077 & VLAN_VID_MASK;
0078 eth_type = vlan_hdr->h_vlan_encapsulated_proto;
0079 offset += sizeof(*vlan_hdr);
0080 }
0081
0082
0083 if (eth_type == bpf_htons(ETH_P_8021Q)
0084 || eth_type == bpf_htons(ETH_P_8021AD)) {
0085 struct _vlan_hdr *vlan_hdr;
0086
0087 vlan_hdr = (void *)eth + offset;
0088 pkt->vlan_inner_offset = offset;
0089 pkt->vlan_inner = bpf_ntohs(vlan_hdr->h_vlan_TCI)
0090 & VLAN_VID_MASK;
0091 eth_type = vlan_hdr->h_vlan_encapsulated_proto;
0092 offset += sizeof(*vlan_hdr);
0093 }
0094
0095 pkt->l3_proto = bpf_ntohs(eth_type);
0096 pkt->l3_offset = offset;
0097
0098 return true;
0099 }
0100
0101
0102 #define TESTVLAN 4011
0103
0104
0105 SEC("xdp_drop_vlan_4011")
0106 int xdp_prognum0(struct xdp_md *ctx)
0107 {
0108 void *data_end = (void *)(long)ctx->data_end;
0109 void *data = (void *)(long)ctx->data;
0110 struct parse_pkt pkt = { 0 };
0111
0112 if (!parse_eth_frame(data, data_end, &pkt))
0113 return XDP_ABORTED;
0114
0115
0116 if (pkt.vlan_outer == TESTVLAN)
0117 return XDP_ABORTED;
0118
0119
0120
0121
0122
0123
0124 return XDP_PASS;
0125 }
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145 #define TO_VLAN 0
0146
0147 SEC("xdp_vlan_change")
0148 int xdp_prognum1(struct xdp_md *ctx)
0149 {
0150 void *data_end = (void *)(long)ctx->data_end;
0151 void *data = (void *)(long)ctx->data;
0152 struct parse_pkt pkt = { 0 };
0153
0154 if (!parse_eth_frame(data, data_end, &pkt))
0155 return XDP_ABORTED;
0156
0157
0158 if (pkt.vlan_outer == TESTVLAN) {
0159 struct _vlan_hdr *vlan_hdr = data + pkt.vlan_outer_offset;
0160
0161
0162 vlan_hdr->h_vlan_TCI =
0163 bpf_htons((bpf_ntohs(vlan_hdr->h_vlan_TCI) & 0xf000)
0164 | TO_VLAN);
0165 }
0166
0167 return XDP_PASS;
0168 }
0169
0170
0171
0172
0173
0174
0175
0176 #ifndef ETH_ALEN
0177 #define ETH_ALEN 6
0178 #endif
0179 #define VLAN_HDR_SZ 4
0180
0181 SEC("xdp_vlan_remove_outer")
0182 int xdp_prognum2(struct xdp_md *ctx)
0183 {
0184 void *data_end = (void *)(long)ctx->data_end;
0185 void *data = (void *)(long)ctx->data;
0186 struct parse_pkt pkt = { 0 };
0187 char *dest;
0188
0189 if (!parse_eth_frame(data, data_end, &pkt))
0190 return XDP_ABORTED;
0191
0192
0193 if (pkt.vlan_outer_offset == 0)
0194 return XDP_PASS;
0195
0196
0197 dest = data;
0198 dest+= VLAN_HDR_SZ;
0199
0200
0201
0202
0203 __builtin_memmove(dest, data, ETH_ALEN * 2);
0204
0205
0206
0207 bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ);
0208
0209 return XDP_PASS;
0210 }
0211
0212 static __always_inline
0213 void shift_mac_4bytes_16bit(void *data)
0214 {
0215 __u16 *p = data;
0216
0217 p[7] = p[5];
0218 p[6] = p[4];
0219 p[5] = p[3];
0220 p[4] = p[2];
0221 p[3] = p[1];
0222 p[2] = p[0];
0223 }
0224
0225 static __always_inline
0226 void shift_mac_4bytes_32bit(void *data)
0227 {
0228 __u32 *p = data;
0229
0230
0231
0232
0233
0234
0235 p[3] = p[2];
0236 p[2] = p[1];
0237 p[1] = p[0];
0238 }
0239
0240 SEC("xdp_vlan_remove_outer2")
0241 int xdp_prognum3(struct xdp_md *ctx)
0242 {
0243 void *data_end = (void *)(long)ctx->data_end;
0244 void *data = (void *)(long)ctx->data;
0245 struct ethhdr *orig_eth = data;
0246 struct parse_pkt pkt = { 0 };
0247
0248 if (!parse_eth_frame(orig_eth, data_end, &pkt))
0249 return XDP_ABORTED;
0250
0251
0252 if (pkt.vlan_outer_offset == 0)
0253 return XDP_PASS;
0254
0255
0256 shift_mac_4bytes_32bit(data);
0257
0258
0259 bpf_xdp_adjust_head(ctx, VLAN_HDR_SZ);
0260
0261 return XDP_PASS;
0262 }
0263
0264
0265
0266
0267
0268
0269
0270 SEC("tc_vlan_push")
0271 int _tc_progA(struct __sk_buff *ctx)
0272 {
0273 bpf_skb_vlan_push(ctx, bpf_htons(ETH_P_8021Q), TESTVLAN);
0274
0275 return TC_ACT_OK;
0276 }
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292