Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F168128806
D20206.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
9 KB
Referenced Files
None
Subscribers
None
D20206.diff
View Options
Index: head/sys/netinet/netdump/netdump_client.c
===================================================================
--- head/sys/netinet/netdump/netdump_client.c
+++ head/sys/netinet/netdump/netdump_client.c
@@ -93,6 +93,8 @@
struct thread *);
static int netdump_dumper(void *priv __unused, void *virtual,
vm_offset_t physical __unused, off_t offset, size_t length);
+static bool netdump_enabled(void);
+static int netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS);
static int netdump_ether_output(struct mbuf *m, struct ifnet *ifp,
struct ether_addr dst, u_short etype);
static void netdump_handle_arp(struct mbuf **mb);
@@ -102,11 +104,13 @@
static int netdump_modevent(module_t mod, int type, void *priv);
static void netdump_network_poll(void);
static void netdump_pkt_in(struct ifnet *ifp, struct mbuf *m);
+static void netdump_reinit_internal(struct ifnet *ifp);
static int netdump_send(uint32_t type, off_t offset, unsigned char *data,
uint32_t datalen);
static int netdump_send_arp(in_addr_t dst);
static int netdump_start(struct dumperinfo *di);
static int netdump_udp_output(struct mbuf *m);
+static void netdump_unconfigure(void);
/* Must be at least as big as the chunks dumpsys() gives us. */
static unsigned char nd_buf[MAXDUMPPGS * PAGE_SIZE];
@@ -131,8 +135,17 @@
#define nd_gateway nd_conf.ndc_gateway.in4
/* General dynamic settings. */
+static struct sx nd_conf_lk;
+SX_SYSINIT(nd_conf, &nd_conf_lk, "netdump configuration lock");
+#define NETDUMP_WLOCK() sx_xlock(&nd_conf_lk)
+#define NETDUMP_WUNLOCK() sx_xunlock(&nd_conf_lk)
+#define NETDUMP_RLOCK() sx_slock(&nd_conf_lk)
+#define NETDUMP_RUNLOCK() sx_sunlock(&nd_conf_lk)
+#define NETDUMP_ASSERT_WLOCKED() sx_assert(&nd_conf_lk, SA_XLOCKED)
+#define NETDUMP_ASSERT_LOCKED() sx_assert(&nd_conf_lk, SA_LOCKED)
static struct ether_addr nd_gw_mac;
static struct ifnet *nd_ifp;
+static eventhandler_tag nd_detach_cookie;
static uint16_t nd_server_port = NETDUMP_PORT;
FEATURE(netdump, "Netdump client support");
@@ -144,10 +157,8 @@
SYSCTL_INT(_net_netdump, OID_AUTO, debug, CTLFLAG_RWTUN,
&nd_debug, 0,
"Debug message verbosity");
-static int nd_enabled;
-SYSCTL_INT(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD,
- &nd_enabled, 0,
- "netdump configuration status");
+SYSCTL_PROC(_net_netdump, OID_AUTO, enabled, CTLFLAG_RD | CTLTYPE_INT,
+ &nd_ifp, 0, netdump_enabled_sysctl, "I", "netdump configuration status");
static char nd_path[MAXPATHLEN];
SYSCTL_STRING(_net_netdump, OID_AUTO, path, CTLFLAG_RW,
nd_path, sizeof(nd_path),
@@ -165,6 +176,29 @@
&nd_arp_retries, 0,
"Number of ARP attempts before giving up");
+static bool
+netdump_enabled(void)
+{
+
+ NETDUMP_ASSERT_LOCKED();
+ return (nd_ifp != NULL);
+}
+
+static int
+netdump_enabled_sysctl(SYSCTL_HANDLER_ARGS)
+{
+ int en, error;
+
+ NETDUMP_RLOCK();
+ en = netdump_enabled();
+ NETDUMP_RUNLOCK();
+
+ error = SYSCTL_OUT(req, &en, sizeof(en));
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ return (EPERM);
+}
+
/*
* Checks for netdump support on a network interface
*
@@ -248,7 +282,7 @@
struct udpiphdr *ui;
struct ip *ip;
- MPASS(nd_ifp != NULL);
+ MPASS(netdump_enabled());
M_PREPEND(m, sizeof(struct udpiphdr), M_NOWAIT);
if (m == NULL) {
@@ -306,7 +340,7 @@
struct arphdr *ah;
int pktlen;
- MPASS(nd_ifp != NULL);
+ MPASS(netdump_enabled());
/* Fill-up a broadcast address. */
memset(&bcast, 0xFF, ETHER_ADDR_LEN);
@@ -409,7 +443,7 @@
rcvd_acks = 0;
retries = 0;
- MPASS(nd_ifp != NULL);
+ MPASS(netdump_enabled());
retransmit:
/* Chunks can be too big to fit in packets. */
@@ -875,7 +909,7 @@
netdump_network_poll(void)
{
- MPASS(nd_ifp != NULL);
+ MPASS(netdump_enabled());
nd_ifp->if_netdump_methods->nd_poll(nd_ifp, 1000);
}
@@ -945,7 +979,7 @@
error = 0;
/* Check if the dumping is allowed to continue. */
- if (nd_enabled == 0)
+ if (!netdump_enabled())
return (EINVAL);
if (panicstr == NULL) {
@@ -954,8 +988,6 @@
return (EINVAL);
}
- MPASS(nd_ifp != NULL);
-
if (nd_server.s_addr == INADDR_ANY) {
printf("netdump_start: can't netdump; no server IP given\n");
return (EINVAL);
@@ -1065,36 +1097,68 @@
static struct cdev *netdump_cdev;
+static void
+netdump_unconfigure(void)
+{
+ struct diocskerneldump_arg kda;
+
+ NETDUMP_ASSERT_WLOCKED();
+ KASSERT(netdump_enabled(), ("%s: nd_ifp NULL", __func__));
+
+ bzero(&kda, sizeof(kda));
+ kda.kda_index = KDA_REMOVE_DEV;
+ (void)dumper_remove(nd_conf.ndc_iface, &kda);
+
+ netdump_mbuf_drain();
+
+ if_rele(nd_ifp);
+ nd_ifp = NULL;
+
+ bzero(&nd_conf, sizeof(nd_conf));
+}
+
+static void
+netdump_ifdetach(void *arg __unused, struct ifnet *ifp)
+{
+
+ NETDUMP_WLOCK();
+ if (ifp == nd_ifp)
+ netdump_unconfigure();
+ NETDUMP_WUNLOCK();
+}
+
static int
netdump_configure(struct diocskerneldump_arg *conf, struct thread *td)
{
- struct epoch_tracker et;
struct ifnet *ifp;
+ NETDUMP_ASSERT_WLOCKED();
+
CURVNET_SET(TD_TO_VNET(td));
if (!IS_DEFAULT_VNET(curvnet)) {
CURVNET_RESTORE();
return (EINVAL);
}
- NET_EPOCH_ENTER(et);
- CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
- if (strcmp(ifp->if_xname, conf->kda_iface) == 0)
- break;
- }
- /* XXX ref */
- NET_EPOCH_EXIT(et);
+ ifp = ifunit_ref(conf->kda_iface);
CURVNET_RESTORE();
if (ifp == NULL)
return (ENOENT);
- if ((if_getflags(ifp) & IFF_UP) == 0)
+ if ((if_getflags(ifp) & IFF_UP) == 0) {
+ if_rele(ifp);
return (ENXIO);
- if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER)
+ }
+ if (!netdump_supported_nic(ifp) || ifp->if_type != IFT_ETHER) {
+ if_rele(ifp);
return (ENODEV);
+ }
+ if (netdump_enabled())
+ if_rele(nd_ifp);
nd_ifp = ifp;
- netdump_reinit(ifp);
+ netdump_reinit_internal(ifp);
+
#define COPY_SIZED(elm) do { \
_Static_assert(sizeof(nd_conf.ndc_ ## elm) == \
sizeof(conf->kda_ ## elm), "elm " __XSTRING(elm) " mismatch"); \
@@ -1107,23 +1171,35 @@
COPY_SIZED(gateway);
COPY_SIZED(af);
#undef COPY_SIZED
- nd_enabled = 1;
+
return (0);
}
/*
* Reinitialize the mbuf pool used by drivers while dumping. This is called
- * from the generic ioctl handler for SIOCSIFMTU after the driver has
- * reconfigured itself.
+ * from the generic ioctl handler for SIOCSIFMTU after any NIC driver has
+ * reconfigured itself. (I.e., it may not be a configured netdump interface.)
*/
void
netdump_reinit(struct ifnet *ifp)
{
- int clsize, nmbuf, ncl, nrxr;
- if (ifp != nd_ifp)
+ NETDUMP_WLOCK();
+ if (ifp != nd_ifp) {
+ NETDUMP_WUNLOCK();
return;
+ }
+ netdump_reinit_internal(ifp);
+ NETDUMP_WUNLOCK();
+}
+static void
+netdump_reinit_internal(struct ifnet *ifp)
+{
+ int clsize, nmbuf, ncl, nrxr;
+
+ NETDUMP_ASSERT_WLOCKED();
+
ifp->if_netdump_methods->nd_init(ifp, &nrxr, &ncl, &clsize);
KASSERT(nrxr > 0, ("invalid receive ring count %d", nrxr));
@@ -1168,6 +1244,8 @@
conf = NULL;
error = 0;
+ NETDUMP_WLOCK();
+
switch (cmd) {
#ifdef COMPAT_FREEBSD11
case DIOCSKERNELDUMP_FREEBSD11:
@@ -1177,10 +1255,8 @@
error = ENXIO;
break;
}
- if (nd_enabled) {
- nd_enabled = 0;
- netdump_mbuf_drain();
- }
+ if (netdump_enabled())
+ netdump_unconfigure();
break;
#endif
#ifdef COMPAT_FREEBSD12
@@ -1197,17 +1273,15 @@
error = ENXIO;
break;
}
- if (nd_enabled) {
- nd_enabled = 0;
- netdump_mbuf_drain();
- }
+ if (netdump_enabled())
+ netdump_unconfigure();
break;
case NETDUMPGCONF_FREEBSD12:
gone_in(14, "FreeBSD 12.x ABI compat");
conf12 = (void *)addr;
- if (!nd_enabled) {
+ if (!netdump_enabled()) {
error = ENXIO;
break;
}
@@ -1232,7 +1306,7 @@
* For now, index is ignored; netdump doesn't support multiple
* configurations (yet).
*/
- if (!nd_enabled) {
+ if (!netdump_enabled()) {
error = ENXIO;
conf = NULL;
break;
@@ -1293,13 +1367,10 @@
if (conf->kda_index == KDA_REMOVE ||
conf->kda_index == KDA_REMOVE_DEV ||
conf->kda_index == KDA_REMOVE_ALL) {
- if (nd_enabled || conf->kda_index == KDA_REMOVE_ALL) {
- error = dumper_remove(conf->kda_iface, conf);
- if (error == 0) {
- nd_enabled = 0;
- netdump_mbuf_drain();
- }
- }
+ if (netdump_enabled())
+ netdump_unconfigure();
+ if (conf->kda_index == KDA_REMOVE_ALL)
+ error = dumper_remove(NULL, conf);
break;
}
@@ -1342,10 +1413,8 @@
conf->kda_encryptedkeysize);
free(encryptedkey, M_TEMP);
}
- if (error != 0) {
- nd_enabled = 0;
- netdump_mbuf_drain();
- }
+ if (error != 0)
+ netdump_unconfigure();
break;
default:
error = ENOTTY;
@@ -1354,6 +1423,7 @@
explicit_bzero(&kda_copy, sizeof(kda_copy));
if (conf != NULL)
explicit_bzero(conf, sizeof(*conf));
+ NETDUMP_WUNLOCK();
return (error);
}
@@ -1385,6 +1455,9 @@
if (error != 0)
return (error);
+ nd_detach_cookie = EVENTHANDLER_REGISTER(ifnet_departure_event,
+ netdump_ifdetach, NULL, EVENTHANDLER_PRI_ANY);
+
if ((arg = kern_getenv("net.dump.iface")) != NULL) {
strlcpy(conf.kda_iface, arg, sizeof(conf.kda_iface));
freeenv(arg);
@@ -1404,23 +1477,21 @@
conf.kda_af = AF_INET;
/* Ignore errors; we print a message to the console. */
+ NETDUMP_WLOCK();
(void)netdump_configure(&conf, curthread);
+ NETDUMP_WUNLOCK();
}
break;
case MOD_UNLOAD:
- if (nd_enabled) {
- struct diocskerneldump_arg kda;
-
+ NETDUMP_WLOCK();
+ if (netdump_enabled()) {
printf("netdump: disabling dump device for unload\n");
-
- bzero(&kda, sizeof(kda));
- kda.kda_index = KDA_REMOVE_DEV;
- (void)dumper_remove(nd_conf.ndc_iface, &kda);
-
- netdump_mbuf_drain();
- nd_enabled = 0;
+ netdump_unconfigure();
}
+ NETDUMP_WUNLOCK();
destroy_dev(netdump_cdev);
+ EVENTHANDLER_DEREGISTER(ifnet_departure_event,
+ nd_detach_cookie);
break;
default:
error = EOPNOTSUPP;
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Aug 27, 12:33 PM (20 m, 35 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37384639
Default Alt Text
D20206.diff (9 KB)
Attached To
Mode
D20206: netdump: Ref the interface we're attached to
Attached
Detach File
Event Timeline
Log In to Comment