Split Chelsio send tags into a generic base tag and a ratelimit tag.

NIC KTLS will add a new TLS send tag type in cxgbe(4) that is a
distinct tag from a ratelimit tag.  To support this, refactor
cxgbe_snd_tag to be a simple send tag with a type and convert the
existing ratelimit tag to a new cxgbe_rate_tag structure.

Reviewed by:	np
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D22072
This commit is contained in:
John Baldwin 2019-10-22 20:41:54 +00:00
parent 866a7f286f
commit e38a50e8b6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=353900
5 changed files with 167 additions and 48 deletions

View file

@ -1155,6 +1155,7 @@ int update_mac_settings(struct ifnet *, int);
int adapter_full_init(struct adapter *);
int adapter_full_uninit(struct adapter *);
uint64_t cxgbe_get_counter(struct ifnet *, ift_counter);
void cxgbe_snd_tag_init(struct cxgbe_snd_tag *, struct ifnet *, int);
int vi_full_init(struct vi_info *);
int vi_full_uninit(struct vi_info *);
void vi_sysctls(struct vi_info *);
@ -1212,7 +1213,7 @@ void t4_register_cpl_handler(int, cpl_handler_t);
void t4_register_shared_cpl_handler(int, cpl_handler_t, int);
#ifdef RATELIMIT
int ethofld_transmit(struct ifnet *, struct mbuf *);
void send_etid_flush_wr(struct cxgbe_snd_tag *);
void send_etid_flush_wr(struct cxgbe_rate_tag *);
#endif
/* t4_tracer.c */
@ -1238,13 +1239,13 @@ int sysctl_tc_params(SYSCTL_HANDLER_ARGS);
#ifdef RATELIMIT
void t4_init_etid_table(struct adapter *);
void t4_free_etid_table(struct adapter *);
struct cxgbe_snd_tag *lookup_etid(struct adapter *, int);
int cxgbe_snd_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *,
struct cxgbe_rate_tag *lookup_etid(struct adapter *, int);
int cxgbe_rate_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *,
struct m_snd_tag **);
int cxgbe_snd_tag_modify(struct m_snd_tag *, union if_snd_tag_modify_params *);
int cxgbe_snd_tag_query(struct m_snd_tag *, union if_snd_tag_query_params *);
void cxgbe_snd_tag_free(struct m_snd_tag *);
void cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *);
int cxgbe_rate_tag_modify(struct m_snd_tag *, union if_snd_tag_modify_params *);
int cxgbe_rate_tag_query(struct m_snd_tag *, union if_snd_tag_query_params *);
void cxgbe_rate_tag_free(struct m_snd_tag *);
void cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *);
void cxgbe_ratelimit_query(struct ifnet *, struct if_ratelimit_query_results *);
#endif

View file

