Re: libpcap: add basic MPLS support

2018-12-09 Thread Claudio Jeker
On Sat, Dec 08, 2018 at 10:48:37AM +0100, Denis Fondras wrote:
> Add basic MPLS support in libpcap.
> 
> Index: gencode.c
> ===
> RCS file: /cvs/src/lib/libpcap/gencode.c,v
> retrieving revision 1.51
> diff -u -p -r1.51 gencode.c
> --- gencode.c 10 Nov 2018 10:17:37 -  1.51
> +++ gencode.c 14 Nov 2018 12:50:46 -
> @@ -37,6 +37,8 @@ struct rtentry;
>  #include 
>  #include 
>  
> +#include 
> +
>  #include 
>  #include 
>  
> @@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
>  
>  /* Hack for updating VLAN offsets. */
>  static u_int orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
> +static u_int mpls_stack = 0;
>  
>  /* XXX */
>  #ifdef PCAP_FDDIPAD
> @@ -837,11 +840,11 @@ gen_linktype(proto)
>   struct block *b0, *b1;
>  
>   /* If we're not using encapsulation and checking for IP, we're done */
> - if (off_linktype == -1 && proto == ETHERTYPE_IP)
> + if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP)
>   return gen_true();
>  #ifdef INET6
>   /* this isn't the right thing to do, but sometimes necessary */
> - if (off_linktype == -1 && proto == ETHERTYPE_IPV6)
> + if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6)
>   return gen_true();
>  #endif
>  
> @@ -3348,6 +3351,34 @@ gen_acode(eaddr, q)
>   }
>   bpf_error("ARCnet address used in non-arc expression");
>   /* NOTREACHED */
> +}
> +
> +struct block *
> +gen_mpls(label)
> + int label;
> +{
> + struct block*b0;
> +
> + if (label > MPLS_LABEL_MAX)
> + bpf_error("invalid MPLS label : %d", label);
> +
> + if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
> + b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
> + else 
> + b0 = gen_linktype(ETHERTYPE_MPLS);
> +
> + if (label >= 0) {
> + struct block *b1;
> +
> + b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
> + MPLS_LABEL_MASK);
> + gen_and(b0, b1);
> + b0 = b1;
> + }
> + off_nl += 4;
> + off_linktype += 4;
> + mpls_stack++;
> + return (b0);
>  }
>  
>  /*
> Index: gencode.h
> ===
> RCS file: /cvs/src/lib/libpcap/gencode.h,v
> retrieving revision 1.18
> diff -u -p -r1.18 gencode.h
> --- gencode.h 3 Jun 2018 10:29:28 -   1.18
> +++ gencode.h 14 Nov 2018 12:50:46 -
> @@ -179,6 +179,7 @@ struct block *gen_multicast(int);
>  struct block *gen_inbound(int);
>  
>  struct block *gen_vlan(int);
> +struct block *gen_mpls(int);
>  
>  struct block *gen_pf_ifname(char *);
>  struct block *gen_pf_rnr(int);
> Index: grammar.y
> ===
> RCS file: /cvs/src/lib/libpcap/grammar.y,v
> retrieving revision 1.19
> diff -u -p -r1.19 grammar.y
> --- grammar.y 27 Oct 2009 23:59:30 -  1.19
> +++ grammar.y 14 Nov 2018 12:50:46 -
> @@ -115,7 +115,7 @@ pcap_parse()
>  %token   LSH RSH
>  %token  LEN
>  %token  IPV6 ICMPV6 AH ESP
> -%token   VLAN
> +%token   VLAN MPLS
>  
>  %type ID
>  %type EID
> @@ -279,6 +279,8 @@ other:  pqual TK_BROADCAST{ $$ = gen_b
>   | OUTBOUND  { $$ = gen_inbound(1); }
>   | VLAN pnum { $$ = gen_vlan($2); }
>   | VLAN  { $$ = gen_vlan(-1); }
> + | MPLS pnum { $$ = gen_mpls($2); }
> + | MPLS  { $$ = gen_mpls(-1); }
>   | pfvar { $$ = $1; }
>   | pqual p80211  { $$ = $2; }
>   ;
> Index: pcap-filter.3
> ===
> RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
> retrieving revision 1.2
> diff -u -p -r1.2 pcap-filter.3
> --- pcap-filter.3 19 Feb 2014 04:51:32 -  1.2
> +++ pcap-filter.3 14 Nov 2018 12:50:46 -
> @@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
>  .in -.5i
>  filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
>  higher order VLAN.
> +.IP "\fBmpls \fI[label]\fR"
> +True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
> +If \fIlabel\fR is specified, only true if the packet has the specified
> +\fIlabel\fR.
> +Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
> +changes the decoding offsets for the remainder of \fIexpression\fR on
> +the assumption that the packet is an MPLS packet.  The \fBmpls
> +\fI[label]\fR expression may be used more than once, to filter on MPLS
> +labels stack.  Each use of that expression increments the filter offsets
> +by 4.
> +.IP
> +For example:
> +.in +.5i
> +.nf
> +\fBmpls 42 && mpls 12\fR
> +.fi
> +.in -.5i
> +filters on MPLS label 42 on top of MPLS label 12, and

I find this a bit unclear. On top is not very clear to me.
Is it [ 42, 12 ] or [ 12, 42 ]?
How about:
   filters on 

libpcap: add basic MPLS support

2018-12-08 Thread Denis Fondras
Add basic MPLS support in libpcap.

Index: gencode.c
===
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.51
diff -u -p -r1.51 gencode.c
--- gencode.c   10 Nov 2018 10:17:37 -  1.51
+++ gencode.c   14 Nov 2018 12:50:46 -
@@ -37,6 +37,8 @@ struct rtentry;
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 
@@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
 
 /* Hack for updating VLAN offsets. */
 static u_int   orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+static u_int   mpls_stack = 0;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -837,11 +840,11 @@ gen_linktype(proto)
