diff options
| author | luqiuwen <[email protected]> | 2019-01-05 15:27:59 +0600 |
|---|---|---|
| committer | luqiuwen <[email protected]> | 2019-01-05 15:27:59 +0600 |
| commit | 969d4f06f36bbf20d9186e4afda98f661fe16290 (patch) | |
| tree | 3b731fec2473ee07492c54f7c494721f85d03eb7 | |
| parent | 4d3c76da25fb0e9392ab5d39ee6cd376ec2c265e (diff) | |
Close #8 识别GTPv1-U隧道并支持按隧道内IP地址分流v4.3.5-20190108
| -rw-r--r-- | infra/include/gtp_header.h | 48 | ||||
| -rw-r--r-- | infra/include/ldbc.h | 3 | ||||
| -rw-r--r-- | infra/src/ldbc.c | 44 | ||||
| -rw-r--r-- | infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcap | bin | 0 -> 535123 bytes | |||
| -rw-r--r-- | infra/test/TestDistributer.cc | 6 | ||||
| -rw-r--r-- | infra/test/TestPacketParser.cc | 45 |
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 Binary files differnew file mode 100644 index 0000000..cde7d98 --- /dev/null +++ b/infra/test/100_95_37_122_to_149_3_200_32_gtpv1_u.pcap 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) |
