On Fri, Jul 17, 2015 at 03:24:17PM -0300, Rafael Zalamena wrote:
> This diff adds support for detection of pseudowires inside of MPLS tagged
> packets. Basically it teaches MPLS to look for ethernet headers when there
> is no sign of IP headers.
> 
> --- SNIPPED OLD DIFF ---

This is an updated diff to teach tcpdump mpls parser to identify VPLS
packets and display the ethernet payload. This time it doesn't do any
clever tricks: it will only show VPLS encapsulated ethernet packet if
there is a control word (which is used by default in ldpd(8)).

ok?

Index: interface.h
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/interface.h,v
retrieving revision 1.65
diff -u -p -r1.65 interface.h
--- interface.h 5 Apr 2015 17:02:57 -0000       1.65
+++ interface.h 26 Sep 2015 21:57:42 -0000
@@ -205,6 +205,7 @@ extern void pfsync_if_print(u_char *, co
 extern void pfsync_ip_print(const u_char *, u_int, const u_char *);
 extern void ether_if_print(u_char *, const struct pcap_pkthdr *,
        const u_char *);
+void ether_tryprint(const u_char *, u_int, int);
 extern void fddi_if_print(u_char *, const struct pcap_pkthdr *, const u_char 
*);
 extern void ppp_ether_if_print(u_char *, const struct pcap_pkthdr *,
        const u_char *);
Index: print-ether.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-ether.c,v
retrieving revision 1.29
diff -u -p -r1.29 print-ether.c
--- print-ether.c       16 Jan 2015 06:40:21 -0000      1.29
+++ print-ether.c       26 Sep 2015 21:58:24 -0000
@@ -89,29 +89,34 @@ u_short extracted_ethertype;
 void
 ether_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
 {
-       u_int caplen = h->caplen;
-       u_int length = h->len;
-       struct ether_header *ep;
-       u_short ether_type;
-
        ts_print(&h->ts);
 
-       if (caplen < sizeof(struct ether_header)) {
-               printf("[|ether]");
-               goto out;
-       }
-
        /*
         * Some printers want to get back at the ethernet addresses,
         * and/or check that they're not walking off the end of the packet.
         * Rather than pass them all the way down, we set these globals.
         */
-       packetp = p;
-       snapend = p + caplen;
+       snapend = p + h->caplen;
+
+       ether_tryprint(p, h->len, 1);
+}
+
+void
+ether_tryprint(const u_char *p, u_int length, int first_header)
+{
+       u_int caplen = snapend - p;
+       struct ether_header *ep;
+       u_short ether_type;
+
+       if (caplen < sizeof(struct ether_header)) {
+               printf("[|ether]");
+               goto out;
+       }
 
        if (eflag)
                ether_print(p, length);
 
+       packetp = p;
        length -= sizeof(struct ether_header);
        caplen -= sizeof(struct ether_header);
        ep = (struct ether_header *)p;
@@ -152,14 +157,15 @@ ether_if_print(u_char *user, const struc
                                default_print(p, caplen);
                }
        }
-       if (xflag) {
+       if (xflag && first_header) {
                if (eflag)
                        default_print(packetp, snapend - packetp);
                else
                        default_print(p, caplen);
        }
  out:
-       putchar('\n');
+       if (first_header)
+               putchar('\n');
 }
 
 /*
Index: print-mpls.c
===================================================================
RCS file: /cvs/src/usr.sbin/tcpdump/print-mpls.c,v
retrieving revision 1.2
diff -u -p -r1.2 print-mpls.c
--- print-mpls.c        30 Jun 2010 19:01:06 -0000      1.2
+++ print-mpls.c        26 Sep 2015 21:57:53 -0000
@@ -31,10 +31,17 @@
 #include "interface.h"
 #include "extract.h"               /* must come after interface.h */
 
+#define CW_ZERO_MASK           (0xf0000000U)
+#define CW_FRAG_MASK           (0x0fff0000U)
+#define CW_SEQUENCE_MASK       (0x0000ffffU)
+
+int controlword_tryprint(const u_char **, u_int *);
+
 void
 mpls_print(const u_char *bp, u_int len)
 {
        u_int32_t tag, label, exp, bottom, ttl;
+       int has_cw;
 
  again:
        if (bp + sizeof(tag) > snapend)
@@ -56,6 +63,9 @@ mpls_print(const u_char *bp, u_int len)
        if (!bottom)
                goto again;
 
+       /* Handle pseudowire control word. */
+       has_cw = controlword_tryprint(&bp, &len);
+
        /*
         * guessing the underlying protocol is about all we can do if
         * it's not explicitly defined.
@@ -107,7 +117,34 @@ mpls_print(const u_char *bp, u_int len)
                }
        }
 
+       if (has_cw)
+               ether_tryprint(bp, len, 0);
+
        return;
 trunc:
        printf("[|mpls]");
+}
+
+/* Print control word if any and returns 1 on success. */
+int
+controlword_tryprint(const u_char **bp, u_int *lenp)
+{
+       u_int32_t cw, frag, seq;
+
+       if (*lenp < 4)
+               return (0);
+
+       cw = EXTRACT_32BITS(*bp);
+       if (cw & CW_ZERO_MASK)
+               return (0);
+
+       *bp += sizeof(cw);
+       *lenp += sizeof(cw);
+
+       frag = (cw & CW_FRAG_MASK) >> 16;
+       seq = cw & CW_SEQUENCE_MASK;
+
+       printf("CW(frag %u, sequence %u) ", frag, seq);
+
+       return (1);
 }

Reply via email to