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" 19eb700029SDmitry Fleytman #include "trace.h" 20605d52e6SDmitry Fleytman #include "net_rx_pkt.h" 21e263cd49SDmitry Fleytman #include "net/checksum.h" 22e263cd49SDmitry Fleytman #include "net/tap.h" 23e263cd49SDmitry Fleytman 24605d52e6SDmitry Fleytman struct NetRxPkt { 25e263cd49SDmitry Fleytman struct virtio_net_hdr virt_hdr; 26df8bf7a7SDmitry Fleytman uint8_t ehdr_buf[sizeof(struct eth_header) + sizeof(struct vlan_header)]; 27eb700029SDmitry Fleytman struct iovec *vec; 28eb700029SDmitry Fleytman uint16_t vec_len_total; 29e263cd49SDmitry Fleytman uint16_t vec_len; 30e263cd49SDmitry Fleytman uint32_t tot_len; 31e263cd49SDmitry Fleytman uint16_t tci; 32df8bf7a7SDmitry Fleytman size_t ehdr_buf_len; 33e263cd49SDmitry Fleytman eth_pkt_types_e packet_type; 34e263cd49SDmitry Fleytman 35e263cd49SDmitry Fleytman /* Analysis results */ 3669ff5ef8SAkihiko Odaki bool hasip4; 3769ff5ef8SAkihiko Odaki bool hasip6; 38eb700029SDmitry Fleytman 39eb700029SDmitry Fleytman size_t l3hdr_off; 40eb700029SDmitry Fleytman size_t l4hdr_off; 41eb700029SDmitry Fleytman size_t l5hdr_off; 42eb700029SDmitry Fleytman 43eb700029SDmitry Fleytman eth_ip6_hdr_info ip6hdr_info; 44eb700029SDmitry Fleytman eth_ip4_hdr_info ip4hdr_info; 45eb700029SDmitry Fleytman eth_l4_hdr_info l4hdr_info; 46e263cd49SDmitry Fleytman }; 47e263cd49SDmitry Fleytman 48aac8f89dSAkihiko Odaki void net_rx_pkt_init(struct NetRxPkt **pkt) 49e263cd49SDmitry Fleytman { 50605d52e6SDmitry Fleytman struct NetRxPkt *p = g_malloc0(sizeof *p); 51eb700029SDmitry Fleytman p->vec = NULL; 52eb700029SDmitry Fleytman p->vec_len_total = 0; 53e263cd49SDmitry Fleytman *pkt = p; 54e263cd49SDmitry Fleytman } 55e263cd49SDmitry Fleytman 56605d52e6SDmitry Fleytman void net_rx_pkt_uninit(struct NetRxPkt *pkt) 57e263cd49SDmitry Fleytman { 58eb700029SDmitry Fleytman if (pkt->vec_len_total != 0) { 59eb700029SDmitry Fleytman g_free(pkt->vec); 60eb700029SDmitry Fleytman } 61eb700029SDmitry Fleytman 62e263cd49SDmitry Fleytman g_free(pkt); 63e263cd49SDmitry Fleytman } 64e263cd49SDmitry Fleytman 65605d52e6SDmitry Fleytman struct virtio_net_hdr *net_rx_pkt_get_vhdr(struct NetRxPkt *pkt) 66e263cd49SDmitry Fleytman { 67e263cd49SDmitry Fleytman assert(pkt); 68e263cd49SDmitry Fleytman return &pkt->virt_hdr; 69e263cd49SDmitry Fleytman } 70e263cd49SDmitry Fleytman 71eb700029SDmitry Fleytman static inline void 72eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(struct NetRxPkt *pkt, 73eb700029SDmitry Fleytman int new_iov_len) 74eb700029SDmitry Fleytman { 75eb700029SDmitry Fleytman if (pkt->vec_len_total < new_iov_len) { 76eb700029SDmitry Fleytman g_free(pkt->vec); 77eb700029SDmitry Fleytman pkt->vec = g_malloc(sizeof(*pkt->vec) * new_iov_len); 78eb700029SDmitry Fleytman pkt->vec_len_total = new_iov_len; 79eb700029SDmitry Fleytman } 80eb700029SDmitry Fleytman } 81eb700029SDmitry Fleytman 82eb700029SDmitry Fleytman static void 83eb700029SDmitry Fleytman net_rx_pkt_pull_data(struct NetRxPkt *pkt, 84eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 85eb700029SDmitry Fleytman size_t ploff) 86eb700029SDmitry Fleytman { 87002d394fSDmitry Fleytman uint32_t pllen = iov_size(iov, iovcnt) - ploff; 88002d394fSDmitry Fleytman 89df8bf7a7SDmitry Fleytman if (pkt->ehdr_buf_len) { 90eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(pkt, iovcnt + 1); 91eb700029SDmitry Fleytman 92eb700029SDmitry Fleytman pkt->vec[0].iov_base = pkt->ehdr_buf; 93df8bf7a7SDmitry Fleytman pkt->vec[0].iov_len = pkt->ehdr_buf_len; 94eb700029SDmitry Fleytman 95002d394fSDmitry Fleytman pkt->tot_len = pllen + pkt->ehdr_buf_len; 96eb700029SDmitry Fleytman pkt->vec_len = iov_copy(pkt->vec + 1, pkt->vec_len_total - 1, 97002d394fSDmitry Fleytman iov, iovcnt, ploff, pllen) + 1; 98eb700029SDmitry Fleytman } else { 99eb700029SDmitry Fleytman net_rx_pkt_iovec_realloc(pkt, iovcnt); 100eb700029SDmitry Fleytman 101002d394fSDmitry Fleytman pkt->tot_len = pllen; 102eb700029SDmitry Fleytman pkt->vec_len = iov_copy(pkt->vec, pkt->vec_len_total, 103eb700029SDmitry Fleytman iov, iovcnt, ploff, pkt->tot_len); 104eb700029SDmitry Fleytman } 105eb700029SDmitry Fleytman 10669ff5ef8SAkihiko Odaki eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->hasip4, &pkt->hasip6, 107eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 108eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 109eb700029SDmitry Fleytman 110*65f474bbSAkihiko Odaki trace_net_rx_pkt_parsed(pkt->hasip4, pkt->hasip6, pkt->l4hdr_info.proto, 111eb700029SDmitry Fleytman pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off); 112eb700029SDmitry Fleytman } 113eb700029SDmitry Fleytman 114eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt, 115eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 116eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan) 117e263cd49SDmitry Fleytman { 118e263cd49SDmitry Fleytman uint16_t tci = 0; 119eb700029SDmitry Fleytman uint16_t ploff = iovoff; 120e263cd49SDmitry Fleytman assert(pkt); 121e263cd49SDmitry Fleytman 122e263cd49SDmitry Fleytman if (strip_vlan) { 123df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf, 124eb700029SDmitry Fleytman &ploff, &tci); 125df8bf7a7SDmitry Fleytman } else { 126df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 127e263cd49SDmitry Fleytman } 128e263cd49SDmitry Fleytman 129e263cd49SDmitry Fleytman pkt->tci = tci; 130eb700029SDmitry Fleytman 131eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 132eb700029SDmitry Fleytman } 133eb700029SDmitry Fleytman 134eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, 135eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 136eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan, 137eb700029SDmitry Fleytman uint16_t vet) 138eb700029SDmitry Fleytman { 139eb700029SDmitry Fleytman uint16_t tci = 0; 140eb700029SDmitry Fleytman uint16_t ploff = iovoff; 141eb700029SDmitry Fleytman assert(pkt); 142eb700029SDmitry Fleytman 143eb700029SDmitry Fleytman if (strip_vlan) { 144df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, 145eb700029SDmitry Fleytman pkt->ehdr_buf, 146eb700029SDmitry Fleytman &ploff, &tci); 147df8bf7a7SDmitry Fleytman } else { 148df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 149eb700029SDmitry Fleytman } 150eb700029SDmitry Fleytman 151eb700029SDmitry Fleytman pkt->tci = tci; 152eb700029SDmitry Fleytman 153eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 154e263cd49SDmitry Fleytman } 155e263cd49SDmitry Fleytman 156605d52e6SDmitry Fleytman void net_rx_pkt_dump(struct NetRxPkt *pkt) 157e263cd49SDmitry Fleytman { 158605d52e6SDmitry Fleytman #ifdef NET_RX_PKT_DEBUG 159e263cd49SDmitry Fleytman assert(pkt); 160e263cd49SDmitry Fleytman 161df8bf7a7SDmitry Fleytman printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n", 162df8bf7a7SDmitry Fleytman pkt->tot_len, pkt->ehdr_buf_len, pkt->tci); 163e263cd49SDmitry Fleytman #endif 164e263cd49SDmitry Fleytman } 165e263cd49SDmitry Fleytman 166605d52e6SDmitry Fleytman void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, 167e263cd49SDmitry Fleytman eth_pkt_types_e packet_type) 168e263cd49SDmitry Fleytman { 169e263cd49SDmitry Fleytman assert(pkt); 170e263cd49SDmitry Fleytman 171e263cd49SDmitry Fleytman pkt->packet_type = packet_type; 172e263cd49SDmitry Fleytman 173e263cd49SDmitry Fleytman } 174e263cd49SDmitry Fleytman 175605d52e6SDmitry Fleytman eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt) 176e263cd49SDmitry Fleytman { 177e263cd49SDmitry Fleytman assert(pkt); 178e263cd49SDmitry Fleytman 179e263cd49SDmitry Fleytman return pkt->packet_type; 180e263cd49SDmitry Fleytman } 181e263cd49SDmitry Fleytman 182605d52e6SDmitry Fleytman size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt) 183e263cd49SDmitry Fleytman { 184e263cd49SDmitry Fleytman assert(pkt); 185e263cd49SDmitry Fleytman 186e263cd49SDmitry Fleytman return pkt->tot_len; 187e263cd49SDmitry Fleytman } 188e263cd49SDmitry Fleytman 189605d52e6SDmitry Fleytman void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, 190fcf0cdc3SShmulik Ladkani size_t len) 191fcf0cdc3SShmulik Ladkani { 192eb700029SDmitry Fleytman const struct iovec iov = { 193eb700029SDmitry Fleytman .iov_base = (void *)data, 194eb700029SDmitry Fleytman .iov_len = len 195eb700029SDmitry Fleytman }; 196eb700029SDmitry Fleytman 197fcf0cdc3SShmulik Ladkani assert(pkt); 198fcf0cdc3SShmulik Ladkani 19969ff5ef8SAkihiko Odaki eth_get_protocols(&iov, 1, &pkt->hasip4, &pkt->hasip6, 200eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 201eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 202fcf0cdc3SShmulik Ladkani } 203fcf0cdc3SShmulik Ladkani 204605d52e6SDmitry Fleytman void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, 20569ff5ef8SAkihiko Odaki bool *hasip4, bool *hasip6, 206*65f474bbSAkihiko Odaki EthL4HdrProto *l4hdr_proto) 207e263cd49SDmitry Fleytman { 208e263cd49SDmitry Fleytman assert(pkt); 209e263cd49SDmitry Fleytman 21069ff5ef8SAkihiko Odaki *hasip4 = pkt->hasip4; 21169ff5ef8SAkihiko Odaki *hasip6 = pkt->hasip6; 212*65f474bbSAkihiko Odaki *l4hdr_proto = pkt->l4hdr_info.proto; 213e263cd49SDmitry Fleytman } 214e263cd49SDmitry Fleytman 215eb700029SDmitry Fleytman size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt) 216eb700029SDmitry Fleytman { 217eb700029SDmitry Fleytman assert(pkt); 218eb700029SDmitry Fleytman return pkt->l3hdr_off; 219eb700029SDmitry Fleytman } 220eb700029SDmitry Fleytman 221eb700029SDmitry Fleytman size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt) 222eb700029SDmitry Fleytman { 223eb700029SDmitry Fleytman assert(pkt); 224eb700029SDmitry Fleytman return pkt->l4hdr_off; 225eb700029SDmitry Fleytman } 226eb700029SDmitry Fleytman 227eb700029SDmitry Fleytman size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt) 228eb700029SDmitry Fleytman { 229eb700029SDmitry Fleytman assert(pkt); 230eb700029SDmitry Fleytman return pkt->l5hdr_off; 231eb700029SDmitry Fleytman } 232eb700029SDmitry Fleytman 233eb700029SDmitry Fleytman eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt) 234eb700029SDmitry Fleytman { 235eb700029SDmitry Fleytman return &pkt->ip6hdr_info; 236eb700029SDmitry Fleytman } 237eb700029SDmitry Fleytman 238eb700029SDmitry Fleytman eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt) 239eb700029SDmitry Fleytman { 240eb700029SDmitry Fleytman return &pkt->ip4hdr_info; 241eb700029SDmitry Fleytman } 242eb700029SDmitry Fleytman 243eb700029SDmitry Fleytman eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt) 244eb700029SDmitry Fleytman { 245eb700029SDmitry Fleytman return &pkt->l4hdr_info; 246eb700029SDmitry Fleytman } 247eb700029SDmitry Fleytman 248eb700029SDmitry Fleytman static inline void 249eb700029SDmitry Fleytman _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, 250eb700029SDmitry Fleytman void *ptr, size_t size) 251eb700029SDmitry Fleytman { 252eb700029SDmitry Fleytman memcpy(&rss_input[*bytes_written], ptr, size); 253eb700029SDmitry Fleytman trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written); 254eb700029SDmitry Fleytman *bytes_written += size; 255eb700029SDmitry Fleytman } 256eb700029SDmitry Fleytman 257eb700029SDmitry Fleytman static inline void 258eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(uint8_t *rss_input, 259eb700029SDmitry Fleytman struct NetRxPkt *pkt, 260eb700029SDmitry Fleytman size_t *bytes_written) 261eb700029SDmitry Fleytman { 262eb700029SDmitry Fleytman struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr; 263eb700029SDmitry Fleytman 264eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 265eb700029SDmitry Fleytman &ip4_hdr->ip_src, sizeof(uint32_t)); 266eb700029SDmitry Fleytman 267eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 268eb700029SDmitry Fleytman &ip4_hdr->ip_dst, sizeof(uint32_t)); 269eb700029SDmitry Fleytman } 270eb700029SDmitry Fleytman 271eb700029SDmitry Fleytman static inline void 272eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(uint8_t *rss_input, 273eb700029SDmitry Fleytman struct NetRxPkt *pkt, 274eb700029SDmitry Fleytman bool ipv6ex, size_t *bytes_written) 275eb700029SDmitry Fleytman { 276eb700029SDmitry Fleytman eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info; 277eb700029SDmitry Fleytman 278eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 279eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src 280eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_src, 281eb700029SDmitry Fleytman sizeof(struct in6_address)); 282eb700029SDmitry Fleytman 283eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 284eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst 285eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_dst, 286eb700029SDmitry Fleytman sizeof(struct in6_address)); 287eb700029SDmitry Fleytman } 288eb700029SDmitry Fleytman 289eb700029SDmitry Fleytman static inline void 290eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(uint8_t *rss_input, 291eb700029SDmitry Fleytman struct NetRxPkt *pkt, 292eb700029SDmitry Fleytman size_t *bytes_written) 293eb700029SDmitry Fleytman { 294eb700029SDmitry Fleytman struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp; 295eb700029SDmitry Fleytman 296eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 297eb700029SDmitry Fleytman &tcphdr->th_sport, sizeof(uint16_t)); 298eb700029SDmitry Fleytman 299eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 300eb700029SDmitry Fleytman &tcphdr->th_dport, sizeof(uint16_t)); 301eb700029SDmitry Fleytman } 302eb700029SDmitry Fleytman 30333bbc05eSYuri Benditovich static inline void 30433bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(uint8_t *rss_input, 30533bbc05eSYuri Benditovich struct NetRxPkt *pkt, 30633bbc05eSYuri Benditovich size_t *bytes_written) 30733bbc05eSYuri Benditovich { 30833bbc05eSYuri Benditovich struct udp_header *udphdr = &pkt->l4hdr_info.hdr.udp; 30933bbc05eSYuri Benditovich 31033bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 31133bbc05eSYuri Benditovich &udphdr->uh_sport, sizeof(uint16_t)); 31233bbc05eSYuri Benditovich 31333bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 31433bbc05eSYuri Benditovich &udphdr->uh_dport, sizeof(uint16_t)); 31533bbc05eSYuri Benditovich } 31633bbc05eSYuri Benditovich 317eb700029SDmitry Fleytman uint32_t 318eb700029SDmitry Fleytman net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, 319eb700029SDmitry Fleytman NetRxPktRssType type, 320eb700029SDmitry Fleytman uint8_t *key) 321eb700029SDmitry Fleytman { 322eb700029SDmitry Fleytman uint8_t rss_input[36]; 323eb700029SDmitry Fleytman size_t rss_length = 0; 324eb700029SDmitry Fleytman uint32_t rss_hash = 0; 325eb700029SDmitry Fleytman net_toeplitz_key key_data; 326eb700029SDmitry Fleytman 327eb700029SDmitry Fleytman switch (type) { 328eb700029SDmitry Fleytman case NetPktRssIpV4: 32969ff5ef8SAkihiko Odaki assert(pkt->hasip4); 330eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4(); 331eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 332eb700029SDmitry Fleytman break; 333eb700029SDmitry Fleytman case NetPktRssIpV4Tcp: 33469ff5ef8SAkihiko Odaki assert(pkt->hasip4); 335*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 336eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4_tcp(); 337eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 338eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 339eb700029SDmitry Fleytman break; 340eb700029SDmitry Fleytman case NetPktRssIpV6Tcp: 34169ff5ef8SAkihiko Odaki assert(pkt->hasip6); 342*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 343eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_tcp(); 3442683a927SYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 345eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 346eb700029SDmitry Fleytman break; 347eb700029SDmitry Fleytman case NetPktRssIpV6: 34869ff5ef8SAkihiko Odaki assert(pkt->hasip6); 349eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6(); 350eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 351eb700029SDmitry Fleytman break; 352eb700029SDmitry Fleytman case NetPktRssIpV6Ex: 35369ff5ef8SAkihiko Odaki assert(pkt->hasip6); 354eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_ex(); 355eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 356eb700029SDmitry Fleytman break; 35733bbc05eSYuri Benditovich case NetPktRssIpV6TcpEx: 35869ff5ef8SAkihiko Odaki assert(pkt->hasip6); 359*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 36033bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_tcp(); 36133bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 36233bbc05eSYuri Benditovich _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 36333bbc05eSYuri Benditovich break; 36433bbc05eSYuri Benditovich case NetPktRssIpV4Udp: 36569ff5ef8SAkihiko Odaki assert(pkt->hasip4); 366*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 36733bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip4_udp(); 36833bbc05eSYuri Benditovich _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 36933bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 37033bbc05eSYuri Benditovich break; 37133bbc05eSYuri Benditovich case NetPktRssIpV6Udp: 37269ff5ef8SAkihiko Odaki assert(pkt->hasip6); 373*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 37433bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_udp(); 37533bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 37633bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 37733bbc05eSYuri Benditovich break; 37833bbc05eSYuri Benditovich case NetPktRssIpV6UdpEx: 37969ff5ef8SAkihiko Odaki assert(pkt->hasip6); 380*65f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 38133bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_udp(); 38233bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 38333bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 38433bbc05eSYuri Benditovich break; 385eb700029SDmitry Fleytman default: 386eb700029SDmitry Fleytman assert(false); 387eb700029SDmitry Fleytman break; 388eb700029SDmitry Fleytman } 389eb700029SDmitry Fleytman 390eb700029SDmitry Fleytman net_toeplitz_key_init(&key_data, key); 391eb700029SDmitry Fleytman net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data); 392eb700029SDmitry Fleytman 393eb700029SDmitry Fleytman trace_net_rx_pkt_rss_hash(rss_length, rss_hash); 394eb700029SDmitry Fleytman 395eb700029SDmitry Fleytman return rss_hash; 396eb700029SDmitry Fleytman } 397eb700029SDmitry Fleytman 398eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt) 399eb700029SDmitry Fleytman { 400eb700029SDmitry Fleytman assert(pkt); 401eb700029SDmitry Fleytman 40269ff5ef8SAkihiko Odaki if (pkt->hasip4) { 403eb700029SDmitry Fleytman return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id); 404eb700029SDmitry Fleytman } 405eb700029SDmitry Fleytman 406eb700029SDmitry Fleytman return 0; 407eb700029SDmitry Fleytman } 408eb700029SDmitry Fleytman 409eb700029SDmitry Fleytman bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt) 410eb700029SDmitry Fleytman { 411eb700029SDmitry Fleytman assert(pkt); 412eb700029SDmitry Fleytman 413*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 414eb700029SDmitry Fleytman return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK; 415eb700029SDmitry Fleytman } 416eb700029SDmitry Fleytman 417eb700029SDmitry Fleytman return false; 418eb700029SDmitry Fleytman } 419eb700029SDmitry Fleytman 420eb700029SDmitry Fleytman bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt) 421eb700029SDmitry Fleytman { 422eb700029SDmitry Fleytman assert(pkt); 423eb700029SDmitry Fleytman 424*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 425eb700029SDmitry Fleytman return pkt->l4hdr_info.has_tcp_data; 426eb700029SDmitry Fleytman } 427eb700029SDmitry Fleytman 428eb700029SDmitry Fleytman return false; 429eb700029SDmitry Fleytman } 430eb700029SDmitry Fleytman 431605d52e6SDmitry Fleytman struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) 432e263cd49SDmitry Fleytman { 433e263cd49SDmitry Fleytman assert(pkt); 434e263cd49SDmitry Fleytman 435e263cd49SDmitry Fleytman return pkt->vec; 436e263cd49SDmitry Fleytman } 437e263cd49SDmitry Fleytman 438eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) 439eb700029SDmitry Fleytman { 440eb700029SDmitry Fleytman assert(pkt); 441eb700029SDmitry Fleytman 442eb700029SDmitry Fleytman return pkt->vec_len; 443eb700029SDmitry Fleytman } 444eb700029SDmitry Fleytman 445605d52e6SDmitry Fleytman void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, 446e263cd49SDmitry Fleytman struct virtio_net_hdr *vhdr) 447e263cd49SDmitry Fleytman { 448e263cd49SDmitry Fleytman assert(pkt); 449e263cd49SDmitry Fleytman 450e263cd49SDmitry Fleytman memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); 451e263cd49SDmitry Fleytman } 452e263cd49SDmitry Fleytman 453eb700029SDmitry Fleytman void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, 454eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt) 455eb700029SDmitry Fleytman { 456eb700029SDmitry Fleytman assert(pkt); 457eb700029SDmitry Fleytman 458eb700029SDmitry Fleytman iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr); 459eb700029SDmitry Fleytman } 460eb700029SDmitry Fleytman 461ffbd2dbdSAkihiko Odaki void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt) 462ffbd2dbdSAkihiko Odaki { 463ffbd2dbdSAkihiko Odaki assert(pkt); 464ffbd2dbdSAkihiko Odaki 465ffbd2dbdSAkihiko Odaki memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr)); 466ffbd2dbdSAkihiko Odaki } 467ffbd2dbdSAkihiko Odaki 468605d52e6SDmitry Fleytman bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt) 469e263cd49SDmitry Fleytman { 470e263cd49SDmitry Fleytman assert(pkt); 471e263cd49SDmitry Fleytman 472df8bf7a7SDmitry Fleytman return pkt->ehdr_buf_len ? true : false; 473e263cd49SDmitry Fleytman } 474e263cd49SDmitry Fleytman 475605d52e6SDmitry Fleytman uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt) 476e263cd49SDmitry Fleytman { 477e263cd49SDmitry Fleytman assert(pkt); 478e263cd49SDmitry Fleytman 479e263cd49SDmitry Fleytman return pkt->tci; 480e263cd49SDmitry Fleytman } 481eb700029SDmitry Fleytman 482eb700029SDmitry Fleytman bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid) 483eb700029SDmitry Fleytman { 484eb700029SDmitry Fleytman uint32_t cntr; 485eb700029SDmitry Fleytman uint16_t csum; 486eb700029SDmitry Fleytman uint32_t csl; 487eb700029SDmitry Fleytman 488eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_entry(); 489eb700029SDmitry Fleytman 49069ff5ef8SAkihiko Odaki if (!pkt->hasip4) { 491eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_not_ip4(); 492eb700029SDmitry Fleytman return false; 493eb700029SDmitry Fleytman } 494eb700029SDmitry Fleytman 495eb700029SDmitry Fleytman csl = pkt->l4hdr_off - pkt->l3hdr_off; 496eb700029SDmitry Fleytman 497eb700029SDmitry Fleytman cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len, 498eb700029SDmitry Fleytman pkt->l3hdr_off, 499eb700029SDmitry Fleytman csl, 0); 500eb700029SDmitry Fleytman 501eb700029SDmitry Fleytman csum = net_checksum_finish(cntr); 502eb700029SDmitry Fleytman 503eb700029SDmitry Fleytman *csum_valid = (csum == 0); 504eb700029SDmitry Fleytman 505eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl, 506eb700029SDmitry Fleytman cntr, csum, *csum_valid); 507eb700029SDmitry Fleytman 508eb700029SDmitry Fleytman return true; 509eb700029SDmitry Fleytman } 510eb700029SDmitry Fleytman 511eb700029SDmitry Fleytman static uint16_t 512eb700029SDmitry Fleytman _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt) 513eb700029SDmitry Fleytman { 514eb700029SDmitry Fleytman uint32_t cntr; 515eb700029SDmitry Fleytman uint16_t csum; 516eb700029SDmitry Fleytman uint16_t csl; 517eb700029SDmitry Fleytman uint32_t cso; 518eb700029SDmitry Fleytman 519eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_entry(); 520eb700029SDmitry Fleytman 52169ff5ef8SAkihiko Odaki if (pkt->hasip4) { 522*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 523eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 524eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_udp(); 525eb700029SDmitry Fleytman } else { 526eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) - 527eb700029SDmitry Fleytman IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr); 528eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_tcp(); 529eb700029SDmitry Fleytman } 530eb700029SDmitry Fleytman 531eb700029SDmitry Fleytman cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr, 532eb700029SDmitry Fleytman csl, &cso); 533eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 534eb700029SDmitry Fleytman } else { 535*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 536eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 537eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_udp(); 538eb700029SDmitry Fleytman } else { 539eb700029SDmitry Fleytman struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr; 540eb700029SDmitry Fleytman size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off; 541eb700029SDmitry Fleytman size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header); 542eb700029SDmitry Fleytman 543eb700029SDmitry Fleytman csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - 544eb700029SDmitry Fleytman ip6opts_len; 545eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_tcp(); 546eb700029SDmitry Fleytman } 547eb700029SDmitry Fleytman 548eb700029SDmitry Fleytman cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl, 549eb700029SDmitry Fleytman pkt->ip6hdr_info.l4proto, &cso); 550eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 551eb700029SDmitry Fleytman } 552eb700029SDmitry Fleytman 553eb700029SDmitry Fleytman cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len, 554eb700029SDmitry Fleytman pkt->l4hdr_off, csl, cso); 555eb700029SDmitry Fleytman 5560dacea92SEd Swierk csum = net_checksum_finish_nozero(cntr); 557eb700029SDmitry Fleytman 558eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum); 559eb700029SDmitry Fleytman 560eb700029SDmitry Fleytman return csum; 561eb700029SDmitry Fleytman } 562eb700029SDmitry Fleytman 563eb700029SDmitry Fleytman bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) 564eb700029SDmitry Fleytman { 565eb700029SDmitry Fleytman uint16_t csum; 566eb700029SDmitry Fleytman 567eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_entry(); 568eb700029SDmitry Fleytman 569*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_TCP && 570*65f474bbSAkihiko Odaki pkt->l4hdr_info.proto != ETH_L4_HDR_PROTO_UDP) { 571eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_not_xxp(); 572eb700029SDmitry Fleytman return false; 573eb700029SDmitry Fleytman } 574eb700029SDmitry Fleytman 575*65f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP && 576*65f474bbSAkihiko Odaki pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 577eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum(); 578eb700029SDmitry Fleytman return false; 579eb700029SDmitry Fleytman } 580eb700029SDmitry Fleytman 58169ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 582eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); 583eb700029SDmitry Fleytman return false; 584eb700029SDmitry Fleytman } 585eb700029SDmitry Fleytman 586eb700029SDmitry Fleytman csum = _net_rx_pkt_calc_l4_csum(pkt); 587eb700029SDmitry Fleytman 588eb700029SDmitry Fleytman *csum_valid = ((csum == 0) || (csum == 0xFFFF)); 589eb700029SDmitry Fleytman 590eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); 591eb700029SDmitry Fleytman 592eb700029SDmitry Fleytman return true; 593eb700029SDmitry Fleytman } 594eb700029SDmitry Fleytman 595eb700029SDmitry Fleytman bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt) 596eb700029SDmitry Fleytman { 597eb700029SDmitry Fleytman uint16_t csum = 0; 598eb700029SDmitry Fleytman uint32_t l4_cso; 599eb700029SDmitry Fleytman 600eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_entry(); 601eb700029SDmitry Fleytman 602*65f474bbSAkihiko Odaki switch (pkt->l4hdr_info.proto) { 603*65f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_TCP: 604eb700029SDmitry Fleytman l4_cso = offsetof(struct tcp_header, th_sum); 605eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso); 606*65f474bbSAkihiko Odaki break; 607*65f474bbSAkihiko Odaki 608*65f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_UDP: 609eb700029SDmitry Fleytman if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 610eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum(); 611eb700029SDmitry Fleytman return false; 612eb700029SDmitry Fleytman } 613eb700029SDmitry Fleytman l4_cso = offsetof(struct udp_header, uh_sum); 614eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp(l4_cso); 615*65f474bbSAkihiko Odaki break; 616*65f474bbSAkihiko Odaki 617*65f474bbSAkihiko Odaki default: 618eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_not_xxp(); 619eb700029SDmitry Fleytman return false; 620eb700029SDmitry Fleytman } 621eb700029SDmitry Fleytman 62269ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 623eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_ip4_fragment(); 624eb700029SDmitry Fleytman return false; 625eb700029SDmitry Fleytman } 626eb700029SDmitry Fleytman 627eb700029SDmitry Fleytman /* Set zero to checksum word */ 628eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 629eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 630eb700029SDmitry Fleytman &csum, sizeof(csum)); 631eb700029SDmitry Fleytman 632eb700029SDmitry Fleytman /* Calculate L4 checksum */ 633eb700029SDmitry Fleytman csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt)); 634eb700029SDmitry Fleytman 635eb700029SDmitry Fleytman /* Set calculated checksum to checksum word */ 636eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 637eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 638eb700029SDmitry Fleytman &csum, sizeof(csum)); 639eb700029SDmitry Fleytman 640eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum); 641eb700029SDmitry Fleytman 642eb700029SDmitry Fleytman return true; 643eb700029SDmitry Fleytman } 644