From a726a5d480383baf1657d32ac2f44aef0d47b1b3 Mon Sep 17 00:00:00 2001 From: luqiuwen Date: Sun, 23 Dec 2018 15:22:57 +0600 Subject: 增加Ethernet over MPLS的解析功能及对应的单元测试用例 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- infra/src/ldbc.c | 39 +++++++++++++++++---- infra/test/TestPacketParser.cc | 78 +++++++++++++++++++++++++++++++++++++++++ infra/test/mpls_eth.pcap | Bin 0 -> 471 bytes infra/test/mpls_pw.pcap | Bin 0 -> 159 bytes 4 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 infra/test/mpls_eth.pcap create mode 100644 infra/test/mpls_pw.pcap diff --git a/infra/src/ldbc.c b/infra/src/ldbc.c index f1e3fa1..0c90978 100644 --- a/infra/src/ldbc.c +++ b/infra/src/ldbc.c @@ -132,7 +132,7 @@ static const void * __complex_parser_ipv4(struct pkt_parser * handler, return data; struct ipv4_hdr * ipv4_hdr = (struct ipv4_hdr *)data; - unsigned int ipv4_hdr_len = (ipv4_hdr->version_ihl & 0xf) * 4; + unsigned int ipv4_hdr_len = (ipv4_hdr->version_ihl & 0xf) * 4u; void * data_next_layer = (uint8_t *)data + ipv4_hdr_len; switch (ipv4_hdr->next_proto_id) @@ -206,14 +206,41 @@ static const void * __complex_parser_mpls_uc(struct pkt_parser * handler, unsigned int mpls_bls = (ntohl(*_mpls_header) & MPLS_BLS_MASK) >> 8; void * data_next_layer = _mpls_header + 1; + uint8_t * __data_next_layer = (uint8_t *)data_next_layer; // 判断MPLS是否是最后一个,如果是,认为下一层是IPv4 - // TODO: 解析下一层协议类型。路由器是怎么解析的? - + // 下一层协议解析,参看Linux内核实现,直接判断IPv4/IPv6版本号。 + // 现网中遇到了MPLS后是以太头的报文,不符合RFC。现直接判断是否为v4/v6,否则按以太报文处理。 + // https://github.com/torvalds/linux/blob/9097a058d49e049925d8da72db07fffcee24efa0/drivers/net/tun.c#L1876 if (mpls_bls == 1) - { - return __complex_parser_ipv4(handler, data_next_layer, LAYER_TYPE_IPV4); - } + { + 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); + } + + /* PW Ethernet Control Word, + * 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |0 0 0 0| Reserved | Sequence Number | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * Reference: https://tools.ietf.org/html/rfc4448 + */ + else if(ip_version == 0) + { + return __complex_parser_ether(handler, data_next_layer + 4, LAYER_TYPE_ETHER); + } + else + { + return __complex_parser_ether(handler, data_next_layer, LAYER_TYPE_ETHER); + } + } // 如果不是,嵌套的MPLS标签,解下一个 else diff --git a/infra/test/TestPacketParser.cc b/infra/test/TestPacketParser.cc index 462526c..ce77505 100644 --- a/infra/test/TestPacketParser.cc +++ b/infra/test/TestPacketParser.cc @@ -183,6 +183,51 @@ static const unsigned char pkt94[98] = { 0x05, 0xb4 /* .. */ }; +/* Frame (119 bytes) + * 81.211.157.203 10.160.72.52 UDP 119 6564 → 13530 Len=39 + */ +static const unsigned char pkt_mpls_pw[119] = { + 0x18, 0x10, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x00, /* ........ */ + 0x00, 0x00, 0x04, 0x36, 0x88, 0x47, 0x93, 0x75, /* ...6.G.u */ + 0x0a, 0xff, 0x4a, 0xe5, 0x0a, 0xff, 0xc3, 0x60, /* ..J....` */ + 0x2b, 0xff, 0x00, 0x00, 0x00, 0x00, 0xd8, 0x49, /* +......I */ + 0x0b, 0xc0, 0x71, 0xca, 0x28, 0xa6, 0xdb, 0xee, /* ..q.(... */ + 0xb0, 0xd0, 0x81, 0x00, 0xa4, 0xad, 0x81, 0x00, /* ........ */ + 0xa1, 0x04, 0x08, 0x00, 0x45, 0xb8, 0x00, 0x43, /* ....E..C */ + 0x52, 0xee, 0x00, 0x00, 0x3e, 0x11, 0xe6, 0x91, /* R...>... */ + 0x51, 0xd3, 0x9d, 0xcb, 0x0a, 0xa0, 0x48, 0x34, /* Q.....H4 */ + 0x19, 0xa4, 0x34, 0xda, 0x00, 0x2f, 0x00, 0x00, /* ..4../.. */ + 0x8e, 0x2e, 0x09, 0x08, 0x02, 0x1b, 0x30, 0x0a, /* ......0. */ + 0x20, 0x88, 0xec, 0xfc, 0xcf, 0x2f, 0xa4, 0x3f, /* ..../.? */ + 0x59, 0x58, 0xb4, 0x05, 0x90, 0x84, 0x05, 0x0c, /* YX...... */ + 0x06, 0x86, 0x9e, 0x3b, 0x79, 0xa9, 0x0f, 0x0d, /* ...;y... */ + 0x11, 0x08, 0xf8, 0x64, 0x90, 0x32, 0x06 /* ...d.2. */ +}; + +/* Frame (143 bytes) + * 10.33.60.116 217.76.77.34 GTP 143 Standard query 0xc4a8 A config.inmobi.com + * */ +static const unsigned char pkt_mpls_eth[143] = { + 0x18, 0x10, 0x04, 0x00, 0x00, 0x1c, 0x00, 0x00, /* ........ */ + 0x00, 0x00, 0x04, 0x17, 0x88, 0x47, 0x40, 0x14, /* .....G@. */ + 0x41, 0xfd, 0x04, 0x27, 0x58, 0x6f, 0x9f, 0x8d, /* A..'Xo.. */ + 0x28, 0xa6, 0xdb, 0xee, 0xb0, 0x97, 0x81, 0x00, /* (....... */ + 0x01, 0x4d, 0x81, 0x00, 0x02, 0xc3, 0x88, 0x47, /* .M.....G */ + 0x08, 0x05, 0x21, 0xff, 0x45, 0x00, 0x00, 0x63, /* ..!.E..c */ + 0x86, 0xbe, 0x00, 0x00, 0xfd, 0x11, 0x54, 0x69, /* ......Ti */ + 0x51, 0xd3, 0x87, 0x91, 0x51, 0xd3, 0xb7, 0x2a, /* Q...Q..* */ + 0x08, 0x68, 0x08, 0x68, 0x00, 0x4f, 0x33, 0xa3, /* .h.h.O3. */ + 0x30, 0xff, 0x00, 0x3f, 0x0d, 0x24, 0x07, 0x59, /* 0..?.$.Y */ + 0x45, 0x00, 0x00, 0x3f, 0x7f, 0x24, 0x40, 0x00, /* E..?.$@. */ + 0x40, 0x11, 0x4e, 0x86, 0x0a, 0x21, 0x3c, 0x74, /* @.N..!data; \ @@ -260,6 +305,39 @@ TEST(PacketParseOuterL3, EtherIPv6) "3ffe:501:410:0:2c0:dfff:fe47:33e"); } +TEST(PacketParserOuterL3, EthernetOverMPLSWithPW) +{ + struct pkt_parser _pkt_mpls_handler; + _pkt_mpls_handler.expect_layer_type = LAYER_TYPE_L3; + _pkt_mpls_handler.nr_expect_results = 1; + _pkt_mpls_handler.nr_results = 0; + + ASSERT_TRUE(complex_parser_ether(&_pkt_mpls_handler, pkt_mpls_pw) != NULL); + EXPECT_EQ(_pkt_mpls_handler.nr_results, 1); + + struct pkt_parser_result * result = &_pkt_mpls_handler.results[0]; + EXPECT_EQ(result->this_layer_type, LAYER_TYPE_IPV4); + EXPECT_TRUE(result->data != NULL); + + TestCheckIPv4Addr(result, "81.211.157.203", "10.160.72.52"); +} + +TEST(PacketParserOuterL3, EthernetOverMPLSWithoutPW) +{ + struct pkt_parser _pkt_mpls_handler; + _pkt_mpls_handler.expect_layer_type = LAYER_TYPE_L3; + _pkt_mpls_handler.nr_expect_results = 1; + _pkt_mpls_handler.nr_results = 0; + + ASSERT_TRUE(complex_parser_ether(&_pkt_mpls_handler, pkt_mpls_eth) != NULL); + EXPECT_EQ(_pkt_mpls_handler.nr_results, 1); + + struct pkt_parser_result * result = &_pkt_mpls_handler.results[0]; + EXPECT_EQ(result->this_layer_type, LAYER_TYPE_IPV4); + EXPECT_TRUE(result->data != NULL); + TestCheckIPv4Addr(result, "81.211.135.145", "81.211.183.42"); +} + TEST(PacketParseOuterL4, EtherIPv4TCP) { struct pkt_parser _pkt_031_handler; diff --git a/infra/test/mpls_eth.pcap b/infra/test/mpls_eth.pcap new file mode 100644 index 0000000..906d788 Binary files /dev/null and b/infra/test/mpls_eth.pcap differ diff --git a/infra/test/mpls_pw.pcap b/infra/test/mpls_pw.pcap new file mode 100644 index 0000000..efa273b Binary files /dev/null and b/infra/test/mpls_pw.pcap differ -- cgit v1.2.3