@ -79,7 +79,7 @@ union aopen_entry {
union aopen_entry *next;
};
/* cxgbe_snd_tag flags */
/* cxgbe_rate_tag flags */
enum {
EO_FLOWC_PENDING = (1 << 0), /* flowc needs to be sent */
EO_FLOWC_RPL_PENDING = (1 << 1), /* flowc credits due back */
@ -89,6 +89,11 @@ enum {
struct cxgbe_snd_tag {
struct m_snd_tag com;
int type;
};
struct cxgbe_rate_tag {
struct cxgbe_snd_tag com;
struct adapter *adapter;
u_int flags;
struct mtx lock;
@ -114,8 +119,14 @@ mst_to_cst(struct m_snd_tag *t)
return (__containerof(t, struct cxgbe_snd_tag, com));
}
static inline struct cxgbe_rate_tag *
mst_to_crt(struct m_snd_tag *t)
{
return ((struct cxgbe_rate_tag *)mst_to_cst(t));
}
union etid_entry {
struct cxgbe_snd_tag *cst;
struct cxgbe_rate_tag *cst;
union etid_entry *next;
};

View file

@ -230,6 +230,15 @@ static void cxgbe_init(void *);
static int cxgbe_ioctl(struct ifnet *, unsigned long, caddr_t);
static int cxgbe_transmit(struct ifnet *, struct mbuf *);
static void cxgbe_qflush(struct ifnet *);
#ifdef RATELIMIT
static int cxgbe_snd_tag_alloc(struct ifnet *, union if_snd_tag_alloc_params *,
struct m_snd_tag **);
static int cxgbe_snd_tag_modify(struct m_snd_tag *,
union if_snd_tag_modify_params *);
static int cxgbe_snd_tag_query(struct m_snd_tag *,
union if_snd_tag_query_params *);
static void cxgbe_snd_tag_free(struct m_snd_tag *);
#endif
MALLOC_DEFINE(M_CXGBE, "cxgbe", "Chelsio T4/T5 Ethernet driver and services");
@ -2044,11 +2053,18 @@ cxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
struct port_info *pi = vi->pi;
struct adapter *sc = pi->adapter;
struct sge_txq *txq;
#ifdef RATELIMIT
struct cxgbe_snd_tag *cst;
#endif
void *items[1];
int rc;
M_ASSERTPKTHDR(m);
MPASS(m->m_nextpkt == NULL); /* not quite ready for this yet */
#ifdef RATELIMIT
if (m->m_pkthdr.csum_flags & CSUM_SND_TAG)
MPASS(m->m_pkthdr.snd_tag->ifp == ifp);
#endif
if (__predict_false(pi->link_cfg.link_ok == false)) {
m_freem(m);
@ -2063,8 +2079,9 @@ cxgbe_transmit(struct ifnet *ifp, struct mbuf *m)
}
#ifdef RATELIMIT
if (m->m_pkthdr.csum_flags & CSUM_SND_TAG) {
MPASS(m->m_pkthdr.snd_tag->ifp == ifp);
return (ethofld_transmit(ifp, m));
cst = mst_to_cst(m->m_pkthdr.snd_tag);
if (cst->type == IF_SND_TAG_TYPE_RATE_LIMIT)
return (ethofld_transmit(ifp, m));
}
#endif
@ -2222,6 +2239,87 @@ cxgbe_get_counter(struct ifnet *ifp, ift_counter c)
}
}
#ifdef RATELIMIT
void
cxgbe_snd_tag_init(struct cxgbe_snd_tag *cst, struct ifnet *ifp, int type)
{
m_snd_tag_init(&cst->com, ifp);
cst->type = type;
}
static int
cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
struct m_snd_tag **pt)
{
int error;
switch (params->hdr.type) {
#ifdef RATELIMIT
case IF_SND_TAG_TYPE_RATE_LIMIT:
error = cxgbe_rate_tag_alloc(ifp, params, pt);
break;
#endif
default:
error = EOPNOTSUPP;
}
if (error == 0)
MPASS(mst_to_cst(*pt)->type == params->hdr.type);
return (error);
}
static int
cxgbe_snd_tag_modify(struct m_snd_tag *mst,
union if_snd_tag_modify_params *params)
{
struct cxgbe_snd_tag *cst;
cst = mst_to_cst(mst);
switch (cst->type) {
#ifdef RATELIMIT
case IF_SND_TAG_TYPE_RATE_LIMIT:
return (cxgbe_rate_tag_modify(mst, params));
#endif
default:
return (EOPNOTSUPP);
}
}
static int
cxgbe_snd_tag_query(struct m_snd_tag *mst,
union if_snd_tag_query_params *params)
{
struct cxgbe_snd_tag *cst;
cst = mst_to_cst(mst);
switch (cst->type) {
#ifdef RATELIMIT
case IF_SND_TAG_TYPE_RATE_LIMIT:
return (cxgbe_rate_tag_query(mst, params));
#endif
default:
return (EOPNOTSUPP);
}
}
static void
cxgbe_snd_tag_free(struct m_snd_tag *mst)
{
struct cxgbe_snd_tag *cst;
cst = mst_to_cst(mst);
switch (cst->type) {
#ifdef RATELIMIT
case IF_SND_TAG_TYPE_RATE_LIMIT:
cxgbe_rate_tag_free(mst);
return;
#endif
default:
panic("shouldn't get here");
}
}
#endif
/*
* The kernel picks a media from the list we had provided but we still validate
* the requeste.

View file

@ -711,11 +711,11 @@ t4_free_etid_table(struct adapter *sc)
}
/* etid services */
static int alloc_etid(struct adapter *, struct cxgbe_snd_tag *);
static int alloc_etid(struct adapter *, struct cxgbe_rate_tag *);
static void free_etid(struct adapter *, int);
static int
alloc_etid(struct adapter *sc, struct cxgbe_snd_tag *cst)
alloc_etid(struct adapter *sc, struct cxgbe_rate_tag *cst)
{
struct tid_info *t = &sc->tids;
int etid = -1;
@ -733,7 +733,7 @@ alloc_etid(struct adapter *sc, struct cxgbe_snd_tag *cst)
return (etid);
}
struct cxgbe_snd_tag *
struct cxgbe_rate_tag *
lookup_etid(struct adapter *sc, int etid)
{
struct tid_info *t = &sc->tids;
@ -755,17 +755,16 @@ free_etid(struct adapter *sc, int etid)
}
int
cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
cxgbe_rate_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
struct m_snd_tag **pt)
{
int rc, schedcl;
struct vi_info *vi = ifp->if_softc;
struct port_info *pi = vi->pi;
struct adapter *sc = pi->adapter;
struct cxgbe_snd_tag *cst;
struct cxgbe_rate_tag *cst;
if (params->hdr.type != IF_SND_TAG_TYPE_RATE_LIMIT)
return (ENOTSUP);
MPASS(params->hdr.type == IF_SND_TAG_TYPE_RATE_LIMIT);
rc = t4_reserve_cl_rl_kbps(sc, pi->port_id,
(params->rate_limit.max_rate * 8ULL / 1000), &schedcl);
@ -789,7 +788,7 @@ cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF);
mbufq_init(&cst->pending_tx, INT_MAX);
mbufq_init(&cst->pending_fwack, INT_MAX);
m_snd_tag_init(&cst->com, ifp);
cxgbe_snd_tag_init(&cst->com, ifp, IF_SND_TAG_TYPE_RATE_LIMIT);
cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF;
cst->adapter = sc;
cst->port_id = pi->port_id;
@ -806,7 +805,7 @@ cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
* Queues will be selected later when the connection flowid is available.
*/
*pt = &cst->com;
*pt = &cst->com.com;
return (0);
}
@ -814,11 +813,11 @@ cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
* Change in parameters, no change in ifp.
*/
int
cxgbe_snd_tag_modify(struct m_snd_tag *mst,
cxgbe_rate_tag_modify(struct m_snd_tag *mst,
union if_snd_tag_modify_params *params)
{
int rc, schedcl;
struct cxgbe_snd_tag *cst = mst_to_cst(mst);
struct cxgbe_rate_tag *cst = mst_to_crt(mst);
struct adapter *sc = cst->adapter;
/* XXX: is schedcl -1 ok here? */
@ -840,10 +839,10 @@ cxgbe_snd_tag_modify(struct m_snd_tag *mst,
}
int
cxgbe_snd_tag_query(struct m_snd_tag *mst,
cxgbe_rate_tag_query(struct m_snd_tag *mst,
union if_snd_tag_query_params *params)
{
struct cxgbe_snd_tag *cst = mst_to_cst(mst);
struct cxgbe_rate_tag *cst = mst_to_crt(mst);
params->rate_limit.max_rate = cst->max_rate;
@ -858,7 +857,7 @@ cxgbe_snd_tag_query(struct m_snd_tag *mst,
* Unlocks cst and frees it.
*/
void
cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *cst)
cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *cst)
{
struct adapter *sc = cst->adapter;
@ -879,9 +878,9 @@ cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *cst)
}
void
cxgbe_snd_tag_free(struct m_snd_tag *mst)
cxgbe_rate_tag_free(struct m_snd_tag *mst)
{
struct cxgbe_snd_tag *cst = mst_to_cst(mst);
struct cxgbe_rate_tag *cst = mst_to_crt(mst);
mtx_lock(&cst->lock);
@ -896,7 +895,7 @@ cxgbe_snd_tag_free(struct m_snd_tag *mst)
* credits for the etid otherwise.
*/
if (cst->tx_credits == cst->tx_total) {
cxgbe_snd_tag_free_locked(cst);
cxgbe_rate_tag_free_locked(cst);
return; /* cst is gone. */
}
send_etid_flush_wr(cst);

View file

@ -2307,10 +2307,10 @@ set_mbuf_eo_tsclk_tsoff(struct mbuf *m, uint8_t tsclk_tsoff)
}
static inline int
needs_eo(struct mbuf *m)
needs_eo(struct cxgbe_snd_tag *cst)
{
return (m->m_pkthdr.csum_flags & CSUM_SND_TAG);
return (cst != NULL && cst->type == IF_SND_TAG_TYPE_RATE_LIMIT);
}
#endif
@ -2541,6 +2541,9 @@ parse_pkt(struct adapter *sc, struct mbuf **mp)
void *l3hdr;
#if defined(INET) || defined(INET6)
struct tcphdr *tcp;
#endif
#ifdef RATELIMIT
struct cxgbe_snd_tag *cst;
#endif
uint16_t eh_type;
uint8_t cflags;
@ -2562,6 +2565,12 @@ parse_pkt(struct adapter *sc, struct mbuf **mp)
M_ASSERTPKTHDR(m0);
MPASS(m0->m_pkthdr.len > 0);
nsegs = count_mbuf_nsegs(m0, 0, &cflags);
#ifdef RATELIMIT
if (m0->m_pkthdr.csum_flags & CSUM_SND_TAG)
cst = mst_to_cst(m0->m_pkthdr.snd_tag);
else
cst = NULL;
#endif
if (nsegs > (needs_tso(m0) ? TX_SGL_SEGS_TSO : TX_SGL_SEGS)) {
if (defragged++ > 0 || (m = m_defrag(m0, M_NOWAIT)) == NULL) {
rc = EFBIG;
@ -2595,16 +2604,17 @@ parse_pkt(struct adapter *sc, struct mbuf **mp)
* checksumming is enabled. needs_l4_csum happens to check for all the
* right things.
*/
if (__predict_false(needs_eo(m0) && !needs_l4_csum(m0))) {
if (__predict_false(needs_eo(cst) && !needs_l4_csum(m0))) {
m_snd_tag_rele(m0->m_pkthdr.snd_tag);
m0->m_pkthdr.snd_tag = NULL;
m0->m_pkthdr.csum_flags &= ~CSUM_SND_TAG;
cst = NULL;
}
#endif
if (!needs_tso(m0) &&
#ifdef RATELIMIT
!needs_eo(m0) &&
!needs_eo(cst) &&
#endif
!(sc->flags & IS_VF && (needs_l3_csum(m0) || needs_l4_csum(m0))))
return (0);
@ -2666,7 +2676,7 @@ parse_pkt(struct adapter *sc, struct mbuf **mp)
#endif
}
#ifdef RATELIMIT
if (needs_eo(m0)) {
if (needs_eo(cst)) {
u_int immhdrs;
/* EO WRs have the headers in the WR and not the GL. */
@ -5723,7 +5733,7 @@ txpkt_eo_len16(u_int nsegs, u_int immhdrs, u_int tso)
#define ETID_FLOWC_LEN16 (howmany(ETID_FLOWC_LEN, 16))
static int
send_etid_flowc_wr(struct cxgbe_snd_tag *cst, struct port_info *pi,
send_etid_flowc_wr(struct cxgbe_rate_tag *cst, struct port_info *pi,
struct vi_info *vi)
{
struct wrq_cookie cookie;
@ -5769,7 +5779,7 @@ send_etid_flowc_wr(struct cxgbe_snd_tag *cst, struct port_info *pi,
#define ETID_FLUSH_LEN16 (howmany(sizeof (struct fw_flowc_wr), 16))
void
send_etid_flush_wr(struct cxgbe_snd_tag *cst)
send_etid_flush_wr(struct cxgbe_rate_tag *cst)
{
struct fw_flowc_wr *flowc;
struct wrq_cookie cookie;
@ -5795,7 +5805,7 @@ send_etid_flush_wr(struct cxgbe_snd_tag *cst)
}
static void
write_ethofld_wr(struct cxgbe_snd_tag *cst, struct fw_eth_tx_eo_wr *wr,
write_ethofld_wr(struct cxgbe_rate_tag *cst, struct fw_eth_tx_eo_wr *wr,
struct mbuf *m0, int compl)
{
struct cpl_tx_pkt_core *cpl;
@ -5944,7 +5954,7 @@ write_ethofld_wr(struct cxgbe_snd_tag *cst, struct fw_eth_tx_eo_wr *wr,
}
static void
ethofld_tx(struct cxgbe_snd_tag *cst)
ethofld_tx(struct cxgbe_rate_tag *cst)
{
struct mbuf *m;
struct wrq_cookie cookie;
@ -5977,7 +5987,7 @@ ethofld_tx(struct cxgbe_snd_tag *cst)
cst->tx_credits -= next_credits;
cst->tx_nocompl += next_credits;
compl = cst->ncompl == 0 || cst->tx_nocompl >= cst->tx_total / 2;
ETHER_BPF_MTAP(cst->com.ifp, m);
ETHER_BPF_MTAP(cst->com.com.ifp, m);
write_ethofld_wr(cst, wr, m, compl);
commit_wrq_wr(cst->eo_txq, wr, &cookie);
if (compl) {
@ -5989,7 +5999,7 @@ ethofld_tx(struct cxgbe_snd_tag *cst)
/*
* Drop the mbuf's reference on the tag now rather
* than waiting until m_freem(). This ensures that
* cxgbe_snd_tag_free gets called when the inp drops
* cxgbe_rate_tag_free gets called when the inp drops
* its reference on the tag and there are no more
* mbufs in the pending_tx queue and can flush any
* pending requests. Otherwise if the last mbuf
@ -5998,7 +6008,7 @@ ethofld_tx(struct cxgbe_snd_tag *cst)
*/
m->m_pkthdr.snd_tag = NULL;
m->m_pkthdr.csum_flags &= ~CSUM_SND_TAG;
m_snd_tag_rele(&cst->com);
m_snd_tag_rele(&cst->com.com);
mbufq_enqueue(&cst->pending_fwack, m);
}
@ -6007,13 +6017,13 @@ ethofld_tx(struct cxgbe_snd_tag *cst)
int
ethofld_transmit(struct ifnet *ifp, struct mbuf *m0)
{
struct cxgbe_snd_tag *cst;
struct cxgbe_rate_tag *cst;
int rc;
MPASS(m0->m_nextpkt == NULL);
MPASS(m0->m_pkthdr.csum_flags & CSUM_SND_TAG);
MPASS(m0->m_pkthdr.snd_tag != NULL);
cst = mst_to_cst(m0->m_pkthdr.snd_tag);
cst = mst_to_crt(m0->m_pkthdr.snd_tag);
mtx_lock(&cst->lock);
MPASS(cst->flags & EO_SND_TAG_REF);
@ -6052,10 +6062,10 @@ ethofld_transmit(struct ifnet *ifp, struct mbuf *m0)
* ethofld_tx() in case we are sending the final mbuf after
* the inp was freed.
*/
m_snd_tag_ref(&cst->com);
m_snd_tag_ref(&cst->com.com);
ethofld_tx(cst);
mtx_unlock(&cst->lock);
m_snd_tag_rele(&cst->com);
m_snd_tag_rele(&cst->com.com);
return (0);
done:
@ -6072,7 +6082,7 @@ ethofld_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m0
const struct cpl_fw4_ack *cpl = (const void *)(rss + 1);
struct mbuf *m;
u_int etid = G_CPL_FW4_ACK_FLOWID(be32toh(OPCODE_TID(cpl)));
struct cxgbe_snd_tag *cst;
struct cxgbe_rate_tag *cst;
uint8_t credits = cpl->credits;
cst = lookup_etid(sc, etid);
@ -6104,7 +6114,7 @@ ethofld_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m0
cst->flags &= ~EO_FLUSH_RPL_PENDING;
cst->tx_credits += cpl->credits;
cxgbe_snd_tag_free_locked(cst);
cxgbe_rate_tag_free_locked(cst);
return (0); /* cst is gone. */
}
KASSERT(m != NULL,
@ -6126,12 +6136,12 @@ ethofld_fw4_ack(struct sge_iq *iq, const struct rss_header *rss, struct mbuf *m0
* As with ethofld_transmit(), hold an extra reference
* so that the tag is stable across ethold_tx().
*/
m_snd_tag_ref(&cst->com);
m_snd_tag_ref(&cst->com.com);
m = mbufq_first(&cst->pending_tx);
if (m != NULL && cst->tx_credits >= mbuf_eo_len16(m))
ethofld_tx(cst);
mtx_unlock(&cst->lock);
m_snd_tag_rele(&cst->com);
m_snd_tag_rele(&cst->com.com);
} else {
/*
* There shouldn't be any pending packets if the tag