struct block *b0, *b1;
 
/* If we're not using encapsulation and checking for IP, we're done */
-   if (off_linktype == -1 && proto == ETHERTYPE_IP)
+   if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP)
return gen_true();
 #ifdef INET6
/* this isn't the right thing to do, but sometimes necessary */
-   if (off_linktype == -1 && proto == ETHERTYPE_IPV6)
+   if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6)
return gen_true();
 #endif
 
@@ -3348,6 +3351,34 @@ gen_acode(eaddr, q)
}
bpf_error("ARCnet address used in non-arc expression");
/* NOTREACHED */
+}
+
+struct block *
+gen_mpls(label)
+   int label;
+{
+   struct block*b0;
+
+   if (label > MPLS_LABEL_MAX)
+   bpf_error("invalid MPLS label : %d", label);
+
+   if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
+   b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
+   else 
+   b0 = gen_linktype(ETHERTYPE_MPLS);
+
+   if (label >= 0) {
+   struct block *b1;
+
+   b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
+   MPLS_LABEL_MASK);
+   gen_and(b0, b1);
+   b0 = b1;
+   }
+   off_nl += 4;
+   off_linktype += 4;
+   mpls_stack++;
+   return (b0);
 }
 
 /*
Index: gencode.h
===
RCS file: /cvs/src/lib/libpcap/gencode.h,v
retrieving revision 1.18
diff -u -p -r1.18 gencode.h
--- gencode.h   3 Jun 2018 10:29:28 -   1.18
+++ gencode.h   14 Nov 2018 12:50:46 -
@@ -179,6 +179,7 @@ struct block *gen_multicast(int);
 struct block *gen_inbound(int);
 
 struct block *gen_vlan(int);
+struct block *gen_mpls(int);
 
 struct block *gen_pf_ifname(char *);
 struct block *gen_pf_rnr(int);
Index: grammar.y
===
RCS file: /cvs/src/lib/libpcap/grammar.y,v
retrieving revision 1.19
diff -u -p -r1.19 grammar.y
--- grammar.y   27 Oct 2009 23:59:30 -  1.19
+++ grammar.y   14 Nov 2018 12:50:46 -
@@ -115,7 +115,7 @@ pcap_parse()
 %token LSH RSH
 %token  LEN
 %token  IPV6 ICMPV6 AH ESP
-%token VLAN
+%token VLAN MPLS
 
 %type   ID
 %type   EID
@@ -279,6 +279,8 @@ other:pqual TK_BROADCAST{ $$ = gen_b
| OUTBOUND  { $$ = gen_inbound(1); }
| VLAN pnum { $$ = gen_vlan($2); }
| VLAN  { $$ = gen_vlan(-1); }
+   | MPLS pnum { $$ = gen_mpls($2); }
+   | MPLS  { $$ = gen_mpls(-1); }
| pfvar { $$ = $1; }
| pqual p80211  { $$ = $2; }
;
Index: pcap-filter.3
===
RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
retrieving revision 1.2
diff -u -p -r1.2 pcap-filter.3
--- pcap-filter.3   19 Feb 2014 04:51:32 -  1.2
+++ pcap-filter.3   14 Nov 2018 12:50:46 -
@@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
 .in -.5i
 filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
+.IP "\fBmpls \fI[label]\fR"
+True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
+If \fIlabel\fR is specified, only true if the packet has the specified
+\fIlabel\fR.
+Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
+changes the decoding offsets for the remainder of \fIexpression\fR on
+the assumption that the packet is an MPLS packet.  The \fBmpls
+\fI[label]\fR expression may be used more than once, to filter on MPLS
+labels stack.  Each use of that expression increments the filter offsets
+by 4.
+.IP
+For example:
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12\fR
+.fi
+.in -.5i
+filters on MPLS label 42 on top of MPLS label 12, and
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12 && net 192.0.2.0/24\fR
+.fi
+.in -.5i
+filters network 192.0.2.0/24 transported inside packet with label 42 on
+top of label 12.
 .IP  "\fBtcp\fR, \fBudp\fR, \fBicmp\fR"
 Abbreviations for:
 .in +.5i
Index: scanner.l
===
RCS file: /cvs/src/lib/libpcap/scanner.l,v
retrieving revision 1.25
diff 

libpcap: add basic MPLS support

2018-11-14 Thread Denis Fondras
Add basic MPLS support in libpcap.

This version simplifies protocol filtering. There is no need to check if we are
in an MPLS packet for each protocol.
With one change, we can check icmp/udp/tcp/host

Index: gencode.c
===
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.51
diff -u -p -r1.51 gencode.c
--- gencode.c   10 Nov 2018 10:17:37 -  1.51
+++ gencode.c   14 Nov 2018 12:50:46 -
@@ -37,6 +37,8 @@ struct rtentry;
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 
@@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
 
 /* Hack for updating VLAN offsets. */
 static u_int   orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+static u_int   mpls_stack = 0;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -837,11 +840,11 @@ gen_linktype(proto)
