static int xlgmac_prep_tso(struct sk_buff *skb, struct xlgmac_pkt_info *pkt_info) { int ret; if (!XLGMAC_GET_REG_BITS(pkt_info->attributes, TX_PACKET_ATTRIBUTES_TSO_ENABLE_POS, TX_PACKET_ATTRIBUTES_TSO_ENABLE_LEN)) return 0; ret = skb_cow_head(skb, 0); if (ret) return ret; pkt_info->header_len = skb_transport_offset(skb) + tcp_hdrlen(skb); pkt_info->tcp_header_len = tcp_hdrlen(skb); pkt_info->tcp_payload_len = skb->len - pkt_info->header_len; pkt_info->mss = skb_shinfo(skb)->gso_size; XLGMAC_PR("header_len=%u\n", pkt_info->header_len); XLGMAC_PR("tcp_header_len=%u, tcp_payload_len=%u\n", pkt_info->tcp_header_len, pkt_info->tcp_payload_len); XLGMAC_PR("mss=%u\n", pkt_info->mss); /* Update the number of packets that will ultimately be transmitted * along with the extra bytes for each extra packet */ pkt_info->tx_packets = skb_shinfo(skb)->gso_segs; pkt_info->tx_bytes += (pkt_info->tx_packets - 1) * pkt_info->header_len; return 0; }
static int get_real_size(struct sk_buff *skb, struct net_device *dev, int *lso_header_size) { struct mlx4_en_priv *priv = netdev_priv(dev); int real_size; if (skb_is_gso(skb)) { *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb); real_size = CTRL_SIZE + skb_shinfo(skb)->nr_frags * DS_SIZE + ALIGN(*lso_header_size + 4, DS_SIZE); if (unlikely(*lso_header_size != skb_headlen(skb))) { /* We add a segment for the skb linear buffer only if * it contains data */ if (*lso_header_size < skb_headlen(skb)) real_size += DS_SIZE; else { if (netif_msg_tx_err(priv)) en_warn(priv, "Non-linear headers\n"); return 0; } } } else { *lso_header_size = 0; if (!is_inline(skb, NULL)) real_size = CTRL_SIZE + (skb_shinfo(skb)->nr_frags + 1) * DS_SIZE; else real_size = inline_size(skb); } return real_size; }
static inline void enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, int vlan_tag_insert, unsigned int vlan_tag) { unsigned int head_len = skb_headlen(skb); unsigned int len_left = skb->len - head_len; unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int eop = (len_left == 0); /* Preload TCP csum field with IP pseudo hdr calculated * with IP length set to zero. HW will later add in length * to each TCP segment resulting from the TSO. */ if (skb->protocol == __constant_htons(ETH_P_IP)) { ip_hdr(skb)->check = 0; tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } else if (skb->protocol == __constant_htons(ETH_P_IPV6)) { tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } /* Queue the main skb fragment */ enic_queue_wq_desc_tso(wq, skb, pci_map_single(enic->pdev, skb->data, head_len, PCI_DMA_TODEVICE), head_len, mss, hdr_len, vlan_tag_insert, vlan_tag, eop); if (!eop) enic_queue_wq_skb_cont(enic, wq, skb, len_left); }
/** * nfp_net_tx_tso() - Set up Tx descriptor for LSO * @nn: NFP Net device * @r_vec: per-ring structure * @txbuf: Pointer to driver soft TX descriptor * @txd: Pointer to HW TX descriptor * @skb: Pointer to SKB * * Set up Tx descriptor for LSO, do nothing for non-LSO skbs. * Return error on packet header greater than maximum supported LSO header size. */ static void nfp_net_tx_tso(struct nfp_net *nn, struct nfp_net_r_vector *r_vec, struct nfp_net_tx_buf *txbuf, struct nfp_net_tx_desc *txd, struct sk_buff *skb) { u32 hdrlen; u16 mss; if (!skb_is_gso(skb)) return; if (!skb->encapsulation) hdrlen = skb_transport_offset(skb) + tcp_hdrlen(skb); else hdrlen = skb_inner_transport_header(skb) - skb->data + inner_tcp_hdrlen(skb); txbuf->pkt_cnt = skb_shinfo(skb)->gso_segs; txbuf->real_len += hdrlen * (txbuf->pkt_cnt - 1); mss = skb_shinfo(skb)->gso_size & PCIE_DESC_TX_MSS_MASK; txd->l4_offset = hdrlen; txd->mss = cpu_to_le16(mss); txd->flags |= PCIE_DESC_TX_LSO; u64_stats_update_begin(&r_vec->tx_sync); r_vec->tx_lso++; u64_stats_update_end(&r_vec->tx_sync); }
static unsigned int tcpoptstrip_mangle_packet(struct sk_buff *skb, const struct xt_tcpoptstrip_target_info *info, unsigned int tcphoff, unsigned int minlen) { unsigned int optl, i, j; struct tcphdr *tcph; u_int16_t n, o; u_int8_t *opt; if (!skb_make_writable(skb, skb->len)) return NF_DROP; tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff); opt = (u_int8_t *)tcph; /* * Walk through all TCP options - if we find some option to remove, * set all octets to %TCPOPT_NOP and adjust checksum. */ for (i = sizeof(struct tcphdr); i < tcp_hdrlen(skb); i += optl) { optl = optlen(opt, i); if (i + optl > tcp_hdrlen(skb)) break; if (!tcpoptstrip_test_bit(info->strip_bmap, opt[i])) continue; for (j = 0; j < optl; ++j) { o = opt[i+j]; n = TCPOPT_NOP; if ((i + j) % 2 == 0) { o <<= 8; n <<= 8; } inet_proto_csum_replace2(&tcph->check, skb, htons(o), htons(n), 0); } memset(opt + i, TCPOPT_NOP, optl); } return XT_CONTINUE; }
static u64 xgene_enet_work_msg(struct sk_buff *skb) { struct net_device *ndev = skb->dev; struct xgene_enet_pdata *pdata = netdev_priv(ndev); struct iphdr *iph; u8 l3hlen = 0, l4hlen = 0; u8 ethhdr, proto = 0, csum_enable = 0; u64 hopinfo = 0; u32 hdr_len, mss = 0; u32 i, len, nr_frags; ethhdr = xgene_enet_hdr_len(skb->data); if (unlikely(skb->protocol != htons(ETH_P_IP)) && unlikely(skb->protocol != htons(ETH_P_8021Q))) goto out; if (unlikely(!(skb->dev->features & NETIF_F_IP_CSUM))) goto out; iph = ip_hdr(skb); if (unlikely(ip_is_fragment(iph))) goto out; if (likely(iph->protocol == IPPROTO_TCP)) { l4hlen = tcp_hdrlen(skb) >> 2; csum_enable = 1; proto = TSO_IPPROTO_TCP; if (ndev->features & NETIF_F_TSO) { hdr_len = ethhdr + ip_hdrlen(skb) + tcp_hdrlen(skb); mss = skb_shinfo(skb)->gso_size; if (skb_is_nonlinear(skb)) { len = skb_headlen(skb); nr_frags = skb_shinfo(skb)->nr_frags; for (i = 0; i < 2 && i < nr_frags; i++) len += skb_shinfo(skb)->frags[i].size; /* HW requires header must reside in 3 buffer */ if (unlikely(hdr_len > len)) { if (skb_linearize(skb)) return 0; } } if (!mss || ((skb->len - hdr_len) <= mss)) goto out; if (mss != pdata->mss) { pdata->mss = mss; pdata->mac_ops->set_mss(pdata); } hopinfo |= SET_BIT(ET); } } else if (iph->protocol == IPPROTO_UDP) {
/** * Initializes both "pipeline" and "in" using the data from "tuple", "skb", and the assumption that * we're translating from 6 to 4. * "pipeline" defines the sequence of functions that will be executed later and "in" is basically a * summary of "skb". */ static bool init_pipeline_ipv6(struct pipeline *pipeline, struct packet_in *in, struct nf_conntrack_tuple *tuple, struct sk_buff *skb) { struct ipv6hdr *ip6_hdr = ipv6_hdr(skb); struct hdr_iterator iterator = HDR_ITERATOR_INIT(ip6_hdr); pipeline->l3_hdr_function = create_ipv4_hdr; pipeline->create_skb_function = create_skb; pipeline->l3_post_function = post_ipv4; in->packet = skb; in->tuple = tuple; in->l3_hdr = ip6_hdr; in->l3_hdr_type = IPPROTO_IPV6; in->l3_hdr_len = skb_transport_header(skb) - skb_network_header(skb); in->l3_hdr_basic_len = sizeof(*ip6_hdr); in->compute_l3_hdr_len = compute_ipv6_hdr_len; hdr_iterator_last(&iterator); if (iterator.hdr_type == NEXTHDR_AUTH || iterator.hdr_type == NEXTHDR_ESP) { // RFC 6146 section 5.1. log_warning(" Incoming IPv6 packet has an Auth header or an ESP header. Cannot translate; " "will drop the packet."); return false; } in->l4_hdr_type = iterator.hdr_type; switch (in->l4_hdr_type) { case NEXTHDR_TCP: in->l4_hdr_len = tcp_hdrlen(skb); pipeline->l4_post_function = post_tcp_ipv4; pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload; break; case NEXTHDR_UDP: in->l4_hdr_len = sizeof(struct udphdr); pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload; pipeline->l4_post_function = post_udp_ipv4; break; case NEXTHDR_ICMP: in->l4_hdr_len = sizeof(struct icmp6hdr); pipeline->l4_hdr_and_payload_function = create_icmp4_hdr_and_payload; pipeline->l4_post_function = post_icmp4; break; default: log_warning(" Unsupported l4 protocol (%d). Cannot translate.", in->l4_hdr_type); return false; } in->payload = iterator.data + in->l4_hdr_len; in->payload_len = be16_to_cpu(ip6_hdr->payload_len) // - (in->l3_hdr_len - sizeof(*ip6_hdr)) // - in->l4_hdr_len; return true; }
/* * Return length of individual segments of a gso packet, * including all headers (MAC, IP, TCP/UDP) */ static unsigned int skb_gso_seglen(const struct sk_buff *skb) { unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb); const struct skb_shared_info *shinfo = skb_shinfo(skb); if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))) hdr_len += tcp_hdrlen(skb); else hdr_len += sizeof(struct udphdr); return hdr_len + shinfo->gso_size; }
static bool tcphdr_ok(struct sk_buff *skb) { int th_ofs = skb_transport_offset(skb); int tcp_len; if (unlikely(!pskb_may_pull(skb, th_ofs + sizeof(struct tcphdr)))) return false; tcp_len = tcp_hdrlen(skb); if (unlikely(tcp_len < sizeof(struct tcphdr) || skb->len < th_ofs + tcp_len)) return false; return true; }
static struct sk_buff *tls_sw_fallback(struct sock *sk, struct sk_buff *skb) { int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); struct tls_context *tls_ctx = tls_get_ctx(sk); struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); int payload_len = skb->len - tcp_payload_offset; struct scatterlist *sg_in, sg_out[3]; struct sk_buff *nskb = NULL; int sg_in_max_elements; int resync_sgs = 0; s32 sync_size = 0; u64 rcd_sn; /* worst case is: * MAX_SKB_FRAGS in tls_record_info * MAX_SKB_FRAGS + 1 in SKB head and frags. */ sg_in_max_elements = 2 * MAX_SKB_FRAGS + 1; if (!payload_len) return skb; sg_in = kmalloc_array(sg_in_max_elements, sizeof(*sg_in), GFP_ATOMIC); if (!sg_in) goto free_orig; sg_init_table(sg_in, sg_in_max_elements); sg_init_table(sg_out, ARRAY_SIZE(sg_out)); if (fill_sg_in(sg_in, skb, ctx, &rcd_sn, &sync_size, &resync_sgs)) { /* bypass packets before kernel TLS socket option was set */ if (sync_size < 0 && payload_len <= -sync_size) nskb = skb_get(skb); goto put_sg; } nskb = tls_enc_skb(tls_ctx, sg_out, sg_in, skb, sync_size, rcd_sn); put_sg: while (resync_sgs) put_page(sg_page(&sg_in[--resync_sgs])); kfree(sg_in); free_orig: kfree_skb(skb); return nskb; }
/** * Initializes both "pipeline" and "in" using the data from "tuple", "skb", and the assumption that * we're translating from 4 to 6. * "pipeline" defines the sequence of functions that will be executed later and "in" is basically a * summary of "skb". */ static bool init_pipeline_ipv4(struct pipeline *pipeline, struct packet_in *in, struct nf_conntrack_tuple *tuple, struct sk_buff *skb) { struct iphdr *ip4_hdr = ip_hdr(skb); pipeline->l3_hdr_function = create_ipv6_hdr; pipeline->create_skb_function = create_skb; pipeline->l3_post_function = post_ipv6; in->packet = skb; in->tuple = tuple; in->l3_hdr = ip4_hdr; in->l3_hdr_type = IPPROTO_IP; in->l3_hdr_len = skb_transport_header(skb) - skb_network_header(skb); in->l3_hdr_basic_len = sizeof(*ip4_hdr); in->compute_l3_hdr_len = compute_ipv4_hdr_len; in->l4_hdr_type = ip4_hdr->protocol; switch (in->l4_hdr_type) { case IPPROTO_TCP: in->l4_hdr_len = tcp_hdrlen(skb); pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload; pipeline->l4_post_function = post_tcp_ipv6; break; case IPPROTO_UDP: in->l4_hdr_len = sizeof(struct udphdr); pipeline->l4_hdr_and_payload_function = copy_l4_hdr_and_payload; pipeline->l4_post_function = post_udp_ipv6; break; case IPPROTO_ICMP: in->l4_hdr_len = sizeof(struct icmphdr); pipeline->l4_hdr_and_payload_function = create_icmp6_hdr_and_payload; pipeline->l4_post_function = post_icmp6; break; default: log_warning(" Unsupported l4 protocol (%d). Cannot translate.", in->l4_hdr_type); return false; } in->payload = skb_transport_header(skb) + in->l4_hdr_len; in->payload_len = be16_to_cpu(ip4_hdr->tot_len) - in->l3_hdr_len - in->l4_hdr_len; return true; }
static int enic_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph, u64 *hdr_flags, void *priv) { struct cq_enet_rq_desc *cq_desc = priv; unsigned int ip_len; struct iphdr *iph; u8 type, color, eop, sop, ingress_port, vlan_stripped; u8 fcoe, fcoe_sof, fcoe_fc_crc_ok, fcoe_enc_error, fcoe_eof; u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; u8 ipv6, ipv4, ipv4_fragment, fcs_ok, rss_type, csum_not_calc; u8 packet_error; u16 q_number, completed_index, bytes_written, vlan, checksum; u32 rss_hash; cq_enet_rq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index, &ingress_port, &fcoe, &eop, &sop, &rss_type, &csum_not_calc, &rss_hash, &bytes_written, &packet_error, &vlan_stripped, &vlan, &checksum, &fcoe_sof, &fcoe_fc_crc_ok, &fcoe_enc_error, &fcoe_eof, &tcp_udp_csum_ok, &udp, &tcp, &ipv4_csum_ok, &ipv6, &ipv4, &ipv4_fragment, &fcs_ok); if (!(ipv4 && tcp && !ipv4_fragment)) return -1; skb_reset_network_header(skb); iph = ip_hdr(skb); ip_len = ip_hdrlen(skb); skb_set_transport_header(skb, ip_len); if (ntohs(iph->tot_len) < ip_len + tcp_hdrlen(skb)) return -1; *hdr_flags = LRO_IPV4 | LRO_TCP; *tcph = tcp_hdr(skb); *iphdr = iph; return 0; }
static int get_real_size(const struct sk_buff *skb, const struct skb_shared_info *shinfo, struct net_device *dev, int *lso_header_size, bool *inline_ok, void **pfrag) { struct mlx4_en_priv *priv = netdev_priv(dev); int real_size; if (shinfo->gso_size) { *inline_ok = false; if (skb->encapsulation) *lso_header_size = (skb_inner_transport_header(skb) - skb->data) + inner_tcp_hdrlen(skb); else *lso_header_size = skb_transport_offset(skb) + tcp_hdrlen(skb); real_size = CTRL_SIZE + shinfo->nr_frags * DS_SIZE + ALIGN(*lso_header_size + 4, DS_SIZE); if (unlikely(*lso_header_size != skb_headlen(skb))) { /* We add a segment for the skb linear buffer only if * it contains data */ if (*lso_header_size < skb_headlen(skb)) real_size += DS_SIZE; else { if (netif_msg_tx_err(priv)) en_warn(priv, "Non-linear headers\n"); return 0; } } } else { *lso_header_size = 0; *inline_ok = is_inline(priv->prof->inline_thold, skb, shinfo, pfrag); if (*inline_ok) real_size = inline_size(skb); else real_size = CTRL_SIZE + (shinfo->nr_frags + 1) * DS_SIZE; } return real_size; }
void tso_start(struct sk_buff *skb, struct tso_t *tso) { int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); tso->ip_id = ntohs(ip_hdr(skb)->id); tso->tcp_seq = ntohl(tcp_hdr(skb)->seq); tso->next_frag_idx = 0; /* Build first data */ tso->size = skb_headlen(skb) - hdr_len; tso->data = skb->data + hdr_len; if ((tso->size == 0) && (tso->next_frag_idx < skb_shinfo(skb)->nr_frags)) { skb_frag_t *frag = &skb_shinfo(skb)->frags[tso->next_frag_idx]; /* Move to next segment */ tso->size = frag->size; tso->data = page_address(frag->page.p) + frag->page_offset; tso->next_frag_idx++; } }
/* If an incoming SYN or SYNACK frame contains a payload and/or FIN, * queue this additional data / FIN. */ void tcp_fastopen_add_skb(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); if (TCP_SKB_CB(skb)->end_seq == tp->rcv_nxt) return; skb = skb_clone(skb, GFP_ATOMIC); if (!skb) return; skb_dst_drop(skb); /* segs_in has been initialized to 1 in tcp_create_openreq_child(). * Hence, reset segs_in to 0 before calling tcp_segs_in() * to avoid double counting. Also, tcp_segs_in() expects * skb->len to include the tcp_hdrlen. Hence, it should * be called before __skb_pull(). */ tp->segs_in = 0; tcp_segs_in(tp, skb); __skb_pull(skb, tcp_hdrlen(skb)); sk_forced_mem_schedule(sk, skb->truesize); skb_set_owner_r(skb, sk); TCP_SKB_CB(skb)->seq++; TCP_SKB_CB(skb)->tcp_flags &= ~TCPHDR_SYN; tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; __skb_queue_tail(&sk->sk_receive_queue, skb); tp->syn_data_acked = 1; /* u64_stats_update_begin(&tp->syncp) not needed here, * as we certainly are not changing upper 32bit value (0) */ tp->bytes_received = skb->len; if (TCP_SKB_CB(skb)->tcp_flags & TCPHDR_FIN) tcp_fin(sk); }
void tso_build_hdr(struct sk_buff *skb, char *hdr, struct tso_t *tso, int size, bool is_last) { struct iphdr *iph; struct tcphdr *tcph; int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int mac_hdr_len = skb_network_offset(skb); memcpy(hdr, skb->data, hdr_len); iph = (struct iphdr *)(hdr + mac_hdr_len); iph->id = htons(tso->ip_id); iph->tot_len = htons(size + hdr_len - mac_hdr_len); tcph = (struct tcphdr *)(hdr + skb_transport_offset(skb)); tcph->seq = htonl(tso->tcp_seq); tso->ip_id++; if (!is_last) { /* Clear all special flags for not last packet */ tcph->psh = 0; tcph->fin = 0; tcph->rst = 0; } }
static int iwl_pcie_gen2_build_amsdu(struct iwl_trans *trans, struct sk_buff *skb, struct iwl_tfh_tfd *tfd, int start_len, u8 hdr_len, struct iwl_device_cmd *dev_cmd) { #ifdef CONFIG_INET struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans); struct iwl_tx_cmd_gen2 *tx_cmd = (void *)dev_cmd->payload; struct ieee80211_hdr *hdr = (void *)skb->data; unsigned int snap_ip_tcp_hdrlen, ip_hdrlen, total_len, hdr_room; unsigned int mss = skb_shinfo(skb)->gso_size; u16 length, iv_len, amsdu_pad; u8 *start_hdr; struct iwl_tso_hdr_page *hdr_page; struct page **page_ptr; struct tso_t tso; /* if the packet is protected, then it must be CCMP or GCMP */ iv_len = ieee80211_has_protected(hdr->frame_control) ? IEEE80211_CCMP_HDR_LEN : 0; trace_iwlwifi_dev_tx(trans->dev, skb, tfd, sizeof(*tfd), &dev_cmd->hdr, start_len, 0); ip_hdrlen = skb_transport_header(skb) - skb_network_header(skb); snap_ip_tcp_hdrlen = 8 + ip_hdrlen + tcp_hdrlen(skb); total_len = skb->len - snap_ip_tcp_hdrlen - hdr_len - iv_len; amsdu_pad = 0; /* total amount of header we may need for this A-MSDU */ hdr_room = DIV_ROUND_UP(total_len, mss) * (3 + snap_ip_tcp_hdrlen + sizeof(struct ethhdr)) + iv_len; /* Our device supports 9 segments at most, it will fit in 1 page */ hdr_page = get_page_hdr(trans, hdr_room); if (!hdr_page) return -ENOMEM; get_page(hdr_page->page); start_hdr = hdr_page->pos; page_ptr = (void *)((u8 *)skb->cb + trans_pcie->page_offs); *page_ptr = hdr_page->page; memcpy(hdr_page->pos, skb->data + hdr_len, iv_len); hdr_page->pos += iv_len; /* * Pull the ieee80211 header + IV to be able to use TSO core, * we will restore it for the tx_status flow. */ skb_pull(skb, hdr_len + iv_len); /* * Remove the length of all the headers that we don't actually * have in the MPDU by themselves, but that we duplicate into * all the different MSDUs inside the A-MSDU. */ le16_add_cpu(&tx_cmd->len, -snap_ip_tcp_hdrlen); tso_start(skb, &tso); while (total_len) { /* this is the data left for this subframe */ unsigned int data_left = min_t(unsigned int, mss, total_len); struct sk_buff *csum_skb = NULL; unsigned int tb_len; dma_addr_t tb_phys; u8 *subf_hdrs_start = hdr_page->pos; total_len -= data_left; memset(hdr_page->pos, 0, amsdu_pad); hdr_page->pos += amsdu_pad; amsdu_pad = (4 - (sizeof(struct ethhdr) + snap_ip_tcp_hdrlen + data_left)) & 0x3; ether_addr_copy(hdr_page->pos, ieee80211_get_DA(hdr)); hdr_page->pos += ETH_ALEN; ether_addr_copy(hdr_page->pos, ieee80211_get_SA(hdr)); hdr_page->pos += ETH_ALEN; length = snap_ip_tcp_hdrlen + data_left; *((__be16 *)hdr_page->pos) = cpu_to_be16(length); hdr_page->pos += sizeof(length); /* * This will copy the SNAP as well which will be considered * as MAC header. */ tso_build_hdr(skb, hdr_page->pos, &tso, data_left, !total_len); hdr_page->pos += snap_ip_tcp_hdrlen; tb_len = hdr_page->pos - start_hdr; tb_phys = dma_map_single(trans->dev, start_hdr, tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { dev_kfree_skb(csum_skb); goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); trace_iwlwifi_dev_tx_tb(trans->dev, skb, start_hdr, tb_len); /* add this subframe's headers' length to the tx_cmd */ le16_add_cpu(&tx_cmd->len, hdr_page->pos - subf_hdrs_start); /* prepare the start_hdr for the next subframe */ start_hdr = hdr_page->pos; /* put the payload */ while (data_left) { tb_len = min_t(unsigned int, tso.size, data_left); tb_phys = dma_map_single(trans->dev, tso.data, tb_len, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(trans->dev, tb_phys))) { dev_kfree_skb(csum_skb); goto out_err; } iwl_pcie_gen2_set_tb(trans, tfd, tb_phys, tb_len); trace_iwlwifi_dev_tx_tb(trans->dev, skb, tso.data, tb_len); data_left -= tb_len; tso_build_data(skb, &tso, tb_len); } } /* re -add the WiFi header and IV */ skb_push(skb, hdr_len + iv_len); return 0; out_err: #endif return -EINVAL; }
static bool tcp_fastopen_create_child(struct sock *sk, struct sk_buff *skb, struct dst_entry *dst, struct request_sock *req) { struct tcp_sock *tp; struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue; struct sock *child; u32 end_seq; req->num_retrans = 0; req->num_timeout = 0; req->sk = NULL; child = inet_csk(sk)->icsk_af_ops->syn_recv_sock(sk, skb, req, NULL); if (!child) return false; spin_lock(&queue->fastopenq->lock); queue->fastopenq->qlen++; spin_unlock(&queue->fastopenq->lock); /* Initialize the child socket. Have to fix some values to take * into account the child is a Fast Open socket and is created * only out of the bits carried in the SYN packet. */ tp = tcp_sk(child); tp->fastopen_rsk = req; tcp_rsk(req)->tfo_listener = true; /* RFC1323: The window in SYN & SYN/ACK segments is never * scaled. So correct it appropriately. */ tp->snd_wnd = ntohs(tcp_hdr(skb)->window); /* Activate the retrans timer so that SYNACK can be retransmitted. * The request socket is not added to the SYN table of the parent * because it's been added to the accept queue directly. */ inet_csk_reset_xmit_timer(child, ICSK_TIME_RETRANS, TCP_TIMEOUT_INIT, TCP_RTO_MAX); atomic_set(&req->rsk_refcnt, 1); /* Add the child socket directly into the accept queue */ inet_csk_reqsk_queue_add(sk, req, child); /* Now finish processing the fastopen child socket. */ inet_csk(child)->icsk_af_ops->rebuild_header(child); tcp_init_congestion_control(child); tcp_mtup_init(child); tcp_init_metrics(child); tcp_init_buffer_space(child); /* Queue the data carried in the SYN packet. We need to first * bump skb's refcnt because the caller will attempt to free it. * Note that IPv6 might also have used skb_get() trick * in tcp_v6_conn_request() to keep this SYN around (treq->pktopts) * So we need to eventually get a clone of the packet, * before inserting it in sk_receive_queue. * * XXX (TFO) - we honor a zero-payload TFO request for now, * (any reason not to?) but no need to queue the skb since * there is no data. How about SYN+FIN? */ end_seq = TCP_SKB_CB(skb)->end_seq; if (end_seq != TCP_SKB_CB(skb)->seq + 1) { struct sk_buff *skb2; if (unlikely(skb_shared(skb))) skb2 = skb_clone(skb, GFP_ATOMIC); else skb2 = skb_get(skb); if (likely(skb2)) { skb_dst_drop(skb2); __skb_pull(skb2, tcp_hdrlen(skb)); skb_set_owner_r(skb2, child); __skb_queue_tail(&child->sk_receive_queue, skb2); tp->syn_data_acked = 1; /* u64_stats_update_begin(&tp->syncp) not needed here, * as we certainly are not changing upper 32bit value (0) */ tp->bytes_received = end_seq - TCP_SKB_CB(skb)->seq - 1; } else { end_seq = TCP_SKB_CB(skb)->seq + 1; } } tcp_rsk(req)->rcv_nxt = tp->rcv_nxt = end_seq; sk->sk_data_ready(sk); bh_unlock_sock(child); sock_put(child); WARN_ON(!req->sk); return true; }
static int fill_sg_in(struct scatterlist *sg_in, struct sk_buff *skb, struct tls_offload_context_tx *ctx, u64 *rcd_sn, s32 *sync_size, int *resync_sgs) { int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); int payload_len = skb->len - tcp_payload_offset; u32 tcp_seq = ntohl(tcp_hdr(skb)->seq); struct tls_record_info *record; unsigned long flags; int remaining; int i; spin_lock_irqsave(&ctx->lock, flags); record = tls_get_record(ctx, tcp_seq, rcd_sn); if (!record) { spin_unlock_irqrestore(&ctx->lock, flags); WARN(1, "Record not found for seq %u\n", tcp_seq); return -EINVAL; } *sync_size = tcp_seq - tls_record_start_seq(record); if (*sync_size < 0) { int is_start_marker = tls_record_is_start_marker(record); spin_unlock_irqrestore(&ctx->lock, flags); /* This should only occur if the relevant record was * already acked. In that case it should be ok * to drop the packet and avoid retransmission. * * There is a corner case where the packet contains * both an acked and a non-acked record. * We currently don't handle that case and rely * on TCP to retranmit a packet that doesn't contain * already acked payload. */ if (!is_start_marker) *sync_size = 0; return -EINVAL; } remaining = *sync_size; for (i = 0; remaining > 0; i++) { skb_frag_t *frag = &record->frags[i]; __skb_frag_ref(frag); sg_set_page(sg_in + i, skb_frag_page(frag), skb_frag_size(frag), frag->page_offset); remaining -= skb_frag_size(frag); if (remaining < 0) sg_in[i].length += remaining; } *resync_sgs = i; spin_unlock_irqrestore(&ctx->lock, flags); if (skb_to_sgvec(skb, &sg_in[i], tcp_payload_offset, payload_len) < 0) return -EINVAL; return 0; }
static inline int dma_xmit(struct sk_buff *skb, struct net_device *dev, END_DEVICE *ei_local, int gmac_no) { struct netdev_queue *txq; dma_addr_t frag_addr; u32 frag_size, nr_desc; u32 txd_info3, txd_info4; #if defined (CONFIG_RAETH_SG_DMA_TX) u32 i, nr_frags; const skb_frag_t *tx_frag; const struct skb_shared_info *shinfo; #else #define nr_frags 0 #endif #if defined (CONFIG_RA_HW_NAT) || defined (CONFIG_RA_HW_NAT_MODULE) if (ra_sw_nat_hook_tx != NULL) { #if defined (CONFIG_RA_HW_NAT_WIFI) || defined (CONFIG_RA_HW_NAT_PCI) if (IS_DPORT_PPE_VALID(skb)) gmac_no = PSE_PORT_PPE; else #endif if (ra_sw_nat_hook_tx(skb, gmac_no) == 0) { dev_kfree_skb(skb); return NETDEV_TX_OK; } } #endif txd_info3 = TX3_QDMA_SWC; if (gmac_no != PSE_PORT_PPE) { u32 QID = M2Q_table[(skb->mark & 0x3f)]; if (QID < 8 && M2Q_wan_lan) { #if defined (CONFIG_PSEUDO_SUPPORT) if (gmac_no == PSE_PORT_GMAC2) QID += 8; #elif defined (CONFIG_RAETH_HW_VLAN_TX) if ((skb_vlan_tag_get(skb) & VLAN_VID_MASK) > 1) QID += 8; #endif } txd_info3 |= TX3_QDMA_QID(QID); } txd_info4 = TX4_DMA_FPORT(gmac_no); #if defined (CONFIG_RAETH_CHECKSUM_OFFLOAD) if (skb->ip_summed == CHECKSUM_PARTIAL) txd_info4 |= TX4_DMA_TUI_CO(7); #endif #if defined (CONFIG_RAETH_HW_VLAN_TX) if (skb_vlan_tag_present(skb)) txd_info4 |= (0x10000 | skb_vlan_tag_get(skb)); #endif #if defined (CONFIG_RAETH_SG_DMA_TX) shinfo = skb_shinfo(skb); #endif #if defined (CONFIG_RAETH_TSO) /* fill MSS info in tcp checksum field */ if (shinfo->gso_size) { u32 hdr_len; if (!(shinfo->gso_type & (SKB_GSO_TCPV4|SKB_GSO_TCPV6))) { dev_kfree_skb(skb); return NETDEV_TX_OK; } if (skb_header_cloned(skb)) { if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } } hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); if (hdr_len >= skb->len) { dev_kfree_skb(skb); return NETDEV_TX_OK; } tcp_hdr(skb)->check = htons(shinfo->gso_size); txd_info4 |= TX4_DMA_TSO; } #endif nr_desc = DIV_ROUND_UP(skb_headlen(skb), TXD_MAX_SEG_SIZE); #if defined (CONFIG_RAETH_SG_DMA_TX) nr_frags = (u32)shinfo->nr_frags; for (i = 0; i < nr_frags; i++) { tx_frag = &shinfo->frags[i]; nr_desc += DIV_ROUND_UP(skb_frag_size(tx_frag), TXD_MAX_SEG_SIZE); } #endif txq = netdev_get_tx_queue(dev, 0); /* flush main skb part before spin_lock() */ frag_size = (u32)skb_headlen(skb); frag_addr = dma_map_single(NULL, skb->data, frag_size, DMA_TO_DEVICE); /* protect TX ring access (from eth2/eth3 queues) */ spin_lock(&ei_local->page_lock); /* check nr_desc+2 free descriptors (2 need to prevent head/tail overlap) */ if (ei_local->txd_pool_free_num < (nr_desc+2)) { spin_unlock(&ei_local->page_lock); netif_tx_stop_queue(txq); #if defined (CONFIG_RAETH_DEBUG) if (net_ratelimit()) printk("%s: QDMA TX pool is run out! (GMAC: %d)\n", RAETH_DEV_NAME, gmac_no); #endif return NETDEV_TX_BUSY; } qdma_write_skb_fragment(ei_local, frag_addr, frag_size, txd_info3, txd_info4, skb, nr_frags == 0); #if defined (CONFIG_RAETH_SG_DMA_TX) for (i = 0; i < nr_frags; i++) { tx_frag = &shinfo->frags[i]; frag_size = skb_frag_size(tx_frag); frag_addr = skb_frag_dma_map(NULL, tx_frag, 0, frag_size, DMA_TO_DEVICE); qdma_write_skb_fragment(ei_local, frag_addr, frag_size, txd_info3, txd_info4, skb, i == nr_frags - 1); } #endif #if defined (CONFIG_RAETH_BQL) netdev_tx_sent_queue(txq, skb->len); #endif #if !defined (CONFIG_RAETH_BQL) || !defined (CONFIG_SMP) /* smp_mb() already inlined in netdev_tx_sent_queue */ wmb(); #endif /* kick the QDMA TX */ sysRegWrite(QTX_CTX_PTR, (u32)get_txd_ptr_phy(ei_local, ei_local->txd_last_idx)); spin_unlock(&ei_local->page_lock); return NETDEV_TX_OK; }
static int xenvif_tx_submit(struct xenvif *vif) { struct gnttab_map_grant_ref *gop_map = vif->tx_map_ops; struct gnttab_copy *gop_copy = vif->tx_copy_ops; struct sk_buff *skb; int work_done = 0; while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) { struct xen_netif_tx_request *txp; u16 pending_idx; unsigned data_len; pending_idx = XENVIF_TX_CB(skb)->pending_idx; txp = &vif->pending_tx_info[pending_idx].req; /* Check the remap error code. */ if (unlikely(xenvif_tx_check_gop(vif, skb, &gop_map, &gop_copy))) { skb_shinfo(skb)->nr_frags = 0; kfree_skb(skb); continue; } data_len = skb->len; callback_param(vif, pending_idx).ctx = NULL; if (data_len < txp->size) { /* Append the packet payload as a fragment. */ txp->offset += data_len; txp->size -= data_len; } else { /* Schedule a response immediately. */ xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } if (txp->flags & XEN_NETTXF_csum_blank) skb->ip_summed = CHECKSUM_PARTIAL; else if (txp->flags & XEN_NETTXF_data_validated) skb->ip_summed = CHECKSUM_UNNECESSARY; xenvif_fill_frags(vif, skb); if (unlikely(skb_has_frag_list(skb))) { if (xenvif_handle_frag_list(vif, skb)) { if (net_ratelimit()) netdev_err(vif->dev, "Not enough memory to consolidate frag_list!\n"); skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; kfree_skb(skb); continue; } } if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) { int target = min_t(int, skb->len, PKT_PROT_LEN); __pskb_pull_tail(skb, target - skb_headlen(skb)); } skb->dev = vif->dev; skb->protocol = eth_type_trans(skb, skb->dev); skb_reset_network_header(skb); if (checksum_setup(vif, skb)) { netdev_dbg(vif->dev, "Can't setup checksum in net_tx_action\n"); /* We have to set this flag to trigger the callback */ if (skb_shinfo(skb)->destructor_arg) skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; kfree_skb(skb); continue; } skb_probe_transport_header(skb, 0); /* If the packet is GSO then we will have just set up the * transport header offset in checksum_setup so it's now * straightforward to calculate gso_segs. */ if (skb_is_gso(skb)) { int mss = skb_shinfo(skb)->gso_size; int hdrlen = skb_transport_header(skb) - skb_mac_header(skb) + tcp_hdrlen(skb); skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len - hdrlen, mss); } vif->dev->stats.rx_bytes += skb->len; vif->dev->stats.rx_packets++; work_done++; /* Set this flag right before netif_receive_skb, otherwise * someone might think this packet already left netback, and * do a skb_copy_ubufs while we are still in control of the * skb. E.g. the __pskb_pull_tail earlier can do such thing. */ if (skb_shinfo(skb)->destructor_arg) { skb_shinfo(skb)->tx_flags |= SKBTX_DEV_ZEROCOPY; vif->tx_zerocopy_sent++; } netif_receive_skb(skb); }
static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) { struct mlx5_wq_cyc *wq = &sq->wq; u16 pi = sq->pc & wq->sz_m1; struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi); struct mlx5e_tx_wqe_info *wi = &sq->wqe_info[pi]; struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl; struct mlx5_wqe_eth_seg *eseg = &wqe->eth; struct mlx5_wqe_data_seg *dseg; unsigned char *skb_data = skb->data; unsigned int skb_len = skb->len; u8 opcode = MLX5_OPCODE_SEND; dma_addr_t dma_addr = 0; unsigned int num_bytes; bool bf = false; u16 headlen; u16 ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS; u16 ihs; int i; memset(wqe, 0, sizeof(*wqe)); if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) { eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM; if (skb->encapsulation) { eseg->cs_flags |= MLX5_ETH_WQE_L3_INNER_CSUM | MLX5_ETH_WQE_L4_INNER_CSUM; sq->stats.csum_partial_inner++; } else { eseg->cs_flags |= MLX5_ETH_WQE_L4_CSUM; sq->stats.csum_partial++; } } else sq->stats.csum_none++; if (sq->cc != sq->prev_cc) { sq->prev_cc = sq->cc; sq->bf_budget = (sq->cc == sq->pc) ? MLX5E_SQ_BF_BUDGET : 0; } if (skb_is_gso(skb)) { eseg->mss = cpu_to_be16(skb_shinfo(skb)->gso_size); opcode = MLX5_OPCODE_LSO; if (skb->encapsulation) { ihs = skb_inner_transport_header(skb) - skb->data + inner_tcp_hdrlen(skb); sq->stats.tso_inner_packets++; sq->stats.tso_inner_bytes += skb->len - ihs; } else { ihs = skb_transport_offset(skb) + tcp_hdrlen(skb); sq->stats.tso_packets++; sq->stats.tso_bytes += skb->len - ihs; } num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs; } else { bf = sq->bf_budget && !skb->xmit_more && !skb_shinfo(skb)->nr_frags; ihs = mlx5e_get_inline_hdr_size(sq, skb, bf); num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); } wi->num_bytes = num_bytes; if (skb_vlan_tag_present(skb)) { mlx5e_insert_vlan(eseg->inline_hdr_start, skb, ihs, &skb_data, &skb_len); ihs += VLAN_HLEN; } else { memcpy(eseg->inline_hdr_start, skb_data, ihs); mlx5e_tx_skb_pull_inline(&skb_data, &skb_len, ihs); } eseg->inline_hdr_sz = cpu_to_be16(ihs); ds_cnt += DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr_start), MLX5_SEND_WQE_DS); dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt; wi->num_dma = 0; headlen = skb_len - skb->data_len; if (headlen) { dma_addr = dma_map_single(sq->pdev, skb_data, headlen, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) goto dma_unmap_wqe_err; dseg->addr = cpu_to_be64(dma_addr); dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(headlen); mlx5e_dma_push(sq, dma_addr, headlen, MLX5E_DMA_MAP_SINGLE); wi->num_dma++; dseg++; } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; int fsz = skb_frag_size(frag); dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) goto dma_unmap_wqe_err; dseg->addr = cpu_to_be64(dma_addr); dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(fsz); mlx5e_dma_push(sq, dma_addr, fsz, MLX5E_DMA_MAP_PAGE); wi->num_dma++; dseg++; } ds_cnt += wi->num_dma; cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode); cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt); sq->skb[pi] = skb; wi->num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS); sq->pc += wi->num_wqebbs; if (unlikely(MLX5E_TX_HW_STAMP(sq->channel->priv, skb))) skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; netdev_tx_sent_queue(sq->txq, wi->num_bytes); if (unlikely(!mlx5e_sq_has_room_for(sq, MLX5E_SQ_STOP_ROOM))) { netif_tx_stop_queue(sq->txq); sq->stats.queue_stopped++; } if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) { int bf_sz = 0; if (bf && sq->uar_bf_map) bf_sz = wi->num_wqebbs << 3; cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; mlx5e_tx_notify_hw(sq, &wqe->ctrl, bf_sz); } sq->bf_budget = bf ? sq->bf_budget - 1 : 0; /* fill sq edge with nops to avoid wqe wrap around */ while ((sq->pc & wq->sz_m1) > sq->edge) mlx5e_send_nop(sq, false); sq->stats.packets++; sq->stats.bytes += num_bytes; return NETDEV_TX_OK; dma_unmap_wqe_err: sq->stats.queue_dropped++; mlx5e_dma_unmap_wqe_err(sq, wi->num_dma); dev_kfree_skb_any(skb); return NETDEV_TX_OK; }
static inline int dma_xmit(struct sk_buff* skb, struct net_device *dev, END_DEVICE *ei_local, int gmac_no) { struct netdev_queue *txq; dma_addr_t frag_addr; u32 frag_size, nr_desc; u32 next_idx, desc_odd = 0; u32 txd_info2 = 0, txd_info4; #if defined (CONFIG_RAETH_SG_DMA_TX) u32 i, nr_frags; const skb_frag_t *tx_frag; const struct skb_shared_info *shinfo; #else #define nr_frags 0 #endif #if defined (CONFIG_RA_HW_NAT) || defined (CONFIG_RA_HW_NAT_MODULE) if (ra_sw_nat_hook_tx != NULL) { #if defined (CONFIG_RA_HW_NAT_WIFI) || defined (CONFIG_RA_HW_NAT_PCI) if (IS_DPORT_PPE_VALID(skb)) gmac_no = PSE_PORT_PPE; else #endif if (ra_sw_nat_hook_tx(skb, gmac_no) == 0) { dev_kfree_skb(skb); return NETDEV_TX_OK; } } #endif #if !defined (RAETH_HW_PADPKT) if (skb->len < ei_local->min_pkt_len) { if (skb_padto(skb, ei_local->min_pkt_len)) { #if defined (CONFIG_RAETH_DEBUG) if (net_ratelimit()) printk(KERN_ERR "%s: skb_padto failed\n", RAETH_DEV_NAME); #endif return NETDEV_TX_OK; } skb_put(skb, ei_local->min_pkt_len - skb->len); } #endif #if defined (CONFIG_RALINK_MT7620) if (gmac_no == PSE_PORT_PPE) txd_info4 = TX4_DMA_FP_BMAP(0x80); /* P7 */ else #if defined (CONFIG_RAETH_HAS_PORT5) && !defined (CONFIG_RAETH_HAS_PORT4) && !defined (CONFIG_RAETH_ESW) txd_info4 = TX4_DMA_FP_BMAP(0x20); /* P5 */ #elif defined (CONFIG_RAETH_HAS_PORT4) && !defined (CONFIG_RAETH_HAS_PORT5) && !defined (CONFIG_RAETH_ESW) txd_info4 = TX4_DMA_FP_BMAP(0x10); /* P4 */ #else txd_info4 = 0; /* routing by DA */ #endif #elif defined (CONFIG_RALINK_MT7621) txd_info4 = TX4_DMA_FPORT(gmac_no); #else txd_info4 = (TX4_DMA_QN(3) | TX4_DMA_PN(gmac_no)); #endif #if defined (CONFIG_RAETH_CHECKSUM_OFFLOAD) && !defined (RAETH_SDMA) if (skb->ip_summed == CHECKSUM_PARTIAL) txd_info4 |= TX4_DMA_TUI_CO(7); #endif #if defined (CONFIG_RAETH_HW_VLAN_TX) if (skb_vlan_tag_present(skb)) { #if defined (RAETH_HW_VLAN4K) txd_info4 |= (0x10000 | skb_vlan_tag_get(skb)); #else u32 vlan_tci = skb_vlan_tag_get(skb); txd_info4 |= (TX4_DMA_INSV | TX4_DMA_VPRI(vlan_tci)); txd_info4 |= (u32)ei_local->vlan_4k_map[(vlan_tci & VLAN_VID_MASK)]; #endif } #endif #if defined (CONFIG_RAETH_SG_DMA_TX) shinfo = skb_shinfo(skb); #endif #if defined (CONFIG_RAETH_TSO) /* fill MSS info in tcp checksum field */ if (shinfo->gso_size) { u32 hdr_len; if (!(shinfo->gso_type & (SKB_GSO_TCPV4|SKB_GSO_TCPV6))) { dev_kfree_skb(skb); return NETDEV_TX_OK; } if (skb_header_cloned(skb)) { if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) { dev_kfree_skb(skb); return NETDEV_TX_OK; } } hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb)); if (hdr_len >= skb->len) { dev_kfree_skb(skb); return NETDEV_TX_OK; } tcp_hdr(skb)->check = htons(shinfo->gso_size); txd_info4 |= TX4_DMA_TSO; } #endif nr_desc = DIV_ROUND_UP(skb_headlen(skb), TXD_MAX_SEG_SIZE); #if defined (CONFIG_RAETH_SG_DMA_TX) nr_frags = (u32)shinfo->nr_frags; for (i = 0; i < nr_frags; i++) { tx_frag = &shinfo->frags[i]; nr_desc += DIV_ROUND_UP(skb_frag_size(tx_frag), TXD_MAX_SEG_SIZE); } #endif nr_desc = DIV_ROUND_UP(nr_desc, 2); txq = netdev_get_tx_queue(dev, 0); /* flush main skb part before spin_lock() */ frag_size = (u32)skb_headlen(skb); frag_addr = dma_map_single(NULL, skb->data, frag_size, DMA_TO_DEVICE); /* protect TX ring access (from eth2/eth3 queues) */ spin_lock(&ei_local->page_lock); /* check nr_desc+1 free descriptors */ next_idx = (ei_local->txd_last_idx + nr_desc) % NUM_TX_DESC; if (ei_local->txd_buff[ei_local->txd_last_idx] || ei_local->txd_buff[next_idx]) { spin_unlock(&ei_local->page_lock); netif_tx_stop_queue(txq); #if defined (CONFIG_RAETH_DEBUG) if (net_ratelimit()) printk("%s: PDMA TX ring is full! (GMAC: %d)\n", RAETH_DEV_NAME, gmac_no); #endif return NETDEV_TX_BUSY; } pdma_write_skb_fragment(ei_local, frag_addr, frag_size, &desc_odd, &txd_info2, txd_info4, skb, nr_frags == 0); #if defined (CONFIG_RAETH_SG_DMA_TX) for (i = 0; i < nr_frags; i++) { tx_frag = &shinfo->frags[i]; frag_size = skb_frag_size(tx_frag); frag_addr = skb_frag_dma_map(NULL, tx_frag, 0, frag_size, DMA_TO_DEVICE); pdma_write_skb_fragment(ei_local, frag_addr, frag_size, &desc_odd, &txd_info2, txd_info4, skb, i == nr_frags - 1); } #endif #if defined (CONFIG_RAETH_BQL) netdev_tx_sent_queue(txq, skb->len); #endif #if !defined (CONFIG_RAETH_BQL) || !defined (CONFIG_SMP) /* smp_mb() already inlined in netdev_tx_sent_queue */ wmb(); #endif /* kick the DMA TX */ sysRegWrite(TX_CTX_IDX0, cpu_to_le32(ei_local->txd_last_idx)); spin_unlock(&ei_local->page_lock); return NETDEV_TX_OK; }
static netdev_tx_t mlx5e_sq_xmit(struct mlx5e_sq *sq, struct sk_buff *skb) { struct mlx5_wq_cyc *wq = &sq->wq; u16 pi = sq->pc & wq->sz_m1; struct mlx5e_tx_wqe *wqe = mlx5_wq_cyc_get_wqe(wq, pi); struct mlx5_wqe_ctrl_seg *cseg = &wqe->ctrl; struct mlx5_wqe_eth_seg *eseg = &wqe->eth; struct mlx5_wqe_data_seg *dseg; u8 opcode = MLX5_OPCODE_SEND; dma_addr_t dma_addr = 0; bool bf = false; u16 headlen; u16 ds_cnt; u16 ihs; int i; memset(wqe, 0, sizeof(*wqe)); if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) eseg->cs_flags = MLX5_ETH_WQE_L3_CSUM | MLX5_ETH_WQE_L4_CSUM; else sq->stats.csum_offload_none++; if (sq->cc != sq->prev_cc) { sq->prev_cc = sq->cc; sq->bf_budget = (sq->cc == sq->pc) ? MLX5E_SQ_BF_BUDGET : 0; } if (skb_is_gso(skb)) { u32 payload_len; eseg->mss = cpu_to_be16(skb_shinfo(skb)->gso_size); opcode = MLX5_OPCODE_LSO; ihs = skb_transport_offset(skb) + tcp_hdrlen(skb); payload_len = skb->len - ihs; MLX5E_TX_SKB_CB(skb)->num_bytes = skb->len + (skb_shinfo(skb)->gso_segs - 1) * ihs; sq->stats.tso_packets++; sq->stats.tso_bytes += payload_len; } else { bf = sq->bf_budget && !skb->xmit_more && !skb_shinfo(skb)->nr_frags; ihs = mlx5e_get_inline_hdr_size(sq, skb, bf); MLX5E_TX_SKB_CB(skb)->num_bytes = max_t(unsigned int, skb->len, ETH_ZLEN); } skb_copy_from_linear_data(skb, eseg->inline_hdr_start, ihs); skb_pull_inline(skb, ihs); eseg->inline_hdr_sz = cpu_to_be16(ihs); ds_cnt = sizeof(*wqe) / MLX5_SEND_WQE_DS; ds_cnt += DIV_ROUND_UP(ihs - sizeof(eseg->inline_hdr_start), MLX5_SEND_WQE_DS); dseg = (struct mlx5_wqe_data_seg *)cseg + ds_cnt; MLX5E_TX_SKB_CB(skb)->num_dma = 0; headlen = skb_headlen(skb); if (headlen) { dma_addr = dma_map_single(sq->pdev, skb->data, headlen, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) goto dma_unmap_wqe_err; dseg->addr = cpu_to_be64(dma_addr); dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(headlen); mlx5e_dma_push(sq, dma_addr, headlen); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; } for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; int fsz = skb_frag_size(frag); dma_addr = skb_frag_dma_map(sq->pdev, frag, 0, fsz, DMA_TO_DEVICE); if (unlikely(dma_mapping_error(sq->pdev, dma_addr))) goto dma_unmap_wqe_err; dseg->addr = cpu_to_be64(dma_addr); dseg->lkey = sq->mkey_be; dseg->byte_count = cpu_to_be32(fsz); mlx5e_dma_push(sq, dma_addr, fsz); MLX5E_TX_SKB_CB(skb)->num_dma++; dseg++; } ds_cnt += MLX5E_TX_SKB_CB(skb)->num_dma; cseg->opmod_idx_opcode = cpu_to_be32((sq->pc << 8) | opcode); cseg->qpn_ds = cpu_to_be32((sq->sqn << 8) | ds_cnt); sq->skb[pi] = skb; MLX5E_TX_SKB_CB(skb)->num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS); sq->pc += MLX5E_TX_SKB_CB(skb)->num_wqebbs; netdev_tx_sent_queue(sq->txq, MLX5E_TX_SKB_CB(skb)->num_bytes); if (unlikely(!mlx5e_sq_has_room_for(sq, MLX5E_SQ_STOP_ROOM))) { netif_tx_stop_queue(sq->txq); sq->stats.stopped++; } if (!skb->xmit_more || netif_xmit_stopped(sq->txq)) { int bf_sz = 0; if (bf && sq->uar_bf_map) bf_sz = MLX5E_TX_SKB_CB(skb)->num_wqebbs << 3; cseg->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE; mlx5e_tx_notify_hw(sq, wqe, bf_sz); } /* fill sq edge with nops to avoid wqe wrap around */ while ((sq->pc & wq->sz_m1) > sq->edge) mlx5e_send_nop(sq, false); sq->bf_budget = bf ? sq->bf_budget - 1 : 0; sq->stats.packets++; return NETDEV_TX_OK; dma_unmap_wqe_err: sq->stats.dropped++; mlx5e_dma_unmap_wqe_err(sq, skb); dev_kfree_skb_any(skb); return NETDEV_TX_OK; }
static struct sk_buff *tls_enc_skb(struct tls_context *tls_ctx, struct scatterlist sg_out[3], struct scatterlist *sg_in, struct sk_buff *skb, s32 sync_size, u64 rcd_sn) { int tcp_payload_offset = skb_transport_offset(skb) + tcp_hdrlen(skb); struct tls_offload_context_tx *ctx = tls_offload_ctx_tx(tls_ctx); int payload_len = skb->len - tcp_payload_offset; void *buf, *iv, *aad, *dummy_buf; struct aead_request *aead_req; struct sk_buff *nskb = NULL; int buf_len; aead_req = tls_alloc_aead_request(ctx->aead_send, GFP_ATOMIC); if (!aead_req) return NULL; buf_len = TLS_CIPHER_AES_GCM_128_SALT_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE + TLS_AAD_SPACE_SIZE + sync_size + TLS_CIPHER_AES_GCM_128_TAG_SIZE; buf = kmalloc(buf_len, GFP_ATOMIC); if (!buf) goto free_req; iv = buf; memcpy(iv, tls_ctx->crypto_send.aes_gcm_128.salt, TLS_CIPHER_AES_GCM_128_SALT_SIZE); aad = buf + TLS_CIPHER_AES_GCM_128_SALT_SIZE + TLS_CIPHER_AES_GCM_128_IV_SIZE; dummy_buf = aad + TLS_AAD_SPACE_SIZE; nskb = alloc_skb(skb_headroom(skb) + skb->len, GFP_ATOMIC); if (!nskb) goto free_buf; skb_reserve(nskb, skb_headroom(skb)); fill_sg_out(sg_out, buf, tls_ctx, nskb, tcp_payload_offset, payload_len, sync_size, dummy_buf); if (tls_enc_records(aead_req, ctx->aead_send, sg_in, sg_out, aad, iv, rcd_sn, sync_size + payload_len) < 0) goto free_nskb; complete_skb(nskb, skb, tcp_payload_offset); /* validate_xmit_skb_list assumes that if the skb wasn't segmented * nskb->prev will point to the skb itself */ nskb->prev = nskb; free_buf: kfree(buf); free_req: kfree(aead_req); return nskb; free_nskb: kfree_skb(nskb); nskb = NULL; goto free_buf; }
static int xenvif_tx_submit(struct xenvif *vif) { struct gnttab_copy *gop = vif->tx_copy_ops; struct sk_buff *skb; int work_done = 0; while ((skb = __skb_dequeue(&vif->tx_queue)) != NULL) { struct xen_netif_tx_request *txp; u16 pending_idx; unsigned data_len; pending_idx = *((u16 *)skb->data); txp = &vif->pending_tx_info[pending_idx].req; /* Check the remap error code. */ if (unlikely(xenvif_tx_check_gop(vif, skb, &gop))) { netdev_dbg(vif->dev, "netback grant failed.\n"); skb_shinfo(skb)->nr_frags = 0; kfree_skb(skb); continue; } data_len = skb->len; memcpy(skb->data, (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset), data_len); if (data_len < txp->size) { /* Append the packet payload as a fragment. */ txp->offset += data_len; txp->size -= data_len; } else { /* Schedule a response immediately. */ xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_OKAY); } if (txp->flags & XEN_NETTXF_csum_blank) skb->ip_summed = CHECKSUM_PARTIAL; else if (txp->flags & XEN_NETTXF_data_validated) skb->ip_summed = CHECKSUM_UNNECESSARY; xenvif_fill_frags(vif, skb); if (skb_is_nonlinear(skb) && skb_headlen(skb) < PKT_PROT_LEN) { int target = min_t(int, skb->len, PKT_PROT_LEN); __pskb_pull_tail(skb, target - skb_headlen(skb)); } skb->dev = vif->dev; skb->protocol = eth_type_trans(skb, skb->dev); skb_reset_network_header(skb); if (checksum_setup(vif, skb)) { netdev_dbg(vif->dev, "Can't setup checksum in net_tx_action\n"); kfree_skb(skb); continue; } skb_probe_transport_header(skb, 0); /* If the packet is GSO then we will have just set up the * transport header offset in checksum_setup so it's now * straightforward to calculate gso_segs. */ if (skb_is_gso(skb)) { int mss = skb_shinfo(skb)->gso_size; int hdrlen = skb_transport_header(skb) - skb_mac_header(skb) + tcp_hdrlen(skb); skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len - hdrlen, mss); } vif->dev->stats.rx_bytes += skb->len; vif->dev->stats.rx_packets++; work_done++; netif_receive_skb(skb); }
static inline void enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss, int vlan_tag_insert, unsigned int vlan_tag) { unsigned int frag_len_left = skb_headlen(skb); unsigned int len_left = skb->len - frag_len_left; unsigned int hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); int eop = (len_left == 0); unsigned int len; dma_addr_t dma_addr; unsigned int offset = 0; skb_frag_t *frag; if (skb->protocol == cpu_to_be16(ETH_P_IP)) { ip_hdr(skb)->check = 0; tcp_hdr(skb)->check = ~csum_tcpudp_magic(ip_hdr(skb)->saddr, ip_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } else if (skb->protocol == cpu_to_be16(ETH_P_IPV6)) { tcp_hdr(skb)->check = ~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, 0, IPPROTO_TCP, 0); } while (frag_len_left) { len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); dma_addr = pci_map_single(enic->pdev, skb->data + offset, len, PCI_DMA_TODEVICE); enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len, vlan_tag_insert, vlan_tag, eop && (len == frag_len_left)); frag_len_left -= len; offset += len; } if (eop) return; for (frag = skb_shinfo(skb)->frags; len_left; frag++) { len_left -= frag->size; frag_len_left = frag->size; offset = frag->page_offset; while (frag_len_left) { len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN); dma_addr = pci_map_page(enic->pdev, frag->page, offset, len, PCI_DMA_TODEVICE); enic_queue_wq_desc_cont(wq, skb, dma_addr, len, (len_left == 0) && (len == frag_len_left)); frag_len_left -= len; offset += len; } } }