summaryrefslogtreecommitdiffstats
path: root/sys/netinet/if_ether.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/if_ether.c')
-rw-r--r--sys/netinet/if_ether.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/sys/netinet/if_ether.c b/sys/netinet/if_ether.c
index 6d38388..ef59cdb 100644
--- a/sys/netinet/if_ether.c
+++ b/sys/netinet/if_ether.c
@@ -89,13 +89,16 @@ VNET_DEFINE(int, useloopback) = 1; /* use loopback interface for
static VNET_DEFINE(int, arp_proxyall) = 0;
static VNET_DEFINE(int, arpt_down) = 20; /* keep incomplete entries for
* 20 seconds */
-static VNET_DEFINE(struct arpstat, arpstat); /* ARP statistics, see if_arp.h */
+VNET_DEFINE(struct arpstat, arpstat); /* ARP statistics, see if_arp.h */
+
+static VNET_DEFINE(int, arp_maxhold) = 1;
#define V_arpt_keep VNET(arpt_keep)
#define V_arpt_down VNET(arpt_down)
#define V_arp_maxtries VNET(arp_maxtries)
#define V_arp_proxyall VNET(arp_proxyall)
#define V_arpstat VNET(arpstat)
+#define V_arp_maxhold VNET(arp_maxhold)
SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, max_age, CTLFLAG_RW,
&VNET_NAME(arpt_keep), 0,
@@ -109,9 +112,15 @@ SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, useloopback, CTLFLAG_RW,
SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, proxyall, CTLFLAG_RW,
&VNET_NAME(arp_proxyall), 0,
"Enable proxy ARP for all suitable requests");
+SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, wait, CTLFLAG_RW,
+ &VNET_NAME(arpt_down), 0,
+ "Incomplete ARP entry lifetime in seconds");
SYSCTL_VNET_STRUCT(_net_link_ether_arp, OID_AUTO, stats, CTLFLAG_RW,
&VNET_NAME(arpstat), arpstat,
"ARP statistics (struct arpstat, net/if_arp.h)");
+SYSCTL_VNET_INT(_net_link_ether_inet, OID_AUTO, maxhold, CTLFLAG_RW,
+ &VNET_NAME(arp_maxhold), 0,
+ "Number of packets to hold per ARP entry");
static void arp_init(void);
void arprequest(struct ifnet *,
@@ -162,6 +171,7 @@ arptimer(void *arg)
{
struct ifnet *ifp;
struct llentry *lle;
+ int pkts_dropped;
KASSERT(arg != NULL, ("%s: arg NULL", __func__));
lle = (struct llentry *)arg;
@@ -176,7 +186,8 @@ arptimer(void *arg)
callout_active(&lle->la_timer)) {
callout_stop(&lle->la_timer);
LLE_REMREF(lle);
- (void) llentry_free(lle);
+ pkts_dropped = llentry_free(lle);
+ ARPSTAT_ADD(dropped, pkts_dropped);
ARPSTAT_INC(timeouts);
} else {
#ifdef DIAGNOSTIC
@@ -275,6 +286,8 @@ arpresolve(struct ifnet *ifp, struct rtentry *rt0, struct mbuf *m,
{
struct llentry *la = 0;
u_int flags = 0;
+ struct mbuf *curr = NULL;
+ struct mbuf *next = NULL;
int error, renew;
*lle = NULL;
@@ -348,15 +361,28 @@ retry:
}
/*
* There is an arptab entry, but no ethernet address
- * response yet. Replace the held mbuf with this
- * latest one.
+ * response yet. Add the mbuf to the list, dropping
+ * the oldest packet if we have exceeded the system
+ * setting.
*/
if (m != NULL) {
+ if (la->la_numheld >= V_arp_maxhold) {
+ if (la->la_hold != NULL) {
+ next = la->la_hold->m_nextpkt;
+ m_freem(la->la_hold);
+ la->la_hold = next;
+ la->la_numheld--;
+ ARPSTAT_INC(dropped);
+ }
+ }
if (la->la_hold != NULL) {
- m_freem(la->la_hold);
- ARPSTAT_INC(dropped);
- }
- la->la_hold = m;
+ curr = la->la_hold;
+ while (curr->m_nextpkt != NULL)
+ curr = curr->m_nextpkt;
+ curr->m_nextpkt = m;
+ } else
+ la->la_hold = m;
+ la->la_numheld++;
if (renew == 0 && (flags & LLE_EXCLUSIVE)) {
flags &= ~LLE_EXCLUSIVE;
LLE_DOWNGRADE(la);
@@ -483,7 +509,6 @@ in_arpinput(struct mbuf *m)
struct rtentry *rt;
struct ifaddr *ifa;
struct in_ifaddr *ia;
- struct mbuf *hold;
struct sockaddr sa;
struct in_addr isaddr, itaddr, myaddr;
u_int8_t *enaddr = NULL;
@@ -698,15 +723,29 @@ match:
}
la->la_asked = 0;
la->la_preempt = V_arp_maxtries;
- hold = la->la_hold;
- if (hold != NULL) {
- la->la_hold = NULL;
+ /*
+ * The packets are all freed within the call to the output
+ * routine.
+ *
+ * NB: The lock MUST be released before the call to the
+ * output routine.
+ */
+ if (la->la_hold != NULL) {
+ struct mbuf *m_hold, *m_hold_next;
+
memcpy(&sa, L3_ADDR(la), sizeof(sa));
- }
- LLE_WUNLOCK(la);
- if (hold != NULL)
- (*ifp->if_output)(ifp, hold, &sa, NULL);
- }
+ LLE_WUNLOCK(la);
+ for (m_hold = la->la_hold, la->la_hold = NULL;
+ m_hold != NULL; m_hold = m_hold_next) {
+ m_hold_next = m_hold->m_nextpkt;
+ m_hold->m_nextpkt = NULL;
+ (*ifp->if_output)(ifp, m_hold, &sa, NULL);
+ }
+ } else
+ LLE_WUNLOCK(la);
+ la->la_hold = NULL;
+ la->la_numheld = 0;
+ } /* end of FIB loop */
reply:
if (op != ARPOP_REQUEST)
goto drop;
OpenPOWER on IntegriCloud