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; }