diff options
Diffstat (limited to 'freebsd/sys/netinet/if_ether.c')
-rw-r--r-- | freebsd/sys/netinet/if_ether.c | 82 |
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(); } /* |