Changeset View
Changeset View
Standalone View
Standalone View
netinet/in_pcb.c
Context not available. | |||||
&VNET_NAME(ipport_randomtime), 0, | &VNET_NAME(ipport_randomtime), 0, | ||||
"Minimum time to keep sequental port " | "Minimum time to keep sequental port " | ||||
"allocation before switching to a random one"); | "allocation before switching to a random one"); | ||||
#ifdef RATELIMIT | |||||
counter_u64_t rate_limit_active; | |||||
counter_u64_t rate_limit_alloc_fail; | |||||
counter_u64_t rate_limit_set_ok; | |||||
static SYSCTL_NODE(_net_inet_ip, OID_AUTO, rl, CTLFLAG_RD, 0, | |||||
"IP Rate Limiting"); | |||||
SYSCTL_COUNTER_U64(_net_inet_ip_rl, OID_AUTO, active, CTLFLAG_RD, | |||||
&rate_limit_active, "Active rate limited connections"); | |||||
SYSCTL_COUNTER_U64(_net_inet_ip_rl, OID_AUTO, alloc_fail, CTLFLAG_RD, | |||||
&rate_limit_alloc_fail, "Rate limited connection failures"); | |||||
SYSCTL_COUNTER_U64(_net_inet_ip_rl, OID_AUTO, set_ok, CTLFLAG_RD, | |||||
&rate_limit_set_ok, "Rate limited setting succeeded"); | |||||
#endif /* RATELIMIT */ | |||||
#endif /* INET */ | #endif /* INET */ | ||||
/* | /* | ||||
Context not available. | |||||
{ | { | ||||
union if_snd_tag_modify_params params = { | union if_snd_tag_modify_params params = { | ||||
.rate_limit.max_rate = max_pacing_rate, | .rate_limit.max_rate = max_pacing_rate, | ||||
.rate_limit.flags = M_NOWAIT, | |||||
}; | }; | ||||
struct m_snd_tag *mst; | struct m_snd_tag *mst; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
Context not available. | |||||
*/ | */ | ||||
int | int | ||||
in_pcbattach_txrtlmt(struct inpcb *inp, struct ifnet *ifp, | in_pcbattach_txrtlmt(struct inpcb *inp, struct ifnet *ifp, | ||||
uint32_t flowtype, uint32_t flowid, uint32_t max_pacing_rate) | uint32_t flowtype, uint32_t flowid, uint32_t max_pacing_rate, struct m_snd_tag **st) | ||||
{ | { | ||||
union if_snd_tag_alloc_params params = { | union if_snd_tag_alloc_params params = { | ||||
.rate_limit.hdr.type = (max_pacing_rate == -1U) ? | .rate_limit.hdr.type = (max_pacing_rate == -1U) ? | ||||
Context not available. | |||||
.rate_limit.hdr.flowid = flowid, | .rate_limit.hdr.flowid = flowid, | ||||
.rate_limit.hdr.flowtype = flowtype, | .rate_limit.hdr.flowtype = flowtype, | ||||
.rate_limit.max_rate = max_pacing_rate, | .rate_limit.max_rate = max_pacing_rate, | ||||
.rate_limit.flags = M_NOWAIT, | |||||
}; | }; | ||||
int error; | int error; | ||||
INP_WLOCK_ASSERT(inp); | INP_WLOCK_ASSERT(inp); | ||||
if (inp->inp_snd_tag != NULL) | if (*st != NULL) | ||||
return (EINVAL); | return (EINVAL); | ||||
if (ifp->if_snd_tag_alloc == NULL) { | if (ifp->if_snd_tag_alloc == NULL) { | ||||
Context not available. | |||||
error = EOPNOTSUPP; | error = EOPNOTSUPP; | ||||
} else { | } else { | ||||
error = ifp->if_snd_tag_alloc(ifp, ¶ms, &inp->inp_snd_tag); | error = ifp->if_snd_tag_alloc(ifp, ¶ms, &inp->inp_snd_tag); | ||||
if (error == 0) { | |||||
counter_u64_add(rate_limit_set_ok, 1); | |||||
counter_u64_add(rate_limit_active, 1); | |||||
} else | |||||
counter_u64_add(rate_limit_alloc_fail, 1); | |||||
} | } | ||||
return (error); | return (error); | ||||
} | } | ||||
void | |||||
in_pcbdetach_tag(struct ifnet *ifp, struct m_snd_tag *mst) | |||||
{ | |||||
if (ifp == NULL) | |||||
return; | |||||
/* | |||||
* If the device was detached while we still had reference(s) | |||||
* on the ifp, we assume if_snd_tag_free() was replaced with | |||||
* stubs. | |||||
*/ | |||||
ifp->if_snd_tag_free(mst); | |||||
/* release reference count on network interface */ | |||||
if_rele(ifp); | |||||
counter_u64_add(rate_limit_active, -1); | |||||
} | |||||
/* | /* | ||||
* Free an existing TX rate limit tag based on the "inp->inp_snd_tag", | * Free an existing TX rate limit tag based on the "inp->inp_snd_tag", | ||||
* if any: | * if any: | ||||
Context not available. | |||||
m_snd_tag_rele(mst); | m_snd_tag_rele(mst); | ||||
} | } | ||||
int | |||||
in_pcboutput_txrtlmt_locked(struct inpcb *inp, struct ifnet *ifp, struct mbuf *mb, uint32_t max_pacing_rate) | |||||
{ | |||||
int error; | |||||
/* | |||||
* If the existing send tag is for the wrong interface due to | |||||
* a route change, first drop the existing tag. Set the | |||||
* CHANGED flag so that we will keep trying to allocate a new | |||||
* tag if we fail to allocate one this time. | |||||
*/ | |||||
if (inp->inp_snd_tag != NULL && inp->inp_snd_tag->ifp != ifp) { | |||||
in_pcbdetach_txrtlmt(inp); | |||||
inp->inp_flags2 |= INP_RATE_LIMIT_CHANGED; | |||||
} | |||||
/* | |||||
* NOTE: When attaching to a network interface a reference is | |||||
* made to ensure the network interface doesn't go away until | |||||
* all ratelimit connections are gone. The network interface | |||||
* pointers compared below represent valid network interfaces, | |||||
* except when comparing towards NULL. | |||||
*/ | |||||
if (max_pacing_rate == 0 && inp->inp_snd_tag == NULL) { | |||||
error = 0; | |||||
} else if (!(ifp->if_capenable & IFCAP_TXRTLMT)) { | |||||
if (inp->inp_snd_tag != NULL) | |||||
in_pcbdetach_txrtlmt(inp); | |||||
error = 0; | |||||
} else if (inp->inp_snd_tag == NULL) { | |||||
/* | |||||
* In order to utilize packet pacing with RSS, we need | |||||
* to wait until there is a valid RSS hash before we | |||||
* can proceed: | |||||
*/ | |||||
if (M_HASHTYPE_GET(mb) == M_HASHTYPE_NONE) { | |||||
error = EAGAIN; | |||||
} else { | |||||
error = in_pcbattach_txrtlmt(inp, ifp, M_HASHTYPE_GET(mb), | |||||
mb->m_pkthdr.flowid, max_pacing_rate, &inp->inp_snd_tag); | |||||
} | |||||
} else { | |||||
error = in_pcbmodify_txrtlmt(inp, max_pacing_rate); | |||||
} | |||||
if (error == 0 || error == EOPNOTSUPP) | |||||
inp->inp_flags2 &= ~INP_RATE_LIMIT_CHANGED; | |||||
return (error); | |||||
} | |||||
/* | /* | ||||
* This function should be called when the INP_RATE_LIMIT_CHANGED flag | * This function should be called when the INP_RATE_LIMIT_CHANGED flag | ||||
* is set in the fast path and will attach/detach/modify the TX rate | * is set in the fast path and will attach/detach/modify the TX rate | ||||
Context not available. | |||||
*/ | */ | ||||
max_pacing_rate = socket->so_max_pacing_rate; | max_pacing_rate = socket->so_max_pacing_rate; | ||||
/* | error = in_pcboutput_txrtlmt_locked(inp, ifp, mb, max_pacing_rate); | ||||
* If the existing send tag is for the wrong interface due to | |||||
* a route change, first drop the existing tag. Set the | |||||
* CHANGED flag so that we will keep trying to allocate a new | |||||
* tag if we fail to allocate one this time. | |||||
*/ | |||||
if (inp->inp_snd_tag != NULL && inp->inp_snd_tag->ifp != ifp) { | |||||
in_pcbdetach_txrtlmt(inp); | |||||
inp->inp_flags2 |= INP_RATE_LIMIT_CHANGED; | |||||
} | |||||
/* | |||||
* NOTE: When attaching to a network interface a reference is | |||||
* made to ensure the network interface doesn't go away until | |||||
* all ratelimit connections are gone. The network interface | |||||
* pointers compared below represent valid network interfaces, | |||||
* except when comparing towards NULL. | |||||
*/ | |||||
if (max_pacing_rate == 0 && inp->inp_snd_tag == NULL) { | |||||
error = 0; | |||||
} else if (!(ifp->if_capenable & IFCAP_TXRTLMT)) { | |||||
if (inp->inp_snd_tag != NULL) | |||||
in_pcbdetach_txrtlmt(inp); | |||||
error = 0; | |||||
} else if (inp->inp_snd_tag == NULL) { | |||||
/* | |||||
* In order to utilize packet pacing with RSS, we need | |||||
* to wait until there is a valid RSS hash before we | |||||
* can proceed: | |||||
*/ | |||||
if (M_HASHTYPE_GET(mb) == M_HASHTYPE_NONE) { | |||||
error = EAGAIN; | |||||
} else { | |||||
error = in_pcbattach_txrtlmt(inp, ifp, M_HASHTYPE_GET(mb), | |||||
mb->m_pkthdr.flowid, max_pacing_rate); | |||||
} | |||||
} else { | |||||
error = in_pcbmodify_txrtlmt(inp, max_pacing_rate); | |||||
} | |||||
if (error == 0 || error == EOPNOTSUPP) | |||||
inp->inp_flags2 &= ~INP_RATE_LIMIT_CHANGED; | |||||
if (did_upgrade) | if (did_upgrade) | ||||
INP_DOWNGRADE(inp); | INP_DOWNGRADE(inp); | ||||
} | } | ||||
Context not available. | |||||
if (did_upgrade) | if (did_upgrade) | ||||
INP_DOWNGRADE(inp); | INP_DOWNGRADE(inp); | ||||
} | } | ||||
static void | |||||
rl_init(void *st) | |||||
{ | |||||
rate_limit_active = counter_u64_alloc(M_WAITOK); | |||||
rate_limit_alloc_fail = counter_u64_alloc(M_WAITOK); | |||||
rate_limit_set_ok = counter_u64_alloc(M_WAITOK); | |||||
} | |||||
SYSINIT(rl, SI_SUB_PROTO_DOMAININIT, SI_ORDER_ANY, rl_init, NULL); | |||||
#endif /* RATELIMIT */ | #endif /* RATELIMIT */ | ||||
Context not available. |