Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F102701403
D43460.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
D43460.diff
View Options
diff --git a/share/man/man4/wg.4 b/share/man/man4/wg.4
--- a/share/man/man4/wg.4
+++ b/share/man/man4/wg.4
@@ -121,6 +121,19 @@
Although a valid Curve25519 key must have 5 bits set to
specific values, this is done by the interface and so it
will accept any random 32-byte base64 string.
+.Sh NETMAP
+.Xr netmap 4
+applications may open a WireGuard interface in emulated mode.
+The netmap application will receive decrypted, unencapsulated packets prepended
+by a dummy Ethernet header.
+The Ethertype field will be one of
+.Dv ETHERTYPE_IP
+or
+.Dv ETHERTYPE_IPV6
+depending on the address family of the packet.
+Packets transmitted by the application should similarly begin with a dummy
+Ethernet header; this header will be stripped before the packet is encrypted
+and tunneled.
.Sh EXAMPLES
Create a
.Nm
@@ -183,6 +196,7 @@
.Xr ip 4 ,
.Xr ipsec 4 ,
.Xr netintro 4 ,
+.Xr netmap 4 ,
.Xr ovpn 4 ,
.Xr ipf 5 ,
.Xr pf.conf 5 ,
diff --git a/sys/dev/wg/if_wg.c b/sys/dev/wg/if_wg.c
--- a/sys/dev/wg/if_wg.c
+++ b/sys/dev/wg/if_wg.c
@@ -1674,6 +1674,31 @@
}
}
+#ifdef DEV_NETMAP
+/*
+ * Hand a packet to the netmap RX ring, via netmap's
+ * freebsd_generic_rx_handler().
+ */
+static void
+wg_deliver_netmap(if_t ifp, struct mbuf *m, int af)
+{
+ struct ether_header *eh;
+
+ M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
+ if (__predict_false(m == NULL)) {
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
+ return;
+ }
+
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = af == AF_INET ?
+ htons(ETHERTYPE_IP) : htons(ETHERTYPE_IPV6);
+ memcpy(eh->ether_shost, "\x02\x02\x02\x02\x02\x02", ETHER_ADDR_LEN);
+ memcpy(eh->ether_dhost, "\xff\xff\xff\xff\xff\xff", ETHER_ADDR_LEN);
+ if_input(ifp, m);
+}
+#endif
+
static void
wg_deliver_in(struct wg_peer *peer)
{
@@ -1682,6 +1707,7 @@
struct wg_packet *pkt;
struct mbuf *m;
struct epoch_tracker et;
+ int af;
while ((pkt = wg_queue_dequeue_serial(&peer->p_decrypt_serial)) != NULL) {
if (atomic_load_acq_int(&pkt->p_state) != WG_PACKET_CRYPTED)
@@ -1707,19 +1733,25 @@
if (m->m_pkthdr.len == 0)
goto done;
- MPASS(pkt->p_af == AF_INET || pkt->p_af == AF_INET6);
+ af = pkt->p_af;
+ MPASS(af == AF_INET || af == AF_INET6);
pkt->p_mbuf = NULL;
m->m_pkthdr.rcvif = ifp;
NET_EPOCH_ENTER(et);
- BPF_MTAP2_AF(ifp, m, pkt->p_af);
+ BPF_MTAP2_AF(ifp, m, af);
CURVNET_SET(if_getvnet(ifp));
M_SETFIB(m, if_getfib(ifp));
- if (pkt->p_af == AF_INET)
+#ifdef DEV_NETMAP
+ if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0)
+ wg_deliver_netmap(ifp, m, af);
+ else
+#endif
+ if (af == AF_INET)
netisr_dispatch(NETISR_IP, m);
- if (pkt->p_af == AF_INET6)
+ else if (af == AF_INET6)
netisr_dispatch(NETISR_IPV6, m);
CURVNET_RESTORE();
NET_EPOCH_EXIT(et);
@@ -2164,13 +2196,36 @@
return (0);
}
+#ifdef DEV_NETMAP
+static int
+determine_ethertype_and_pullup(struct mbuf **m, int *etp)
+{
+ struct ether_header *eh;
+
+ *m = m_pullup(*m, sizeof(struct ether_header));
+ if (__predict_false(*m == NULL))
+ return (ENOBUFS);
+ eh = mtod(*m, struct ether_header *);
+ *etp = ntohs(eh->ether_type);
+ if (*etp != ETHERTYPE_IP && *etp != ETHERTYPE_IPV6)
+ return (EAFNOSUPPORT);
+ return (0);
+}
+
+/*
+ * This should only be invoked by netmap, via nm_os_generic_xmit_frame(), to
+ * transmit packets from the netmap TX ring.
+ */
static int
wg_transmit(if_t ifp, struct mbuf *m)
{
sa_family_t af;
- int ret;
+ int et, ret;
struct mbuf *defragged;
+ KASSERT((if_getcapenable(ifp) & IFCAP_NETMAP) != 0,
+ ("%s: ifp %p is not in netmap mode", __func__, ifp));
+
defragged = m_defrag(m, M_NOWAIT);
if (defragged)
m = defragged;
@@ -2180,14 +2235,94 @@
return (ENOBUFS);
}
+ ret = determine_ethertype_and_pullup(&m, &et);
+ if (ret) {
+ xmit_err(ifp, m, NULL, AF_UNSPEC);
+ return (ret);
+ }
+ m_adj(m, sizeof(struct ether_header));
+
ret = determine_af_and_pullup(&m, &af);
if (ret) {
xmit_err(ifp, m, NULL, AF_UNSPEC);
return (ret);
}
- return (wg_xmit(ifp, m, af, if_getmtu(ifp)));
+
+ /*
+ * netmap only gets to see transient errors, since it handles errors by
+ * refusing to advance the transmit ring and retrying later.
+ */
+ ret = wg_xmit(ifp, m, af, if_getmtu(ifp));
+ if (ret == ENOBUFS)
+ return (ret);
+ return (0);
}
+/*
+ * This should only be invoked by netmap, via nm_os_send_up(), to process
+ * packets from the host TX ring.
+ */
+static void
+wg_if_input(if_t ifp, struct mbuf *m)
+{
+ int et;
+
+ KASSERT((if_getcapenable(ifp) & IFCAP_NETMAP) != 0,
+ ("%s: ifp %p is not in netmap mode", __func__, ifp));
+
+ if (determine_ethertype_and_pullup(&m, &et) != 0) {
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ return;
+ }
+ CURVNET_SET(if_getvnet(ifp));
+ switch (et) {
+ case ETHERTYPE_IP:
+ m_adj(m, sizeof(struct ether_header));
+ netisr_dispatch(NETISR_IP, m);
+ break;
+ case ETHERTYPE_IPV6:
+ m_adj(m, sizeof(struct ether_header));
+ netisr_dispatch(NETISR_IPV6, m);
+ break;
+ default:
+ __assert_unreachable();
+ }
+ CURVNET_RESTORE();
+}
+
+/*
+ * Deliver a packet to the host RX ring. Because the interface is in netmap
+ * mode, the if_transmit() call should pass the packet to netmap_transmit().
+ */
+static int
+wg_xmit_netmap(if_t ifp, struct mbuf *m, int af)
+{
+ struct ether_header *eh;
+
+ if (__predict_false(if_tunnel_check_nesting(ifp, m, MTAG_WGLOOP,
+ MAX_LOOPS))) {
+ printf("%s:%d\n", __func__, __LINE__);
+ if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
+ m_freem(m);
+ return (ELOOP);
+ }
+
+ M_PREPEND(m, ETHER_HDR_LEN, M_NOWAIT);
+ if (__predict_false(m == NULL)) {
+ if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
+ return (ENOBUFS);
+ }
+
+ eh = mtod(m, struct ether_header *);
+ eh->ether_type = af == AF_INET ?
+ htons(ETHERTYPE_IP) : htons(ETHERTYPE_IPV6);
+ memcpy(eh->ether_shost, "\x06\x06\x06\x06\x06\x06", ETHER_ADDR_LEN);
+ memcpy(eh->ether_dhost, "\xff\xff\xff\xff\xff\xff", ETHER_ADDR_LEN);
+ return (if_transmit(ifp, m));
+}
+#endif /* DEV_NETMAP */
+
static int
wg_output(if_t ifp, struct mbuf *m, const struct sockaddr *dst, struct route *ro)
{
@@ -2206,6 +2341,11 @@
return (EAFNOSUPPORT);
}
+#ifdef DEV_NETMAP
+ if ((if_getcapenable(ifp) & IFCAP_NETMAP) != 0)
+ return (wg_xmit_netmap(ifp, m, af));
+#endif
+
defragged = m_defrag(m, M_NOWAIT);
if (defragged)
m = defragged;
@@ -2781,7 +2921,10 @@
if_setinitfn(ifp, wg_init);
if_setreassignfn(ifp, wg_reassign);
if_setqflushfn(ifp, wg_qflush);
+#ifdef DEV_NETMAP
if_settransmitfn(ifp, wg_transmit);
+ if_setinputfn(ifp, wg_if_input);
+#endif
if_setoutputfn(ifp, wg_output);
if_setioctlfn(ifp, wg_ioctl);
if_attach(ifp);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Nov 17, 1:33 AM (21 h, 44 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
14668786
Default Alt Text
D43460.diff (6 KB)
Attached To
Mode
D43460: wg: Add netmap support
Attached
Detach File
Event Timeline
Log In to Comment