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.