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