svn commit: r353696 - in head/sys: net netinet/netdump
Conrad Meyer
cem at FreeBSD.org
Thu Oct 17 20:25:17 UTC 2019
Author: cem
Date: Thu Oct 17 20:25:15 2019
New Revision: 353696
URL: https://svnweb.freebsd.org/changeset/base/353696
Log:
debugnet(4): Add optional full-duplex mode
It remains unattached to any client protocol. Netdump is unaffected
(remaining half-duplex). The intended consumer is NetGDB.
Submitted by: John Reimer <john.reimer AT emc.com> (earlier version)
Discussed with: markj
Differential Revision: https://reviews.freebsd.org/D21541
Modified:
head/sys/net/debugnet.c
head/sys/net/debugnet.h
head/sys/net/debugnet_int.h
head/sys/netinet/netdump/netdump_client.c
Modified: head/sys/net/debugnet.c
==============================================================================
--- head/sys/net/debugnet.c Thu Oct 17 20:18:07 2019 (r353695)
+++ head/sys/net/debugnet.c Thu Oct 17 20:25:15 2019 (r353696)
@@ -175,7 +175,7 @@ debugnet_udp_output(struct debugnet_pcb *pcb, struct m
udp = mtod(m, void *);
udp->uh_ulen = htons(m->m_pkthdr.len);
/* Use this src port so that the server can connect() the socket */
- udp->uh_sport = htons(pcb->dp_client_ack_port);
+ udp->uh_sport = htons(pcb->dp_client_port);
udp->uh_dport = htons(pcb->dp_server_port);
/* Computed later (protocol-dependent). */
udp->uh_sum = 0;
@@ -183,6 +183,28 @@ debugnet_udp_output(struct debugnet_pcb *pcb, struct m
return (debugnet_ip_output(pcb, m));
}
+static int
+debugnet_ack_output(struct debugnet_pcb *pcb, uint32_t seqno /* net endian */)
+{
+ struct debugnet_ack *dn_ack;
+ struct mbuf *m;
+
+ DNETDEBUG("Acking with seqno %u\n", ntohl(seqno));
+
+ m = m_gethdr(M_NOWAIT, MT_DATA);
+ if (m == NULL) {
+ printf("%s: Out of mbufs\n", __func__);
+ return (ENOBUFS);
+ }
+ m->m_len = sizeof(*dn_ack);
+ m->m_pkthdr.len = sizeof(*dn_ack);
+ MH_ALIGN(m, sizeof(*dn_ack));
+ dn_ack = mtod(m, void *);
+ dn_ack->da_seqno = seqno;
+
+ return (debugnet_udp_output(pcb, m));
+}
+
/*
* Dummy free function for debugnet clusters.
*/
@@ -216,6 +238,9 @@ debugnet_send(struct debugnet_pcb *pcb, uint32_t type,
uint32_t i, pktlen, sent_so_far;
int retries, polls, error;
+ if (pcb->dp_state == DN_STATE_REMOTE_CLOSED)
+ return (ECONNRESET);
+
want_acks = 0;
pcb->dp_rcvd_acks = 0;
retries = 0;
@@ -307,6 +332,8 @@ retransmit:
}
debugnet_network_poll(pcb->dp_ifp);
DELAY(500);
+ if (pcb->dp_state == DN_STATE_REMOTE_CLOSED)
+ return (ECONNRESET);
}
pcb->dp_seqno += i;
return (0);
@@ -316,7 +343,63 @@ retransmit:
* Network input primitives.
*/
+/*
+ * Just introspect the header enough to fire off a seqno ack and validate
+ * length fits.
+ */
static void
+debugnet_handle_rx_msg(struct debugnet_pcb *pcb, struct mbuf **mb)
+{
+ const struct debugnet_msg_hdr *dnh;
+ struct mbuf *m;
+ int error;
+
+ m = *mb;
+
+ if (m->m_pkthdr.len < sizeof(*dnh)) {
+ DNETDEBUG("ignoring small debugnet_msg packet\n");
+ return;
+ }
+
+ /* Get ND header. */
+ if (m->m_len < sizeof(*dnh)) {
+ m = m_pullup(m, sizeof(*dnh));
+ *mb = m;
+ if (m == NULL) {
+ DNETDEBUG("m_pullup failed\n");
+ return;
+ }
+ }
+ dnh = mtod(m, const void *);
+
+ if (ntohl(dnh->mh_len) + sizeof(*dnh) > m->m_pkthdr.len) {
+ DNETDEBUG("Dropping short packet.\n");
+ return;
+ }
+
+ /*
+ * If the issue is transient (ENOBUFS), sender should resend. If
+ * non-transient (like driver objecting to rx -> tx from the same
+ * thread), not much else we can do.
+ */
+ error = debugnet_ack_output(pcb, dnh->mh_seqno);
+ if (error != 0)
+ return;
+
+ if (ntohl(dnh->mh_type) == DEBUGNET_FINISHED) {
+ printf("Remote shut down the connection on us!\n");
+ pcb->dp_state = DN_STATE_REMOTE_CLOSED;
+
+ /*
+ * Continue through to the user handler so they are signalled
+ * not to wait for further rx.
+ */
+ }
+
+ pcb->dp_rx_handler(pcb, mb);
+}
+
+static void
debugnet_handle_ack(struct debugnet_pcb *pcb, struct mbuf **mb, uint16_t sport)
{
const struct debugnet_ack *dn_ack;
@@ -325,10 +408,6 @@ debugnet_handle_ack(struct debugnet_pcb *pcb, struct m
m = *mb;
- if (m->m_pkthdr.len < sizeof(*dn_ack)) {
- DNETDEBUG("ignoring small ACK packet\n");
- return;
- }
/* Get Ack. */
if (m->m_len < sizeof(*dn_ack)) {
m = m_pullup(m, sizeof(*dn_ack));
@@ -363,7 +442,7 @@ debugnet_handle_udp(struct debugnet_pcb *pcb, struct m
{
const struct udphdr *udp;
struct mbuf *m;
- uint16_t sport;
+ uint16_t sport, ulen;
/* UDP processing. */
@@ -384,15 +463,39 @@ debugnet_handle_udp(struct debugnet_pcb *pcb, struct m
}
udp = mtod(m, const void *);
- /* For now, the only UDP packets we expect to receive are acks. */
- if (ntohs(udp->uh_dport) != pcb->dp_client_ack_port) {
- DNETDEBUG("not on the expected ACK port.\n");
+ /* We expect to receive UDP packets on the configured client port. */
+ if (ntohs(udp->uh_dport) != pcb->dp_client_port) {
+ DNETDEBUG("not on the expected port.\n");
return;
}
+
+ /* Check that ulen does not exceed actual size of data. */
+ ulen = ntohs(udp->uh_ulen);
+ if (m->m_pkthdr.len < ulen) {
+ DNETDEBUG("ignoring runt UDP packet\n");
+ return;
+ }
+
sport = ntohs(udp->uh_sport);
m_adj(m, sizeof(*udp));
- debugnet_handle_ack(pcb, mb, sport);
+ ulen -= sizeof(*udp);
+
+ if (ulen == sizeof(struct debugnet_ack)) {
+ debugnet_handle_ack(pcb, mb, sport);
+ return;
+ }
+
+ if (pcb->dp_rx_handler == NULL) {
+ if (ulen < sizeof(struct debugnet_ack))
+ DNETDEBUG("ignoring small ACK packet\n");
+ else
+ DNETDEBUG("ignoring unexpected non-ACK packet on "
+ "half-duplex connection.\n");
+ return;
+ }
+
+ debugnet_handle_rx_msg(pcb, mb);
}
/*
@@ -523,9 +626,10 @@ debugnet_connect(const struct debugnet_conn_params *dc
.dp_server = dcp->dc_server,
.dp_gateway = dcp->dc_gateway,
.dp_server_port = dcp->dc_herald_port, /* Initially */
- .dp_client_ack_port = dcp->dc_client_ack_port,
+ .dp_client_port = dcp->dc_client_port,
.dp_seqno = 1,
.dp_ifp = dcp->dc_ifp,
+ .dp_rx_handler = dcp->dc_rx_handler,
};
/* Switch to the debugnet mbuf zones. */
@@ -593,7 +697,7 @@ debugnet_connect(const struct debugnet_conn_params *dc
serbuf, pcb->dp_server_port,
(pcb->dp_gateway == INADDR_ANY) ? "" : " via ",
(pcb->dp_gateway == INADDR_ANY) ? "" : gwbuf,
- clibuf, pcb->dp_client_ack_port, if_name(ifp));
+ clibuf, pcb->dp_client_port, if_name(ifp));
}
/* Validate iface is online and supported. */
Modified: head/sys/net/debugnet.h
==============================================================================
--- head/sys/net/debugnet.h Thu Oct 17 20:18:07 2019 (r353695)
+++ head/sys/net/debugnet.h Thu Oct 17 20:25:15 2019 (r353696)
@@ -90,6 +90,8 @@ struct debugnet_methods {
#define DEBUGNET_SUPPORTED_NIC(ifp) \
((ifp)->if_debugnet_methods != NULL && (ifp)->if_type == IFT_ETHER)
+struct debugnet_pcb; /* opaque */
+
/*
* Debugnet consumer API.
*/
@@ -100,13 +102,30 @@ struct debugnet_conn_params {
in_addr_t dc_gateway;
uint16_t dc_herald_port;
- uint16_t dc_client_ack_port;
+ uint16_t dc_client_port;
const void *dc_herald_data;
uint32_t dc_herald_datalen;
-};
-struct debugnet_pcb; /* opaque */
+ /*
+ * If NULL, debugnet is a unidirectional channel from panic machine to
+ * remote server (like netdump).
+ *
+ * If handler is non-NULL, packets received on the client port that are
+ * not just tx acks are forwarded to the provided handler.
+ *
+ * The mbuf chain will have all non-debugnet framing headers removed
+ * (ethernet, inet, udp). It will start with a debugnet_msg_hdr, of
+ * which the header is guaranteed to be contiguous. If m_pullup is
+ * used, the supplied in-out mbuf pointer should be updated
+ * appropriately.
+ *
+ * If the handler frees the mbuf chain, it should set the mbuf pointer
+ * to NULL. Otherwise, the debugnet input framework will free the
+ * chain.
+ */
+ void (*dc_rx_handler)(struct debugnet_pcb *, struct mbuf **);
+};
/*
* Open a unidirectional stream to the specified server's herald port.
Modified: head/sys/net/debugnet_int.h
==============================================================================
--- head/sys/net/debugnet_int.h Thu Oct 17 20:18:07 2019 (r353695)
+++ head/sys/net/debugnet_int.h Thu Oct 17 20:25:15 2019 (r353696)
@@ -50,6 +50,7 @@ enum dnet_pcb_st {
DN_STATE_INIT = 1,
DN_STATE_HAVE_GW_MAC,
DN_STATE_GOT_HERALD_PORT,
+ DN_STATE_REMOTE_CLOSED,
};
struct debugnet_pcb {
@@ -67,8 +68,12 @@ struct debugnet_pcb {
/* Saved driver if_input to restore on close. */
void (*dp_drv_input)(struct ifnet *, struct mbuf *);
+ /* RX handler for bidirectional protocols. */
+ void (*dp_rx_handler)(struct debugnet_pcb *,
+ struct mbuf **);
+
enum dnet_pcb_st dp_state;
- uint16_t dp_client_ack_port;
+ uint16_t dp_client_port;
bool dp_event_started;
};
Modified: head/sys/netinet/netdump/netdump_client.c
==============================================================================
--- head/sys/netinet/netdump/netdump_client.c Thu Oct 17 20:18:07 2019 (r353695)
+++ head/sys/netinet/netdump/netdump_client.c Thu Oct 17 20:25:15 2019 (r353696)
@@ -316,7 +316,7 @@ netdump_start(struct dumperinfo *di)
dcp.dc_gateway = nd_gateway.s_addr;
dcp.dc_herald_port = NETDUMP_PORT;
- dcp.dc_client_ack_port = NETDUMP_ACKPORT;
+ dcp.dc_client_port = NETDUMP_ACKPORT;
dcp.dc_herald_data = nd_path;
dcp.dc_herald_datalen = (nd_path[0] == 0) ? 0 : strlen(nd_path) + 1;
More information about the svn-src-head
mailing list