0.0.0.1. Test case two linux guest vm on a same host(physical machine), there is a tcp session between them.
0.0.0.2. conclusion: the checksum in tcp header is only cover the faked tcp header not the whole tcp packet.
0.0.0.2.1. call trace vm1(netfront) —> host backend(vif_1) —> bridge —> host backend(vif_2) —> vm2(netfrontend)
0.0.0.2.1.1. netfront before sent to backend, netfront driver set two flags:XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated;"
1 2 3 4 5 6 575 if (skb->ip_summed == CHECKSUM_PARTIAL)576 /* local packet? */577 tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated;578 else if (skb->ip_summed == CHECKSUM_UNNECESSARY)579 /* 580 tx->flags |= XEN_NETTXF_data_validated;
0.0.0.2.1.2. net backend 1 2 3 4 5 6 7 8 9 1409 static int xenvif_tx_submit( struct xenvif_queue *queue) 1410 { ...1452 if ( txp->flags & XEN_NETTXF_csum_blank) 1453 skb->ip_summed = CHECKSUM_PARTIAL1454 else if ( txp->flags & XEN_NETTXF_data_validated) 1455 skb->ip_summed = CHECKSUM_UNNECESSARY ...1515 netif_receive_skb( skb)
0.0.0.2.1.3. bridge forward this packet to vm2’s backend.
0.0.0.2.1.4. netbackend after bridge, skb reach peer vm2’s backend’s ndo xmit function.
1 2 3 4 5 6 7 8 9 10 11 12 139 static int xenvif_start_xmit (struct sk_buff *skb, struct net_device *dev) ... 497 static void xenvif_rx_action (struct xenvif_queue *queue) 498 { ... 567 568 if (skb->ip_summed == CHECKSUM_PARTIAL) 569 flags |= XEN_NETRXF_csum_blank | XEN_NETRXF_data_validated; 570 else if (skb->ip_summed == CHECKSUM_UNNECESSARY) 571 572 flags |= XEN_NETRXF_data_validated;
0.0.0.2.1.5. netfront xen net front driver will do nothing. just setup the csum offset and len in skb, even the fake tcp header checksum is not re-calculated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 876 static int handle_incoming_queue(struct netfront_queue *queue,877 struct sk_buff_head *rxq)878 { ...893 if (checksum_setup(queue->info -> netdev, skb)) {894 kfree_skb(skb);895 packets_dropped++;896 queue ->info ->netdev -> stats.rx_errors++;897 continue;898 } ...905 906 napi_gro_receive (&queue-> napi, skb);907 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 852 static int checksum_setup(struct net_device *dev, struct sk_buff *skb)853 {854 bool recalculate_partial_csum = false;855 856 /*857 * A GSO SKB must be CHECKSUM_PARTIAL. However some buggy858 * peers can fail to set NETRXF_csum_blank when sending a GSO859 * frame. In this case force the SKB to CHECKSUM_PARTIAL and 860 * recalculate the partial checksum.861 */862 if (skb->ip_summed != CHECKSUM_PARTIAL && skb_is_gso(skb)) {863 struct netfront_info *np = netdev_priv(dev);864 atomic_inc(&np->rx_gso_checksum_fixup);865 skb->ip_summed = CHECKSUM_PARTIAL;866 recalculate_partial_csum = true;867 }868 869 /* A non-CHECKSUM_PARTIAL SKB does not require setup. */870 if (skb->ip_summed != CHECKSUM_PARTIAL)871 return 0 ;872 873 return skb_checksum_setup(skb, recalculate_partial_csum);874 }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 4006 /**4007 * skb_checksum_setup - set up partial checksum offset4008 * @skb: the skb to set up4009 * @recalculate: if true the pseudo-header checksum will be recalculated4010 */4011 int skb_checksum_setup(struct sk_buff *skb, bool recalculate)4012 {4013 int err ;4014 4015 switch (skb->protocol) {4016 case htons(ETH_P_IP):4017 err = skb_checksum_setup_ipv4(skb, recalculate);4018 break;4019 4020 case htons(ETH_P_IPV6):4021 err = skb_checksum_setup_ipv6(skb, recalculate);4022 break;4023 4024 default:4025 err = -EPROTO;4026 break;4027 }4028 4029 return err ;4030 }4031 EXPORT_SYMBOL(skb_checksum_setup);