summaryrefslogtreecommitdiff
path: root/sys/net/if_pflow.c
diff options
context:
space:
mode:
authorFlorian Obser <florian@cvs.openbsd.org>2015-07-20 23:15:55 +0000
committerFlorian Obser <florian@cvs.openbsd.org>2015-07-20 23:15:55 +0000
commit14071a0c75a36d39e8d34aa808b9aa4c3bc6d02f (patch)
tree5812cf3281c7ec1be3124d4aa2e1373e95c34708 /sys/net/if_pflow.c
parente9802d3090cd41b49b68a2dc6fff1da11b5f4b89 (diff)
Use the kernel socket interface (sosend(9) etc) instead of shoving
packets directly into the network stack with ip_output(). The locking is intentionally left as is and will be improved in another commit. Input / OK bluhm@, OK benno@
Diffstat (limited to 'sys/net/if_pflow.c')
-rw-r--r--sys/net/if_pflow.c224
1 files changed, 96 insertions, 128 deletions
diff --git a/sys/net/if_pflow.c b/sys/net/if_pflow.c
index 4f3ac5e82d4..d2f7ad9c5a3 100644
--- a/sys/net/if_pflow.c
+++ b/sys/net/if_pflow.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pflow.c,v 1.52 2015/07/16 18:36:59 florian Exp $ */
+/* $OpenBSD: if_pflow.c,v 1.53 2015/07/20 23:15:54 florian Exp $ */
/*
* Copyright (c) 2011 Florian Obser <florian@narrans.de>
@@ -28,6 +28,8 @@
#include <sys/timeout.h>
#include <sys/ioctl.h>
#include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
#include <sys/sysctl.h>
#include <net/if.h>
@@ -68,10 +70,7 @@ int pflow_clone_destroy(struct ifnet *);
void pflow_init_timeouts(struct pflow_softc *);
int pflow_calc_mtu(struct pflow_softc *, int, int);
void pflow_setmtu(struct pflow_softc *, int);
-int pflowoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
- struct rtentry *);
int pflowioctl(struct ifnet *, u_long, caddr_t);
-void pflowstart(struct ifnet *);
struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
void pflow_flush(struct pflow_softc *);
@@ -94,7 +93,6 @@ int pflow_pack_flow(struct pf_state *, struct pf_state_key *,
struct pflow_softc *);
int pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *,
struct pflow_softc *);
-int pflow_get_dynport(void);
int export_pflow_if(struct pf_state*, struct pf_state_key *,
struct pflow_softc *);
int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
@@ -107,6 +105,8 @@ struct if_clone pflow_cloner =
IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
pflow_clone_destroy);
+extern struct proc proc0;
+
void
pflowattach(int npflow)
{
@@ -119,22 +119,48 @@ pflow_clone_create(struct if_clone *ifc, int unit)
{
struct ifnet *ifp;
struct pflow_softc *pflowif;
+ struct socket *so;
+ struct sockaddr_in *sin;
+ struct mbuf *m;
+ int error;
+
+ error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
+ if (error)
+ return (error);
+
+ MGET(m, M_WAIT, MT_SONAME);
+ sin = mtod(m, struct sockaddr_in *);
+ memset(sin, 0 , sizeof(*sin));
+ sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = htons(0);
+ error = sobind(so, m, &proc0);
+ m_freem(m);
+ if (error) {
+ soclose(so);
+ return (error);
+ }
if ((pflowif = malloc(sizeof(*pflowif),
- M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
- return (ENOMEM);
-
- if ((pflowif->sc_imo.imo_membership = malloc(
- (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
- M_WAITOK|M_ZERO)) == NULL) {
- free(pflowif, M_DEVBUF, 0);
+ M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
+ soclose(so);
return (ENOMEM);
}
- pflowif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+
+ pflowif->so = so;
+
+ MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
+ sin = mtod(pflowif->send_nam, struct sockaddr_in *);
+ memset(sin, 0 , sizeof(*sin));
+ sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = INADDR_ANY;
+ sin->sin_port = 0;
+
pflowif->sc_receiver_ip.s_addr = INADDR_ANY;
pflowif->sc_receiver_port = 0;
pflowif->sc_sender_ip.s_addr = INADDR_ANY;
- pflowif->sc_sender_port = pflow_get_dynport();
pflowif->sc_version = PFLOW_PROTO_DEFAULT;
/* ipfix template init */
@@ -232,8 +258,8 @@ pflow_clone_create(struct if_clone *ifc, int unit)
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit);
ifp->if_softc = pflowif;
ifp->if_ioctl = pflowioctl;
- ifp->if_output = pflowoutput;
- ifp->if_start = pflowstart;
+ ifp->if_output = NULL;
+ ifp->if_start = NULL;
ifp->if_type = IFT_PFLOW;
IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
ifp->if_hdrlen = PFLOW_HDRLEN;
@@ -244,10 +270,6 @@ pflow_clone_create(struct if_clone *ifc, int unit)
if_attach(ifp);
if_alloc_sadl(ifp);
-#if NBPFILTER > 0
- bpfattach(&pflowif->sc_if.if_bpf, ifp, DLT_RAW, 0);
-#endif
-
/* Insert into list of pflows */
SLIST_INSERT_HEAD(&pflowif_list, pflowif, sc_next);
return (0);
@@ -257,9 +279,12 @@ int
pflow_clone_destroy(struct ifnet *ifp)
{
struct pflow_softc *sc = ifp->if_softc;
- int s;
+ int s, error;
+
+ error = 0;
s = splnet();
+ m_freem(sc->send_nam);
if (timeout_initialized(&sc->sc_tmo))
timeout_del(&sc->sc_tmo);
if (timeout_initialized(&sc->sc_tmo6))
@@ -267,41 +292,15 @@ pflow_clone_destroy(struct ifnet *ifp)
if (timeout_initialized(&sc->sc_tmo_tmpl))
timeout_del(&sc->sc_tmo_tmpl);
pflow_flush(sc);
+ if (sc->so != NULL) {
+ error = soclose(sc->so);
+ sc->so = NULL;
+ }
if_detach(ifp);
SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
- free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
free(sc, M_DEVBUF, 0);
splx(s);
- return (0);
-}
-
-/*
- * Start output on the pflow interface.
- */
-void
-pflowstart(struct ifnet *ifp)
-{
- struct mbuf *m;
- int s;
-
- for (;;) {
- s = splnet();
- IF_DROP(&ifp->if_snd);
- IF_DEQUEUE(&ifp->if_snd, m);
- splx(s);
-
- if (m == NULL)
- return;
- m_freem(m);
- }
-}
-
-int
-pflowoutput(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
- struct rtentry *rt)
-{
- m_freem(m);
- return (0);
+ return (error);
}
/* ARGSUSED */
@@ -312,6 +311,9 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct pflow_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct pflowreq pflowr;
+ struct socket *so;
+ struct sockaddr_in *sin;
+ struct mbuf *m;
int s, error;
switch (cmd) {
@@ -321,8 +323,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCSIFFLAGS:
if ((ifp->if_flags & IFF_UP) &&
sc->sc_receiver_ip.s_addr != INADDR_ANY &&
- sc->sc_receiver_port != 0 &&
- sc->sc_sender_port != 0) {
+ sc->sc_receiver_port != 0 && sc->so != NULL) {
ifp->if_flags |= IFF_RUNNING;
sc->sc_gcounter=pflowstats.pflow_flows;
/* send templates on startup */
@@ -374,16 +375,48 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
return(EINVAL);
}
}
- s = splnet();
+ s = splnet();
pflow_flush(sc);
- if (pflowr.addrmask & PFLOW_MASK_DSTIP)
+ if (pflowr.addrmask & PFLOW_MASK_DSTIP) {
sc->sc_receiver_ip.s_addr = pflowr.receiver_ip.s_addr;
- if (pflowr.addrmask & PFLOW_MASK_DSTPRT)
+ sin = mtod(sc->send_nam, struct sockaddr_in *);
+ sin->sin_addr.s_addr = sc->sc_receiver_ip.s_addr;
+ }
+ if (pflowr.addrmask & PFLOW_MASK_DSTPRT) {
sc->sc_receiver_port = pflowr.receiver_port;
- if (pflowr.addrmask & PFLOW_MASK_SRCIP)
+ sin = mtod(sc->send_nam, struct sockaddr_in *);
+ sin->sin_port = pflowr.receiver_port;
+ }
+ if (pflowr.addrmask & PFLOW_MASK_SRCIP) {
+ error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
+ if (error) {
+ splx(s);
+ return (error);
+ }
+
+ MGET(m, M_WAIT, MT_SONAME);
+ sin = mtod(m, struct sockaddr_in *);
+ memset(sin, 0 , sizeof(*sin));
+ sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = pflowr.sender_ip.s_addr;
+ sin->sin_port = 0;
+
+ error = sobind(so, m, &proc0);
+ m_freem(m);
+ if (error) {
+ soclose(so);
+ splx(s);
+ return (error);
+ }
+
sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr;
+ soclose(sc->so);
+ sc->so = so;
+ }
+
/* error check is above */
if (pflowr.addrmask & PFLOW_MASK_VERSION)
sc->sc_version = pflowr.version;
@@ -395,8 +428,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((ifp->if_flags & IFF_UP) &&
sc->sc_receiver_ip.s_addr != INADDR_ANY &&
- sc->sc_receiver_port != 0 &&
- sc->sc_sender_port != 0) {
+ sc->sc_receiver_port != 0 && sc->so != NULL) {
ifp->if_flags |= IFF_RUNNING;
sc->sc_gcounter=pflowstats.pflow_flows;
if (sc->sc_version == PFLOW_PROTO_10) {
@@ -1083,78 +1115,14 @@ pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
int
pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
{
- struct udpiphdr *ui;
- u_int16_t len = m->m_pkthdr.len;
-#if NBPFILTER > 0
- struct ifnet *ifp = &sc->sc_if;
-#endif
- struct ip *ip;
- int err;
-
- /* UDP Header*/
- M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
- if (m == NULL) {
- pflowstats.pflow_onomem++;
- return (ENOBUFS);
- }
-
- ui = mtod(m, struct udpiphdr *);
- ui->ui_pr = IPPROTO_UDP;
- ui->ui_src = sc->sc_sender_ip;
- ui->ui_sport = sc->sc_sender_port;
- ui->ui_dst = sc->sc_receiver_ip;
- ui->ui_dport = sc->sc_receiver_port;
- ui->ui_ulen = htons(sizeof(struct udphdr) + len);
- ui->ui_sum = 0;
- m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
- m->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
-
- ip = (struct ip *)ui;
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(struct ip) >> 2;
- ip->ip_id = htons(ip_randomid());
- ip->ip_off = htons(IP_DF);
- ip->ip_tos = IPTOS_LOWDELAY;
- ip->ip_ttl = IPDEFTTL;
- ip->ip_len = htons(sizeof(struct udpiphdr) + len);
-
-#if NBPFILTER > 0
- if (ifp->if_bpf)
- bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
-#endif
-
sc->sc_if.if_opackets++;
sc->sc_if.if_obytes += m->m_pkthdr.len;
- if ((err = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL,
- 0))) {
- pflowstats.pflow_oerrors++;
- sc->sc_if.if_oerrors++;
- }
- return (err);
-}
-
-int
-pflow_get_dynport(void)
-{
- u_int16_t tmp, low, high, cut;
-
- low = ipport_hifirstauto; /* sysctl */
- high = ipport_hilastauto;
-
- cut = arc4random_uniform(1 + high - low) + low;
-
- for (tmp = cut; tmp <= high; ++(tmp)) {
- if (!in_baddynamic(tmp, IPPROTO_UDP))
- return (htons(tmp));
- }
-
- for (tmp = cut - 1; tmp >= low; --(tmp)) {
- if (!in_baddynamic(tmp, IPPROTO_UDP))
- return (htons(tmp));
+ if (sc->so == NULL) {
+ m_freem(m);
+ return (EINVAL);
}
-
- return (htons(ipport_hilastauto)); /* XXX */
+ return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
}
int