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" 19*907209e3SAkihiko 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, 140eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan, 141eb700029SDmitry Fleytman uint16_t vet) 142eb700029SDmitry Fleytman { 143eb700029SDmitry Fleytman uint16_t tci = 0; 144eb700029SDmitry Fleytman uint16_t ploff = iovoff; 145eb700029SDmitry Fleytman assert(pkt); 146eb700029SDmitry Fleytman 147eb700029SDmitry Fleytman if (strip_vlan) { 148df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, 1497edf2f1dSAkihiko Odaki &pkt->ehdr_buf, 150eb700029SDmitry Fleytman &ploff, &tci); 151df8bf7a7SDmitry Fleytman } else { 152df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 153eb700029SDmitry Fleytman } 154eb700029SDmitry Fleytman 155eb700029SDmitry Fleytman pkt->tci = tci; 156eb700029SDmitry Fleytman 157eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 158e263cd49SDmitry Fleytman } 159e263cd49SDmitry Fleytman 160605d52e6SDmitry Fleytman void net_rx_pkt_dump(struct NetRxPkt *pkt) 161e263cd49SDmitry Fleytman { 162605d52e6SDmitry Fleytman #ifdef NET_RX_PKT_DEBUG 163e263cd49SDmitry Fleytman assert(pkt); 164e263cd49SDmitry Fleytman 165df8bf7a7SDmitry Fleytman printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n", 166df8bf7a7SDmitry Fleytman pkt->tot_len, pkt->ehdr_buf_len, pkt->tci); 167e263cd49SDmitry Fleytman #endif 168e263cd49SDmitry Fleytman } 169e263cd49SDmitry Fleytman 170605d52e6SDmitry Fleytman void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, 171e263cd49SDmitry Fleytman eth_pkt_types_e packet_type) 172e263cd49SDmitry Fleytman { 173e263cd49SDmitry Fleytman assert(pkt); 174e263cd49SDmitry Fleytman 175e263cd49SDmitry Fleytman pkt->packet_type = packet_type; 176e263cd49SDmitry Fleytman 177e263cd49SDmitry Fleytman } 178e263cd49SDmitry Fleytman 179605d52e6SDmitry Fleytman eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt) 180e263cd49SDmitry Fleytman { 181e263cd49SDmitry Fleytman assert(pkt); 182e263cd49SDmitry Fleytman 183e263cd49SDmitry Fleytman return pkt->packet_type; 184e263cd49SDmitry Fleytman } 185e263cd49SDmitry Fleytman 186605d52e6SDmitry Fleytman size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt) 187e263cd49SDmitry Fleytman { 188e263cd49SDmitry Fleytman assert(pkt); 189e263cd49SDmitry Fleytman 190e263cd49SDmitry Fleytman return pkt->tot_len; 191e263cd49SDmitry Fleytman } 192e263cd49SDmitry Fleytman 1932f0fa232SAkihiko Odaki void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, 1942f0fa232SAkihiko Odaki const struct iovec *iov, size_t iovcnt, 1952f0fa232SAkihiko Odaki size_t iovoff) 196fcf0cdc3SShmulik Ladkani { 197fcf0cdc3SShmulik Ladkani assert(pkt); 198fcf0cdc3SShmulik Ladkani 1992f0fa232SAkihiko Odaki eth_get_protocols(iov, iovcnt, iovoff, &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, 20665f474bbSAkihiko Odaki EthL4HdrProto *l4hdr_proto) 207e263cd49SDmitry Fleytman { 208e263cd49SDmitry Fleytman assert(pkt); 209e263cd49SDmitry Fleytman 21069ff5ef8SAkihiko Odaki *hasip4 = pkt->hasip4; 21169ff5ef8SAkihiko Odaki *hasip6 = pkt->hasip6; 21265f474bbSAkihiko 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 static inline void 244eb700029SDmitry Fleytman _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, 245eb700029SDmitry Fleytman void *ptr, size_t size) 246eb700029SDmitry Fleytman { 247eb700029SDmitry Fleytman memcpy(&rss_input[*bytes_written], ptr, size); 248eb700029SDmitry Fleytman trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written); 249eb700029SDmitry Fleytman *bytes_written += size; 250eb700029SDmitry Fleytman } 251eb700029SDmitry Fleytman 252eb700029SDmitry Fleytman static inline void 253eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(uint8_t *rss_input, 254eb700029SDmitry Fleytman struct NetRxPkt *pkt, 255eb700029SDmitry Fleytman size_t *bytes_written) 256eb700029SDmitry Fleytman { 257eb700029SDmitry Fleytman struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr; 258eb700029SDmitry Fleytman 259eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 260eb700029SDmitry Fleytman &ip4_hdr->ip_src, sizeof(uint32_t)); 261eb700029SDmitry Fleytman 262eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 263eb700029SDmitry Fleytman &ip4_hdr->ip_dst, sizeof(uint32_t)); 264eb700029SDmitry Fleytman } 265eb700029SDmitry Fleytman 266eb700029SDmitry Fleytman static inline void 267eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(uint8_t *rss_input, 268eb700029SDmitry Fleytman struct NetRxPkt *pkt, 269eb700029SDmitry Fleytman bool ipv6ex, size_t *bytes_written) 270eb700029SDmitry Fleytman { 271eb700029SDmitry Fleytman eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info; 272eb700029SDmitry Fleytman 273eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 274eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src 275eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_src, 276eb700029SDmitry Fleytman sizeof(struct in6_address)); 277eb700029SDmitry Fleytman 278eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 279eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst 280eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_dst, 281eb700029SDmitry Fleytman sizeof(struct in6_address)); 282eb700029SDmitry Fleytman } 283eb700029SDmitry Fleytman 284eb700029SDmitry Fleytman static inline void 285eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(uint8_t *rss_input, 286eb700029SDmitry Fleytman struct NetRxPkt *pkt, 287eb700029SDmitry Fleytman size_t *bytes_written) 288eb700029SDmitry Fleytman { 289eb700029SDmitry Fleytman struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp; 290eb700029SDmitry Fleytman 291eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 292eb700029SDmitry Fleytman &tcphdr->th_sport, sizeof(uint16_t)); 293eb700029SDmitry Fleytman 294eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 295eb700029SDmitry Fleytman &tcphdr->th_dport, sizeof(uint16_t)); 296eb700029SDmitry Fleytman } 297eb700029SDmitry Fleytman 29833bbc05eSYuri Benditovich static inline void 29933bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(uint8_t *rss_input, 30033bbc05eSYuri Benditovich struct NetRxPkt *pkt, 30133bbc05eSYuri Benditovich size_t *bytes_written) 30233bbc05eSYuri Benditovich { 30333bbc05eSYuri Benditovich struct udp_header *udphdr = &pkt->l4hdr_info.hdr.udp; 30433bbc05eSYuri Benditovich 30533bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 30633bbc05eSYuri Benditovich &udphdr->uh_sport, sizeof(uint16_t)); 30733bbc05eSYuri Benditovich 30833bbc05eSYuri Benditovich _net_rx_rss_add_chunk(rss_input, bytes_written, 30933bbc05eSYuri Benditovich &udphdr->uh_dport, sizeof(uint16_t)); 31033bbc05eSYuri Benditovich } 31133bbc05eSYuri Benditovich 312eb700029SDmitry Fleytman uint32_t 313eb700029SDmitry Fleytman net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, 314eb700029SDmitry Fleytman NetRxPktRssType type, 315eb700029SDmitry Fleytman uint8_t *key) 316eb700029SDmitry Fleytman { 317eb700029SDmitry Fleytman uint8_t rss_input[36]; 318eb700029SDmitry Fleytman size_t rss_length = 0; 319eb700029SDmitry Fleytman uint32_t rss_hash = 0; 320eb700029SDmitry Fleytman net_toeplitz_key key_data; 321eb700029SDmitry Fleytman 322eb700029SDmitry Fleytman switch (type) { 323eb700029SDmitry Fleytman case NetPktRssIpV4: 32469ff5ef8SAkihiko Odaki assert(pkt->hasip4); 325eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4(); 326eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 327eb700029SDmitry Fleytman break; 328eb700029SDmitry Fleytman case NetPktRssIpV4Tcp: 32969ff5ef8SAkihiko Odaki assert(pkt->hasip4); 33065f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 331eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4_tcp(); 332eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 333eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 334eb700029SDmitry Fleytman break; 335eb700029SDmitry Fleytman case NetPktRssIpV6Tcp: 33669ff5ef8SAkihiko Odaki assert(pkt->hasip6); 33765f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 338eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_tcp(); 3392683a927SYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 340eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 341eb700029SDmitry Fleytman break; 342eb700029SDmitry Fleytman case NetPktRssIpV6: 34369ff5ef8SAkihiko Odaki assert(pkt->hasip6); 344eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6(); 345eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 346eb700029SDmitry Fleytman break; 347eb700029SDmitry Fleytman case NetPktRssIpV6Ex: 34869ff5ef8SAkihiko Odaki assert(pkt->hasip6); 349eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_ex(); 350eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 351eb700029SDmitry Fleytman break; 35233bbc05eSYuri Benditovich case NetPktRssIpV6TcpEx: 35369ff5ef8SAkihiko Odaki assert(pkt->hasip6); 35465f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP); 35533bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_tcp(); 35633bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 35733bbc05eSYuri Benditovich _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 35833bbc05eSYuri Benditovich break; 35933bbc05eSYuri Benditovich case NetPktRssIpV4Udp: 36069ff5ef8SAkihiko Odaki assert(pkt->hasip4); 36165f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 36233bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip4_udp(); 36333bbc05eSYuri Benditovich _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 36433bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 36533bbc05eSYuri Benditovich break; 36633bbc05eSYuri Benditovich case NetPktRssIpV6Udp: 36769ff5ef8SAkihiko Odaki assert(pkt->hasip6); 36865f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 36933bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_udp(); 37033bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 37133bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 37233bbc05eSYuri Benditovich break; 37333bbc05eSYuri Benditovich case NetPktRssIpV6UdpEx: 37469ff5ef8SAkihiko Odaki assert(pkt->hasip6); 37565f474bbSAkihiko Odaki assert(pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP); 37633bbc05eSYuri Benditovich trace_net_rx_pkt_rss_ip6_ex_udp(); 37733bbc05eSYuri Benditovich _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 37833bbc05eSYuri Benditovich _net_rx_rss_prepare_udp(&rss_input[0], pkt, &rss_length); 37933bbc05eSYuri Benditovich break; 380eb700029SDmitry Fleytman default: 381eb700029SDmitry Fleytman assert(false); 382eb700029SDmitry Fleytman break; 383eb700029SDmitry Fleytman } 384eb700029SDmitry Fleytman 385eb700029SDmitry Fleytman net_toeplitz_key_init(&key_data, key); 386eb700029SDmitry Fleytman net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data); 387eb700029SDmitry Fleytman 388eb700029SDmitry Fleytman trace_net_rx_pkt_rss_hash(rss_length, rss_hash); 389eb700029SDmitry Fleytman 390eb700029SDmitry Fleytman return rss_hash; 391eb700029SDmitry Fleytman } 392eb700029SDmitry Fleytman 393eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt) 394eb700029SDmitry Fleytman { 395eb700029SDmitry Fleytman assert(pkt); 396eb700029SDmitry Fleytman 39769ff5ef8SAkihiko Odaki if (pkt->hasip4) { 398eb700029SDmitry Fleytman return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id); 399eb700029SDmitry Fleytman } 400eb700029SDmitry Fleytman 401eb700029SDmitry Fleytman return 0; 402eb700029SDmitry Fleytman } 403eb700029SDmitry Fleytman 404eb700029SDmitry Fleytman bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt) 405eb700029SDmitry Fleytman { 406eb700029SDmitry Fleytman assert(pkt); 407eb700029SDmitry Fleytman 40865f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 409eb700029SDmitry Fleytman return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK; 410eb700029SDmitry Fleytman } 411eb700029SDmitry Fleytman 412eb700029SDmitry Fleytman return false; 413eb700029SDmitry Fleytman } 414eb700029SDmitry Fleytman 415eb700029SDmitry Fleytman bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt) 416eb700029SDmitry Fleytman { 417eb700029SDmitry Fleytman assert(pkt); 418eb700029SDmitry Fleytman 41965f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_TCP) { 420eb700029SDmitry Fleytman return pkt->l4hdr_info.has_tcp_data; 421eb700029SDmitry Fleytman } 422eb700029SDmitry Fleytman 423eb700029SDmitry Fleytman return false; 424eb700029SDmitry Fleytman } 425eb700029SDmitry Fleytman 426605d52e6SDmitry Fleytman struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) 427e263cd49SDmitry Fleytman { 428e263cd49SDmitry Fleytman assert(pkt); 429e263cd49SDmitry Fleytman 430e263cd49SDmitry Fleytman return pkt->vec; 431e263cd49SDmitry Fleytman } 432e263cd49SDmitry Fleytman 433eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) 434eb700029SDmitry Fleytman { 435eb700029SDmitry Fleytman assert(pkt); 436eb700029SDmitry Fleytman 437eb700029SDmitry Fleytman return pkt->vec_len; 438eb700029SDmitry Fleytman } 439eb700029SDmitry Fleytman 440605d52e6SDmitry Fleytman void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, 441e263cd49SDmitry Fleytman struct virtio_net_hdr *vhdr) 442e263cd49SDmitry Fleytman { 443e263cd49SDmitry Fleytman assert(pkt); 444e263cd49SDmitry Fleytman 445e263cd49SDmitry Fleytman memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); 446e263cd49SDmitry Fleytman } 447e263cd49SDmitry Fleytman 448eb700029SDmitry Fleytman void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, 449eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt) 450eb700029SDmitry Fleytman { 451eb700029SDmitry Fleytman assert(pkt); 452eb700029SDmitry Fleytman 453eb700029SDmitry Fleytman iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr); 454eb700029SDmitry Fleytman } 455eb700029SDmitry Fleytman 456ffbd2dbdSAkihiko Odaki void net_rx_pkt_unset_vhdr(struct NetRxPkt *pkt) 457ffbd2dbdSAkihiko Odaki { 458ffbd2dbdSAkihiko Odaki assert(pkt); 459ffbd2dbdSAkihiko Odaki 460ffbd2dbdSAkihiko Odaki memset(&pkt->virt_hdr, 0, sizeof(pkt->virt_hdr)); 461ffbd2dbdSAkihiko Odaki } 462ffbd2dbdSAkihiko Odaki 463605d52e6SDmitry Fleytman bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt) 464e263cd49SDmitry Fleytman { 465e263cd49SDmitry Fleytman assert(pkt); 466e263cd49SDmitry Fleytman 467df8bf7a7SDmitry Fleytman return pkt->ehdr_buf_len ? true : false; 468e263cd49SDmitry Fleytman } 469e263cd49SDmitry Fleytman 470605d52e6SDmitry Fleytman uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt) 471e263cd49SDmitry Fleytman { 472e263cd49SDmitry Fleytman assert(pkt); 473e263cd49SDmitry Fleytman 474e263cd49SDmitry Fleytman return pkt->tci; 475e263cd49SDmitry Fleytman } 476eb700029SDmitry Fleytman 477eb700029SDmitry Fleytman bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid) 478eb700029SDmitry Fleytman { 479eb700029SDmitry Fleytman uint32_t cntr; 480eb700029SDmitry Fleytman uint16_t csum; 481eb700029SDmitry Fleytman uint32_t csl; 482eb700029SDmitry Fleytman 483eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_entry(); 484eb700029SDmitry Fleytman 48569ff5ef8SAkihiko Odaki if (!pkt->hasip4) { 486eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_not_ip4(); 487eb700029SDmitry Fleytman return false; 488eb700029SDmitry Fleytman } 489eb700029SDmitry Fleytman 490eb700029SDmitry Fleytman csl = pkt->l4hdr_off - pkt->l3hdr_off; 491eb700029SDmitry Fleytman 492eb700029SDmitry Fleytman cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len, 493eb700029SDmitry Fleytman pkt->l3hdr_off, 494eb700029SDmitry Fleytman csl, 0); 495eb700029SDmitry Fleytman 496eb700029SDmitry Fleytman csum = net_checksum_finish(cntr); 497eb700029SDmitry Fleytman 498eb700029SDmitry Fleytman *csum_valid = (csum == 0); 499eb700029SDmitry Fleytman 500eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl, 501eb700029SDmitry Fleytman cntr, csum, *csum_valid); 502eb700029SDmitry Fleytman 503eb700029SDmitry Fleytman return true; 504eb700029SDmitry Fleytman } 505eb700029SDmitry Fleytman 506eb700029SDmitry Fleytman static uint16_t 507eb700029SDmitry Fleytman _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt) 508eb700029SDmitry Fleytman { 509eb700029SDmitry Fleytman uint32_t cntr; 510eb700029SDmitry Fleytman uint16_t csum; 511eb700029SDmitry Fleytman uint16_t csl; 512eb700029SDmitry Fleytman uint32_t cso; 513eb700029SDmitry Fleytman 514eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_entry(); 515eb700029SDmitry Fleytman 51669ff5ef8SAkihiko Odaki if (pkt->hasip4) { 51765f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 518eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 519eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_udp(); 520eb700029SDmitry Fleytman } else { 521eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) - 522eb700029SDmitry Fleytman IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr); 523eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_tcp(); 524eb700029SDmitry Fleytman } 525eb700029SDmitry Fleytman 526eb700029SDmitry Fleytman cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr, 527eb700029SDmitry Fleytman csl, &cso); 528eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 529eb700029SDmitry Fleytman } else { 53065f474bbSAkihiko Odaki if (pkt->l4hdr_info.proto == ETH_L4_HDR_PROTO_UDP) { 531eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 532eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_udp(); 533eb700029SDmitry Fleytman } else { 534eb700029SDmitry Fleytman struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr; 535eb700029SDmitry Fleytman size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off; 536eb700029SDmitry Fleytman size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header); 537eb700029SDmitry Fleytman 538eb700029SDmitry Fleytman csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - 539eb700029SDmitry Fleytman ip6opts_len; 540eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_tcp(); 541eb700029SDmitry Fleytman } 542eb700029SDmitry Fleytman 543eb700029SDmitry Fleytman cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl, 544eb700029SDmitry Fleytman pkt->ip6hdr_info.l4proto, &cso); 545eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 546eb700029SDmitry Fleytman } 547eb700029SDmitry Fleytman 548eb700029SDmitry Fleytman cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len, 549eb700029SDmitry Fleytman pkt->l4hdr_off, csl, cso); 550eb700029SDmitry Fleytman 5510dacea92SEd Swierk csum = net_checksum_finish_nozero(cntr); 552eb700029SDmitry Fleytman 553eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum); 554eb700029SDmitry Fleytman 555eb700029SDmitry Fleytman return csum; 556eb700029SDmitry Fleytman } 557eb700029SDmitry Fleytman 558*907209e3SAkihiko Odaki static bool 559*907209e3SAkihiko Odaki _net_rx_pkt_validate_sctp_sum(struct NetRxPkt *pkt) 560*907209e3SAkihiko Odaki { 561*907209e3SAkihiko Odaki size_t csum_off; 562*907209e3SAkihiko Odaki size_t off = pkt->l4hdr_off; 563*907209e3SAkihiko Odaki size_t vec_len = pkt->vec_len; 564*907209e3SAkihiko Odaki struct iovec *vec; 565*907209e3SAkihiko Odaki uint32_t calculated = 0; 566*907209e3SAkihiko Odaki uint32_t original; 567*907209e3SAkihiko Odaki bool valid; 568*907209e3SAkihiko Odaki 569*907209e3SAkihiko Odaki for (vec = pkt->vec; vec->iov_len < off; vec++) { 570*907209e3SAkihiko Odaki off -= vec->iov_len; 571*907209e3SAkihiko Odaki vec_len--; 572*907209e3SAkihiko Odaki } 573*907209e3SAkihiko Odaki 574*907209e3SAkihiko Odaki csum_off = off + 8; 575*907209e3SAkihiko Odaki 576*907209e3SAkihiko Odaki if (!iov_to_buf(vec, vec_len, csum_off, &original, sizeof(original))) { 577*907209e3SAkihiko Odaki return false; 578*907209e3SAkihiko Odaki } 579*907209e3SAkihiko Odaki 580*907209e3SAkihiko Odaki if (!iov_from_buf(vec, vec_len, csum_off, 581*907209e3SAkihiko Odaki &calculated, sizeof(calculated))) { 582*907209e3SAkihiko Odaki return false; 583*907209e3SAkihiko Odaki } 584*907209e3SAkihiko Odaki 585*907209e3SAkihiko Odaki calculated = crc32c(0xffffffff, 586*907209e3SAkihiko Odaki (uint8_t *)vec->iov_base + off, vec->iov_len - off); 587*907209e3SAkihiko Odaki calculated = iov_crc32c(calculated ^ 0xffffffff, vec + 1, vec_len - 1); 588*907209e3SAkihiko Odaki valid = calculated == le32_to_cpu(original); 589*907209e3SAkihiko Odaki iov_from_buf(vec, vec_len, csum_off, &original, sizeof(original)); 590*907209e3SAkihiko Odaki 591*907209e3SAkihiko Odaki return valid; 592*907209e3SAkihiko Odaki } 593*907209e3SAkihiko Odaki 594eb700029SDmitry Fleytman bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) 595eb700029SDmitry Fleytman { 596*907209e3SAkihiko Odaki uint32_t csum; 597eb700029SDmitry Fleytman 598eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_entry(); 599eb700029SDmitry Fleytman 60069ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 601eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); 602eb700029SDmitry Fleytman return false; 603eb700029SDmitry Fleytman } 604eb700029SDmitry Fleytman 605*907209e3SAkihiko Odaki switch (pkt->l4hdr_info.proto) { 606*907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_UDP: 607*907209e3SAkihiko Odaki if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 608*907209e3SAkihiko Odaki trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum(); 609*907209e3SAkihiko Odaki return false; 610*907209e3SAkihiko Odaki } 611*907209e3SAkihiko Odaki /* fall through */ 612*907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_TCP: 613eb700029SDmitry Fleytman csum = _net_rx_pkt_calc_l4_csum(pkt); 614eb700029SDmitry Fleytman *csum_valid = ((csum == 0) || (csum == 0xFFFF)); 615*907209e3SAkihiko Odaki break; 616*907209e3SAkihiko Odaki 617*907209e3SAkihiko Odaki case ETH_L4_HDR_PROTO_SCTP: 618*907209e3SAkihiko Odaki *csum_valid = _net_rx_pkt_validate_sctp_sum(pkt); 619*907209e3SAkihiko Odaki break; 620*907209e3SAkihiko Odaki 621*907209e3SAkihiko Odaki default: 622*907209e3SAkihiko Odaki trace_net_rx_pkt_l4_csum_validate_not_xxp(); 623*907209e3SAkihiko Odaki return false; 624*907209e3SAkihiko Odaki } 625eb700029SDmitry Fleytman 626eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); 627eb700029SDmitry Fleytman 628eb700029SDmitry Fleytman return true; 629eb700029SDmitry Fleytman } 630eb700029SDmitry Fleytman 631eb700029SDmitry Fleytman bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt) 632eb700029SDmitry Fleytman { 633eb700029SDmitry Fleytman uint16_t csum = 0; 634eb700029SDmitry Fleytman uint32_t l4_cso; 635eb700029SDmitry Fleytman 636eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_entry(); 637eb700029SDmitry Fleytman 63865f474bbSAkihiko Odaki switch (pkt->l4hdr_info.proto) { 63965f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_TCP: 640eb700029SDmitry Fleytman l4_cso = offsetof(struct tcp_header, th_sum); 641eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso); 64265f474bbSAkihiko Odaki break; 64365f474bbSAkihiko Odaki 64465f474bbSAkihiko Odaki case ETH_L4_HDR_PROTO_UDP: 645eb700029SDmitry Fleytman if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 646eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum(); 647eb700029SDmitry Fleytman return false; 648eb700029SDmitry Fleytman } 649eb700029SDmitry Fleytman l4_cso = offsetof(struct udp_header, uh_sum); 650eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp(l4_cso); 65165f474bbSAkihiko Odaki break; 65265f474bbSAkihiko Odaki 65365f474bbSAkihiko Odaki default: 654eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_not_xxp(); 655eb700029SDmitry Fleytman return false; 656eb700029SDmitry Fleytman } 657eb700029SDmitry Fleytman 65869ff5ef8SAkihiko Odaki if (pkt->hasip4 && pkt->ip4hdr_info.fragment) { 659eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_ip4_fragment(); 660eb700029SDmitry Fleytman return false; 661eb700029SDmitry Fleytman } 662eb700029SDmitry Fleytman 663eb700029SDmitry Fleytman /* Set zero to checksum word */ 664eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 665eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 666eb700029SDmitry Fleytman &csum, sizeof(csum)); 667eb700029SDmitry Fleytman 668eb700029SDmitry Fleytman /* Calculate L4 checksum */ 669eb700029SDmitry Fleytman csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt)); 670eb700029SDmitry Fleytman 671eb700029SDmitry Fleytman /* Set calculated checksum to checksum word */ 672eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 673eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 674eb700029SDmitry Fleytman &csum, sizeof(csum)); 675eb700029SDmitry Fleytman 676eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum); 677eb700029SDmitry Fleytman 678eb700029SDmitry Fleytman return true; 679eb700029SDmitry Fleytman } 680