Hardware Checksum support on NetBSD-current(4)

dev/pci/if_vge.cを例に受信時のHW checksum supportの流れを確認する。

初期化

vge_attach()のifp->if_capabilitiesで対応している機能のフラグを立てる:

	ifp->if_capabilities |=
	    IFCAP_CSUM_IPv4_Tx | IFCAP_CSUM_IPv4_Rx |
	    IFCAP_CSUM_TCPv4_Tx | IFCAP_CSUM_TCPv4_Rx |
	    IFCAP_CSUM_UDPv4_Tx | IFCAP_CSUM_UDPv4_Rx;

これでカーネル側でifp->if_csum_flags_rx, ifp->if_csum_flags_txにもフラグがセットされる。

RX checksum処理

パケットが来るとvge_rxeof()が呼ばれる。
この時、ifp->if_csum_flags_rxに対応するフラグが立っていたらchecksumの処理を行う:

		/* IP header checksumにインタフェースが対応している */
		if (ifp->if_csum_flags_rx & M_CSUM_IPv4) {

			/* rxctlはデバイスのレジスタから読んできた値で
                           VGE_RDCTL_IPPKTビットが立ってるならIPv4のパケットである為、
                           M_CSUM_IPv4フラグを立てる */
			if (rxctl & VGE_RDCTL_IPPKT)
				m->m_pkthdr.csum_flags |= M_CSUM_IPv4;
                        /* VGE_RDCTL_IPCSUMOKビットが立っていないなら
                           checksumがヘッダと一致しなかった為、M_CSUM_IPv4_BADフラグを立てる */
			if ((rxctl & VGE_RDCTL_IPCSUMOK) == 0)
				m->m_pkthdr.csum_flags |= M_CSUM_IPv4_BAD;
		}
		/* TCPv4 checksumにインタフェースが対応している */
		if (ifp->if_csum_flags_rx & M_CSUM_TCPv4) {
			/* VGE_RDCTL_TCPPKTビットが立ってるならTCPv4パケットである為、
                           M_CSUM_TCPv4フラグを立てる */
			if (rxctl & VGE_RDCTL_TCPPKT)
				m->m_pkthdr.csum_flags |= M_CSUM_TCPv4;
                        /* VGE_RDCTL_PROTOCSUMOKビットが立っていないなら
                           checksumがデータと一致しなかった為、M_CSUM_TCP_UDP_BADフラグを立てる */
			if ((rxctl & VGE_RDCTL_PROTOCSUMOK) == 0)
				m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
		}
		/* UDPv4 checksumにインタフェースが対応している */
		if (ifp->if_csum_flags_rx & M_CSUM_UDPv4) {
			/* VGE_RDCTL_UDPPKTビットが立ってるならUDPv4パケットである為、
                           M_CSUM_UDPv4フラグを立てる */
			if (rxctl & VGE_RDCTL_UDPPKT)
				m->m_pkthdr.csum_flags |= M_CSUM_UDPv4;
                        /* VGE_RDCTL_PROTOCSUMOKビットが立っていないなら
                           checksumがデータと一致しなかった為、M_CSUM_TCP_UDP_BADフラグを立てる */
			if ((rxctl & VGE_RDCTL_PROTOCSUMOK) == 0)
				m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
		}