struct block *b0, *b1;
 
/* If we're not using encapsulation and checking for IP, we're done */
-   if (off_linktype == -1 && proto == ETHERTYPE_IP)
+   if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IP)
return gen_true();
 #ifdef INET6
/* this isn't the right thing to do, but sometimes necessary */
-   if (off_linktype == -1 && proto == ETHERTYPE_IPV6)
+   if ((off_linktype == -1 || mpls_stack > 0) && proto == ETHERTYPE_IPV6)
return gen_true();
 #endif
 
@@ -3348,6 +3351,34 @@ gen_acode(eaddr, q)
}
bpf_error("ARCnet address used in non-arc expression");
/* NOTREACHED */
+}
+
+struct block *
+gen_mpls(label)
+   int label;
+{
+   struct block*b0;
+
+   if (label > MPLS_LABEL_MAX)
+   bpf_error("invalid MPLS label : %d", label);
+
+   if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
+   b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
+   else 
+   b0 = gen_linktype(ETHERTYPE_MPLS);
+
+   if (label >= 0) {
+   struct block *b1;
+
+   b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
+   MPLS_LABEL_MASK);
+   gen_and(b0, b1);
+   b0 = b1;
+   }
+   off_nl += 4;
+   off_linktype += 4;
+   mpls_stack++;
+   return (b0);
 }
 
 /*
Index: gencode.h
===
RCS file: /cvs/src/lib/libpcap/gencode.h,v
retrieving revision 1.18
diff -u -p -r1.18 gencode.h
--- gencode.h   3 Jun 2018 10:29:28 -   1.18
+++ gencode.h   14 Nov 2018 12:50:46 -
@@ -179,6 +179,7 @@ struct block *gen_multicast(int);
 struct block *gen_inbound(int);
 
 struct block *gen_vlan(int);
+struct block *gen_mpls(int);
 
 struct block *gen_pf_ifname(char *);
 struct block *gen_pf_rnr(int);
Index: grammar.y
===
RCS file: /cvs/src/lib/libpcap/grammar.y,v
retrieving revision 1.19
diff -u -p -r1.19 grammar.y
--- grammar.y   27 Oct 2009 23:59:30 -  1.19
+++ grammar.y   14 Nov 2018 12:50:46 -
@@ -115,7 +115,7 @@ pcap_parse()
 %token LSH RSH
 %token  LEN
 %token  IPV6 ICMPV6 AH ESP
-%token VLAN
+%token VLAN MPLS
 
 %type   ID
 %type   EID
@@ -279,6 +279,8 @@ other:pqual TK_BROADCAST{ $$ = gen_b
| OUTBOUND  { $$ = gen_inbound(1); }
| VLAN pnum { $$ = gen_vlan($2); }
| VLAN  { $$ = gen_vlan(-1); }
+   | MPLS pnum { $$ = gen_mpls($2); }
+   | MPLS  { $$ = gen_mpls(-1); }
| pfvar { $$ = $1; }
| pqual p80211  { $$ = $2; }
;
Index: pcap-filter.3
===
RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
retrieving revision 1.2
diff -u -p -r1.2 pcap-filter.3
--- pcap-filter.3   19 Feb 2014 04:51:32 -  1.2
+++ pcap-filter.3   14 Nov 2018 12:50:46 -
@@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
 .in -.5i
 filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
+.IP "\fBmpls \fI[label]\fR"
+True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
+If \fIlabel\fR is specified, only true if the packet has the specified
+\fIlabel\fR.
+Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
+changes the decoding offsets for the remainder of \fIexpression\fR on
+the assumption that the packet is an MPLS packet.  The \fBmpls
+\fI[label]\fR expression may be used more than once, to filter on MPLS
+labels stack.  Each use of that expression increments the filter offsets
+by 4.
+.IP
+For example:
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12\fR
+.fi
+.in -.5i
+filters on MPLS label 42 on top of MPLS label 12, and
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12 && net 192.0.2.0/24\fR
+.fi
+.in -.5i
+filters network 192.0.2.0/24 transported inside packet with label 42 on
+top of label 12.
 .IP  "\fBtcp\fR, \fBudp\fR, \fBicmp\fR"
 Abbreviations for:
 

libpcap: add basic MPLS support

2018-11-11 Thread Denis Fondras
(long line in the previous diff)

Add basic MPLS support in libpcap.

Index: gencode.c
===
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.51
diff -u -p -r1.51 gencode.c
--- gencode.c   10 Nov 2018 10:17:37 -  1.51
+++ gencode.c   11 Nov 2018 12:53:20 -
@@ -37,6 +37,8 @@ struct rtentry;
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 
@@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
 
 /* Hack for updating VLAN offsets. */
 static u_int   orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+static u_int   mpls_stack = 0;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -973,9 +976,11 @@ gen_hostop(addr, mask, dir, proto, src_o
bpf_error("direction not supported on linktype 0x%x",
linktype);
}
-   b0 = gen_linktype(proto);
b1 = gen_mcmp_nl(offset, BPF_W, (bpf_int32)addr, mask);
-   gen_and(b0, b1);
+   if (mpls_stack == 0) {
+   b0 = gen_linktype(proto);
+   gen_and(b0, b1);
+   }
return b1;
 }
 
