#include #include #include #include #define __FAVOR_BSD 1 #include #include #include #include #include "uthash.h" #include "packet.h" #include "udp_utils.h" #include "tcp_utils.h" #include "ipv4_utils.h" #include "ipv6_utils.h" #define likely(expr) __builtin_expect((expr), 1) #define unlikely(expr) __builtin_expect((expr), 0) #define PACKET_LOG_DATA_INSUFFICIENCY(type) \ { \ PACKET_LOG_ERROR("layer: %s, data insufficiency", \ layer_type_to_str((type))); \ } #define PACKET_LOG_UNSUPPORT_PROTO(tag, next_proto) \ { \ PACKET_LOG_ERROR("%s: unsupport next proto %d", \ (tag), (next_proto)); \ } #define PACKET_LOG_UNSUPPORT_ETHPROTO(tag, next_proto) \ { \ PACKET_LOG_ERROR("%s: unsupport next proto %d: %s", \ (tag), (next_proto), ethproto_to_str(next_proto)); \ } #define PACKET_LOG_UNSUPPORT_IPPROTO(tag, next_proto) \ { \ PACKET_LOG_ERROR("%s: unsupport next proto %d: %s", \ (tag), (next_proto), ipproto_to_str(next_proto)); \ } /****************************************************************************** * Static API ******************************************************************************/ static const char *ethproto_to_str(uint16_t proto); static const char *ipproto_to_str(uint16_t proto); static inline const char *ldbc_method_to_str(enum ldbc_method method); static inline const char *layer_type_to_str(enum layer_type type); static inline void set_tuple2(const char *data, enum layer_type type, struct tuple2 *tuple); static inline void set_tuple4(const char *data, enum layer_type type, struct tuple4 *tuple); static inline void set_tuple6(const char *data, enum layer_type type, struct tuple6 *tuple, uint64_t domain); static inline struct layer *get_free_layer(struct packet *pkt); static inline uint16_t get_gtp_hdr_len(const char *data, uint16_t len); static inline uint16_t get_gre_hdr_len(const char *data, uint16_t len); // 数据链路层 static inline const char *parse_ether(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16_t len); // 数据链路层 -- 隧道 static inline const char *parse_vlan(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_mpls(struct packet *pkt, const char *data, uint16_t len); // 网络层 static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint16_t len); // 网络层 -- 隧道 static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len); // 传输层 static inline const char *parse_udp(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len); // 传输层 -- 隧道 static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len); static inline const char *parse_gtpv1_u(struct packet *pkt, const char *data, uint16_t len); // L3/L4 static inline const char *parse_l3(struct packet *pkt, uint16_t next_proto, const char *data, uint16_t len); static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const char *data, uint16_t len); /****************************************************************************** * Private API -- Utils ******************************************************************************/ static const char *ethproto_to_str(uint16_t proto) { switch (proto) { case ETH_P_LOOP: return "LOOP"; case ETH_P_PUP: return "PUP"; case ETH_P_PUPAT: return "PUPAT"; case ETH_P_IP: return "IP"; case ETH_P_X25: return "X25"; case ETH_P_ARP: return "ARP"; case ETH_P_BPQ: return "BPQ"; case ETH_P_IEEEPUP: return "IEEEPUP"; case ETH_P_IEEEPUPAT: return "IEEEPUPAT"; case ETH_P_DEC: return "DEC"; case ETH_P_DNA_DL: return "DNA_DL"; case ETH_P_DNA_RC: return "DNA_RC"; case ETH_P_DNA_RT: return "DNA_RT"; case ETH_P_LAT: return "LAT"; case ETH_P_DIAG: return "DIAG"; case ETH_P_CUST: return "CUST"; case ETH_P_SCA: return "SCA"; case ETH_P_TEB: return "TEB"; case ETH_P_RARP: return "RARP"; case ETH_P_ATALK: return "ATALK"; case ETH_P_AARP: return "AARP"; case ETH_P_8021Q: return "8021Q"; case ETH_P_IPX: return "IPX"; case ETH_P_IPV6: return "IPV6"; case ETH_P_PAUSE: return "PAUSE"; case ETH_P_SLOW: return "SLOW"; case ETH_P_WCCP: return "WCCP"; case ETH_P_PPP_DISC: return "PPP_DISC"; case ETH_P_PPP_SES: return "PPP_SES"; case ETH_P_MPLS_UC: return "MPLS_UC"; case ETH_P_MPLS_MC: return "MPLS_MC"; case ETH_P_ATMMPOA: return "ATMMPOA"; case ETH_P_LINK_CTL: return "LINK_CTL"; case ETH_P_ATMFATE: return "ATMFATE"; case ETH_P_PAE: return "PAE"; case ETH_P_AOE: return "AOE"; case ETH_P_8021AD: return "8021AD"; case ETH_P_802_EX1: return "802_EX1"; case ETH_P_TIPC: return "TIPC"; case ETH_P_8021AH: return "8021AH"; case ETH_P_1588: return "1588"; case ETH_P_FCOE: return "FCOE"; case ETH_P_TDLS: return "TDLS"; case ETH_P_FIP: return "FIP"; case ETH_P_QINQ1: return "QINQ1"; case ETH_P_QINQ2: return "QINQ2"; case ETH_P_QINQ3: return "QINQ3"; case ETH_P_EDSA: return "EDSA"; case ETH_P_AF_IUCV: return "AF_IUCV"; default: return "UNKNOWN"; } } static const char *ipproto_to_str(uint16_t proto) { switch (proto) { case IPPROTO_IP: return "IP"; case IPPROTO_ICMP: return "ICMP"; case IPPROTO_IGMP: return "IGMP"; case IPPROTO_IPIP: return "IPIP"; case IPPROTO_TCP: return "TCP"; case IPPROTO_EGP: return "EGP"; case IPPROTO_PUP: return "PUP"; case IPPROTO_UDP: return "UDP"; case IPPROTO_IDP: return "IDP"; case IPPROTO_TP: return "TP"; case IPPROTO_DCCP: return "DCCP"; case IPPROTO_IPV6: return "IPV6"; case IPPROTO_ROUTING: return "ROUTING"; case IPPROTO_FRAGMENT: return "FRAGMENT"; case IPPROTO_RSVP: return "RSVP"; case IPPROTO_GRE: return "GRE"; case IPPROTO_ESP: return "ESP"; case IPPROTO_AH: return "AH"; case IPPROTO_ICMPV6: return "ICMPV6"; case IPPROTO_NONE: return "NONE"; case IPPROTO_DSTOPTS: return "DSTOPTS"; case IPPROTO_MTP: return "MTP"; case IPPROTO_ENCAP: return "ENCAP"; case IPPROTO_PIM: return "PIM"; case IPPROTO_COMP: return "COMP"; case IPPROTO_SCTP: return "SCTP"; case IPPROTO_UDPLITE: return "UDPLITE"; case IPPROTO_RAW: return "RAW"; default: return "UNKNOWN"; } } static inline const char *ldbc_method_to_str(enum ldbc_method method) { switch (method) { case LDBC_METHOD_HASH_INT_IP: return "outter_internal_ip"; case LDBC_METHOD_HASH_EXT_IP: return "outter_external_ip"; case LDBC_METHOD_HASH_INT_IP_AND_EXT_IP: return "outter_internal_ip_and_external_ip"; case LDBC_METHOD_HASH_INNERMOST_INT_IP: return "inner_internal_ip"; case LDBC_METHOD_HASH_INNERMOST_EXT_IP: return "inner_external_ip"; default: return "unknown"; } } static inline const char *layer_type_to_str(enum layer_type type) { switch (type) { case LAYER_TYPE_ETHER: return "ETH"; case LAYER_TYPE_PPP: return "PPP"; case LAYER_TYPE_HDLC: return "HDLC"; case LAYER_TYPE_VLAN: return "VLAN"; case LAYER_TYPE_PPPOE: return "PPPOE"; case LAYER_TYPE_MPLS: return "MPLS"; case LAYER_TYPE_IPV4: return "IPV4"; case LAYER_TYPE_IPV6: return "IPV6"; case LAYER_TYPE_GRE: return "GRE"; case LAYER_TYPE_UDP: return "UDP"; case LAYER_TYPE_TCP: return "TCP"; case LAYER_TYPE_VXLAN: return "VXLAN"; case LAYER_TYPE_GTPV1_U: return "GTPV1"; default: return "UNKNOWN"; } } static inline void set_tuple2(const char *data, enum layer_type type, struct tuple2 *tuple) { const struct ip *ipv4 = NULL; const struct ip6_hdr *ipv6 = NULL; switch (type) { case LAYER_TYPE_IPV4: ipv4 = (const struct ip *)data; tuple->ip_type = IP_TYPE_V4; tuple->src_addr.v4.s_addr = ipv4->ip_src.s_addr; tuple->dst_addr.v4.s_addr = ipv4->ip_dst.s_addr; break; case LAYER_TYPE_IPV6: ipv6 = (const struct ip6_hdr *)data; tuple->ip_type = IP_TYPE_V6; tuple->src_addr.v6 = ipv6->ip6_src; tuple->dst_addr.v6 = ipv6->ip6_dst; break; default: break; } } static inline void set_tuple4(const char *data, enum layer_type type, struct tuple4 *tuple) { const struct ip *ipv4 = NULL; const struct ip6_hdr *ipv6 = NULL; const struct tcphdr *tcp = NULL; const struct udphdr *udp = NULL; switch (type) { case LAYER_TYPE_TCP: tcp = (const struct tcphdr *)data; tuple->src_port = tcp->th_sport; tuple->dst_port = tcp->th_dport; break; case LAYER_TYPE_UDP: udp = (const struct udphdr *)data; tuple->src_port = udp->uh_sport; tuple->dst_port = udp->uh_dport; break; case LAYER_TYPE_IPV4: ipv4 = (const struct ip *)data; tuple->ip_type = IP_TYPE_V4; tuple->src_addr.v4.s_addr = ipv4->ip_src.s_addr; tuple->dst_addr.v4.s_addr = ipv4->ip_dst.s_addr; break; case LAYER_TYPE_IPV6: ipv6 = (const struct ip6_hdr *)data; tuple->ip_type = IP_TYPE_V6; tuple->src_addr.v6 = ipv6->ip6_src; tuple->dst_addr.v6 = ipv6->ip6_dst; break; default: break; } } static inline void set_tuple6(const char *data, enum layer_type type, struct tuple6 *tuple, uint64_t domain) { const struct ip *ipv4 = NULL; const struct ip6_hdr *ipv6 = NULL; const struct tcphdr *tcp = NULL; const struct udphdr *udp = NULL; tuple->domain = domain; switch (type) { case LAYER_TYPE_TCP: tcp = (const struct tcphdr *)data; tuple->ip_proto = IPPROTO_TCP; tuple->src_port = tcp->th_sport; tuple->dst_port = tcp->th_dport; break; case LAYER_TYPE_UDP: udp = (const struct udphdr *)data; tuple->ip_proto = IPPROTO_UDP; tuple->src_port = udp->uh_sport; tuple->dst_port = udp->uh_dport; break; case LAYER_TYPE_IPV4: ipv4 = (const struct ip *)data; tuple->ip_type = IP_TYPE_V4; tuple->src_addr.v4.s_addr = ipv4->ip_src.s_addr; tuple->dst_addr.v4.s_addr = ipv4->ip_dst.s_addr; break; case LAYER_TYPE_IPV6: ipv6 = (const struct ip6_hdr *)data; tuple->ip_type = IP_TYPE_V6; tuple->src_addr.v6 = ipv6->ip6_src; tuple->dst_addr.v6 = ipv6->ip6_dst; break; default: break; } } static inline struct layer *get_free_layer(struct packet *pkt) { if (pkt->layers_used >= pkt->layers_size) { return NULL; } return &pkt->layers[pkt->layers_used]; } #define SET_LAYER(_pkt, _layer, _type, _hdr_len, _data, _len) \ { \ (_layer)->type = (_type); \ (_layer)->hdr_offset = (_pkt)->data_len - (_len); \ (_layer)->hdr_ptr = (_data); \ (_layer)->hdr_len = (_hdr_len); \ (_layer)->pld_ptr = (_data) + (_hdr_len); \ (_layer)->pld_len = (_len) - (_hdr_len); \ (_pkt)->layers_used++; \ PACKET_LOG_DEBUG("layer[%d/%d]: %s, hdr_offset: %d, hdr_ptr: %p, hdr_len: %d, pld_ptr: %p, pld_len: %d", \ (_pkt)->layers_used - 1, (_pkt)->layers_size, layer_type_to_str((_type)), \ (_layer)->hdr_offset, (_layer)->hdr_ptr, (_layer)->hdr_len, (_layer)->pld_ptr, (_layer)->pld_len); \ } /****************************************************************************** * Private API -- Parses ******************************************************************************/ static inline uint16_t get_gtp_hdr_len(const char *data, uint16_t len) { #define GTP_HDR_VER (0xE0) #define GTP_HDR_FLAG_N_PDU (0x01) #define GTP_HDR_FLAG_SEQ_NUM (0x02) #define GTP_HDR_FLAG_EXT_HDR (0x04) struct gtp_hdr { uint8_t flags; uint8_t msg_type; uint16_t msg_len; uint32_t teid; } __attribute__((__packed__)); struct gtp_opt { uint16_t seq_num; uint8_t npdu; uint8_t next_ext_hdr; } __attribute__((__packed__)); uint16_t hdr_offset = 0; if (len < sizeof(struct gtp_hdr)) { return 0; } const struct gtp_hdr *gtp = (const struct gtp_hdr *)data; hdr_offset += sizeof(struct gtp_hdr); // skip gre hdr // GTPv0 Not Supported if (((gtp->flags & GTP_HDR_VER) >> 5) != 1) { return 0; } if (gtp->flags & (GTP_HDR_FLAG_SEQ_NUM | GTP_HDR_FLAG_N_PDU | GTP_HDR_FLAG_EXT_HDR)) { if (hdr_offset + sizeof(struct gtp_opt) > len) { return 0; } struct gtp_opt *opt_hdr = (struct gtp_opt *)((char *)data + hdr_offset); uint8_t next_ext_hdr = opt_hdr->next_ext_hdr; hdr_offset += sizeof(struct gtp_opt); // skip gre opt while (next_ext_hdr) { if (hdr_offset + 1 > len) { return 0; } uint8_t length = *((char *)data + hdr_offset) * 4 - 2; hdr_offset += 1; // skip length field if (hdr_offset + length + 1 > len) { return 0; } hdr_offset += length; // skip data field next_ext_hdr = *((char *)data + hdr_offset); hdr_offset += 1; // skip next ext hdr field } } return hdr_offset; } static inline uint16_t get_gre_hdr_len(const char *data, uint16_t len) { /* * GRE Header Format (Version 0) * * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |C|R|K|S|s|Recur| Flags | Ver | Protocol Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Checksum (optional) | Offset (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Key (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sequence Number (optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Routing (optional) * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Address Family | SRE Offset | SRE Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Routing Information ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * https://datatracker.ietf.org/doc/html/rfc1701 * https://datatracker.ietf.org/doc/html/rfc2890 */ /* * Enhanced GRE header (Version 1) * * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * |C|R|K|S|s|Recur|A| Flags | Ver | Protocol Type | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Key (HW) Payload Length | Key (LW) Call ID | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Sequence Number (Optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Acknowledgment Number (Optional) | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * * https://datatracker.ietf.org/doc/html/rfc2637 */ /* bit positions for flags in header */ #define GRE_CHECKSUM 0x8000 #define GRE_ROUTING 0x4000 #define GRE_KEY 0x2000 #define GRE_SEQUENCE 0x1000 #define GRE_STRICTSOURCE 0x0800 #define GRE_RECURSION 0x0700 #define GRE_ACK 0x0080 /* only in special PPTPized GRE header */ #define GRE_RESERVED_PPP 0x0078 /* only in special PPTPized GRE header */ #define GRE_RESERVED 0x00F8 #define GRE_VERSION 0x0007 if (len < 4) { return 0; } struct SRE { uint16_t address_family; uint8_t sre_offset; uint8_t sre_length; } __attribute__((__packed__)); uint16_t sre_size = sizeof(struct SRE); const uint16_t *gre = (const uint16_t *)data; uint16_t flags = ntohs(gre[0]); uint16_t version = flags & GRE_VERSION; uint16_t hdr_offset = 0; if (version == 0) { hdr_offset = 4; if ((flags & GRE_CHECKSUM) || (flags & GRE_ROUTING)) { hdr_offset += 4; } if (flags & GRE_KEY) { hdr_offset += 4; } if (flags & GRE_SEQUENCE) { hdr_offset += 4; } if (flags & GRE_ROUTING) { while (hdr_offset + sre_size <= len) { struct SRE *sre = (struct SRE *)((char *)data + hdr_offset); if (sre->sre_length == 0) { hdr_offset += sre_size; break; } else { hdr_offset += sre_size + sre->sre_length; } } } } if (version == 1) { hdr_offset = 8; if (flags & GRE_SEQUENCE) { hdr_offset += 4; } if (flags & GRE_ACK) { hdr_offset += 4; } } if (hdr_offset > len) { return 0; } return hdr_offset; } static inline const char *parse_ether(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < sizeof(struct ethhdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_ETHER); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t next_proto = ntohs(((struct ethhdr *)data)->h_proto); SET_LAYER(pkt, layer, LAYER_TYPE_ETHER, sizeof(struct ethhdr), data, len); // TESTED return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len); } static inline const char *parse_ppp(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < 4)) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_PPP); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t next_proto = ntohs(*((uint16_t *)data + 1)); SET_LAYER(pkt, layer, LAYER_TYPE_PPP, 4, data, len); switch (next_proto) { // TESTED case PPP_IP: return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len); case PPP_IPV6: return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len); default: PACKET_LOG_UNSUPPORT_PROTO("ppp", next_proto); return layer->pld_ptr; } } static inline const char *parse_vlan(struct packet *pkt, const char *data, uint16_t len) { struct vlan_hdr { uint16_t vlan_cfi; uint16_t protocol; } __attribute__((__packed__)); if (unlikely(len < sizeof(struct vlan_hdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_VLAN); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t next_proto = ntohs(((struct vlan_hdr *)data)->protocol); SET_LAYER(pkt, layer, LAYER_TYPE_VLAN, sizeof(struct vlan_hdr), data, len); // TESTED return parse_l3(pkt, next_proto, layer->pld_ptr, layer->pld_len); } static inline const char *parse_pppoe_ses(struct packet *pkt, const char *data, uint16_t len) { #define PPPOE_TYPE_IPV4 0x2100 #define PPPOE_TYPE_IPV6 0x5700 if (unlikely(len < 8)) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_PPPOE); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t next_proto = *((uint16_t *)data + 3); SET_LAYER(pkt, layer, LAYER_TYPE_PPPOE, 8, data, len); switch (next_proto) { // TESTED case PPPOE_TYPE_IPV4: return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len); case PPPOE_TYPE_IPV6: return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len); default: PACKET_LOG_UNSUPPORT_PROTO("pppoe", next_proto); return layer->pld_ptr; } } static inline const char *parse_mpls(struct packet *pkt, const char *data, uint16_t len) { /* * MPLS Format * 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Label | Exp |S| TTL | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * Label : Label Value 20 bits * Exp : Experimental Use 3 bits * S : Bottom of Stack 1 bit * TTL : Time to Live 8 bits */ #define MPLS_LABEL_MASK (0xFFFFF000) #define MPLS_EXP_MASK (0x00000E00) #define MPLS_BLS_MASK (0x00000100) #define MPLS_TTL_MASK (0x000000FF) enum mpls_next_proto { MPLS_NEXT_PROTO_ETHER = 0x0, MPLS_NEXT_PROTO_MPLS = 0x1, MPLS_NEXT_PROTO_IPV4 = 0x4, MPLS_NEXT_PROTO_IPV6 = 0x6, }; // 4 + 1 if (unlikely(len < 5)) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_MPLS); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t hdr_len = 4; uint32_t *hdr = (uint32_t *)data; unsigned int mpls_bls = (ntohl(*hdr) & MPLS_BLS_MASK) >> 8; enum mpls_next_proto next_proto; if (mpls_bls == 1) { switch ((((uint8_t *)(data + 4))[0]) >> 4) { case 0: /* * 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 */ hdr_len += 4; // skip PW Ethernet Control Word next_proto = MPLS_NEXT_PROTO_ETHER; break; case 4: next_proto = MPLS_NEXT_PROTO_IPV4; break; case 6: next_proto = MPLS_NEXT_PROTO_IPV6; break; default: next_proto = MPLS_NEXT_PROTO_ETHER; break; } } else { next_proto = MPLS_NEXT_PROTO_MPLS; } SET_LAYER(pkt, layer, LAYER_TYPE_MPLS, hdr_len, data, len); switch (next_proto) { // TESTED case MPLS_NEXT_PROTO_IPV4: return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len); case MPLS_NEXT_PROTO_IPV6: return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len); // TESTED case MPLS_NEXT_PROTO_ETHER: return parse_ether(pkt, layer->pld_ptr, layer->pld_len); // TESTED case MPLS_NEXT_PROTO_MPLS: return parse_mpls(pkt, layer->pld_ptr, layer->pld_len); default: // unreachable return layer->pld_ptr; } } static inline const char *parse_ipv4(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < sizeof(struct ip))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_IPV4); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } struct ip *hdr = (struct ip *)data; uint8_t next_proto = ipv4_hdr_get_proto(hdr); uint16_t hdr_len = ipv4_hdr_get_hdr_len(hdr); SET_LAYER(pkt, layer, LAYER_TYPE_IPV4, hdr_len, data, len); // ip fragmented if (ipv4_hdr_get_mf_flag(hdr) || ipv4_hdr_get_frag_offset(hdr)) { PACKET_LOG_DEBUG("ip is fragmented"); pkt->frag_layer = layer; return layer->pld_ptr; } // TESTED return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len); } static inline const char *parse_ipv6(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < sizeof(struct ip6_hdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_IPV6); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint8_t next_proto = ipv6_hdr_get_next_header((const struct ip6_hdr *)data); SET_LAYER(pkt, layer, LAYER_TYPE_IPV6, sizeof(struct ip6_hdr), data, len); // ipv6 fragment if (next_proto == IPPROTO_FRAGMENT) { PACKET_LOG_DEBUG("ipv6 is fragmented"); pkt->frag_layer = layer; return layer->pld_ptr; } // TESTED return parse_l4(pkt, next_proto, layer->pld_ptr, layer->pld_len); } static inline const char *parse_gre(struct packet *pkt, const char *data, uint16_t len) { #define GRE_PRO_IPV4 (0x0800) #define GRE_PRO_IPV6 (0x86DD) #define GRE_PRO_ARP (0x0806) #define GRE_PRO_PPP (0x880B) uint16_t hdr_len = get_gre_hdr_len(data, len); if (unlikely(hdr_len == 0)) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_GRE); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t next_proto = ntohs(*((uint16_t *)data + 1)); SET_LAYER(pkt, layer, LAYER_TYPE_GRE, hdr_len, data, len); switch (next_proto) { case GRE_PRO_IPV4: return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len); case GRE_PRO_IPV6: return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len); // TESTED case GRE_PRO_PPP: return parse_ppp(pkt, layer->pld_ptr, layer->pld_len); default: PACKET_LOG_UNSUPPORT_PROTO("gre", next_proto); return layer->pld_ptr; } } static inline const char *parse_udp(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < sizeof(struct udphdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_UDP); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } struct udphdr *hdr = (struct udphdr *)data; SET_LAYER(pkt, layer, LAYER_TYPE_UDP, sizeof(struct udphdr), data, len); if (udp_hdr_get_dst_port(hdr) == 4789) { // TESTED // VXLAN_DPORT 4789 return parse_vxlan(pkt, layer->pld_ptr, layer->pld_len); } if (udp_hdr_get_dst_port(hdr) == 2152 || udp_hdr_get_src_port(hdr) == 2152) { // TESTED // GTP1U_PORT 2152 return parse_gtpv1_u(pkt, layer->pld_ptr, layer->pld_len); } return layer->pld_ptr; } static inline const char *parse_tcp(struct packet *pkt, const char *data, uint16_t len) { if (unlikely(len < sizeof(struct tcphdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_TCP); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint16_t hdr_len = tcp_hdr_get_hdr_len((struct tcphdr *)data); SET_LAYER(pkt, layer, LAYER_TYPE_TCP, hdr_len, data, len); return layer->pld_ptr; } static inline const char *parse_vxlan(struct packet *pkt, const char *data, uint16_t len) { struct vxlan_hdr { uint8_t flags[2]; uint16_t gdp; uint8_t vni[3]; uint8_t reserved; } __attribute__((__packed__)); if (unlikely(len < sizeof(struct vxlan_hdr))) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_VXLAN); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } SET_LAYER(pkt, layer, LAYER_TYPE_VXLAN, sizeof(struct vxlan_hdr), data, len); // TESTED return parse_ether(pkt, layer->pld_ptr, layer->pld_len); } static inline const char *parse_gtpv1_u(struct packet *pkt, const char *data, uint16_t len) { uint16_t hdr_len = get_gtp_hdr_len(data, len); if (unlikely(hdr_len == 0)) { PACKET_LOG_DATA_INSUFFICIENCY(LAYER_TYPE_GTPV1_U); return data; } struct layer *layer = get_free_layer(pkt); if (unlikely(layer == NULL)) { return data; } uint8_t next_proto = (((const uint8_t *)(data + hdr_len))[0]) >> 4; SET_LAYER(pkt, layer, LAYER_TYPE_GTPV1_U, hdr_len, data, len); switch (next_proto) { // TESTED case 4: return parse_ipv4(pkt, layer->pld_ptr, layer->pld_len); // TESTED case 6: return parse_ipv6(pkt, layer->pld_ptr, layer->pld_len); default: PACKET_LOG_UNSUPPORT_PROTO("gtp", next_proto); return layer->pld_ptr; } } static inline const char *parse_l3(struct packet *pkt, uint16_t next_proto, const char *data, uint16_t len) { switch (next_proto) { // TESTED case ETH_P_8021Q: case ETH_P_8021AD: return parse_vlan(pkt, data, len); // TESTED case ETH_P_IP: return parse_ipv4(pkt, data, len); // TESTED case ETH_P_IPV6: return parse_ipv6(pkt, data, len); // TESTED case ETH_P_PPP_SES: return parse_pppoe_ses(pkt, data, len); // TESTED case ETH_P_MPLS_UC: return parse_mpls(pkt, data, len); default: // TESTED ARP PACKET_LOG_UNSUPPORT_ETHPROTO("l3", next_proto); return data; } } static inline const char *parse_l4(struct packet *pkt, uint8_t next_proto, const char *data, uint16_t len) { switch (next_proto) { // TESTED case IPPROTO_TCP: return parse_tcp(pkt, data, len); // TESTED case IPPROTO_UDP: return parse_udp(pkt, data, len); // TESTED case IPPROTO_IPIP: return parse_ipv4(pkt, data, len); // TESTED case IPPROTO_IPV6: return parse_ipv6(pkt, data, len); // TESTED case IPPROTO_GRE: return parse_gre(pkt, data, len); default: PACKET_LOG_UNSUPPORT_IPPROTO("l4", next_proto); return data; } } /****************************************************************************** * Public API ******************************************************************************/ // return innermost payload const char *packet_parse(struct packet *pkt, const char *data, uint16_t len) { pkt->frag_layer = NULL; pkt->layers_used = 0; pkt->layers_size = PACKET_MAX_LAYERS; pkt->data_ptr = data; pkt->data_len = len; memset(&pkt->meta, 0, sizeof(struct metadata)); // TESTED return parse_ether(pkt, data, len); } void packet_print(const struct packet *pkt) { if (pkt == NULL) { return; } printf("packet: %p, data_ptr: %p, data_len: %u, layers_used: %u, layers_size: %u\n", pkt, pkt->data_ptr, pkt->data_len, pkt->layers_used, pkt->layers_size); for (uint8_t i = 0; i < pkt->layers_used; i++) { const struct layer *layer = &pkt->layers[i]; printf(" layer[%u]: %p, type: %s, hdr_offset: %u, hdr_ptr: %p, hdr_len: %u, pld_ptr: %p, pld_len: %u\n", i, layer, layer_type_to_str(layer->type), layer->hdr_offset, layer->hdr_ptr, layer->hdr_len, layer->pld_ptr, layer->pld_len); } for (uint16_t i = 0; i < pkt->data_len; i++) { printf("0x%02x, ", (uint8_t)pkt->data_ptr[i]); } printf("\n"); } // return 0 : found // return -1 : not found int packet_get_innermost_tuple2(const struct packet *pkt, struct tuple2 *tuple) { memset(tuple, 0, sizeof(struct tuple2)); const struct layer *layer = NULL; for (int8_t i = pkt->layers_used - 1; i >= 0; i--) { layer = &pkt->layers[i]; if (layer->type & LAYER_TYPE_L3) { set_tuple2((const char *)pkt->data_ptr + layer->hdr_offset, layer->type, tuple); return 0; } } return -1; } // return 0 : found // return -1 : not found int packet_get_outermost_tuple2(const struct packet *pkt, struct tuple2 *tuple) { memset(tuple, 0, sizeof(struct tuple2)); const struct layer *layer = NULL; for (int8_t i = 0; i < pkt->layers_used; i++) { layer = &pkt->layers[i]; if (layer->type & LAYER_TYPE_L3) { set_tuple2((const char *)pkt->data_ptr + layer->hdr_offset, layer->type, tuple); return 0; } } return -1; } // return 0 : found // return -1 : not found int packet_get_innermost_tuple4(const struct packet *pkt, struct tuple4 *tuple) { memset(tuple, 0, sizeof(struct tuple4)); const struct layer *layer_l3 = NULL; const struct layer *layer_l4 = NULL; const struct layer *layer = NULL; for (int8_t i = pkt->layers_used - 1; i >= 0; i--) { layer = &pkt->layers[i]; // first get L4 layer if (layer->type & LAYER_TYPE_L4) { layer_l4 = layer; continue; } // second get L3 layer if (layer->type & LAYER_TYPE_L3) { layer_l3 = layer; break; } } if (layer_l3 && layer_l4) { set_tuple4((const char *)pkt->data_ptr + layer_l3->hdr_offset, layer_l3->type, tuple); set_tuple4((const char *)pkt->data_ptr + layer_l4->hdr_offset, layer_l4->type, tuple); return 0; } else { return -1; } } // return 0 : found // return -1 : not found int packet_get_outermost_tuple4(const struct packet *pkt, struct tuple4 *tuple) { memset(tuple, 0, sizeof(struct tuple4)); const struct layer *layer_l3 = NULL; const struct layer *layer_l4 = NULL; const struct layer *layer = NULL; for (int8_t i = 0; i < pkt->layers_used; i++) { layer = &pkt->layers[i]; // first get L3 layer if (layer->type & LAYER_TYPE_L3) { layer_l3 = layer; continue; } // second get L4 layer if (layer->type & LAYER_TYPE_L4) { layer_l4 = layer; break; } } if (layer_l3 && layer_l4) { set_tuple4((const char *)pkt->data_ptr + layer_l3->hdr_offset, layer_l3->type, tuple); set_tuple4((const char *)pkt->data_ptr + layer_l4->hdr_offset, layer_l4->type, tuple); return 0; } else { return -1; } } // return 0 : found // return -1 : not found int packet_get_innermost_tuple6(const struct packet *pkt, struct tuple6 *tuple) { memset(tuple, 0, sizeof(struct tuple6)); const struct layer *layer_l3 = NULL; const struct layer *layer_l4 = NULL; const struct layer *layer = NULL; const struct metadata *meta = &pkt->meta; for (int8_t i = pkt->layers_used - 1; i >= 0; i--) { layer = &pkt->layers[i]; // first get L4 layer if (layer->type & LAYER_TYPE_L4) { layer_l4 = layer; continue; } // second get L3 layer if (layer->type & LAYER_TYPE_L3) { layer_l3 = layer; break; } } if (layer_l3 && layer_l4) { set_tuple6((const char *)pkt->data_ptr + layer_l3->hdr_offset, layer_l3->type, tuple, meta->domain); set_tuple6((const char *)pkt->data_ptr + layer_l4->hdr_offset, layer_l4->type, tuple, meta->domain); return 0; } else { return -1; } } // return 0 : found // return -1 : not found int packet_get_outermost_tuple6(const struct packet *pkt, struct tuple6 *tuple) { memset(tuple, 0, sizeof(struct tuple6)); const struct layer *layer_l3 = NULL; const struct layer *layer_l4 = NULL; const struct layer *layer = NULL; const struct metadata *meta = &pkt->meta; for (int8_t i = 0; i < pkt->layers_used; i++) { layer = &pkt->layers[i]; // first get L3 layer if (layer->type & LAYER_TYPE_L3) { layer_l3 = layer; continue; } // second get L4 layer if (layer->type & LAYER_TYPE_L4) { layer_l4 = layer; break; } } if (layer_l3 && layer_l4) { set_tuple6((const char *)pkt->data_ptr + layer_l3->hdr_offset, layer_l3->type, tuple, meta->domain); set_tuple6((const char *)pkt->data_ptr + layer_l4->hdr_offset, layer_l4->type, tuple, meta->domain); return 0; } else { return -1; } } const struct layer *packet_get_innermost_layer(const struct packet *pkt, enum layer_type type) { const struct layer *layer = NULL; for (int8_t i = pkt->layers_used - 1; i >= 0; i--) { layer = &pkt->layers[i]; if (layer->type & type) { return layer; } } return NULL; } const struct layer *packet_get_outermost_layer(const struct packet *pkt, enum layer_type type) { const struct layer *layer = NULL; for (int8_t i = 0; i < pkt->layers_used; i++) { layer = &pkt->layers[i]; if (layer->type & type) { return layer; } } return NULL; } // direction 1: E2I // direction 0: I2E uint64_t packet_get_hash(const struct packet *pkt, enum ldbc_method method, int direction) { uint64_t temp = 0; uint64_t hash_value = 1; int inner_addr_len = 0; int outer_addr_len = 0; const char *inner_src_addr = NULL; const char *inner_dst_addr = NULL; const char *outer_src_addr = NULL; const char *outer_dst_addr = NULL; struct tuple2 inner_addr; struct tuple2 outer_addr; if (pkt == NULL) { return hash_value; } if (packet_get_innermost_tuple2(pkt, &inner_addr) == -1) { return hash_value; } if (packet_get_outermost_tuple2(pkt, &outer_addr) == -1) { return hash_value; } if (inner_addr.ip_type == IP_TYPE_V4) { inner_src_addr = (const char *)&inner_addr.src_addr.v4; inner_dst_addr = (const char *)&inner_addr.dst_addr.v4; inner_addr_len = sizeof(struct in_addr); } else { inner_src_addr = (const char *)&inner_addr.src_addr.v6; inner_dst_addr = (const char *)&inner_addr.dst_addr.v6; inner_addr_len = sizeof(struct in6_addr); } if (outer_addr.ip_type == IP_TYPE_V4) { outer_src_addr = (const char *)&outer_addr.src_addr.v4; outer_dst_addr = (const char *)&outer_addr.dst_addr.v4; outer_addr_len = sizeof(struct in_addr); } else { outer_src_addr = (const char *)&outer_addr.src_addr.v6; outer_dst_addr = (const char *)&outer_addr.dst_addr.v6; outer_addr_len = sizeof(struct in6_addr); } switch (method) { case LDBC_METHOD_HASH_INT_IP: if (direction) { // direction 1: E2I HASH_VALUE(outer_dst_addr, outer_addr_len, hash_value); } else { // direction 0: I2E HASH_VALUE(outer_src_addr, outer_addr_len, hash_value); } break; case LDBC_METHOD_HASH_EXT_IP: if (direction) { // direction 1: E2I HASH_VALUE(outer_src_addr, outer_addr_len, hash_value); } else { // direction 0: I2E HASH_VALUE(outer_dst_addr, outer_addr_len, hash_value); } break; case LDBC_METHOD_HASH_INT_IP_AND_EXT_IP: HASH_VALUE(outer_src_addr, outer_addr_len, hash_value); HASH_VALUE(outer_dst_addr, outer_addr_len, temp); hash_value = hash_value ^ temp; break; case LDBC_METHOD_HASH_INNERMOST_INT_IP: if (direction) { // direction 1: E2I HASH_VALUE(inner_dst_addr, inner_addr_len, hash_value); } else { // direction 0: I2E HASH_VALUE(inner_src_addr, inner_addr_len, hash_value); } break; case LDBC_METHOD_HASH_INNERMOST_EXT_IP: if (direction) { // direction 1: E2I HASH_VALUE(inner_src_addr, inner_addr_len, hash_value); } else { // direction 0: I2E HASH_VALUE(inner_dst_addr, inner_addr_len, hash_value); } break; default: return hash_value; } return hash_value; } /****************************************************************************** * Packet Meta Data ******************************************************************************/ // return 0 : success // return -1 : failed int packet_set_sid(struct packet *pkt, uint16_t *sid, int num) { struct metadata *meta = &pkt->meta; if (num > MAX_SID_NUM) { return -1; } meta->sid.used = num; memcpy(meta->sid.list, sid, num * sizeof(uint16_t)); return 0; } // return number of sid int packet_get_sid(const struct packet *pkt, uint16_t *sid, int size) { const struct metadata *meta = &pkt->meta; if (size < meta->sid.used) { return 0; } memcpy(sid, meta->sid.list, meta->sid.used * sizeof(uint16_t)); return meta->sid.used; } // return 0 : success // return -1 : failed int packet_prepend_sid(struct packet *pkt, uint16_t sid) { struct metadata *meta = &pkt->meta; if (meta->sid.used >= MAX_SID_NUM) { return -1; } memmove(meta->sid.list + 1, meta->sid.list, meta->sid.used * sizeof(uint16_t)); meta->sid.list[0] = sid; meta->sid.used++; return 0; } // return 0 : success // return -1 : failed int packet_append_sid(struct packet *pkt, uint16_t sid) { struct metadata *meta = &pkt->meta; if (meta->sid.used >= MAX_SID_NUM) { return -1; } meta->sid.list[meta->sid.used] = sid; meta->sid.used++; return 0; } // return 0 : success // return -1 : failed int packet_set_route_ctx(struct packet *pkt, const char *route, int len) { struct metadata *meta = &pkt->meta; if (len > MAX_ROUTE_LEN) { return -1; } memcpy(meta->route.data, route, len); meta->route.len = len; return 0; } // return len of route ctx int packet_get_route_ctx(const struct packet *pkt, char *buff, int size) { const struct metadata *meta = &pkt->meta; if (meta->route.len > size) { return 0; } memcpy(buff, meta->route.data, meta->route.len); return meta->route.len; } void packet_set_user_data(struct packet *pkt, void *user_data) { struct metadata *meta = &pkt->meta; meta->user_data = user_data; } void *packet_get_user_data(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->user_data; } void packet_set_domain(struct packet *pkt, uint64_t domain) { struct metadata *meta = &pkt->meta; meta->domain = domain; } uint64_t packet_get_domain(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->domain; } void packet_set_session_id(struct packet *pkt, uint64_t session_id) { struct metadata *meta = &pkt->meta; meta->session_id = session_id; } uint64_t packet_get_session_id(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->session_id; } void packet_set_direction(struct packet *pkt, enum packet_direction direction) { struct metadata *meta = &pkt->meta; meta->direction = direction; } enum packet_direction packet_get_direction(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->direction; } void packet_set_action(struct packet *pkt, enum packet_action action) { struct metadata *meta = &pkt->meta; meta->action = action; } enum packet_action packet_get_action(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->action; } void packet_set_type(struct packet *pkt, enum packet_type type) { struct metadata *meta = &pkt->meta; meta->type = type; } enum packet_type packet_get_type(const struct packet *pkt) { const struct metadata *meta = &pkt->meta; return meta->type; } struct packet *packet_new(uint16_t pkt_len) { struct packet *pkt = (struct packet *)calloc(1, sizeof(struct packet) + pkt_len); if (pkt == NULL) { return NULL; } pkt->data_len = pkt_len; pkt->data_ptr = (const char *)pkt + sizeof(struct packet); pkt->need_free = true; return pkt; } void packet_free(struct packet *pkt) { if (pkt && pkt->need_free) { pkt->need_free = false; free((void *)pkt); } } struct packet *packet_dup(const struct packet *pkt) { if (pkt == NULL) { return NULL; } struct packet *dup_pkt = packet_new(pkt->data_len); if (dup_pkt == NULL) { return NULL; } memcpy(dup_pkt, pkt, sizeof(struct packet)); memcpy((char *)dup_pkt->data_ptr, pkt->data_ptr, pkt->data_len); dup_pkt->need_free = true; struct metadata *meta = &dup_pkt->meta; meta->user_data = NULL; // update layers for (int8_t i = 0; i < pkt->layers_used; i++) { dup_pkt->layers[i].hdr_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset; dup_pkt->layers[i].pld_ptr = dup_pkt->data_ptr + pkt->layers[i].hdr_offset + pkt->layers[i].hdr_len; } // update frag_layer if (pkt->frag_layer) { dup_pkt->frag_layer = &dup_pkt->layers[pkt->frag_layer - pkt->layers]; } return dup_pkt; } const char *packet_get_data(const struct packet *pkt) { return pkt->data_ptr; } uint16_t packet_get_len(const struct packet *pkt) { return pkt->data_len; } bool packet_is_fragment(const struct packet *pkt) { if (pkt->frag_layer) { return true; } else { return false; } }