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); }