@@ -1213,10 +1218,12 @@ gen_host(addr, mask, proto, dir)
 
case Q_DEFAULT:
b0 = gen_host(addr, mask, Q_IP, dir);
-   b1 = gen_host(addr, mask, Q_ARP, dir);
-   gen_or(b0, b1);
-   b0 = gen_host(addr, mask, Q_RARP, dir);
-   gen_or(b1, b0);
+   if (mpls_stack == 0) {
+   b1 = gen_host(addr, mask, Q_ARP, dir);
+   gen_or(b0, b1);
+   b0 = gen_host(addr, mask, Q_RARP, dir);
+   gen_or(b1, b0);
+   }
return b0;
 
case Q_IP:
@@ -3348,6 +3355,34 @@ gen_acode(eaddr, q)
}
bpf_error("ARCnet address used in non-arc expression");
/* NOTREACHED */
+}
+
+struct block *
+gen_mpls(label)
+   int label;
+{
+   struct block*b0;
+
+   if (label > MPLS_LABEL_MAX)
+   bpf_error("invalid MPLS label : %d", label);
+
+   if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
+   b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
+   else 
+   b0 = gen_linktype(ETHERTYPE_MPLS);
+
+   if (label >= 0) {
+   struct block *b1;
+
+   b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12),
+   MPLS_LABEL_MASK);
+   gen_and(b0, b1);
+   b0 = b1;
+   }
+   off_nl += 4;
+   off_linktype += 4;
+   mpls_stack++;
+   return (b0);
 }
 
 /*
Index: gencode.h
===
RCS file: /cvs/src/lib/libpcap/gencode.h,v
retrieving revision 1.18
diff -u -p -r1.18 gencode.h
--- gencode.h   3 Jun 2018 10:29:28 -   1.18
+++ gencode.h   11 Nov 2018 12:53:20 -
@@ -179,6 +179,7 @@ struct block *gen_multicast(int);
 struct block *gen_inbound(int);
 
 struct block *gen_vlan(int);
+struct block *gen_mpls(int);
 
 struct block *gen_pf_ifname(char *);
 struct block *gen_pf_rnr(int);
Index: grammar.y
===
RCS file: /cvs/src/lib/libpcap/grammar.y,v
retrieving revision 1.19
diff -u -p -r1.19 grammar.y
--- grammar.y   27 Oct 2009 23:59:30 -  1.19
+++ grammar.y   11 Nov 2018 12:53:20 -
@@ -115,7 +115,7 @@ pcap_parse()
 %token LSH RSH
 %token  LEN
 %token  IPV6 ICMPV6 AH ESP
-%token VLAN
+%token VLAN MPLS
 
 %type   ID
 %type   EID
@@ -279,6 +279,8 @@ other:pqual TK_BROADCAST{ $$ = gen_b
| OUTBOUND  { $$ = gen_inbound(1); }
| VLAN pnum { $$ = gen_vlan($2); }
| VLAN  { $$ = gen_vlan(-1); }
+   | MPLS pnum { $$ = gen_mpls($2); }
+   | MPLS  { $$ = gen_mpls(-1); }
| pfvar { $$ = $1; }
| pqual p80211  { $$ = $2; }
;
Index: pcap-filter.3
===
RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
retrieving revision 1.2
diff -u -p -r1.2 pcap-filter.3
--- pcap-filter.3   19 Feb 2014 04:51:32 -  1.2
+++ pcap-filter.3   11 Nov 2018 12:53:20 -
@@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
 .in -.5i
 filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
+.IP "\fBmpls \fI[label]\fR"
+True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
+If \fIlabel\fR is specified, only true if the packet has the specified
+\fIlabel\fR.
+Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
+changes the decoding offsets for the remainder of \fIexpression\fR on
+the assumption that the packet is an MPLS packet.  The \fBmpls
+\fI[label]\fR expression may be used more than once, to filter on MPLS
+labels stack.  Each use of that expression increments the filter offsets
+by 4.
+.IP
+For example:
+.in 

libpcap: add basic MPLS support

2018-11-11 Thread Denis Fondras
Add basic MPLS support in libpcap.

Index: gencode.c
===
RCS file: /cvs/src/lib/libpcap/gencode.c,v
retrieving revision 1.51
diff -u -p -r1.51 gencode.c
--- gencode.c   10 Nov 2018 10:17:37 -  1.51
+++ gencode.c   11 Nov 2018 12:34:44 -
@@ -37,6 +37,8 @@ struct rtentry;
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 
@@ -69,6 +71,7 @@ static pcap_t *bpf_pcap;
 
 /* Hack for updating VLAN offsets. */
 static u_int   orig_linktype = -1, orig_nl = -1, orig_nl_nosnap = -1;
