[lltable] Unify datapath feedback mechamism.

Use newly-create llentry_request_feedback(),
 llentry_mark_used() and llentry_get_hittime() to
 request datapatch usage check and fetch the results
 in the same fashion both in IPv4 and IPv6.

While here, simplify llentry_provide_feedback() wrapper
 by eliminating 1 condition check.

MFC after:	2 weeks
Differential Revision: https://reviews.freebsd.org/D31390
This commit is contained in:
Alexander V. Chernikov 2021-08-02 22:39:00 +00:00
parent cd2401cdd5
commit f3a3b06121
8 changed files with 72 additions and 82 deletions

View File

@ -315,7 +315,7 @@ ether_output(struct ifnet *ifp, struct mbuf *m,
* the entry was used
* by datapath.
*/
llentry_mark_used(lle);
llentry_provide_feedback(lle);
}
if (lle != NULL) {
phdr = lle->r_linkdata;

View File

@ -329,7 +329,7 @@ infiniband_output(struct ifnet *ifp, struct mbuf *m,
* the entry was used
* by datapath.
*/
llentry_mark_used(lle);
llentry_provide_feedback(lle);
}
if (lle != NULL) {
phdr = lle->r_linkdata;

View File

@ -386,6 +386,52 @@ lltable_calc_llheader(struct ifnet *ifp, int family, char *lladdr,
return (error);
}
/*
* Requests feedback from the datapath.
* First packet using @lle should result in
* setting r_skip_req back to 0 and updating
* lle_hittime to the current time_uptime.
*/
void
llentry_request_feedback(struct llentry *lle)
{
LLE_REQ_LOCK(lle);
lle->r_skip_req = 1;
LLE_REQ_UNLOCK(lle);
}
/*
* Updates the lle state to mark it has been used
* and record the time.
* Used by the llentry_provide_feedback() wrapper.
*/
void
llentry_mark_used(struct llentry *lle)
{
LLE_REQ_LOCK(lle);
lle->r_skip_req = 0;
lle->lle_hittime = time_uptime;
LLE_REQ_UNLOCK(lle);
}
/*
* Fetches the time when lle was used.
* Return 0 if the entry was not used, relevant time_uptime
* otherwise.
*/
time_t
llentry_get_hittime(struct llentry *lle)
{
time_t lle_hittime = 0;
LLE_REQ_LOCK(lle);
if ((lle->r_skip_req == 0) && (lle_hittime < lle->lle_hittime))
lle_hittime = lle->lle_hittime;
LLE_REQ_UNLOCK(lle);
return (lle_hittime);
}
/*
* Update link-layer header for given @lle after
* interface lladdr was changed.

View File

@ -250,17 +250,20 @@ lla_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr)
return (llt->llt_lookup(llt, flags, l3addr));
}
void llentry_request_feedback(struct llentry *lle);
void llentry_mark_used(struct llentry *lle);
time_t llentry_get_hittime(struct llentry *lle);
/*
* Notify the LLE code that the entry was used by datapath.
*/
static __inline void
llentry_mark_used(struct llentry *lle)
llentry_provide_feedback(struct llentry *lle)
{
if (lle->r_skip_req == 0)
if (__predict_true(lle->r_skip_req == 0))
return;
if ((lle->r_flags & RLLE_VALID) != 0)
lle->lle_tbl->llt_mark_used(lle);
llentry_mark_used(lle);
}
int lla_rt_output(struct rt_msghdr *, struct rt_addrinfo *);

View File

@ -207,7 +207,6 @@ arptimer(void *arg)
{
struct llentry *lle = (struct llentry *)arg;
struct ifnet *ifp;
int r_skip_req;
if (lle->la_flags & LLE_STATIC) {
return;
@ -240,27 +239,17 @@ arptimer(void *arg)
/*
* Expiration time is approaching.
* Let's try to refresh entry if it is still
* in use.
*
* Set r_skip_req to get feedback from
* fast path. Change state and re-schedule
* ourselves.
* Request usage feedback from the datapath.
* Change state and re-schedule ourselves.
*/
LLE_REQ_LOCK(lle);
lle->r_skip_req = 1;
LLE_REQ_UNLOCK(lle);
llentry_request_feedback(lle);
lle->ln_state = ARP_LLINFO_VERIFY;
callout_schedule(&lle->lle_timer, hz * V_arpt_rexmit);
LLE_WUNLOCK(lle);
CURVNET_RESTORE();
return;
case ARP_LLINFO_VERIFY:
LLE_REQ_LOCK(lle);
r_skip_req = lle->r_skip_req;
LLE_REQ_UNLOCK(lle);
if (r_skip_req == 0 && lle->la_preempt > 0) {
if (llentry_get_hittime(lle) > 0 && lle->la_preempt > 0) {
/* Entry was used, issue refresh request */
struct epoch_tracker et;
struct in_addr dst;
@ -532,7 +521,7 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
bcopy(lladdr, desten, ll_len);
/* Notify LLE code that the entry was used by datapath */
llentry_mark_used(la);
llentry_provide_feedback(la);
if (pflags != NULL)
*pflags = la->la_flags & (LLE_VALID|LLE_IFADDR);
if (plle) {
@ -656,7 +645,7 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
if (pflags != NULL)
*pflags = LLE_VALID | (la->r_flags & RLLE_IFADDR);
/* Notify the LLE handling code that the entry was used. */
llentry_mark_used(la);
llentry_provide_feedback(la);
if (plle) {
LLE_ADDREF(la);
*plle = la;
@ -1225,7 +1214,7 @@ arp_check_update_lle(struct arphdr *ah, struct in_addr isaddr, struct ifnet *ifp
return;
/* Clear fast path feedback request if set */
la->r_skip_req = 0;
llentry_mark_used(la);
}
arp_mark_lle_reachable(la);

View File

@ -1264,19 +1264,6 @@ in_lltable_destroy_lle_unlocked(epoch_context_t ctx)
free(lle, M_LLTABLE);
}
/*
* Called by the datapath to indicate that
* the entry was used.
*/
static void
in_lltable_mark_used(struct llentry *lle)
{
LLE_REQ_LOCK(lle);
lle->r_skip_req = 0;
LLE_REQ_UNLOCK(lle);
}
/*
* Called by LLE_FREE_LOCKED when number of references
* drops to zero.
@ -1681,7 +1668,7 @@ in_lltattach(struct ifnet *ifp)
llt->llt_fill_sa_entry = in_lltable_fill_sa_entry;
llt->llt_free_entry = in_lltable_free_entry;
llt->llt_match_prefix = in_lltable_match_prefix;
llt->llt_mark_used = in_lltable_mark_used;
llt->llt_mark_used = llentry_mark_used;
lltable_link(llt);
return (llt);

View File

@ -2214,25 +2214,6 @@ in6_lltable_rtcheck(struct ifnet *ifp,
return 0;
}
/*
* Called by the datapath to indicate that the entry was used.
*/
static void
in6_lltable_mark_used(struct llentry *lle)
{
LLE_REQ_LOCK(lle);
lle->r_skip_req = 0;
/*
* Set the hit time so the callback function
* can determine the remaining time before
* transiting to the DELAY state.
*/
lle->lle_hittime = time_uptime;
LLE_REQ_UNLOCK(lle);
}
static inline uint32_t
in6_lltable_hash_dst(const struct in6_addr *dst, uint32_t hsize)
{
@ -2469,7 +2450,7 @@ in6_lltattach(struct ifnet *ifp)
llt->llt_fill_sa_entry = in6_lltable_fill_sa_entry;
llt->llt_free_entry = in6_lltable_free_entry;
llt->llt_match_prefix = in6_lltable_match_prefix;
llt->llt_mark_used = in6_lltable_mark_used;
llt->llt_mark_used = llentry_mark_used;
lltable_link(llt);
return (llt);

View File

@ -617,7 +617,7 @@ nd6_llinfo_get_holdsrc(struct llentry *ln, struct in6_addr *src)
static int
nd6_is_stale(struct llentry *lle, long *pdelay, int *do_switch)
{
int nd_delay, nd_gctimer, r_skip_req;
int nd_delay, nd_gctimer;
time_t lle_hittime;
long delay;
@ -625,17 +625,13 @@ nd6_is_stale(struct llentry *lle, long *pdelay, int *do_switch)
nd_gctimer = V_nd6_gctimer;
nd_delay = V_nd6_delay;
LLE_REQ_LOCK(lle);
r_skip_req = lle->r_skip_req;
lle_hittime = lle->lle_hittime;
LLE_REQ_UNLOCK(lle);
lle_hittime = llentry_get_hittime(lle);
if (r_skip_req > 0) {
if (lle_hittime == 0) {
/*
* Nonzero r_skip_req value was set upon entering
* STALE state. Since value was not changed, no
* packets were passed using this lle. Ask for
* timer reschedule and keep STALE state.
* Datapath feedback has been requested upon entering
* STALE state. No packets has been passed using this lle.
* Ask for the timer reschedule and keep STALE state.
*/
delay = (long)(MIN(nd_gctimer, nd_delay));
delay *= hz;
@ -705,13 +701,7 @@ nd6_llinfo_setstate(struct llentry *lle, int newstate)
break;
case ND6_LLINFO_STALE:
/*
* Notify fast path that we want to know if any packet
* is transmitted by setting r_skip_req.
*/
LLE_REQ_LOCK(lle);
lle->r_skip_req = 1;
LLE_REQ_UNLOCK(lle);
llentry_request_feedback(lle);
nd_delay = V_nd6_delay;
nd_gctimer = V_nd6_gctimer;
@ -2254,13 +2244,7 @@ nd6_resolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
bcopy(ln->r_linkdata, desten, ln->r_hdrlen);
if (pflags != NULL)
*pflags = LLE_VALID | (ln->r_flags & RLLE_IFADDR);
/* Check if we have feedback request from nd6 timer */
if (ln->r_skip_req != 0) {
LLE_REQ_LOCK(ln);
ln->r_skip_req = 0; /* Notify that entry was used */
ln->lle_hittime = time_uptime;
LLE_REQ_UNLOCK(ln);
}
llentry_provide_feedback(ln);
if (plle) {
LLE_ADDREF(ln);
*plle = ln;