#include <linux/netdevice.h>
 #include <linux/filter.h>
 #include <linux/cache.h>
+#include <linux/if_vlan.h>
 
 #include <asm/cacheflush.h>
 #include <asm/ptrace.h>
 #define emit_addi(R1, IMM, R3) \
        *prog++ = (ADD | IMMED | RS1(R1) | S13(IMM) | RD(R3))
 
+#define emit_and(R1, R2, R3) \
+       *prog++ = (AND | RS1(R1) | RS2(R2) | RD(R3))
+
+#define emit_andi(R1, IMM, R3) \
+       *prog++ = (AND | IMMED | RS1(R1) | S13(IMM) | RD(R3))
+
 #define emit_alloc_stack(SZ) \
        *prog++ = (SUB | IMMED | RS1(SP) | S13(SZ) | RD(SP))
 
                case BPF_S_ANC_IFINDEX:
                case BPF_S_ANC_MARK:
                case BPF_S_ANC_RXHASH:
+               case BPF_S_ANC_VLAN_TAG:
+               case BPF_S_ANC_VLAN_TAG_PRESENT:
                case BPF_S_ANC_CPU:
                case BPF_S_ANC_QUEUE:
                case BPF_S_LD_W_ABS:
                        case BPF_S_ANC_RXHASH:
                                emit_skb_load32(rxhash, r_A);
                                break;
+                       case BPF_S_ANC_VLAN_TAG:
+                       case BPF_S_ANC_VLAN_TAG_PRESENT:
+                               emit_skb_load16(vlan_tci, r_A);
+                               if (filter[i].code == BPF_S_ANC_VLAN_TAG) {
+                                       emit_andi(r_A, VLAN_VID_MASK, r_A);
+                               } else {
+                                       emit_loadimm(VLAN_TAG_PRESENT, r_TMP);
+                                       emit_and(r_A, r_TMP, r_A);
+                               }
+                               break;
 
                        case BPF_S_LD_IMM:
                                emit_loadimm(K, r_A);