1e263cd49SDmitry Fleytman /* 2605d52e6SDmitry Fleytman * QEMU RX packets abstractions 3e263cd49SDmitry Fleytman * 4e263cd49SDmitry Fleytman * Copyright (c) 2012 Ravello Systems LTD (http://ravellosystems.com) 5e263cd49SDmitry Fleytman * 6e263cd49SDmitry Fleytman * Developed by Daynix Computing LTD (http://www.daynix.com) 7e263cd49SDmitry Fleytman * 8e263cd49SDmitry Fleytman * Authors: 9e263cd49SDmitry Fleytman * Dmitry Fleytman <dmitry@daynix.com> 10e263cd49SDmitry Fleytman * Tamir Shomer <tamirs@daynix.com> 11e263cd49SDmitry Fleytman * Yan Vugenfirer <yan@daynix.com> 12e263cd49SDmitry Fleytman * 13e263cd49SDmitry Fleytman * This work is licensed under the terms of the GNU GPL, version 2 or later. 14e263cd49SDmitry Fleytman * See the COPYING file in the top-level directory. 15e263cd49SDmitry Fleytman * 16e263cd49SDmitry Fleytman */ 17e263cd49SDmitry Fleytman 18e8d40465SPeter Maydell #include "qemu/osdep.h" 19907209e3SAkihiko Odaki #include "qemu/crc32c.h" 20eb700029SDmitry Fleytman #include "trace.h" 21605d52e6SDmitry Fleytman #include "net_rx_pkt.h" 22e263cd49SDmitry Fleytman #include "net/checksum.h" 23e263cd49SDmitry Fleytman #include "net/tap.h" 24e263cd49SDmitry Fleytman 25605d52e6SDmitry Fleytman struct NetRxPkt { 26e263cd49SDmitry Fleytman struct virtio_net_hdr virt_hdr; 277edf2f1dSAkihiko Odaki struct { 287edf2f1dSAkihiko Odaki struct eth_header eth; 297edf2f1dSAkihiko Odaki struct vlan_header vlan; 307edf2f1dSAkihiko Odaki } ehdr_buf; 31eb700029SDmitry Fleytman struct iovec *vec; 32eb700029SDmitry Fleytman uint16_t vec_len_total; 33e263cd49SDmitry Fleytman uint16_t vec_len; 34e263cd49SDmitry Fleytman uint32_t tot_len; 35e263cd49SDmitry Fleytman uint16_t tci; 36df8bf7a7SDmitry Fleytman size_t ehdr_buf_len; 37e263cd49SDmitry Fleytman eth_pkt_types_e packet_type; 38e263cd49SDmitry Fleytman 39e263cd49SDmitry Fleytman /* Analysis results */ 4069ff5ef8SAkihiko Odaki bool hasip4; 4169ff5ef8SAkihiko Odaki bool hasip6; 42eb700029SDmitry Fleytman 43eb700029SDmitry Fleytman size_t l3hdr_off; 44eb700029SDmitry Fleytman size_t l4hdr_off; 45eb700029SDmitry Fleytman size_t l5hdr_off; 46eb700029SDmitry Fleytman 47eb700029SDmitry Fleytman eth_ip6_hdr_info ip6hdr_info; 48eb700029SDmitry Fleytman eth_ip4_hdr_info ip4hdr_info; 49eb700029SDmitry Fleytman eth_l4_hdr_info l4hdr_info; 50e263cd49SDmitry Fleytman }; 51e263cd49SDmitry Fleytman 52aac8f89dSAkihiko Odaki void net_rx_pkt_init(struct NetRxPkt **pkt) 53e263cd49SDmitry Fleytman { 54605d52e6SDmitry Fleytman struct NetRxPkt *p = g_malloc0(sizeof *p); 55eb700029SDmitry Fleytman p->vec = NULL; 56eb700029SDmitry Fleytman p->vec_len_total = 0; 57e263cd49SDmitry Fleytman *pkt = p; 58e263cd49SDmitry Fleytman } 59e263cd49SDmitry Fleytman 60605d52e6SDmitry Fleytman void net_rx_pkt_uninit(struct NetRxPkt *pkt) 61e263cd49SDmitry Fleytman { 62eb700029SDmitry Fleytman if (pkt->vec_len_total != 0) { 63eb700029SDmitry Fleytman g_free(pkt->vec); 64eb700029SDmitry Fleytman } 65eb700029SDmitry Fleytman 66e263cd49SDmitry Fleytman g_free(pkt); 67e263cd49SDmitry Fleytman } 68e263cd49SDmitry Fleytman 69605d52e6SDmitry Fleytman struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt) 70e263cd49SDmitry Fleytman { 71e263cd49SDmitry Fleytman assert(pkt); 72e263cd49SDmitry Fleytman return &pkt->virt_hdr; 73e263cd49SDmitry Fleytman } 74e263cd49SDmitry Fleytman 75eb700029SDmitry Fleytman static inline void 76eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt, 77eb700029SDmitry Fleytman int new_iov_len) 78eb700029SDmitry Fleytman { 79eb700029SDmitry Fleytman if (pkt->vec_len_total < new_iov_len) { 80eb700029SDmitry Fleytman g_free(pkt->vec); 81eb700029SDmitry Fleytman pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len); 82eb700029SDmitry Fleytman pkt->vec_len_total = new_iov_len; 83eb700029SDmitry Fleytman } 84eb700029SDmitry Fleytman } 85eb700029SDmitry Fleytman 86eb700029SDmitry Fleytman static void 87eb700029SDmitry Fleytman net_rx_pkt_pull_data(struct NetRxPkt *pkt, 88eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 89eb700029SDmitry Fleytman size_t ploff) 90eb700029SDmitry Fleytman { 91002d394fSDmitry Fleytman uint32_t pllen = iov_size(iov, iovcnt) - ploff; 92002d394fSDmitry Fleytman 93df8bf7a7SDmitry Fleytman if (pkt->ehdr_buf_len) { 94eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(pkt, iovcnt + 1); 95eb700029SDmitry Fleytman 967edf2f1dSAkihiko Odaki pkt->vec[0].iov_base = &pkt->ehdr_buf; 97df8bf7a7SDmitry Fleytman pkt->vec[0].iov_len = pkt->ehdr_buf_len; 98eb700029SDmitry Fleytman 99002d394fSDmitry Fleytman pkt->tot_len = pllen + pkt->ehdr_buf_len; 100eb700029SDmitry Fleytman pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1, 101002d394fSDmitry Fleytman iov, iovcnt, ploff, pllen) + 1; 102eb700029SDmitry Fleytman } else { 103eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(pkt, iovcnt); 104eb700029SDmitry Fleytman 105002d394fSDmitry Fleytman pkt->tot_len = pllen; 106eb700029SDmitry Fleytman pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total, 107eb700029SDmitry Fleytman iov, iovcnt, ploff, pkt->tot_len); 108eb700029SDmitry Fleytman } 109eb700029SDmitry Fleytman 1102f0fa232SAkihiko Odaki eth_get_protocols(pkt->vec, pkt->vec_len, 0, &pkt->hasip4, &pkt->hasip6, 111eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 112eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 113eb700029SDmitry Fleytman 11465f474bbSAkihiko Odaki trace_net_rx_pkt_parsed(pkt->hasip4, pkt->hasip6, pkt->l4hdr_info.proto, 115eb700029SDmitry Fleytman pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off); 116eb700029SDmitry Fleytman } 117eb700029SDmitry Fleytman 118eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt, 119eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 120eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan) 121e263cd49SDmitry Fleytman { 122e263cd49SDmitry Fleytman uint16_t tci = 0; 123eb700029SDmitry Fleytman uint16_t ploff = iovoff; 124e263cd49SDmitry Fleytman assert(pkt); 125e263cd49SDmitry Fleytman 126e263cd49SDmitry Fleytman if (strip_vlan) { 1277edf2f1dSAkihiko Odaki pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, &pkt->ehdr_buf, 128eb700029SDmitry Fleytman &ploff, &tci); 129df8bf7a7SDmitry Fleytman } else { 130df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 131e263cd49SDmitry Fleytman } 132e263cd49SDmitry Fleytman 133e263cd49SDmitry Fleytman pkt->tci = tci; 134eb700029SDmitry Fleytman 135eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 136eb700029SDmitry Fleytman } 137eb700029SDmitry Fleytman 138eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, 139eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 1407e64a9caSAkihiko Odaki size_t iovoff, int strip_vlan_index, 1417e64a9caSAkihiko Odaki uint16_t vet, uint16_t vet_ext) 142eb700029SDmitry Fleytman { 143eb700029SDmitry Fleytman uint16_t tci = 0; 144eb700029SDmitry Fleytman uint16_t ploff = iovoff; 145eb700029SDmitry Fleytman assert(pkt); 146eb700029SDmitry Fleytman 1477e64a9caSAkihiko Odaki pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, 1487e64a9caSAkihiko Odaki strip_vlan_index, vet, vet_ext, 1497edf2f1dSAkihiko Odaki &pkt->ehdr_buf, 150eb700029SDmitry Fleytman &ploff, &tci); 151eb700029SDmitry Fleytman 152eb700029SDmitry Fleytman pkt->tci = tci; 153eb700029SDmitry Fleytman 154eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 155e263cd49SDmitry Fleytman } 156e263cd49SDmitry Fleytman 157605d52e6SDmitry Fleytman void net_rx_pkt_dump(struct NetRxPkt *pkt) 158e263cd49SDmitry Fleytman { 159605d52e6SDmitry Fleytman #ifdef NET_RX_PKT_DEBUG 160e263cd49SDmitry Fleytman assert(pkt); 161e263cd49SDmitry Fleytman 162df8bf7a7SDmitry Fleytman printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n", 163df8bf7a7SDmitry Fleytman pkt->tot_len, pkt->ehdr_buf_len, pkt->tci); 164e263cd49SDmitry Fleytman #endif 165e263cd49SDmitry Fleytman } 166e263cd49SDmitry Fleytman 167605d52e6SDmitry Fleytman void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, 168e263cd49SDmitry Fleytman eth_pkt_types_e packet_type) 169e263cd49SDmitry Fleytman { 170e263cd49SDmitry Fleytman assert(pkt); 171e263cd49SDmitry Fleytman 172e263cd49SDmitry Fleytman pkt->packet_type = packet_type; 173e263cd49SDmitry Fleytman 174e263cd49SDmitry Fleytman } 175e263cd49SDmitry Fleytman 176605d52e6SDmitry Fleytman eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt) 177e263cd49SDmitry Fleytman { 178e263cd49SDmitry Fleytman assert(pkt); 179e263cd49SDmitry Fleytman 180e263cd49SDmitry Fleytman return pkt->packet_type; 181e263cd49SDmitry Fleytman } 182e263cd49SDmitry Fleytman 183605d52e6SDmitry Fleytman size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt) 184e263cd49SDmitry Fleytman { 185e263cd49SDmitry Fleytman assert(pkt); 186e263cd49SDmitry Fleytman 187e263cd49SDmitry Fleytman return pkt->tot_len; 188e263cd49SDmitry Fleytman } 189e263cd49SDmitry Fleytman 1902f0fa232SAkihiko Odaki void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, 1912f0fa232SAkihiko Odaki const struct iovec *iov, size_t iovcnt, 1922f0fa232SAkihiko Odaki size_t iovoff) 193fcf0cdc3SShmulik Ladkani { 194fcf0cdc3SShmulik Ladkani assert(pkt); 195fcf0cdc3SShmulik Ladkani 1962f0fa232SAkihiko Odaki eth_get_protocols(iov, iovcnt, iovoff, &pkt->hasip4, &pkt->hasip6, 197eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 198eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 199fcf0cdc3SShmulik Ladkani } 200fcf0cdc3SShmulik Ladkani 201605d52e6SDmitry Fleytman void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, 20269ff5ef8SAkihiko Odaki bool *hasip4, bool *hasip6, 20365f474bbSAkihiko Odaki EthL4HdrProto *l4hdr_proto) 204e263cd49SDmitry Fleytman { 205e263cd49SDmitry Fleytman assert(pkt); 206e263cd49SDmitry Fleytman 20769ff5ef8SAkihiko Odaki *hasip4 = pkt->hasip4; 20869ff5ef8SAkihiko Odaki *hasip6 = pkt->hasip6; 20965f474bbSAkihiko Odaki *l4hdr_proto = pkt->l4hdr_info.proto; 210e263cd49SDmitry Fleytman } 211e263cd49SDmitry Fleytman 212eb700029SDmitry Fleytman size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt) 213eb700029SDmitry Fleytman { 214eb700029SDmitry Fleytman assert(pkt); 215eb700029SDmitry Fleytman return pkt->l3hdr_off; 216eb700029SDmitry Fleytman } 217eb700029SDmitry Fleytman 218eb700029SDmitry Fleytman size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt) 219eb700029SDmitry Fleytman { 220eb700029SDmitry Fleytman assert(pkt); 221eb700029SDmitry Fleytman return pkt->l4hdr_off; 222eb700029SDmitry Fleytman } 223eb700029SDmitry Fleytman 224eb700029SDmitry Fleytman size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt) 225eb700029SDmitry Fleytman { 226eb700029SDmitry Fleytman assert(pkt); 227eb700029SDmitry Fleytman return pkt->l5hdr_off; 228eb700029SDmitry Fleytman } 229eb700029SDmitry Fleytman 230eb700029SDmitry Fleytman eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt) 231eb700029SDmitry Fleytman { 232eb700029SDmitry Fleytman return &pkt->ip6hdr_info; 233eb700029SDmitry Fleytman } 234eb700029SDmitry Fleytman 235eb700029SDmitry Fleytman eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt) 236eb700029SDmitry Fleytman { 237eb700029SDmitry Fleytman return &pkt->ip4hdr_info; 238eb700029SDmitry Fleytman } 239eb700029SDmitry Fleytman 240eb700029SDmitry Fleytman static inline void 241eb700029SDmitry Fleytman _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, 242eb700029SDmitry Fleytman void *ptr, size_t size) 243eb700029SDmitry Fleytman { 244eb700029SDmitry Fleytman memcpy(&rss_input[*bytes_written], ptr, size); 245eb700029SDmitry Fleytman trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written); 246eb700029SDmitry Fleytman *bytes_written += size; 247eb700029SDmitry Fleytman } 248eb700029SDmitry Fleytman 249eb700029SDmitry Fleytman static inline void 250eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(uint8_t *rss_input, 251eb700029SDmitry Fleytman struct NetRxPkt *pkt, 252eb700029SDmitry Fleytman size_t *bytes_written) 253eb700029SDmitry Fleytman { 254eb700029SDmitry Fleytman struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr; 255eb700029SDmitry Fleytman 256eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 257eb700029SDmitry Fleytman &ip4_hdr->ip_src, sizeof(uint32_t)); 258eb700029SDmitry Fleytman 259eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 260eb700029SDmitry Fleytman &ip4_hdr->ip_dst, sizeof(uint32_t)); 261eb700029SDmitry Fleytman } 262eb700029SDmitry Fleytman 263eb700029SDmitry Fleytman static inline void 264eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(uint8_t *rss_input, 265eb700029SDmitry Fleytman struct NetRxPkt *pkt, 266eb700029SDmitry Fleytman bool ipv6ex, size_t *bytes_written) 267eb700029SDmitry Fleytman { 268eb700029SDmitry Fleytman eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info; 269eb700029SDmitry Fleytman 270eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 271eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src 272eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_src, 273eb700029SDmitry Fleytman sizeof(struct in6_address)); 274eb700029SDmitry Fleytman 275eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 276eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst 277eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_dst, 278eb700029SDmitry Fleytman sizeof(struct in6_address)); 279eb700029SDmitry Fleytman } 280eb700029SDmitry Fleytman 281eb700029SDmitry Fleytman static inline void 282eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(uint8_t *rss_input, 283eb700029SDmitry Fleytman struct NetRxPkt *pkt, 284eb700029SDmitry Fleytman size_t *bytes_written) 285eb700029SDmitry Fleytman { 286eb700029SDmitry Fleytman struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp; 287eb700029SDmitry Fleytman 288eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 289eb700029SDmitry Fleytman &tcphdr->th_sport, sizeof(uint16_t)); 290eb700029SDmitry Fleytman 291eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 292eb700029SDmitry Fleytman &tcphdr->th_dport, sizeof(uint16_t)); 293eb700029SDmitry Fleytman } 294eb700029SDmitry Fleytman 29533bbc05eSYuri Benditovich static inline void 29633bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(uint8_t *rss_input, 29733bbc05eSYuri Benditovich struct NetRxPkt *pkt, 29833bbc05eSYuri Benditovich size_t *bytes_written) 29933bbc05eSYuri Benditovich { 30033bbc05eSYuri Benditovich struct udp_header *udphdr = &pkt->l4hdr_info.hdr.udp; 30133bbc05eSYuri Benditovich 30233bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 30333bbc05eSYuri Benditovich &udphdr->uh_sport, sizeof(uint16_t)); 30433bbc05eSYuri Benditovich 30533bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 30633bbc05eSYuri Benditovich &udphdr->uh_dport, sizeof(uint16_t)); 30733bbc05eSYuri Benditovich } 30833bbc05eSYuri Benditovich 309eb700029SDmitry Fleytman uint32_t 310eb700029SDmitry Fleytman net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, 311eb700029SDmitry Fleytman NetRxPktRssType type, 312eb700029SDmitry Fleytman uint8_t *key) 313eb700029SDmitry Fleytman { 314eb700029SDmitry Fleytman uint8_t rss_input[36]; 315eb700029SDmitry Fleytman size_t rss_length = 0; 316eb700029SDmitry Fleytman uint32_t rss_hash = 0; 317eb700029SDmitry Fleytman net_toeplitz_key key_data; 318eb700029SDmitry Fleytman 319eb700029SDmitry Fleytman switch (type) { 320eb700029SDmitry Fleytman case NetPktRssIpV4: 32169ff5ef8SAkihiko Odaki assert(pkt->hasip4); 322eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4(); 323eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 324eb700029SDmitry Fleytman break; 325eb700029SDmitry Fleytman case NetPktRssIpV4Tcp: 32669ff5ef8SAkihiko Odaki assert(pkt->hasip4); 32765f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 328eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4_tcp(); 329eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 330eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 331eb700029SDmitry Fleytman break; 332eb700029SDmitry Fleytman case NetPktRssIpV6Tcp: 33369ff5ef8SAkihiko Odaki assert(pkt->hasip6); 33465f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 335eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_tcp(); 3362683a927SYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 337eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 338eb700029SDmitry Fleytman break; 339eb700029SDmitry Fleytman case NetPktRssIpV6: 34069ff5ef8SAkihiko Odaki assert(pkt->hasip6); 341eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6(); 342eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 343eb700029SDmitry Fleytman break; 344eb700029SDmitry Fleytman case NetPktRssIpV6Ex: 34569ff5ef8SAkihiko Odaki assert(pkt->hasip6); 346eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_ex(); 347eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 348eb700029SDmitry Fleytman break; 34933bbc05eSYuri Benditovich case NetPktRssIpV6TcpEx: 35069ff5ef8SAkihiko Odaki assert(pkt->hasip6); 35165f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 35233bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_tcp(); 35333bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 35433bbc05eSYuri Benditovich _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 35533bbc05eSYuri Benditovich break; 35633bbc05eSYuri Benditovich case NetPktRssIpV4Udp: 35769ff5ef8SAkihiko Odaki assert(pkt->hasip4); 35865f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 35933bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip4_udp(); 36033bbc05eSYuri Benditovich _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 36133bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 36233bbc05eSYuri Benditovich break; 36333bbc05eSYuri Benditovich case NetPktRssIpV6Udp: 36469ff5ef8SAkihiko Odaki assert(pkt->hasip6); 36565f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 36633bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_udp(); 36733bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 36833bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 36933bbc05eSYuri Benditovich break; 37033bbc05eSYuri Benditovich case NetPktRssIpV6UdpEx: 37169ff5ef8SAkihiko Odaki assert(pkt->hasip6); 37265f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 37333bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_udp(); 37433bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 37533bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 37633bbc05eSYuri Benditovich break; 377eb700029SDmitry Fleytman default: 378*d81e87e9SPierrick Bouvier g_assert_not_reached(); 379eb700029SDmitry Fleytman break; 380eb700029SDmitry Fleytman } 381eb700029SDmitry Fleytman 382eb700029SDmitry Fleytman net_toeplitz_key_init(&key_data, key); 383eb700029SDmitry Fleytman net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data); 384eb700029SDmitry Fleytman 385eb700029SDmitry Fleytman trace_net_rx_pkt_rss_hash(rss_length, rss_hash); 386eb700029SDmitry Fleytman 387eb700029SDmitry Fleytman return rss_hash; 388eb700029SDmitry Fleytman } 389eb700029SDmitry Fleytman 390eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt) 391eb700029SDmitry Fleytman { 392eb700029SDmitry Fleytman assert(pkt); 393eb700029SDmitry Fleytman 39469ff5ef8SAkihiko Odaki if (pkt->hasip4) { 395eb700029SDmitry Fleytman return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id); 396eb700029SDmitry Fleytman } 397eb700029SDmitry Fleytman 398eb700029SDmitry Fleytman return 0; 399eb700029SDmitry Fleytman } 400eb700029SDmitry Fleytman 401eb700029SDmitry Fleytman bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt) 402eb700029SDmitry Fleytman { 403eb700029SDmitry Fleytman assert(pkt); 404eb700029SDmitry Fleytman 40565f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 406eb700029SDmitry Fleytman return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK; 407eb700029SDmitry Fleytman } 408eb700029SDmitry Fleytman 409eb700029SDmitry Fleytman return false; 410eb700029SDmitry Fleytman } 411eb700029SDmitry Fleytman 412eb700029SDmitry Fleytman bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt) 413eb700029SDmitry Fleytman { 414eb700029SDmitry Fleytman assert(pkt); 415eb700029SDmitry Fleytman 41665f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 417eb700029SDmitry Fleytman return pkt->l4hdr_info.has_tcp_data; 418eb700029SDmitry Fleytman } 419eb700029SDmitry Fleytman 420eb700029SDmitry Fleytman return false; 421eb700029SDmitry Fleytman } 422eb700029SDmitry Fleytman 423605d52e6SDmitry Fleytman struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) 424e263cd49SDmitry Fleytman { 425e263cd49SDmitry Fleytman assert(pkt); 426e263cd49SDmitry Fleytman 427e263cd49SDmitry Fleytman return pkt->vec; 428e263cd49SDmitry Fleytman } 429e263cd49SDmitry Fleytman 430eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) 431eb700029SDmitry Fleytman { 432eb700029SDmitry Fleytman assert(pkt); 433eb700029SDmitry Fleytman 434eb700029SDmitry Fleytman return pkt->vec_len; 435eb700029SDmitry Fleytman } 436eb700029SDmitry Fleytman 437605d52e6SDmitry Fleytman void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, 438e263cd49SDmitry Fleytman struct virtio_net_hdr *vhdr) 439e263cd49SDmitry Fleytman { 440e263cd49SDmitry Fleytman assert(pkt); 441e263cd49SDmitry Fleytman 442e263cd49SDmitry Fleytman memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); 443e263cd49SDmitry Fleytman } 444e263cd49SDmitry Fleytman 445eb700029SDmitry Fleytman void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, 446eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt) 447eb700029SDmitry Fleytman { 448eb700029SDmitry Fleytman assert(pkt); 449eb700029SDmitry Fleytman 450eb700029SDmitry Fleytman iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr); 451eb700029SDmitry Fleytman } 452eb700029SDmitry Fleytman 453ffbd2dbdSAkihiko Odaki void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt) 454ffbd2dbdSAkihiko Odaki { 455ffbd2dbdSAkihiko Odaki assert(pkt); 456ffbd2dbdSAkihiko Odaki 457ffbd2dbdSAkihiko Odaki memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr)); 458ffbd2dbdSAkihiko Odaki } 459ffbd2dbdSAkihiko Odaki 460605d52e6SDmitry Fleytman bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt) 461e263cd49SDmitry Fleytman { 462e263cd49SDmitry Fleytman assert(pkt); 463e263cd49SDmitry Fleytman 464df8bf7a7SDmitry Fleytman return pkt->ehdr_buf_len ? true : false; 465e263cd49SDmitry Fleytman } 466e263cd49SDmitry Fleytman 467605d52e6SDmitry Fleytman uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt) 468e263cd49SDmitry Fleytman { 469e263cd49SDmitry Fleytman assert(pkt); 470e263cd49SDmitry Fleytman 471e263cd49SDmitry Fleytman return pkt->tci; 472e263cd49SDmitry Fleytman } 473eb700029SDmitry Fleytman 474eb700029SDmitry Fleytman bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid) 475eb700029SDmitry Fleytman { 476eb700029SDmitry Fleytman uint32_t cntr; 477eb700029SDmitry Fleytman uint16_t csum; 478eb700029SDmitry Fleytman uint32_t csl; 479eb700029SDmitry Fleytman 480eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_entry(); 481eb700029SDmitry Fleytman 48269ff5ef8SAkihiko Odaki if (!pkt->hasip4) { 483eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_not_ip4(); 484eb700029SDmitry Fleytman return false; 485eb700029SDmitry Fleytman } 486eb700029SDmitry Fleytman 487eb700029SDmitry Fleytman csl = pkt->l4hdr_off - pkt->l3hdr_off; 488eb700029SDmitry Fleytman 489eb700029SDmitry Fleytman cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len, 490eb700029SDmitry Fleytman pkt->l3hdr_off, 491eb700029SDmitry Fleytman csl, 0); 492eb700029SDmitry Fleytman 493eb700029SDmitry Fleytman csum = net_checksum_finish(cntr); 494eb700029SDmitry Fleytman 495eb700029SDmitry Fleytman *csum_valid = (csum == 0); 496eb700029SDmitry Fleytman 497eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl, 498eb700029SDmitry Fleytman cntr, csum, *csum_valid); 499eb700029SDmitry Fleytman 500eb700029SDmitry Fleytman return true; 501eb700029SDmitry Fleytman } 502eb700029SDmitry Fleytman 503eb700029SDmitry Fleytman static uint16_t 504eb700029SDmitry Fleytman _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt) 505eb700029SDmitry Fleytman { 506eb700029SDmitry Fleytman uint32_t cntr; 507eb700029SDmitry Fleytman uint16_t csum; 508eb700029SDmitry Fleytman uint16_t csl; 509eb700029SDmitry Fleytman uint32_t cso; 510eb700029SDmitry Fleytman 511eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_entry(); 512eb700029SDmitry Fleytman 51369ff5ef8SAkihiko Odaki if (pkt->hasip4) { 51465f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 515eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 516eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_udp(); 517eb700029SDmitry Fleytman } else { 518eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) - 519eb700029SDmitry Fleytman IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr); 520eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_tcp(); 521eb700029SDmitry Fleytman } 522eb700029SDmitry Fleytman 523eb700029SDmitry Fleytman cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr, 524eb700029SDmitry Fleytman csl, &cso); 525eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 526eb700029SDmitry Fleytman } else { 52765f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 528eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 529eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_udp(); 530eb700029SDmitry Fleytman } else { 531eb700029SDmitry Fleytman struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr; 532eb700029SDmitry Fleytman size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off; 533eb700029SDmitry Fleytman size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header); 534eb700029SDmitry Fleytman 535eb700029SDmitry Fleytman csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - 536eb700029SDmitry Fleytman ip6opts_len; 537eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_tcp(); 538eb700029SDmitry Fleytman } 539eb700029SDmitry Fleytman 540eb700029SDmitry Fleytman cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl, 541eb700029SDmitry Fleytman pkt->ip6hdr_info.l4proto, &cso); 542eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 543eb700029SDmitry Fleytman } 544eb700029SDmitry Fleytman 545eb700029SDmitry Fleytman cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len, 546eb700029SDmitry Fleytman pkt->l4hdr_off, csl, cso); 547eb700029SDmitry Fleytman 5480dacea92SEd Swierk csum = net_checksum_finish_nozero(cntr); 549eb700029SDmitry Fleytman 550eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum); 551eb700029SDmitry Fleytman 552eb700029SDmitry Fleytman return csum; 553eb700029SDmitry Fleytman } 554eb700029SDmitry Fleytman 555907209e3SAkihiko Odaki static bool 556907209e3SAkihiko Odaki _net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt) 557907209e3SAkihiko Odaki { 558907209e3SAkihiko Odaki size_t csum_off; 559907209e3SAkihiko Odaki size_t off = pkt->l4hdr_off; 560907209e3SAkihiko Odaki size_t vec_len = pkt->vec_len; 561907209e3SAkihiko Odaki struct iovec *vec; 562907209e3SAkihiko Odaki uint32_t calculated = 0; 563907209e3SAkihiko Odaki uint32_t original; 564907209e3SAkihiko Odaki bool valid; 565907209e3SAkihiko Odaki 566907209e3SAkihiko Odaki for (vec = pkt->vec; vec->iov_len < off; vec++) { 567907209e3SAkihiko Odaki off -= vec->iov_len; 568907209e3SAkihiko Odaki vec_len--; 569907209e3SAkihiko Odaki } 570907209e3SAkihiko Odaki 571907209e3SAkihiko Odaki csum_off = off + 8; 572907209e3SAkihiko Odaki 573907209e3SAkihiko Odaki if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) { 574907209e3SAkihiko Odaki return false; 575907209e3SAkihiko Odaki } 576907209e3SAkihiko Odaki 577907209e3SAkihiko Odaki if (!iov_from_buf(vec, vec_len, csum_off, 578907209e3SAkihiko Odaki &calculated, sizeof(calculated))) { 579907209e3SAkihiko Odaki return false; 580907209e3SAkihiko Odaki } 581907209e3SAkihiko Odaki 582907209e3SAkihiko Odaki calculated = crc32c(0xffffffff, 583907209e3SAkihiko Odaki (uint8_t *)vec->iov_base + off, vec->iov_len - off); 584907209e3SAkihiko Odaki calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1); 585907209e3SAkihiko Odaki valid = calculated == le32_to_cpu(original); 586907209e3SAkihiko Odaki iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original)); 587907209e3SAkihiko Odaki 588907209e3SAkihiko Odaki return valid; 589907209e3SAkihiko Odaki } 590907209e3SAkihiko Odaki 591eb700029SDmitry Fleytman bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) 592eb700029SDmitry Fleytman { 593907209e3SAkihiko Odaki uint32_t csum; 594eb700029SDmitry Fleytman 595eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_entry(); 596eb700029SDmitry Fleytman 59769ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 598eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); 599eb700029SDmitry Fleytman return false; 600eb700029SDmitry Fleytman } 601eb700029SDmitry Fleytman 602907209e3SAkihiko Odaki switch (pkt->l4hdr_info.proto) { 603907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_UDP: 604907209e3SAkihiko Odaki if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 605907209e3SAkihiko Odaki trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum(); 606907209e3SAkihiko Odaki return false; 607907209e3SAkihiko Odaki } 608907209e3SAkihiko Odaki /* fall through */ 609907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_TCP: 610eb700029SDmitry Fleytman csum = _net_rx_pkt_calc_l4_csum(pkt); 611eb700029SDmitry Fleytman *csum_valid = ((csum == 0) || (csum == 0xFFFF)); 612907209e3SAkihiko Odaki break; 613907209e3SAkihiko Odaki 614907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_SCTP: 615907209e3SAkihiko Odaki *csum_valid = _net_rx_pkt_validate_sctp_sum(pkt); 616907209e3SAkihiko Odaki break; 617907209e3SAkihiko Odaki 618907209e3SAkihiko Odaki default: 619907209e3SAkihiko Odaki trace_net_rx_pkt_l4_csum_validate_not_xxp(); 620907209e3SAkihiko Odaki return false; 621907209e3SAkihiko Odaki } 622eb700029SDmitry Fleytman 623eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); 624eb700029SDmitry Fleytman 625eb700029SDmitry Fleytman return true; 626eb700029SDmitry Fleytman } 627eb700029SDmitry Fleytman 628eb700029SDmitry Fleytman bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt) 629eb700029SDmitry Fleytman { 630eb700029SDmitry Fleytman uint16_t csum = 0; 631eb700029SDmitry Fleytman uint32_t l4_cso; 632eb700029SDmitry Fleytman 633eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_entry(); 634eb700029SDmitry Fleytman 63565f474bbSAkihiko Odaki switch (pkt->l4hdr_info.proto) { 63665f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_TCP: 637eb700029SDmitry Fleytman l4_cso = offsetof(struct tcp_header, th_sum); 638eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso); 63965f474bbSAkihiko Odaki break; 64065f474bbSAkihiko Odaki 64165f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_UDP: 642eb700029SDmitry Fleytman if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 643eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum(); 644eb700029SDmitry Fleytman return false; 645eb700029SDmitry Fleytman } 646eb700029SDmitry Fleytman l4_cso = offsetof(struct udp_header, uh_sum); 647eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp(l4_cso); 64865f474bbSAkihiko Odaki break; 64965f474bbSAkihiko Odaki 65065f474bbSAkihiko Odaki default: 651eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_not_xxp(); 652eb700029SDmitry Fleytman return false; 653eb700029SDmitry Fleytman } 654eb700029SDmitry Fleytman 65569ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 656eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_ip4_fragment(); 657eb700029SDmitry Fleytman return false; 658eb700029SDmitry Fleytman } 659eb700029SDmitry Fleytman 660eb700029SDmitry Fleytman /* Set zero to checksum word */ 661eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 662eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 663eb700029SDmitry Fleytman &csum, sizeof(csum)); 664eb700029SDmitry Fleytman 665eb700029SDmitry Fleytman /* Calculate L4 checksum */ 666eb700029SDmitry Fleytman csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt)); 667eb700029SDmitry Fleytman 668eb700029SDmitry Fleytman /* Set calculated checksum to checksum word */ 669eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 670eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 671eb700029SDmitry Fleytman &csum, sizeof(csum)); 672eb700029SDmitry Fleytman 673eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum); 674eb700029SDmitry Fleytman 675eb700029SDmitry Fleytman return true; 676eb700029SDmitry Fleytman } 677