When using TCPDUMP, you have to be aware of the fact that BPF filter (at least the default libpcap and Linux kernel implementations of it) doesn't do proper decoding based on ethertypes.
In the presence of both tagged and untagged traffic, the naively occuring expression of (example):
(port 80 or port 25)
will not catch VLAN-tagged packets at all.
You have to be explicit and specify the vlan keyword, which (in absence of a VLAN ID) just moves the Ethernet payload offset to the correct place:
(vlan and (port 80 or port 25))
And then you miss the untagged traffic.
The proper expression to use is:
(port 80 or port 25) or (vlan and (port 80 or port 25))
Of course you never do this.
Of course double-tagging makes thins even worse.
Of course the same happens with MPLS (and probably whatever else L2-encapsulation scheme drunk CISCO engineers will patch into an "industry standard" next year).
Of course all this is noted in the TCPDUMP documentation that you never read:
vlan [vlan_id]: True if the packet is an IEEE 802.1Q VLAN packet. If [vlan_id] is specified, only true if the packet has the specified vlan_id. Note that the first vlan keyword encountered in expression changes the decoding offsets for the remainder of expression on the assumption that the packet is a VLAN packet. The vlan [vlan_id] expression may be used more than once, to filter on VLAN hierarchies. Each use of that expression increments the filter offsets by 4.
Shame on you.