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