+static u_int   mpls_stack = 0;
 
 /* XXX */
 #ifdef PCAP_FDDIPAD
@@ -973,9 +976,11 @@ gen_hostop(addr, mask, dir, proto, src_o
bpf_error("direction not supported on linktype 0x%x",
linktype);
}
-   b0 = gen_linktype(proto);
b1 = gen_mcmp_nl(offset, BPF_W, (bpf_int32)addr, mask);
-   gen_and(b0, b1);
+   if (mpls_stack == 0) {
+   b0 = gen_linktype(proto);
+   gen_and(b0, b1);
+   }
return b1;
 }
 
@@ -1213,10 +1218,12 @@ gen_host(addr, mask, proto, dir)
 
case Q_DEFAULT:
b0 = gen_host(addr, mask, Q_IP, dir);
-   b1 = gen_host(addr, mask, Q_ARP, dir);
-   gen_or(b0, b1);
-   b0 = gen_host(addr, mask, Q_RARP, dir);
-   gen_or(b1, b0);
+   if (mpls_stack == 0) {
+   b1 = gen_host(addr, mask, Q_ARP, dir);
+   gen_or(b0, b1);
+   b0 = gen_host(addr, mask, Q_RARP, dir);
+   gen_or(b1, b0);
+   }
return b0;
 
