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 bool has_virt_hdr; 34e263cd49SDmitry Fleytman eth_pkt_types_e packet_type; 35e263cd49SDmitry Fleytman 36e263cd49SDmitry Fleytman /* Analysis results */ 37e263cd49SDmitry Fleytman bool isip4; 38e263cd49SDmitry Fleytman bool isip6; 39e263cd49SDmitry Fleytman bool isudp; 40e263cd49SDmitry Fleytman bool istcp; 41eb700029SDmitry Fleytman 42eb700029SDmitry Fleytman size_t l3hdr_off; 43eb700029SDmitry Fleytman size_t l4hdr_off; 44eb700029SDmitry Fleytman size_t l5hdr_off; 45eb700029SDmitry Fleytman 46eb700029SDmitry Fleytman eth_ip6_hdr_info ip6hdr_info; 47eb700029SDmitry Fleytman eth_ip4_hdr_info ip4hdr_info; 48eb700029SDmitry Fleytman eth_l4_hdr_info l4hdr_info; 49e263cd49SDmitry Fleytman }; 50e263cd49SDmitry Fleytman 51605d52e6SDmitry Fleytman void net_rx_pkt_init(struct NetRxPkt **pkt, bool has_virt_hdr) 52e263cd49SDmitry Fleytman { 53605d52e6SDmitry Fleytman struct NetRxPkt *p = g_malloc0(sizeof *p); 54e263cd49SDmitry Fleytman p->has_virt_hdr = has_virt_hdr; 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 96eb700029SDmitry Fleytman 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 110eb700029SDmitry Fleytman eth_get_protocols(pkt->vec, pkt->vec_len, &pkt->isip4, &pkt->isip6, 111eb700029SDmitry Fleytman &pkt->isudp, &pkt->istcp, 112eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 113eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 114eb700029SDmitry Fleytman 115eb700029SDmitry Fleytman trace_net_rx_pkt_parsed(pkt->isip4, pkt->isip6, pkt->isudp, pkt->istcp, 116eb700029SDmitry Fleytman pkt->l3hdr_off, pkt->l4hdr_off, pkt->l5hdr_off); 117eb700029SDmitry Fleytman } 118eb700029SDmitry Fleytman 119eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec(struct NetRxPkt *pkt, 120eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 121eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan) 122e263cd49SDmitry Fleytman { 123e263cd49SDmitry Fleytman uint16_t tci = 0; 124eb700029SDmitry Fleytman uint16_t ploff = iovoff; 125e263cd49SDmitry Fleytman assert(pkt); 126e263cd49SDmitry Fleytman 127e263cd49SDmitry Fleytman if (strip_vlan) { 128df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = eth_strip_vlan(iov, iovcnt, iovoff, pkt->ehdr_buf, 129eb700029SDmitry Fleytman &ploff, &tci); 130df8bf7a7SDmitry Fleytman } else { 131df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 132e263cd49SDmitry Fleytman } 133e263cd49SDmitry Fleytman 134e263cd49SDmitry Fleytman pkt->tci = tci; 135eb700029SDmitry Fleytman 136eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 137eb700029SDmitry Fleytman } 138eb700029SDmitry Fleytman 139eb700029SDmitry Fleytman void net_rx_pkt_attach_iovec_ex(struct NetRxPkt *pkt, 140eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt, 141eb700029SDmitry Fleytman size_t iovoff, bool strip_vlan, 142eb700029SDmitry Fleytman uint16_t vet) 143eb700029SDmitry Fleytman { 144eb700029SDmitry Fleytman uint16_t tci = 0; 145eb700029SDmitry Fleytman uint16_t ploff = iovoff; 146eb700029SDmitry Fleytman assert(pkt); 147eb700029SDmitry Fleytman 148eb700029SDmitry Fleytman if (strip_vlan) { 149df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = eth_strip_vlan_ex(iov, iovcnt, iovoff, vet, 150eb700029SDmitry Fleytman pkt->ehdr_buf, 151eb700029SDmitry Fleytman &ploff, &tci); 152df8bf7a7SDmitry Fleytman } else { 153df8bf7a7SDmitry Fleytman pkt->ehdr_buf_len = 0; 154eb700029SDmitry Fleytman } 155eb700029SDmitry Fleytman 156eb700029SDmitry Fleytman pkt->tci = tci; 157eb700029SDmitry Fleytman 158eb700029SDmitry Fleytman net_rx_pkt_pull_data(pkt, iov, iovcnt, ploff); 159e263cd49SDmitry Fleytman } 160e263cd49SDmitry Fleytman 161605d52e6SDmitry Fleytman void net_rx_pkt_dump(struct NetRxPkt *pkt) 162e263cd49SDmitry Fleytman { 163605d52e6SDmitry Fleytman #ifdef NET_RX_PKT_DEBUG 164e263cd49SDmitry Fleytman assert(pkt); 165e263cd49SDmitry Fleytman 166df8bf7a7SDmitry Fleytman printf("RX PKT: tot_len: %d, ehdr_buf_len: %lu, vlan_tag: %d\n", 167df8bf7a7SDmitry Fleytman pkt->tot_len, pkt->ehdr_buf_len, pkt->tci); 168e263cd49SDmitry Fleytman #endif 169e263cd49SDmitry Fleytman } 170e263cd49SDmitry Fleytman 171605d52e6SDmitry Fleytman void net_rx_pkt_set_packet_type(struct NetRxPkt *pkt, 172e263cd49SDmitry Fleytman eth_pkt_types_e packet_type) 173e263cd49SDmitry Fleytman { 174e263cd49SDmitry Fleytman assert(pkt); 175e263cd49SDmitry Fleytman 176e263cd49SDmitry Fleytman pkt->packet_type = packet_type; 177e263cd49SDmitry Fleytman 178e263cd49SDmitry Fleytman } 179e263cd49SDmitry Fleytman 180605d52e6SDmitry Fleytman eth_pkt_types_e net_rx_pkt_get_packet_type(struct NetRxPkt *pkt) 181e263cd49SDmitry Fleytman { 182e263cd49SDmitry Fleytman assert(pkt); 183e263cd49SDmitry Fleytman 184e263cd49SDmitry Fleytman return pkt->packet_type; 185e263cd49SDmitry Fleytman } 186e263cd49SDmitry Fleytman 187605d52e6SDmitry Fleytman size_t net_rx_pkt_get_total_len(struct NetRxPkt *pkt) 188e263cd49SDmitry Fleytman { 189e263cd49SDmitry Fleytman assert(pkt); 190e263cd49SDmitry Fleytman 191e263cd49SDmitry Fleytman return pkt->tot_len; 192e263cd49SDmitry Fleytman } 193e263cd49SDmitry Fleytman 194605d52e6SDmitry Fleytman void net_rx_pkt_set_protocols(struct NetRxPkt *pkt, const void *data, 195fcf0cdc3SShmulik Ladkani size_t len) 196fcf0cdc3SShmulik Ladkani { 197eb700029SDmitry Fleytman const struct iovec iov = { 198eb700029SDmitry Fleytman .iov_base = (void *)data, 199eb700029SDmitry Fleytman .iov_len = len 200eb700029SDmitry Fleytman }; 201eb700029SDmitry Fleytman 202fcf0cdc3SShmulik Ladkani assert(pkt); 203fcf0cdc3SShmulik Ladkani 204eb700029SDmitry Fleytman eth_get_protocols(&iov, 1, &pkt->isip4, &pkt->isip6, 205eb700029SDmitry Fleytman &pkt->isudp, &pkt->istcp, 206eb700029SDmitry Fleytman &pkt->l3hdr_off, &pkt->l4hdr_off, &pkt->l5hdr_off, 207eb700029SDmitry Fleytman &pkt->ip6hdr_info, &pkt->ip4hdr_info, &pkt->l4hdr_info); 208fcf0cdc3SShmulik Ladkani } 209fcf0cdc3SShmulik Ladkani 210605d52e6SDmitry Fleytman void net_rx_pkt_get_protocols(struct NetRxPkt *pkt, 211e263cd49SDmitry Fleytman bool *isip4, bool *isip6, 212e263cd49SDmitry Fleytman bool *isudp, bool *istcp) 213e263cd49SDmitry Fleytman { 214e263cd49SDmitry Fleytman assert(pkt); 215e263cd49SDmitry Fleytman 216e263cd49SDmitry Fleytman *isip4 = pkt->isip4; 217e263cd49SDmitry Fleytman *isip6 = pkt->isip6; 218e263cd49SDmitry Fleytman *isudp = pkt->isudp; 219e263cd49SDmitry Fleytman *istcp = pkt->istcp; 220e263cd49SDmitry Fleytman } 221e263cd49SDmitry Fleytman 222eb700029SDmitry Fleytman size_t net_rx_pkt_get_l3_hdr_offset(struct NetRxPkt *pkt) 223eb700029SDmitry Fleytman { 224eb700029SDmitry Fleytman assert(pkt); 225eb700029SDmitry Fleytman return pkt->l3hdr_off; 226eb700029SDmitry Fleytman } 227eb700029SDmitry Fleytman 228eb700029SDmitry Fleytman size_t net_rx_pkt_get_l4_hdr_offset(struct NetRxPkt *pkt) 229eb700029SDmitry Fleytman { 230eb700029SDmitry Fleytman assert(pkt); 231eb700029SDmitry Fleytman return pkt->l4hdr_off; 232eb700029SDmitry Fleytman } 233eb700029SDmitry Fleytman 234eb700029SDmitry Fleytman size_t net_rx_pkt_get_l5_hdr_offset(struct NetRxPkt *pkt) 235eb700029SDmitry Fleytman { 236eb700029SDmitry Fleytman assert(pkt); 237eb700029SDmitry Fleytman return pkt->l5hdr_off; 238eb700029SDmitry Fleytman } 239eb700029SDmitry Fleytman 240eb700029SDmitry Fleytman eth_ip6_hdr_info *net_rx_pkt_get_ip6_info(struct NetRxPkt *pkt) 241eb700029SDmitry Fleytman { 242eb700029SDmitry Fleytman return &pkt->ip6hdr_info; 243eb700029SDmitry Fleytman } 244eb700029SDmitry Fleytman 245eb700029SDmitry Fleytman eth_ip4_hdr_info *net_rx_pkt_get_ip4_info(struct NetRxPkt *pkt) 246eb700029SDmitry Fleytman { 247eb700029SDmitry Fleytman return &pkt->ip4hdr_info; 248eb700029SDmitry Fleytman } 249eb700029SDmitry Fleytman 250eb700029SDmitry Fleytman eth_l4_hdr_info *net_rx_pkt_get_l4_info(struct NetRxPkt *pkt) 251eb700029SDmitry Fleytman { 252eb700029SDmitry Fleytman return &pkt->l4hdr_info; 253eb700029SDmitry Fleytman } 254eb700029SDmitry Fleytman 255eb700029SDmitry Fleytman static inline void 256eb700029SDmitry Fleytman _net_rx_rss_add_chunk(uint8_t *rss_input, size_t *bytes_written, 257eb700029SDmitry Fleytman void *ptr, size_t size) 258eb700029SDmitry Fleytman { 259eb700029SDmitry Fleytman memcpy(&rss_input[*bytes_written], ptr, size); 260eb700029SDmitry Fleytman trace_net_rx_pkt_rss_add_chunk(ptr, size, *bytes_written); 261eb700029SDmitry Fleytman *bytes_written += size; 262eb700029SDmitry Fleytman } 263eb700029SDmitry Fleytman 264eb700029SDmitry Fleytman static inline void 265eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(uint8_t *rss_input, 266eb700029SDmitry Fleytman struct NetRxPkt *pkt, 267eb700029SDmitry Fleytman size_t *bytes_written) 268eb700029SDmitry Fleytman { 269eb700029SDmitry Fleytman struct ip_header *ip4_hdr = &pkt->ip4hdr_info.ip4_hdr; 270eb700029SDmitry Fleytman 271eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 272eb700029SDmitry Fleytman &ip4_hdr->ip_src, sizeof(uint32_t)); 273eb700029SDmitry Fleytman 274eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 275eb700029SDmitry Fleytman &ip4_hdr->ip_dst, sizeof(uint32_t)); 276eb700029SDmitry Fleytman } 277eb700029SDmitry Fleytman 278eb700029SDmitry Fleytman static inline void 279eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(uint8_t *rss_input, 280eb700029SDmitry Fleytman struct NetRxPkt *pkt, 281eb700029SDmitry Fleytman bool ipv6ex, size_t *bytes_written) 282eb700029SDmitry Fleytman { 283eb700029SDmitry Fleytman eth_ip6_hdr_info *ip6info = &pkt->ip6hdr_info; 284eb700029SDmitry Fleytman 285eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 286eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_src_valid) ? &ip6info->rss_ex_src 287eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_src, 288eb700029SDmitry Fleytman sizeof(struct in6_address)); 289eb700029SDmitry Fleytman 290eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 291eb700029SDmitry Fleytman (ipv6ex && ip6info->rss_ex_dst_valid) ? &ip6info->rss_ex_dst 292eb700029SDmitry Fleytman : &ip6info->ip6_hdr.ip6_dst, 293eb700029SDmitry Fleytman sizeof(struct in6_address)); 294eb700029SDmitry Fleytman } 295eb700029SDmitry Fleytman 296eb700029SDmitry Fleytman static inline void 297eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(uint8_t *rss_input, 298eb700029SDmitry Fleytman struct NetRxPkt *pkt, 299eb700029SDmitry Fleytman size_t *bytes_written) 300eb700029SDmitry Fleytman { 301eb700029SDmitry Fleytman struct tcp_header *tcphdr = &pkt->l4hdr_info.hdr.tcp; 302eb700029SDmitry Fleytman 303eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 304eb700029SDmitry Fleytman &tcphdr->th_sport, sizeof(uint16_t)); 305eb700029SDmitry Fleytman 306eb700029SDmitry Fleytman _net_rx_rss_add_chunk(rss_input, bytes_written, 307eb700029SDmitry Fleytman &tcphdr->th_dport, sizeof(uint16_t)); 308eb700029SDmitry Fleytman } 309eb700029SDmitry Fleytman 310eb700029SDmitry Fleytman uint32_t 311eb700029SDmitry Fleytman net_rx_pkt_calc_rss_hash(struct NetRxPkt *pkt, 312eb700029SDmitry Fleytman NetRxPktRssType type, 313eb700029SDmitry Fleytman uint8_t *key) 314eb700029SDmitry Fleytman { 315eb700029SDmitry Fleytman uint8_t rss_input[36]; 316eb700029SDmitry Fleytman size_t rss_length = 0; 317eb700029SDmitry Fleytman uint32_t rss_hash = 0; 318eb700029SDmitry Fleytman net_toeplitz_key key_data; 319eb700029SDmitry Fleytman 320eb700029SDmitry Fleytman switch (type) { 321eb700029SDmitry Fleytman case NetPktRssIpV4: 322eb700029SDmitry Fleytman assert(pkt->isip4); 323eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4(); 324eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 325eb700029SDmitry Fleytman break; 326eb700029SDmitry Fleytman case NetPktRssIpV4Tcp: 327eb700029SDmitry Fleytman assert(pkt->isip4); 328eb700029SDmitry Fleytman assert(pkt->istcp); 329eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip4_tcp(); 330eb700029SDmitry Fleytman _net_rx_rss_prepare_ip4(&rss_input[0], pkt, &rss_length); 331eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 332eb700029SDmitry Fleytman break; 333eb700029SDmitry Fleytman case NetPktRssIpV6Tcp: 334eb700029SDmitry Fleytman assert(pkt->isip6); 335eb700029SDmitry Fleytman assert(pkt->istcp); 336eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_tcp(); 337eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 338eb700029SDmitry Fleytman _net_rx_rss_prepare_tcp(&rss_input[0], pkt, &rss_length); 339eb700029SDmitry Fleytman break; 340eb700029SDmitry Fleytman case NetPktRssIpV6: 341eb700029SDmitry Fleytman assert(pkt->isip6); 342eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6(); 343eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, false, &rss_length); 344eb700029SDmitry Fleytman break; 345eb700029SDmitry Fleytman case NetPktRssIpV6Ex: 346eb700029SDmitry Fleytman assert(pkt->isip6); 347eb700029SDmitry Fleytman trace_net_rx_pkt_rss_ip6_ex(); 348eb700029SDmitry Fleytman _net_rx_rss_prepare_ip6(&rss_input[0], pkt, true, &rss_length); 349eb700029SDmitry Fleytman break; 350eb700029SDmitry Fleytman default: 351eb700029SDmitry Fleytman assert(false); 352eb700029SDmitry Fleytman break; 353eb700029SDmitry Fleytman } 354eb700029SDmitry Fleytman 355eb700029SDmitry Fleytman net_toeplitz_key_init(&key_data, key); 356eb700029SDmitry Fleytman net_toeplitz_add(&rss_hash, rss_input, rss_length, &key_data); 357eb700029SDmitry Fleytman 358eb700029SDmitry Fleytman trace_net_rx_pkt_rss_hash(rss_length, rss_hash); 359eb700029SDmitry Fleytman 360eb700029SDmitry Fleytman return rss_hash; 361eb700029SDmitry Fleytman } 362eb700029SDmitry Fleytman 363eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_ip_id(struct NetRxPkt *pkt) 364eb700029SDmitry Fleytman { 365eb700029SDmitry Fleytman assert(pkt); 366eb700029SDmitry Fleytman 367eb700029SDmitry Fleytman if (pkt->isip4) { 368eb700029SDmitry Fleytman return be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_id); 369eb700029SDmitry Fleytman } 370eb700029SDmitry Fleytman 371eb700029SDmitry Fleytman return 0; 372eb700029SDmitry Fleytman } 373eb700029SDmitry Fleytman 374eb700029SDmitry Fleytman bool net_rx_pkt_is_tcp_ack(struct NetRxPkt *pkt) 375eb700029SDmitry Fleytman { 376eb700029SDmitry Fleytman assert(pkt); 377eb700029SDmitry Fleytman 378eb700029SDmitry Fleytman if (pkt->istcp) { 379eb700029SDmitry Fleytman return TCP_HEADER_FLAGS(&pkt->l4hdr_info.hdr.tcp) & TCP_FLAG_ACK; 380eb700029SDmitry Fleytman } 381eb700029SDmitry Fleytman 382eb700029SDmitry Fleytman return false; 383eb700029SDmitry Fleytman } 384eb700029SDmitry Fleytman 385eb700029SDmitry Fleytman bool net_rx_pkt_has_tcp_data(struct NetRxPkt *pkt) 386eb700029SDmitry Fleytman { 387eb700029SDmitry Fleytman assert(pkt); 388eb700029SDmitry Fleytman 389eb700029SDmitry Fleytman if (pkt->istcp) { 390eb700029SDmitry Fleytman return pkt->l4hdr_info.has_tcp_data; 391eb700029SDmitry Fleytman } 392eb700029SDmitry Fleytman 393eb700029SDmitry Fleytman return false; 394eb700029SDmitry Fleytman } 395eb700029SDmitry Fleytman 396605d52e6SDmitry Fleytman struct iovec *net_rx_pkt_get_iovec(struct NetRxPkt *pkt) 397e263cd49SDmitry Fleytman { 398e263cd49SDmitry Fleytman assert(pkt); 399e263cd49SDmitry Fleytman 400e263cd49SDmitry Fleytman return pkt->vec; 401e263cd49SDmitry Fleytman } 402e263cd49SDmitry Fleytman 403eb700029SDmitry Fleytman uint16_t net_rx_pkt_get_iovec_len(struct NetRxPkt *pkt) 404eb700029SDmitry Fleytman { 405eb700029SDmitry Fleytman assert(pkt); 406eb700029SDmitry Fleytman 407eb700029SDmitry Fleytman return pkt->vec_len; 408eb700029SDmitry Fleytman } 409eb700029SDmitry Fleytman 410605d52e6SDmitry Fleytman void net_rx_pkt_set_vhdr(struct NetRxPkt *pkt, 411e263cd49SDmitry Fleytman struct virtio_net_hdr *vhdr) 412e263cd49SDmitry Fleytman { 413e263cd49SDmitry Fleytman assert(pkt); 414e263cd49SDmitry Fleytman 415e263cd49SDmitry Fleytman memcpy(&pkt->virt_hdr, vhdr, sizeof pkt->virt_hdr); 416e263cd49SDmitry Fleytman } 417e263cd49SDmitry Fleytman 418eb700029SDmitry Fleytman void net_rx_pkt_set_vhdr_iovec(struct NetRxPkt *pkt, 419eb700029SDmitry Fleytman const struct iovec *iov, int iovcnt) 420eb700029SDmitry Fleytman { 421eb700029SDmitry Fleytman assert(pkt); 422eb700029SDmitry Fleytman 423eb700029SDmitry Fleytman iov_to_buf(iov, iovcnt, 0, &pkt->virt_hdr, sizeof pkt->virt_hdr); 424eb700029SDmitry Fleytman } 425eb700029SDmitry Fleytman 426605d52e6SDmitry Fleytman bool net_rx_pkt_is_vlan_stripped(struct NetRxPkt *pkt) 427e263cd49SDmitry Fleytman { 428e263cd49SDmitry Fleytman assert(pkt); 429e263cd49SDmitry Fleytman 430df8bf7a7SDmitry Fleytman return pkt->ehdr_buf_len ? true : false; 431e263cd49SDmitry Fleytman } 432e263cd49SDmitry Fleytman 433605d52e6SDmitry Fleytman bool net_rx_pkt_has_virt_hdr(struct NetRxPkt *pkt) 434e263cd49SDmitry Fleytman { 435e263cd49SDmitry Fleytman assert(pkt); 436e263cd49SDmitry Fleytman 437e263cd49SDmitry Fleytman return pkt->has_virt_hdr; 438e263cd49SDmitry Fleytman } 439e263cd49SDmitry Fleytman 440605d52e6SDmitry Fleytman uint16_t net_rx_pkt_get_vlan_tag(struct NetRxPkt *pkt) 441e263cd49SDmitry Fleytman { 442e263cd49SDmitry Fleytman assert(pkt); 443e263cd49SDmitry Fleytman 444e263cd49SDmitry Fleytman return pkt->tci; 445e263cd49SDmitry Fleytman } 446eb700029SDmitry Fleytman 447eb700029SDmitry Fleytman bool net_rx_pkt_validate_l3_csum(struct NetRxPkt *pkt, bool *csum_valid) 448eb700029SDmitry Fleytman { 449eb700029SDmitry Fleytman uint32_t cntr; 450eb700029SDmitry Fleytman uint16_t csum; 451eb700029SDmitry Fleytman uint32_t csl; 452eb700029SDmitry Fleytman 453eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_entry(); 454eb700029SDmitry Fleytman 455eb700029SDmitry Fleytman if (!pkt->isip4) { 456eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_not_ip4(); 457eb700029SDmitry Fleytman return false; 458eb700029SDmitry Fleytman } 459eb700029SDmitry Fleytman 460eb700029SDmitry Fleytman csl = pkt->l4hdr_off - pkt->l3hdr_off; 461eb700029SDmitry Fleytman 462eb700029SDmitry Fleytman cntr = net_checksum_add_iov(pkt->vec, pkt->vec_len, 463eb700029SDmitry Fleytman pkt->l3hdr_off, 464eb700029SDmitry Fleytman csl, 0); 465eb700029SDmitry Fleytman 466eb700029SDmitry Fleytman csum = net_checksum_finish(cntr); 467eb700029SDmitry Fleytman 468eb700029SDmitry Fleytman *csum_valid = (csum == 0); 469eb700029SDmitry Fleytman 470eb700029SDmitry Fleytman trace_net_rx_pkt_l3_csum_validate_csum(pkt->l3hdr_off, csl, 471eb700029SDmitry Fleytman cntr, csum, *csum_valid); 472eb700029SDmitry Fleytman 473eb700029SDmitry Fleytman return true; 474eb700029SDmitry Fleytman } 475eb700029SDmitry Fleytman 476eb700029SDmitry Fleytman static uint16_t 477eb700029SDmitry Fleytman _net_rx_pkt_calc_l4_csum(struct NetRxPkt *pkt) 478eb700029SDmitry Fleytman { 479eb700029SDmitry Fleytman uint32_t cntr; 480eb700029SDmitry Fleytman uint16_t csum; 481eb700029SDmitry Fleytman uint16_t csl; 482eb700029SDmitry Fleytman uint32_t cso; 483eb700029SDmitry Fleytman 484eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_entry(); 485eb700029SDmitry Fleytman 486eb700029SDmitry Fleytman if (pkt->isip4) { 487eb700029SDmitry Fleytman if (pkt->isudp) { 488eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 489eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_udp(); 490eb700029SDmitry Fleytman } else { 491eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->ip4hdr_info.ip4_hdr.ip_len) - 492eb700029SDmitry Fleytman IP_HDR_GET_LEN(&pkt->ip4hdr_info.ip4_hdr); 493eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip4_tcp(); 494eb700029SDmitry Fleytman } 495eb700029SDmitry Fleytman 496eb700029SDmitry Fleytman cntr = eth_calc_ip4_pseudo_hdr_csum(&pkt->ip4hdr_info.ip4_hdr, 497eb700029SDmitry Fleytman csl, &cso); 498eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 499eb700029SDmitry Fleytman } else { 500eb700029SDmitry Fleytman if (pkt->isudp) { 501eb700029SDmitry Fleytman csl = be16_to_cpu(pkt->l4hdr_info.hdr.udp.uh_ulen); 502eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_udp(); 503eb700029SDmitry Fleytman } else { 504eb700029SDmitry Fleytman struct ip6_header *ip6hdr = &pkt->ip6hdr_info.ip6_hdr; 505eb700029SDmitry Fleytman size_t full_ip6hdr_len = pkt->l4hdr_off - pkt->l3hdr_off; 506eb700029SDmitry Fleytman size_t ip6opts_len = full_ip6hdr_len - sizeof(struct ip6_header); 507eb700029SDmitry Fleytman 508eb700029SDmitry Fleytman csl = be16_to_cpu(ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_plen) - 509eb700029SDmitry Fleytman ip6opts_len; 510eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ip6_tcp(); 511eb700029SDmitry Fleytman } 512eb700029SDmitry Fleytman 513eb700029SDmitry Fleytman cntr = eth_calc_ip6_pseudo_hdr_csum(&pkt->ip6hdr_info.ip6_hdr, csl, 514eb700029SDmitry Fleytman pkt->ip6hdr_info.l4proto, &cso); 515eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_ph_csum(cntr, csl); 516eb700029SDmitry Fleytman } 517eb700029SDmitry Fleytman 518eb700029SDmitry Fleytman cntr += net_checksum_add_iov(pkt->vec, pkt->vec_len, 519eb700029SDmitry Fleytman pkt->l4hdr_off, csl, cso); 520eb700029SDmitry Fleytman 521*0dacea92SEd Swierk csum = net_checksum_finish_nozero(cntr); 522eb700029SDmitry Fleytman 523eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_calc_csum(pkt->l4hdr_off, csl, cntr, csum); 524eb700029SDmitry Fleytman 525eb700029SDmitry Fleytman return csum; 526eb700029SDmitry Fleytman } 527eb700029SDmitry Fleytman 528eb700029SDmitry Fleytman bool net_rx_pkt_validate_l4_csum(struct NetRxPkt *pkt, bool *csum_valid) 529eb700029SDmitry Fleytman { 530eb700029SDmitry Fleytman uint16_t csum; 531eb700029SDmitry Fleytman 532eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_entry(); 533eb700029SDmitry Fleytman 534eb700029SDmitry Fleytman if (!pkt->istcp && !pkt->isudp) { 535eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_not_xxp(); 536eb700029SDmitry Fleytman return false; 537eb700029SDmitry Fleytman } 538eb700029SDmitry Fleytman 539eb700029SDmitry Fleytman if (pkt->isudp && (pkt->l4hdr_info.hdr.udp.uh_sum == 0)) { 540eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_udp_with_no_checksum(); 541eb700029SDmitry Fleytman return false; 542eb700029SDmitry Fleytman } 543eb700029SDmitry Fleytman 544eb700029SDmitry Fleytman if (pkt->isip4 && pkt->ip4hdr_info.fragment) { 545eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_ip4_fragment(); 546eb700029SDmitry Fleytman return false; 547eb700029SDmitry Fleytman } 548eb700029SDmitry Fleytman 549eb700029SDmitry Fleytman csum = _net_rx_pkt_calc_l4_csum(pkt); 550eb700029SDmitry Fleytman 551eb700029SDmitry Fleytman *csum_valid = ((csum == 0) || (csum == 0xFFFF)); 552eb700029SDmitry Fleytman 553eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_validate_csum(*csum_valid); 554eb700029SDmitry Fleytman 555eb700029SDmitry Fleytman return true; 556eb700029SDmitry Fleytman } 557eb700029SDmitry Fleytman 558eb700029SDmitry Fleytman bool net_rx_pkt_fix_l4_csum(struct NetRxPkt *pkt) 559eb700029SDmitry Fleytman { 560eb700029SDmitry Fleytman uint16_t csum = 0; 561eb700029SDmitry Fleytman uint32_t l4_cso; 562eb700029SDmitry Fleytman 563eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_entry(); 564eb700029SDmitry Fleytman 565eb700029SDmitry Fleytman if (pkt->istcp) { 566eb700029SDmitry Fleytman l4_cso = offsetof(struct tcp_header, th_sum); 567eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_tcp(l4_cso); 568eb700029SDmitry Fleytman } else if (pkt->isudp) { 569eb700029SDmitry Fleytman if (pkt->l4hdr_info.hdr.udp.uh_sum == 0) { 570eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp_with_no_checksum(); 571eb700029SDmitry Fleytman return false; 572eb700029SDmitry Fleytman } 573eb700029SDmitry Fleytman l4_cso = offsetof(struct udp_header, uh_sum); 574eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_udp(l4_cso); 575eb700029SDmitry Fleytman } else { 576eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_not_xxp(); 577eb700029SDmitry Fleytman return false; 578eb700029SDmitry Fleytman } 579eb700029SDmitry Fleytman 580eb700029SDmitry Fleytman if (pkt->isip4 && pkt->ip4hdr_info.fragment) { 581eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_ip4_fragment(); 582eb700029SDmitry Fleytman return false; 583eb700029SDmitry Fleytman } 584eb700029SDmitry Fleytman 585eb700029SDmitry Fleytman /* Set zero to checksum word */ 586eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 587eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 588eb700029SDmitry Fleytman &csum, sizeof(csum)); 589eb700029SDmitry Fleytman 590eb700029SDmitry Fleytman /* Calculate L4 checksum */ 591eb700029SDmitry Fleytman csum = cpu_to_be16(_net_rx_pkt_calc_l4_csum(pkt)); 592eb700029SDmitry Fleytman 593eb700029SDmitry Fleytman /* Set calculated checksum to checksum word */ 594eb700029SDmitry Fleytman iov_from_buf(pkt->vec, pkt->vec_len, 595eb700029SDmitry Fleytman pkt->l4hdr_off + l4_cso, 596eb700029SDmitry Fleytman &csum, sizeof(csum)); 597eb700029SDmitry Fleytman 598eb700029SDmitry Fleytman trace_net_rx_pkt_l4_csum_fix_csum(pkt->l4hdr_off + l4_cso, csum); 599eb700029SDmitry Fleytman 600eb700029SDmitry Fleytman return true; 601eb700029SDmitry Fleytman } 602