Transmit and Receive Functions - 0xffffffRabbit/NextBsd GitHub Wiki
Packet Transmit and Receive Functions
IFLIB handles transparently the entire process of packet enqueueing onto the iflib_txq transmit ring and transmission of the packet onto iflib_rxq receive ring. The developer should implement the functions in struct if_txrx to accommodate their driver's hardware.
Note: The void *sc passed as an argument to all of the following functions is a pointer to the driver's softc. All of the functions are part of struct if_txrx.
int (*isc_txd_encap)(void *sc, if_pkt_info_t pi)
iflib_encap places an mbuf onto the iflib transmit queue and initializes the packet information structure if_pkt_info_t, which is sent to the developer defined function isc_txd_encap for transmission. In this section a developer will need to:
-
Set each transmit descriptor to transmit base (paddr) for each seg in pi->nsegs
-
Setup up the TSO/CSUM Offload if required
-
Set up the TSO context descriptor if required
-
Mark the last descriptor as done
-
Set the pi->ipi_new_pidx to the next pidx to process
typedef struct if_pkt_info { uint32_t ipi_len; /* packet length */ bus_dma_segment_t *ipi_segs; /* physical addresses */ uint16_t ipi_qsidx; /* queue set index */ uint16_t ipi_nsegs; /* number of segments */ uint16_t ipi_ndescs; /* number of descriptors used by encap */ uint16_t ipi_flags; /* iflib per-packet flags */ uint32_t ipi_pidx; /* start pidx for encap */ uint32_t ipi_new_pidx; /* next available pidx post-encap */ /* offload handling */ uint64_t ipi_csum_flags; /* packet checksum flags */ uint16_t ipi_tso_segsz; /* tso segment size */ uint16_t ipi_mflags; /* packet mbuf flags */ uint16_t ipi_vtag; /* VLAN tag */ uint16_t ipi_etype; /* ether header type */ uint8_t ipi_ehdrlen; /* ether header length */ uint8_t ipi_ip_hlen; /* ip header length */ uint8_t ipi_tcp_hlen; /* tcp header length */ uint8_t ipi_tcp_hflags; /* tcp header flags */ uint8_t ipi_ipproto; /* ip protocol */ /* implied padding */ } *if_pkt_info_t; void (*isc_txd_flush) (void *sc, uint16_t qid, uint32_t _pidx_or_credits_)
isc_txd_flush should write the hardware producer index or increment the descriptors used by pidx_or_credits in queue number qid. This is often referred to as poking the doorbell register.
int (*isc_txd_credits_update) (void *sc, uint16_t qid, uint32_t cidx_init,
bool clear)
isc_txd_credits_update notifies iflib of the number of new transmit descriptors that have been made available/processed since the last update for queue qid. cidx_init refers to the index value of the last packet processed. clear is true if isc_txd_credits_update is called by iflib_tx_credit_update and false if the function is called by iflib_tx_can_drain.
int (*isc_rxd_available) (void *sc, uint16_t qsid, uint32_t cidx)
isc_rxd_available is a counter function that notifies iflib of the number of new receive descriptors. It calculates for a particular queue qsid starting from a beginning value cidx. It does not count empty descriptors. iflib_rxeof uses this count to determine how many times to call iflib_rxd_pkt_get.
void (*isc_rxd_refill) (void *sc, uint16_t qsid, uint8_t flid,
uint32_t pidx, uint64_t *paddrs, caddr_t *vaddrs, uint16_t count)
isc_rxd_refill refills the freelist flid if isc_rxd_available returns null. The qsid refers to the queue id, pidx refers to the starting index, and paddr refers to the physical address. Note: vaddrs is typically not needed and is provided for devices that place their own metadata in the packet header.
void (*isc_rxd_flush)(void *sc, uint16_t qsid, uint8_t flid, uint32_t pidx)
isc_rxd_flush updates the producer pointer on free list flid in queue set number qsid to value pidx to reflect the presence of new buffers.
typedef struct if_rxd_info {
/* set by iflib */
uint16_t iri_qsidx; /* qset index */
uint16_t iri_vtag; /* vlan tag - if flag set */
uint16_t iri_len; /* packet length */
uint32_t iri_cidx; /* consumer index of cq */
struct ifnet *iri_ifp; /* some drivers >1 interface per softc */
/* Updated by the driver */
uint32_t iri_flowid; /* RSS hash for packet */
int iri_flags; /* mbuf flags for packet */
uint32_t iri_csum_flags; /* m_pkthdr csum flags */
uint32_t iri_csum_data; /* m_pkthdr csum data */
uint8_t iri_nfrags; /* number of fragments in packet */
uint8_t iri_rsstype; /* RSS hash type */
uint8_t iri_pad; /* any padding in the received data */
if_rxd_frag_t iri_frags; /* fragments */
} *if_rxd_info_t;
typedef struct if_rxd_frag {
uint8_t irf_flid; /* free list id */
uint16_t irf_idx; /* fragment index */
} *if_rxd_frag_t;
struct if_rxd_info contains packet information for a single receive software descriptor. Struct if_rxd_frag contains fragment information necessary for assembly of fragments by iflib. Troubleshooting: Developer will always need to set values for ri->iri_frags and ri->iri_nfrags.
int (*isc_rxd_pkt_get) (void *sc, if_rxd_info_t ri)
isc_rxd_pkt_get is called by iflib_rxeof to get the next receive packet and finish initialization of the ri structure. It should make sure that bad packets are discarded, return 0 upon success, and errno on failure.