summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/netinet/if_ether.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/netinet/if_ether.c')
-rw-r--r--freebsd/sys/netinet/if_ether.c82
1 files changed, 59 insertions, 23 deletions
diff --git a/freebsd/sys/netinet/if_ether.c b/freebsd/sys/netinet/if_ether.c
index e9efd89e..1206691f 100644
--- a/freebsd/sys/netinet/if_ether.c
+++ b/freebsd/sys/netinet/if_ether.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/local/opt_inet.h>
#include <sys/param.h>
+#include <sys/eventhandler.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/queue.h>
@@ -163,8 +164,15 @@ SYSCTL_PROC(_net_link_ether_inet, OID_AUTO, garp_rexmit_count,
"Number of times to retransmit GARP packets;"
" 0 to disable, maximum of 16");
+VNET_DEFINE_STATIC(int, arp_log_level) = LOG_INFO; /* Min. log(9) level. */
+#define V_arp_log_level VNET(arp_log_level)
+SYSCTL_INT(_net_link_ether_arp, OID_AUTO, log_level, CTLFLAG_VNET | CTLFLAG_RW,
+ &VNET_NAME(arp_log_level), 0,
+ "Minimum log(9) level for recording rate limited arp log messages. "
+ "The higher will be log more (emerg=0, info=6 (default), debug=7).");
#define ARP_LOG(pri, ...) do { \
- if (ppsratecheck(&arp_lastlog, &arp_curpps, arp_maxpps)) \
+ if ((pri) <= V_arp_log_level && \
+ ppsratecheck(&arp_lastlog, &arp_curpps, arp_maxpps)) \
log((pri), "arp: " __VA_ARGS__); \
} while (0)
@@ -343,8 +351,8 @@ arp_fillheader(struct ifnet *ifp, struct arphdr *ah, int bcast, u_char *buf,
* - arp header target ip address
* - arp header source ethernet address
*/
-void
-arprequest(struct ifnet *ifp, const struct in_addr *sip,
+static int
+arprequest_internal(struct ifnet *ifp, const struct in_addr *sip,
const struct in_addr *tip, u_char *enaddr)
{
struct mbuf *m;
@@ -361,9 +369,10 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
* The caller did not supply a source address, try to find
* a compatible one among those assigned to this interface.
*/
+ struct epoch_tracker et;
struct ifaddr *ifa;
- IF_ADDR_RLOCK(ifp);
+ NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
if (ifa->ifa_addr->sa_family != AF_INET)
continue;
@@ -381,17 +390,17 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
IA_MASKSIN(ifa)->sin_addr.s_addr))
break; /* found it. */
}
- IF_ADDR_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
if (sip == NULL) {
printf("%s: cannot find matching address\n", __func__);
- return;
+ return (EADDRNOTAVAIL);
}
}
if (enaddr == NULL)
enaddr = carpaddr ? carpaddr : (u_char *)IF_LLADDR(ifp);
if ((m = m_gethdr(M_NOWAIT, MT_DATA)) == NULL)
- return;
+ return (ENOMEM);
m->m_len = sizeof(*ah) + 2 * sizeof(struct in_addr) +
2 * ifp->if_addrlen;
m->m_pkthdr.len = m->m_len;
@@ -418,7 +427,7 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
if (error != 0 && error != EAFNOSUPPORT) {
ARP_LOG(LOG_ERR, "Failed to calculate ARP header on %s: %d\n",
if_name(ifp), error);
- return;
+ return (error);
}
ro.ro_prepend = linkhdr;
@@ -427,10 +436,23 @@ arprequest(struct ifnet *ifp, const struct in_addr *sip,
m->m_flags |= M_BCAST;
m_clrprotoflags(m); /* Avoid confusing lower layers. */
- (*ifp->if_output)(ifp, m, &sa, &ro);
+ error = (*ifp->if_output)(ifp, m, &sa, &ro);
ARPSTAT_INC(txrequests);
+ if (error) {
+ ARPSTAT_INC(txerrors);
+ ARP_LOG(LOG_DEBUG, "Failed to send ARP packet on %s: %d\n",
+ if_name(ifp), error);
+ }
+ return (error);
}
+void
+arprequest(struct ifnet *ifp, const struct in_addr *sip,
+ const struct in_addr *tip, u_char *enaddr)
+{
+
+ (void) arprequest_internal(ifp, sip, tip, enaddr);
+}
/*
* Resolve an IP address into an ethernet address - heavy version.
@@ -461,9 +483,11 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
*plle = NULL;
if ((flags & LLE_CREATE) == 0) {
- IF_AFDATA_RLOCK(ifp);
+ struct epoch_tracker et;
+
+ NET_EPOCH_ENTER(et);
la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst);
- IF_AFDATA_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
}
if (la == NULL && (ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) == 0) {
la = lltable_alloc_entry(LLTABLE(ifp), 0, dst);
@@ -556,7 +580,7 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
error = is_gw != 0 ? EHOSTUNREACH : EHOSTDOWN;
if (renew) {
- int canceled;
+ int canceled, e;
LLE_ADDREF(la);
la->la_expire = time_uptime;
@@ -566,7 +590,13 @@ arpresolve_full(struct ifnet *ifp, int is_gw, int flags, struct mbuf *m,
LLE_REMREF(la);
la->la_asked++;
LLE_WUNLOCK(la);
- arprequest(ifp, NULL, &SIN(dst)->sin_addr, NULL);
+ e = arprequest_internal(ifp, NULL, &SIN(dst)->sin_addr, NULL);
+ /*
+ * Only overwrite 'error' in case of error; in case of success
+ * the proper return value was already set above.
+ */
+ if (e != 0)
+ return (e);
return (error);
}
@@ -595,6 +625,7 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
const struct sockaddr *dst, u_char *desten, uint32_t *pflags,
struct llentry **plle)
{
+ struct epoch_tracker et;
struct llentry *la = NULL;
if (pflags != NULL)
@@ -616,7 +647,7 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
}
}
- IF_AFDATA_RLOCK(ifp);
+ NET_EPOCH_ENTER(et);
la = lla_lookup(LLTABLE(ifp), plle ? LLE_EXCLUSIVE : LLE_UNLOCKED, dst);
if (la != NULL && (la->r_flags & RLLE_VALID) != 0) {
/* Entry found, let's copy lle info */
@@ -630,12 +661,12 @@ arpresolve(struct ifnet *ifp, int is_gw, struct mbuf *m,
*plle = la;
LLE_WUNLOCK(la);
}
- IF_AFDATA_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
return (0);
}
if (plle && la)
LLE_WUNLOCK(la);
- IF_AFDATA_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
return (arpresolve_full(ifp, is_gw, la == NULL ? LLE_CREATE : 0, m, dst,
desten, pflags, plle));
@@ -780,6 +811,7 @@ in_arpinput(struct mbuf *m)
int lladdr_off;
int error;
char addrbuf[INET_ADDRSTRLEN];
+ struct epoch_tracker et;
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
@@ -872,17 +904,17 @@ in_arpinput(struct mbuf *m)
* No match, use the first inet address on the receive interface
* as a dummy address for the rest of the function.
*/
- IF_ADDR_RLOCK(ifp);
+ NET_EPOCH_ENTER(et);
CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
if (ifa->ifa_addr->sa_family == AF_INET &&
(ifa->ifa_carp == NULL ||
(*carp_iamatch_p)(ifa, &enaddr))) {
ia = ifatoia(ifa);
ifa_ref(ifa);
- IF_ADDR_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
goto match;
}
- IF_ADDR_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
/*
* If bridging, fall back to using any inet address.
@@ -939,9 +971,9 @@ match:
sin.sin_family = AF_INET;
sin.sin_addr = isaddr;
dst = (struct sockaddr *)&sin;
- IF_AFDATA_RLOCK(ifp);
+ NET_EPOCH_ENTER(et);
la = lla_lookup(LLTABLE(ifp), LLE_EXCLUSIVE, dst);
- IF_AFDATA_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
if (la != NULL)
arp_check_update_lle(ah, isaddr, ifp, bridged, la);
else if (itaddr.s_addr == myaddr.s_addr) {
@@ -1019,9 +1051,9 @@ reply:
struct llentry *lle = NULL;
sin.sin_addr = itaddr;
- IF_AFDATA_RLOCK(ifp);
+ NET_EPOCH_ENTER(et);
lle = lla_lookup(LLTABLE(ifp), 0, (struct sockaddr *)&sin);
- IF_AFDATA_RUNLOCK(ifp);
+ NET_EPOCH_EXIT(et);
if ((lle != NULL) && (lle->la_flags & LLE_PUB)) {
(void)memcpy(ar_tha(ah), ar_sha(ah), ah->ar_hln);
@@ -1332,6 +1364,8 @@ garp_rexmit(void *arg)
return;
}
+ CURVNET_SET(ia->ia_ifa.ifa_ifp->if_vnet);
+
/*
* Drop lock while the ARP request is generated.
*/
@@ -1359,6 +1393,8 @@ garp_rexmit(void *arg)
ifa_free(&ia->ia_ifa);
}
}
+
+ CURVNET_RESTORE();
}
/*