case Q_IP:
@@ -3350,6 +3357,33 @@ gen_acode(eaddr, q)
/* NOTREACHED */
 }
 
+struct block *
+gen_mpls(label)
+   int label;
+{
+   struct block*b0;
+
+   if (label > MPLS_LABEL_MAX)
+   bpf_error("invalid MPLS label : %d", label);
+
+   if (mpls_stack > 0) /* Bottom-Of-Label-Stack bit ? */
+   b0 = gen_mcmp(off_nl-2, BPF_B, (bpf_int32)0, 0x1);
+   else 
+   b0 = gen_linktype(ETHERTYPE_MPLS);
+
+   if (label >= 0) {
+   struct block *b1;
+
+   b1 = gen_mcmp(off_nl, BPF_W, (bpf_int32)(label << 12), 
MPLS_LABEL_MASK);
+   gen_and(b0, b1);
+   b0 = b1;
+   }
+   off_nl += 4;
+   off_linktype += 4;
+   mpls_stack++;
+   return (b0);
+}
+
 /*
  * support IEEE 802.1Q VLAN trunk over ethernet
  */
Index: gencode.h
===
RCS file: /cvs/src/lib/libpcap/gencode.h,v
retrieving revision 1.18
diff -u -p -r1.18 gencode.h
--- gencode.h   3 Jun 2018 10:29:28 -   1.18
+++ gencode.h   11 Nov 2018 12:34:44 -
@@ -179,6 +179,7 @@ struct block *gen_multicast(int);
 struct block *gen_inbound(int);
 
 struct block *gen_vlan(int);
+struct block *gen_mpls(int);
 
 struct block *gen_pf_ifname(char *);
 struct block *gen_pf_rnr(int);
Index: grammar.y
===
RCS file: /cvs/src/lib/libpcap/grammar.y,v
retrieving revision 1.19
diff -u -p -r1.19 grammar.y
--- grammar.y   27 Oct 2009 23:59:30 -  1.19
+++ grammar.y   11 Nov 2018 12:34:44 -
@@ -115,7 +115,7 @@ pcap_parse()
 %token LSH RSH
 %token  LEN
 %token  IPV6 ICMPV6 AH ESP
-%token VLAN
+%token VLAN MPLS
 
 %type   ID
 %type   EID
@@ -279,6 +279,8 @@ other:pqual TK_BROADCAST{ $$ = gen_b
| OUTBOUND  { $$ = gen_inbound(1); }
| VLAN pnum { $$ = gen_vlan($2); }
| VLAN  { $$ = gen_vlan(-1); }
+   | MPLS pnum { $$ = gen_mpls($2); }
+   | MPLS  { $$ = gen_mpls(-1); }
| pfvar { $$ = $1; }
| pqual p80211  { $$ = $2; }
;
Index: pcap-filter.3
===
RCS file: /cvs/src/lib/libpcap/pcap-filter.3,v
retrieving revision 1.2
diff -u -p -r1.2 pcap-filter.3
--- pcap-filter.3   19 Feb 2014 04:51:32 -  1.2
+++ pcap-filter.3   11 Nov 2018 12:34:44 -
@@ -522,6 +522,31 @@ filters on VLAN 200 encapsulated within 
 .in -.5i
 filters IPv4 protocols encapsulated in VLAN 300 encapsulated within any
 higher order VLAN.
+.IP "\fBmpls \fI[label]\fR"
+True if the packet is an MPLS (Multi-Protocol Label Switching) packet.
+If \fIlabel\fR is specified, only true if the packet has the specified
+\fIlabel\fR.
+Note that the first \fBmpls\fR keyword encountered in \fIexpression\fR
+changes the decoding offsets for the remainder of \fIexpression\fR on
+the assumption that the packet is an MPLS packet.  The \fBmpls
+\fI[label]\fR expression may be used more than once, to filter on MPLS
+labels stack.  Each use of that expression increments the filter offsets
+by 4.
+.IP
+For example:
+.in +.5i
+.nf
+\fBmpls 42 && mpls 12\fR
+.fi
+.in -.5i
+filters on MPLS label