summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluqiuwen <[email protected]>2019-01-05 15:27:59 +0600
committerluqiuwen <[email protected]>2019-01-05 15:27:59 +0600
commit969d4f06f36bbf20d9186e4afda98f661fe16290 (patch)
tree3b731fec2473ee07492c54f7c494721f85d03eb7
parent4d3c76da25fb0e9392ab5d39ee6cd376ec2c265e (diff)
Close #8 识别GTPv1-U隧道并支持按隧道内IP地址分流v4.3.5-20190108
-rw-r--r--infra/include/gtp_header.h48
-rw-r--r--infra/include/ldbc.h3
-rw-r--r--infra/src/ldbc.c44
-rw-r--r--infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcapbin0 -> 535123 bytes
-rw-r--r--infra/test/TestDistributer.cc6
-rw-r--r--infra/test/TestPacketParser.cc45
6 files changed, 145 insertions, 1 deletions
diff --git a/infra/include/gtp_header.h b/infra/include/gtp_header.h
new file mode 100644
index 0000000..f9a23bc
--- /dev/null
+++ b/infra/include/gtp_header.h
@@ -0,0 +1,48 @@
+/*
+ * GTP header definition, from Linux 4.20
+ * https://elixir.bootlin.com/linux/latest/source/include/net/gtp.h
+ */
+
+#ifndef MARSIO_GTP_H
+#define MARSIO_GTP_H
+
+#include <stdlib.h>
+
+#define GTP0_PORT 3386
+#define GTP1U_PORT 2152
+#define GTP_TPDU 255
+
+enum gtp_version
+{
+ GTP_VERSION_V0 = 0,
+ GTP_VERSION_V1,
+};
+
+/* According to GSM TS 09.60. */
+struct gtp0_header
+{
+ uint8_t flags;
+ uint8_t type;
+ uint16_t length;
+ uint16_t seq;
+ uint16_t flow;
+ uint8_t number;
+ uint8_t spare[3];
+ uint64_t tid;
+} __attribute__ ((packed));
+
+/* According to 3GPP TS 29.060. */
+struct gtp1_header
+{
+ uint8_t flags;
+ uint8_t type;
+ uint16_t length;
+ uint32_t tid;
+} __attribute__ ((packed));
+
+#define GTP1_F_NPDU 0x01
+#define GTP1_F_SEQ 0x02
+#define GTP1_F_EXTHDR 0x04
+#define GTP1_F_MASK 0x07
+
+#endif //MARSIO_GTP_H
diff --git a/infra/include/ldbc.h b/infra/include/ldbc.h
index 1f6081d..97bbee1 100644
--- a/infra/include/ldbc.h
+++ b/infra/include/ldbc.h
@@ -63,7 +63,8 @@ enum complex_layer
LAYER_TYPE_L4 = (LAYER_TYPE_UDP | LAYER_TYPE_TCP),
/* 传输层 -- 隧道 */
- LAYER_TYPE_G_VXLAN = 1 << 9
+ LAYER_TYPE_G_VXLAN = 1 << 9,
+ LAYER_TYPE_GTPV1_U = 1 << 10
};
#define MR_PKT_PARSE_RESULT_MAX 4
diff --git a/infra/src/ldbc.c b/infra/src/ldbc.c
index 0c90978..e246702 100644
--- a/infra/src/ldbc.c
+++ b/infra/src/ldbc.c
@@ -21,6 +21,7 @@
#include <ldbc.h>
#include <common.h>
+#include <gtp_header.h>
static uint8_t default_rss_key[] =
{
@@ -46,6 +47,9 @@ static inline int __parser_exit_or_continue(struct pkt_parser * handler,
static const void * __complex_parser_g_vxlan(struct pkt_parser * handler,
const void * data, enum complex_layer this_layer_type);
+static const void * __complex_parser_gtpv1_u(struct pkt_parser * handler,
+ const void * data, enum complex_layer this_layer_type);
+
static const void * __complex_parser_tcp(struct pkt_parser * handler,
const void * data, enum complex_layer this_layer_type);
@@ -100,6 +104,44 @@ static const void * __complex_parser_g_vxlan(struct pkt_parser * handler,
return NULL;
}
+static const void * __complex_parser_gtpv1_u(struct pkt_parser * handler,
+ const void * data, enum complex_layer this_layer_type)
+{
+ unsigned int hdrlen = sizeof(struct gtp1_header);
+ struct gtp1_header * gtp1;
+
+ gtp1 = (struct gtp1_header *)(data);
+ if ((gtp1->flags >> 5) != GTP_VERSION_V1)
+ return NULL;
+
+ if (gtp1->type != GTP_TPDU)
+ return NULL;
+
+ /* From 29.060: "This field shall be present if and only if any one or
+ * more of the S, PN and E flags are set.".
+ *
+ * If any of the bit is set, then the remaining ones also have to be
+ * set.
+ */
+ if (gtp1->flags & GTP1_F_MASK)
+ hdrlen += 4;
+
+ const void * data_next_layer = (const void *)(data + hdrlen);
+ const uint8_t * __data_next_layer = (const uint8_t *)data_next_layer;
+
+ uint8_t ip_version = (__data_next_layer[0]) >> 4;
+ if (ip_version == 4)
+ {
+ return __complex_parser_ipv4(handler, data_next_layer, LAYER_TYPE_IPV4);
+ }
+ else if (ip_version == 6)
+ {
+ return __complex_parser_ipv6(handler, data_next_layer, LAYER_TYPE_IPV6);
+ }
+
+ return NULL;
+}
+
static const void * __complex_parser_tcp(struct pkt_parser * handler,
const void * data, enum complex_layer this_layer_type)
{
@@ -121,6 +163,8 @@ static const void * __complex_parser_udp(struct pkt_parser * handler,
/* 专用设备VxLAN封装 */
if (udp_hdr->dst_port == htons(G_VXLAN_DPORT))
return __complex_parser_g_vxlan(handler, data_next_layer, LAYER_TYPE_G_VXLAN);
+ if(udp_hdr->dst_port == htons(GTP1U_PORT))
+ return __complex_parser_gtpv1_u(handler, data_next_layer, LAYER_TYPE_GTPV1_U);
return NULL;
}
diff --git a/infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcap b/infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcap
new file mode 100644
index 0000000..cde7d98
--- /dev/null
+++ b/infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcap
Binary files differ
diff --git a/infra/test/TestDistributer.cc b/infra/test/TestDistributer.cc
index 2cac372..2f67ec2 100644
--- a/infra/test/TestDistributer.cc
+++ b/infra/test/TestDistributer.cc
@@ -130,6 +130,12 @@ std::tuple<const char *, enum e_dist_mode, enum e_hash_mode> testTable[]
std::make_tuple("178_89_4_219_to_117_122_217_89_mpls_vxlan_inner.pcap",
LDBC_DIST_INNER_TUPLE2,
LDBC_HASH_SYM_RSS),
+ std::make_tuple("100_95_37_122_to_149_3_200_32_gtpv1_u.pcap",
+ LDBC_DIST_INNER_TUPLE2,
+ LDBC_HASH_SYM_CRC),
+ std::make_tuple("100_95_37_122_to_149_3_200_32_gtpv1_u.pcap",
+ LDBC_DIST_INNER_TUPLE2,
+ LDBC_HASH_SYM_RSS),
std::make_tuple("178_89_4_219_to_117_122_217_89_ipv4.pcap",
LDBC_DIST_OUTER_TUPLE2,
LDBC_HASH_SYM_CRC),
diff --git a/infra/test/TestPacketParser.cc b/infra/test/TestPacketParser.cc
index ce77505..8f9db0c 100644
--- a/infra/test/TestPacketParser.cc
+++ b/infra/test/TestPacketParser.cc
@@ -512,6 +512,51 @@ TEST(PacketParserInnerL4, EtherIPv4UDPVxlanPPP)
}
+/* Frame (111 bytes)
+ *
+ * Internet Protocol Version 4, Src: 10.7.84.136, Dst: 2.78.63.108
+ * 83 06:00:00.000000 100.80.113.249 2.78.45.204
+ * GTP <GQUIC> 111 40565 → 443 Len=29, PKN: 73, CID: 10917641376885890260
+ */
+static const unsigned char pkt83[111] = {
+ 0x18, 0x10, 0x04, 0x00, 0x03, 0x26, 0x00, 0x00, /* .....&.. */
+ 0x00, 0x00, 0x04, 0x25, 0x88, 0x47, 0x10, 0x03, /* ...%.G.. */
+ 0xfb, 0x3d, 0x45, 0xb8, 0x00, 0x5d, 0x7b, 0x75, /* .=E..]{u */
+ 0x00, 0x00, 0x3e, 0x11, 0x60, 0x1a, 0x0a, 0x07, /* ..>.`... */
+ 0x54, 0x88, 0x02, 0x4e, 0x3f, 0x6c, 0x22, 0x3c, /* T..N?l"< */
+ 0x08, 0x68, 0x00, 0x49, 0x04, 0x70, 0x30, 0xff, /* .h.I.p0. */
+ 0x00, 0x39, 0x25, 0x10, 0xe0, 0x50, 0x45, 0x00, /* .9%..PE. */
+ 0x00, 0x39, 0x0e, 0xda, 0x40, 0x00, 0x40, 0x11, /* .9..@.@. */
+ 0x25, 0x77, 0x64, 0x50, 0x71, 0xf9, 0x02, 0x4e, /* %wdPq..N */
+ 0x2d, 0xcc, 0x9e, 0x75, 0x01, 0xbb, 0x00, 0x25, /* -..u...% */
+ 0x56, 0xfa, 0x0c, 0xd4, 0xdc, 0x63, 0xf6, 0xfc, /* V....c.. */
+ 0x40, 0x83, 0x97, 0x49, 0xea, 0x93, 0x91, 0x0b, /* @..I.... */
+ 0xd1, 0x87, 0xeb, 0x48, 0xa5, 0xf4, 0x25, 0xb5, /* ...H..%. */
+ 0x32, 0x26, 0x05, 0x4d, 0x8f, 0x86, 0x7f /* 2&.M... */
+};
+
+TEST(PacketParseInnerL3, EtherIPv4UDPGTPv1)
+{
+ struct pkt_parser _pkt_83_handler;
+ _pkt_83_handler.expect_layer_type = LAYER_TYPE_L3;
+ _pkt_83_handler.nr_expect_results = 2;
+ _pkt_83_handler.nr_results = 0;
+
+ ASSERT_TRUE(complex_parser_ether(&_pkt_83_handler, pkt83) != NULL);
+ EXPECT_EQ(_pkt_83_handler.nr_results, 2);
+
+ struct pkt_parser_result * result = &_pkt_83_handler.results[0];
+ EXPECT_EQ(result->this_layer_type, LAYER_TYPE_IPV4);
+ EXPECT_TRUE(result->data != NULL);
+
+ TestCheckIPv4Addr(result, "10.7.84.136", "2.78.63.108");
+
+ result = &_pkt_83_handler.results[1];
+ EXPECT_EQ(result->this_layer_type, LAYER_TYPE_IPV4);
+ EXPECT_TRUE(result->data != NULL);
+
+ TestCheckIPv4Addr(result, "100.80.113.249", "2.78.45.204");
+}
#if 0
TEST(DistributerInner4, EtherIPv4VxLANIPv4TCP)