git: 5246f8fade5b - main - if_ovpn: pass control packets through the socket
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 15 Nov 2022 09:38:46 UTC
The branch main has been updated by kp: URL: https://cgit.FreeBSD.org/src/commit/?id=5246f8fade5bdb72d6e61f333d8b815b456a4ef5 commit 5246f8fade5bdb72d6e61f333d8b815b456a4ef5 Author: Kristof Provost <kp@FreeBSD.org> AuthorDate: 2022-11-09 13:48:05 +0000 Commit: Kristof Provost <kp@FreeBSD.org> CommitDate: 2022-11-15 09:01:18 +0000 if_ovpn: pass control packets through the socket Rather than passing control packets through the ioctl interface allow them to pass through the normal UDP socket flow. This simplifies both kernel and userspace, and matches the approach taken (or the one that will be taken) on the Linux side of things. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D37317 --- sys/net/if_ovpn.c | 102 ++++++++++++------------------------------------------ 1 file changed, 23 insertions(+), 79 deletions(-) diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c index 6ce5d07dc230..276927275a2b 100644 --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -170,8 +170,7 @@ struct ovpn_softc { int peercount; struct ovpn_kpeer *peers[OVPN_MAX_PEERS]; /* XXX Hard limit for now? */ - /* Pending packets */ - struct buf_ring *rxring; + /* Pending notification */ struct buf_ring *notifring; counter_u64_t counters[OVPN_COUNTER_SIZE]; @@ -1275,8 +1274,7 @@ ovpn_poll_pkt(struct ovpn_softc *sc, nvlist_t **onvl) if (nvl == NULL) return (ENOMEM); - nvlist_add_number(nvl, "pending", - buf_ring_count(sc->rxring) + buf_ring_count(sc->notifring)); + nvlist_add_number(nvl, "pending", buf_ring_count(sc->notifring)); *onvl = nvl; @@ -1287,57 +1285,24 @@ static int opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl) { struct ovpn_notification *n; - struct ovpn_wire_header *ohdr; - struct mbuf *m; - uint8_t *buf; nvlist_t *nvl; - uint32_t peerid; - u_int mlength; /* Check if we have notifications pending. */ n = buf_ring_dequeue_mc(sc->notifring); - if (n != NULL) { - nvl = nvlist_create(0); - if (nvl == NULL) { - free(n, M_OVPN); - return (ENOMEM); - } - nvlist_add_number(nvl, "peerid", n->peerid); - nvlist_add_number(nvl, "notification", n->type); - free(n, M_OVPN); - - *onvl = nvl; - - return (0); - } - - /* Queued packet. */ - m = buf_ring_dequeue_mc(sc->rxring); - if (m == NULL) + if (n == NULL) return (ENOENT); - mlength = m_length(m, NULL); - buf = malloc(mlength, M_NVLIST, M_WAITOK); - m_copydata(m, 0, mlength, buf); - ohdr = (struct ovpn_wire_header *)buf; - peerid = ntohl(ohdr->opcode) & 0x00ffffff; - nvl = nvlist_create(0); if (nvl == NULL) { - OVPN_COUNTER_ADD(sc, lost_ctrl_pkts_in, 1); - m_freem(m); - free(buf, M_NVLIST); + free(n, M_OVPN); return (ENOMEM); } - - nvlist_move_binary(nvl, "packet", buf, mlength); - buf = NULL; - nvlist_add_number(nvl, "peerid", peerid); + nvlist_add_number(nvl, "peerid", n->peerid); + nvlist_add_number(nvl, "notification", n->type); + free(n, M_OVPN); *onvl = nvl; - m_freem(m); - return (0); } @@ -2086,22 +2051,6 @@ ovpn_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, return (ovpn_transmit_to_peer(ifp, m, peer, _ovpn_lock_trackerp)); } -static void -ovpn_rcv_ctrl(struct ovpn_softc *sc, struct mbuf *m, int off) -{ - /* Lop off the IP and UDP headers */ - m_adj_decap(m, off); - - /* Keep in the local ring until userspace fetches it. */ - if (buf_ring_enqueue(sc->rxring, m) != 0) { - OVPN_COUNTER_ADD(sc, lost_ctrl_pkts_in, 1); - m_freem(m); - return; - } - - OVPN_COUNTER_ADD(sc, received_ctrl_pkts, 1); -} - static bool ovpn_check_replay(struct ovpn_kkey_dir *key, uint32_t seq) { @@ -2174,6 +2123,7 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp, const struct sockaddr *sa, void *ctx) { struct ovpn_softc *sc = ctx; + struct ovpn_wire_header tmphdr; struct ovpn_wire_header *ohdr; struct udphdr *uhdr; struct ovpn_kkey *key; @@ -2199,16 +2149,27 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp, return (false); } + if (m_length(m, NULL) < (off + sizeof(*uhdr) + ohdrlen)) { + /* Short packet. */ + OVPN_RUNLOCK(sc); + return (false); + } + + m_copydata(m, off + sizeof(*uhdr), ohdrlen, (caddr_t)&tmphdr); + + op = ntohl(tmphdr.opcode) >> 24 >> OVPN_OP_SHIFT; + if (op != OVPN_OP_DATA_V2) { + /* Control packet? */ + OVPN_RUNLOCK(sc); + return (false); + } + m = m_pullup(m, off + sizeof(*uhdr) + ohdrlen); if (m == NULL) { OVPN_RUNLOCK(sc); OVPN_COUNTER_ADD(sc, nomem_data_pkts_in, 1); return (true); } - uhdr = mtodo(m, off); - ohdr = mtodo(m, off + sizeof(*uhdr)); - - op = ntohl(ohdr->opcode) >> 24 >> OVPN_OP_SHIFT; /* * Simplify things by getting rid of the preceding headers, we don't @@ -2219,15 +2180,6 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp, uhdr = mtodo(m, 0); ohdr = mtodo(m, sizeof(*uhdr)); - if (op != OVPN_OP_DATA_V2) { - OVPN_RUNLOCK(sc); - ovpn_rcv_ctrl(sc, m, sizeof(struct udphdr)); - INP_WLOCK(inp); - udp_notify(inp, EAGAIN); - INP_WUNLOCK(inp); - return (true); - } - key = ovpn_find_key(sc, peer, ohdr); if (key == NULL || key->decrypt == NULL) { OVPN_RUNLOCK(sc); @@ -2313,16 +2265,10 @@ ovpn_qflush(struct ifnet *ifp __unused) static void ovpn_flush_rxring(struct ovpn_softc *sc) { - struct mbuf *m; struct ovpn_notification *n; OVPN_WASSERT(sc); - while (! buf_ring_empty(sc->rxring)) { - m = buf_ring_dequeue_sc(sc->rxring); - m_freem(m); - } - while (! buf_ring_empty(sc->notifring)) { n = buf_ring_dequeue_sc(sc->notifring); free(n, M_OVPN); @@ -2409,7 +2355,6 @@ ovpn_clone_create(struct if_clone *ifc, char *name, size_t len, rm_init_flags(&sc->lock, "if_ovpn_lock", RM_RECURSE); sc->refcount = 0; - sc->rxring = buf_ring_alloc(32, M_OVPN, M_WAITOK, NULL); sc->notifring = buf_ring_alloc(32, M_OVPN, M_WAITOK, NULL); COUNTER_ARRAY_ALLOC(sc->counters, OVPN_COUNTER_SIZE, M_WAITOK); @@ -2486,7 +2431,6 @@ ovpn_clone_destroy(struct if_clone *ifc, struct ifnet *ifp, uint32_t flags) } while (i < OVPN_MAX_PEERS); ovpn_flush_rxring(sc); - buf_ring_free(sc->rxring, M_OVPN); buf_ring_free(sc->notifring, M_OVPN); OVPN_WUNLOCK(sc);