1*938ff1aeSbluhm /* $OpenBSD: if_pflow.c,v 1.109 2023/12/23 10:52:54 bluhm Exp $ */
218ae10f7Shenning
318ae10f7Shenning /*
4fa1d79b8Sbenno * Copyright (c) 2011 Florian Obser <florian@narrans.de>
5fa1d79b8Sbenno * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de>
618ae10f7Shenning * Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
718ae10f7Shenning * Copyright (c) 2008 Joerg Goltermann <jg@osn.de>
818ae10f7Shenning *
918ae10f7Shenning * Permission to use, copy, modify, and distribute this software for any
1018ae10f7Shenning * purpose with or without fee is hereby granted, provided that the above
1118ae10f7Shenning * copyright notice and this permission notice appear in all copies.
1218ae10f7Shenning *
1318ae10f7Shenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1418ae10f7Shenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1518ae10f7Shenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1618ae10f7Shenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1718ae10f7Shenning * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
1818ae10f7Shenning * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
1918ae10f7Shenning * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2018ae10f7Shenning */
2118ae10f7Shenning
2218ae10f7Shenning #include <sys/param.h>
23b27348b2Sderaadt #include <sys/malloc.h>
249b074ffaStedu #include <sys/systm.h>
2518ae10f7Shenning #include <sys/mbuf.h>
2618ae10f7Shenning #include <sys/socket.h>
27638c25e3Stedu #include <sys/timeout.h>
2818ae10f7Shenning #include <sys/ioctl.h>
2918ae10f7Shenning #include <sys/kernel.h>
30416aa928Sflorian #include <sys/socketvar.h>
3118ae10f7Shenning #include <sys/sysctl.h>
32339bbf62Smvs #include <sys/mutex.h>
3318ae10f7Shenning
3418ae10f7Shenning #include <net/if.h>
3518ae10f7Shenning #include <net/if_types.h>
3618ae10f7Shenning #include <net/bpf.h>
3718ae10f7Shenning #include <net/route.h>
3818ae10f7Shenning #include <netinet/in.h>
3918ae10f7Shenning #include <netinet/if_ether.h>
4018ae10f7Shenning #include <netinet/tcp.h>
4118ae10f7Shenning
4218ae10f7Shenning #include <netinet/ip.h>
4333e54543Sdlg #include <netinet/ip_icmp.h>
4418ae10f7Shenning #include <netinet/ip_var.h>
4518ae10f7Shenning #include <netinet/udp.h>
4618ae10f7Shenning #include <netinet/udp_var.h>
4718ae10f7Shenning #include <netinet/in_pcb.h>
4818ae10f7Shenning
4918ae10f7Shenning #include <net/pfvar.h>
5033e54543Sdlg #include <net/pfvar_priv.h>
5118ae10f7Shenning #include <net/if_pflow.h>
5218ae10f7Shenning
5318ae10f7Shenning #include "bpfilter.h"
5418ae10f7Shenning #include "pflow.h"
5518ae10f7Shenning
5618ae10f7Shenning #define PFLOW_MINMTU \
5718ae10f7Shenning (sizeof(struct pflow_header) + sizeof(struct pflow_flow))
5818ae10f7Shenning
5918ae10f7Shenning #ifdef PFLOWDEBUG
6018ae10f7Shenning #define DPRINTF(x) do { printf x ; } while (0)
6118ae10f7Shenning #else
6218ae10f7Shenning #define DPRINTF(x)
6318ae10f7Shenning #endif
6418ae10f7Shenning
6563a0cdecSmvs SMR_SLIST_HEAD(, pflow_softc) pflowif_list;
66ccf5da69Smvs
67ccf5da69Smvs enum pflowstat_counters {
68ccf5da69Smvs pflow_flows,
69ccf5da69Smvs pflow_packets,
70ccf5da69Smvs pflow_onomem,
71ccf5da69Smvs pflow_oerrors,
72ccf5da69Smvs pflow_ncounters,
73ccf5da69Smvs };
74ccf5da69Smvs
75ccf5da69Smvs struct cpumem *pflow_counters;
76ccf5da69Smvs
77ccf5da69Smvs static inline void
pflowstat_inc(enum pflowstat_counters c)78ccf5da69Smvs pflowstat_inc(enum pflowstat_counters c)
79ccf5da69Smvs {
80ccf5da69Smvs counters_inc(pflow_counters, c);
81ccf5da69Smvs }
8218ae10f7Shenning
8318ae10f7Shenning void pflowattach(int);
8460368739Skrw int pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
8560368739Skrw struct rtentry *rt);
868818ef4eSbenno void pflow_output_process(void *);
8718ae10f7Shenning int pflow_clone_create(struct if_clone *, int);
8818ae10f7Shenning int pflow_clone_destroy(struct ifnet *);
894da5ea9aSmpi int pflow_set(struct pflow_softc *, struct pflowreq *);
90fa1d79b8Sbenno int pflow_calc_mtu(struct pflow_softc *, int, int);
9118ae10f7Shenning void pflow_setmtu(struct pflow_softc *, int);
923baed77aSflorian int pflowvalidsockaddr(const struct sockaddr *, int);
9318ae10f7Shenning int pflowioctl(struct ifnet *, u_long, caddr_t);
9418ae10f7Shenning
95fa1d79b8Sbenno struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
96fa1d79b8Sbenno void pflow_flush(struct pflow_softc *);
97fa1d79b8Sbenno int pflow_sendout_v5(struct pflow_softc *);
98fa1d79b8Sbenno int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
99fa1d79b8Sbenno int pflow_sendout_ipfix_tmpl(struct pflow_softc *);
10018ae10f7Shenning int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
10118ae10f7Shenning void pflow_timeout(void *);
102fa1d79b8Sbenno void pflow_timeout6(void *);
103fa1d79b8Sbenno void pflow_timeout_tmpl(void *);
10418ae10f7Shenning void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
105c07294cfSflorian struct pf_state *, struct pf_state_key *, int, int);
10658354163Sflorian void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
10758354163Sflorian struct pflow_ipfix_flow4 *, struct pf_state *, struct pf_state_key *,
10858354163Sflorian struct pflow_softc *, int, int);
10958354163Sflorian void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *,
11058354163Sflorian struct pflow_ipfix_flow6 *, struct pf_state *, struct pf_state_key *,
11158354163Sflorian struct pflow_softc *, int, int);
112c07294cfSflorian int pflow_pack_flow(struct pf_state *, struct pf_state_key *,
113c07294cfSflorian struct pflow_softc *);
114c07294cfSflorian int pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *,
115c07294cfSflorian struct pflow_softc *);
116c07294cfSflorian int export_pflow_if(struct pf_state*, struct pf_state_key *,
117c07294cfSflorian struct pflow_softc *);
11888e5d322Sgollo int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
11958354163Sflorian int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow,
12058354163Sflorian struct pflow_softc *sc);
12158354163Sflorian int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
12258354163Sflorian struct pflow_softc *sc);
12318ae10f7Shenning
12418ae10f7Shenning struct if_clone pflow_cloner =
12518ae10f7Shenning IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
12618ae10f7Shenning pflow_clone_destroy);
12718ae10f7Shenning
12818ae10f7Shenning void
pflowattach(int npflow)12918ae10f7Shenning pflowattach(int npflow)
13018ae10f7Shenning {
13163a0cdecSmvs SMR_SLIST_INIT(&pflowif_list);
132ccf5da69Smvs pflow_counters = counters_alloc(pflow_ncounters);
13318ae10f7Shenning if_clone_attach(&pflow_cloner);
13418ae10f7Shenning }
13518ae10f7Shenning
13618ae10f7Shenning int
pflow_output(struct ifnet * ifp,struct mbuf * m,struct sockaddr * dst,struct rtentry * rt)13760368739Skrw pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
13860368739Skrw struct rtentry *rt)
13960368739Skrw {
14060368739Skrw m_freem(m); /* drop packet */
14160368739Skrw return (EAFNOSUPPORT);
14260368739Skrw }
14360368739Skrw
1448818ef4eSbenno void
pflow_output_process(void * arg)1458818ef4eSbenno pflow_output_process(void *arg)
1468818ef4eSbenno {
147b52009cbSvisa struct mbuf_list ml;
1488818ef4eSbenno struct pflow_softc *sc = arg;
1498818ef4eSbenno struct mbuf *m;
1508818ef4eSbenno
151b52009cbSvisa mq_delist(&sc->sc_outputqueue, &ml);
152f0d16c93Smvs rw_enter_read(&sc->sc_lock);
153b52009cbSvisa while ((m = ml_dequeue(&ml)) != NULL) {
1548818ef4eSbenno pflow_sendout_mbuf(sc, m);
1558818ef4eSbenno }
156f0d16c93Smvs rw_exit_read(&sc->sc_lock);
1578818ef4eSbenno }
1588818ef4eSbenno
15960368739Skrw int
pflow_clone_create(struct if_clone * ifc,int unit)16018ae10f7Shenning pflow_clone_create(struct if_clone *ifc, int unit)
16118ae10f7Shenning {
16218ae10f7Shenning struct ifnet *ifp;
163d9bf6ab7Sgollo struct pflow_softc *pflowif;
16418ae10f7Shenning
165809d3a3eSbluhm pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO);
166f0d16c93Smvs rw_init(&pflowif->sc_lock, "pflowlk");
167339bbf62Smvs mtx_init(&pflowif->sc_mtx, IPL_MPFLOOR);
168416aa928Sflorian MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
169fa1d79b8Sbenno pflowif->sc_version = PFLOW_PROTO_DEFAULT;
170fa1d79b8Sbenno
17158354163Sflorian /* ipfix template init */
17258354163Sflorian bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix));
17358354163Sflorian pflowif->sc_tmpl_ipfix.set_header.set_id =
17458354163Sflorian htons(PFLOW_IPFIX_TMPL_SET_ID);
17558354163Sflorian pflowif->sc_tmpl_ipfix.set_header.set_length =
17658354163Sflorian htons(sizeof(struct pflow_ipfix_tmpl));
17758354163Sflorian
17858354163Sflorian /* ipfix IPv4 template */
17958354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id =
18058354163Sflorian htons(PFLOW_IPFIX_TMPL_IPV4_ID);
18158354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count
18258354163Sflorian = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT);
18358354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id =
18458354163Sflorian htons(PFIX_IE_sourceIPv4Address);
18558354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4);
18658354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id =
18758354163Sflorian htons(PFIX_IE_destinationIPv4Address);
18858354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4);
18958354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id =
19058354163Sflorian htons(PFIX_IE_ingressInterface);
19158354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4);
19258354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id =
19358354163Sflorian htons(PFIX_IE_egressInterface);
19458354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4);
19558354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.field_id =
19658354163Sflorian htons(PFIX_IE_packetDeltaCount);
19758354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8);
19858354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id =
19958354163Sflorian htons(PFIX_IE_octetDeltaCount);
20058354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8);
20158354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id =
20258354163Sflorian htons(PFIX_IE_flowStartMilliseconds);
20358354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8);
20458354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id =
20558354163Sflorian htons(PFIX_IE_flowEndMilliseconds);
20658354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8);
20758354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.field_id =
20858354163Sflorian htons(PFIX_IE_sourceTransportPort);
20958354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2);
21058354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.field_id =
21158354163Sflorian htons(PFIX_IE_destinationTransportPort);
21258354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2);
21358354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.field_id =
21458354163Sflorian htons(PFIX_IE_ipClassOfService);
21558354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1);
21658354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id =
21758354163Sflorian htons(PFIX_IE_protocolIdentifier);
21858354163Sflorian pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1);
21958354163Sflorian
22058354163Sflorian /* ipfix IPv6 template */
22158354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id =
22258354163Sflorian htons(PFLOW_IPFIX_TMPL_IPV6_ID);
22358354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count =
22458354163Sflorian htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT);
22558354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id =
22658354163Sflorian htons(PFIX_IE_sourceIPv6Address);
22758354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16);
22858354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id =
22958354163Sflorian htons(PFIX_IE_destinationIPv6Address);
23058354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16);
23158354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id =
23258354163Sflorian htons(PFIX_IE_ingressInterface);
23358354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4);
23458354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id =
23558354163Sflorian htons(PFIX_IE_egressInterface);
23658354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4);
23758354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id =
23858354163Sflorian htons(PFIX_IE_packetDeltaCount);
23958354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8);
24058354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id =
24158354163Sflorian htons(PFIX_IE_octetDeltaCount);
24258354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8);
24358354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id =
24458354163Sflorian htons(PFIX_IE_flowStartMilliseconds);
24558354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8);
24658354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id =
24758354163Sflorian htons(PFIX_IE_flowEndMilliseconds);
24858354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8);
24958354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id =
25058354163Sflorian htons(PFIX_IE_sourceTransportPort);
25158354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2);
25258354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id =
25358354163Sflorian htons(PFIX_IE_destinationTransportPort);
25458354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2);
25558354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id =
25658354163Sflorian htons(PFIX_IE_ipClassOfService);
25758354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1);
25858354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id =
25958354163Sflorian htons(PFIX_IE_protocolIdentifier);
26058354163Sflorian pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
261fa1d79b8Sbenno
26218ae10f7Shenning ifp = &pflowif->sc_if;
26318ae10f7Shenning snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit);
26418ae10f7Shenning ifp->if_softc = pflowif;
26518ae10f7Shenning ifp->if_ioctl = pflowioctl;
26660368739Skrw ifp->if_output = pflow_output;
267416aa928Sflorian ifp->if_start = NULL;
26899bf4b5fSmpi ifp->if_xflags = IFXF_CLONED;
26918ae10f7Shenning ifp->if_type = IFT_PFLOW;
27018ae10f7Shenning ifp->if_hdrlen = PFLOW_HDRLEN;
27118ae10f7Shenning ifp->if_flags = IFF_UP;
27218ae10f7Shenning ifp->if_flags &= ~IFF_RUNNING; /* not running, need receiver */
273b52009cbSvisa mq_init(&pflowif->sc_outputqueue, 8192, IPL_SOFTNET);
27418ae10f7Shenning pflow_setmtu(pflowif, ETHERMTU);
275415db4d1Smvs
276415db4d1Smvs timeout_set_proc(&pflowif->sc_tmo, pflow_timeout, pflowif);
277415db4d1Smvs timeout_set_proc(&pflowif->sc_tmo6, pflow_timeout6, pflowif);
278415db4d1Smvs timeout_set_proc(&pflowif->sc_tmo_tmpl, pflow_timeout_tmpl, pflowif);
279415db4d1Smvs
280f69555e6Smvs task_set(&pflowif->sc_outputtask, pflow_output_process, pflowif);
281f69555e6Smvs
282*938ff1aeSbluhm if_counters_alloc(ifp);
28318ae10f7Shenning if_attach(ifp);
28418ae10f7Shenning if_alloc_sadl(ifp);
28518ae10f7Shenning
286d9bf6ab7Sgollo /* Insert into list of pflows */
28763a0cdecSmvs KERNEL_ASSERT_LOCKED();
28863a0cdecSmvs SMR_SLIST_INSERT_HEAD_LOCKED(&pflowif_list, pflowif, sc_next);
28918ae10f7Shenning return (0);
29018ae10f7Shenning }
29118ae10f7Shenning
29218ae10f7Shenning int
pflow_clone_destroy(struct ifnet * ifp)29318ae10f7Shenning pflow_clone_destroy(struct ifnet *ifp)
29418ae10f7Shenning {
29518ae10f7Shenning struct pflow_softc *sc = ifp->if_softc;
296aa28b9a6Smpi int error;
297416aa928Sflorian
298416aa928Sflorian error = 0;
29918ae10f7Shenning
3000b9ea278Smvs rw_enter_write(&sc->sc_lock);
301f0d16c93Smvs sc->sc_dying = 1;
3020b9ea278Smvs rw_exit_write(&sc->sc_lock);
303b170e74aSmvs
30463a0cdecSmvs KERNEL_ASSERT_LOCKED();
30563a0cdecSmvs SMR_SLIST_REMOVE_LOCKED(&pflowif_list, sc, pflow_softc, sc_next);
30663a0cdecSmvs smr_barrier();
30763a0cdecSmvs
308ea893a00Sflorian timeout_del(&sc->sc_tmo);
309ea893a00Sflorian timeout_del(&sc->sc_tmo6);
310ea893a00Sflorian timeout_del(&sc->sc_tmo_tmpl);
311415db4d1Smvs
312fa1d79b8Sbenno pflow_flush(sc);
31393865884Ssashan task_del(net_tq(ifp->if_index), &sc->sc_outputtask);
314b170e74aSmvs taskq_barrier(net_tq(ifp->if_index));
315b52009cbSvisa mq_purge(&sc->sc_outputqueue);
316928053bcSflorian m_freem(sc->send_nam);
317416aa928Sflorian if (sc->so != NULL) {
3184a4dc3eaSmpi error = soclose(sc->so, MSG_DONTWAIT);
319416aa928Sflorian sc->so = NULL;
320416aa928Sflorian }
3213baed77aSflorian if (sc->sc_flowdst != NULL)
3223baed77aSflorian free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
3233baed77aSflorian if (sc->sc_flowsrc != NULL)
3243baed77aSflorian free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
32518ae10f7Shenning if_detach(ifp);
326fa157596Sflorian free(sc, M_DEVBUF, sizeof(*sc));
327416aa928Sflorian return (error);
32818ae10f7Shenning }
32918ae10f7Shenning
33018ae10f7Shenning int
pflowvalidsockaddr(const struct sockaddr * sa,int ignore_port)3313baed77aSflorian pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port)
3323baed77aSflorian {
3333baed77aSflorian struct sockaddr_in6 *sin6;
3343baed77aSflorian struct sockaddr_in *sin;
3353baed77aSflorian
3363baed77aSflorian if (sa == NULL)
3373baed77aSflorian return (0);
3383baed77aSflorian switch(sa->sa_family) {
3393baed77aSflorian case AF_INET:
3403baed77aSflorian sin = (struct sockaddr_in*) sa;
3413baed77aSflorian return (sin->sin_addr.s_addr != INADDR_ANY &&
3423baed77aSflorian (ignore_port || sin->sin_port != 0));
3433baed77aSflorian case AF_INET6:
3443baed77aSflorian sin6 = (struct sockaddr_in6*) sa;
3453baed77aSflorian return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
3463baed77aSflorian (ignore_port || sin6->sin6_port != 0));
3473baed77aSflorian default:
3483baed77aSflorian return (0);
3493baed77aSflorian }
3503baed77aSflorian }
3514da5ea9aSmpi
3524da5ea9aSmpi int
pflow_set(struct pflow_softc * sc,struct pflowreq * pflowr)3534da5ea9aSmpi pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
3544da5ea9aSmpi {
3554da5ea9aSmpi struct proc *p = curproc;
3564da5ea9aSmpi struct socket *so;
3574da5ea9aSmpi struct sockaddr *sa;
3584da5ea9aSmpi int error = 0;
3594da5ea9aSmpi
3604da5ea9aSmpi if (pflowr->addrmask & PFLOW_MASK_VERSION) {
3614da5ea9aSmpi switch(pflowr->version) {
3624da5ea9aSmpi case PFLOW_PROTO_5:
3634da5ea9aSmpi case PFLOW_PROTO_10:
3644da5ea9aSmpi break;
3654da5ea9aSmpi default:
3664da5ea9aSmpi return(EINVAL);
3674da5ea9aSmpi }
3684da5ea9aSmpi }
3694da5ea9aSmpi
370339bbf62Smvs rw_assert_wrlock(&sc->sc_lock);
371339bbf62Smvs
3724da5ea9aSmpi pflow_flush(sc);
3734da5ea9aSmpi
3744da5ea9aSmpi if (pflowr->addrmask & PFLOW_MASK_DSTIP) {
3754da5ea9aSmpi if (sc->sc_flowdst != NULL &&
3764da5ea9aSmpi sc->sc_flowdst->sa_family != pflowr->flowdst.ss_family) {
3774da5ea9aSmpi free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
3784da5ea9aSmpi sc->sc_flowdst = NULL;
3794da5ea9aSmpi if (sc->so != NULL) {
3804a4dc3eaSmpi soclose(sc->so, MSG_DONTWAIT);
3814da5ea9aSmpi sc->so = NULL;
3824da5ea9aSmpi }
3834da5ea9aSmpi }
3844da5ea9aSmpi
3854da5ea9aSmpi switch (pflowr->flowdst.ss_family) {
3864da5ea9aSmpi case AF_INET:
387085e702cSflorian if (sc->sc_flowdst == NULL) {
3884da5ea9aSmpi if ((sc->sc_flowdst = malloc(
3894da5ea9aSmpi sizeof(struct sockaddr_in),
3904da5ea9aSmpi M_DEVBUF, M_NOWAIT)) == NULL)
3914da5ea9aSmpi return (ENOMEM);
392085e702cSflorian }
3934da5ea9aSmpi memcpy(sc->sc_flowdst, &pflowr->flowdst,
3944da5ea9aSmpi sizeof(struct sockaddr_in));
3954da5ea9aSmpi sc->sc_flowdst->sa_len = sizeof(struct
3964da5ea9aSmpi sockaddr_in);
3974da5ea9aSmpi break;
3984da5ea9aSmpi case AF_INET6:
399085e702cSflorian if (sc->sc_flowdst == NULL) {
4004da5ea9aSmpi if ((sc->sc_flowdst = malloc(
4014da5ea9aSmpi sizeof(struct sockaddr_in6),
4024da5ea9aSmpi M_DEVBUF, M_NOWAIT)) == NULL)
4034da5ea9aSmpi return (ENOMEM);
404085e702cSflorian }
4054da5ea9aSmpi memcpy(sc->sc_flowdst, &pflowr->flowdst,
4064da5ea9aSmpi sizeof(struct sockaddr_in6));
4074da5ea9aSmpi sc->sc_flowdst->sa_len = sizeof(struct
4084da5ea9aSmpi sockaddr_in6);
4094da5ea9aSmpi break;
4104da5ea9aSmpi default:
4114da5ea9aSmpi break;
4124da5ea9aSmpi }
413085e702cSflorian
4144da5ea9aSmpi if (sc->sc_flowdst != NULL) {
4154da5ea9aSmpi sc->send_nam->m_len = sc->sc_flowdst->sa_len;
4164da5ea9aSmpi sa = mtod(sc->send_nam, struct sockaddr *);
4174da5ea9aSmpi memcpy(sa, sc->sc_flowdst, sc->sc_flowdst->sa_len);
4184da5ea9aSmpi }
4194da5ea9aSmpi }
4204da5ea9aSmpi
4214da5ea9aSmpi if (pflowr->addrmask & PFLOW_MASK_SRCIP) {
422dcb6b858Sflorian if (sc->sc_flowsrc != NULL)
4234da5ea9aSmpi free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
4244da5ea9aSmpi sc->sc_flowsrc = NULL;
4254da5ea9aSmpi if (sc->so != NULL) {
4264a4dc3eaSmpi soclose(sc->so, MSG_DONTWAIT);
4274da5ea9aSmpi sc->so = NULL;
4284da5ea9aSmpi }
4294da5ea9aSmpi switch(pflowr->flowsrc.ss_family) {
4304da5ea9aSmpi case AF_INET:
4314da5ea9aSmpi if ((sc->sc_flowsrc = malloc(
4324da5ea9aSmpi sizeof(struct sockaddr_in),
4334da5ea9aSmpi M_DEVBUF, M_NOWAIT)) == NULL)
4344da5ea9aSmpi return (ENOMEM);
4354da5ea9aSmpi memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
4364da5ea9aSmpi sizeof(struct sockaddr_in));
4374da5ea9aSmpi sc->sc_flowsrc->sa_len = sizeof(struct
4384da5ea9aSmpi sockaddr_in);
4394da5ea9aSmpi break;
4404da5ea9aSmpi case AF_INET6:
4414da5ea9aSmpi if ((sc->sc_flowsrc = malloc(
4424da5ea9aSmpi sizeof(struct sockaddr_in6),
4434da5ea9aSmpi M_DEVBUF, M_NOWAIT)) == NULL)
4444da5ea9aSmpi return (ENOMEM);
4454da5ea9aSmpi memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
4464da5ea9aSmpi sizeof(struct sockaddr_in6));
4474da5ea9aSmpi sc->sc_flowsrc->sa_len = sizeof(struct
4484da5ea9aSmpi sockaddr_in6);
4494da5ea9aSmpi break;
4504da5ea9aSmpi default:
4514da5ea9aSmpi break;
4524da5ea9aSmpi }
4534da5ea9aSmpi }
4544da5ea9aSmpi
4554da5ea9aSmpi if (sc->so == NULL) {
4564da5ea9aSmpi if (pflowvalidsockaddr(sc->sc_flowdst, 0)) {
4574da5ea9aSmpi error = socreate(sc->sc_flowdst->sa_family,
4584da5ea9aSmpi &so, SOCK_DGRAM, 0);
4594da5ea9aSmpi if (error)
4604da5ea9aSmpi return (error);
4614da5ea9aSmpi if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) {
4624da5ea9aSmpi struct mbuf *m;
4634da5ea9aSmpi
4644da5ea9aSmpi MGET(m, M_WAIT, MT_SONAME);
4654da5ea9aSmpi m->m_len = sc->sc_flowsrc->sa_len;
4664da5ea9aSmpi sa = mtod(m, struct sockaddr *);
4674da5ea9aSmpi memcpy(sa, sc->sc_flowsrc,
4684da5ea9aSmpi sc->sc_flowsrc->sa_len);
4694da5ea9aSmpi
47084245c07Sclaudio solock(so);
4714da5ea9aSmpi error = sobind(so, m, p);
47284245c07Sclaudio sounlock(so);
4734da5ea9aSmpi m_freem(m);
4744da5ea9aSmpi if (error) {
4754a4dc3eaSmpi soclose(so, MSG_DONTWAIT);
4764da5ea9aSmpi return (error);
4774da5ea9aSmpi }
4784da5ea9aSmpi }
4794da5ea9aSmpi sc->so = so;
4804da5ea9aSmpi }
4814da5ea9aSmpi } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) {
4824a4dc3eaSmpi soclose(sc->so, MSG_DONTWAIT);
4834da5ea9aSmpi sc->so = NULL;
4844da5ea9aSmpi }
4854da5ea9aSmpi
4860b9ea278Smvs NET_LOCK();
487339bbf62Smvs mtx_enter(&sc->sc_mtx);
488339bbf62Smvs
4894da5ea9aSmpi /* error check is above */
4904da5ea9aSmpi if (pflowr->addrmask & PFLOW_MASK_VERSION)
4914da5ea9aSmpi sc->sc_version = pflowr->version;
4924da5ea9aSmpi
4934da5ea9aSmpi pflow_setmtu(sc, ETHERMTU);
494415db4d1Smvs
495415db4d1Smvs switch (sc->sc_version) {
496415db4d1Smvs case PFLOW_PROTO_5:
497415db4d1Smvs timeout_del(&sc->sc_tmo6);
498415db4d1Smvs timeout_del(&sc->sc_tmo_tmpl);
499415db4d1Smvs break;
500415db4d1Smvs case PFLOW_PROTO_10:
501415db4d1Smvs timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
502415db4d1Smvs break;
503415db4d1Smvs default: /* NOTREACHED */
504415db4d1Smvs break;
505415db4d1Smvs }
5064da5ea9aSmpi
507339bbf62Smvs mtx_leave(&sc->sc_mtx);
5080b9ea278Smvs NET_UNLOCK();
509339bbf62Smvs
5104da5ea9aSmpi return (0);
5114da5ea9aSmpi }
5124da5ea9aSmpi
5133baed77aSflorian int
pflowioctl(struct ifnet * ifp,u_long cmd,caddr_t data)51418ae10f7Shenning pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
51518ae10f7Shenning {
51618ae10f7Shenning struct proc *p = curproc;
51718ae10f7Shenning struct pflow_softc *sc = ifp->if_softc;
51818ae10f7Shenning struct ifreq *ifr = (struct ifreq *)data;
51918ae10f7Shenning struct pflowreq pflowr;
5200b9ea278Smvs int error = 0;
521f0d16c93Smvs
52218ae10f7Shenning switch (cmd) {
52318ae10f7Shenning case SIOCSIFADDR:
52418ae10f7Shenning case SIOCSIFDSTADDR:
52518ae10f7Shenning case SIOCSIFFLAGS:
5260b9ea278Smvs case SIOCSIFMTU:
5270b9ea278Smvs case SIOCGETPFLOW:
5280b9ea278Smvs case SIOCSETPFLOW:
5290b9ea278Smvs break;
5300b9ea278Smvs default:
5310b9ea278Smvs return (ENOTTY);
5320b9ea278Smvs }
5330b9ea278Smvs
534f0d16c93Smvs /* XXXSMP: enforce lock order */
535f0d16c93Smvs NET_UNLOCK();
5360b9ea278Smvs rw_enter_write(&sc->sc_lock);
5370b9ea278Smvs
5380b9ea278Smvs if (sc->sc_dying) {
5390b9ea278Smvs error = ENXIO;
5400b9ea278Smvs goto out;
5410b9ea278Smvs }
5420b9ea278Smvs
5430b9ea278Smvs switch (cmd) {
5440b9ea278Smvs case SIOCSIFADDR:
5450b9ea278Smvs case SIOCSIFDSTADDR:
5460b9ea278Smvs case SIOCSIFFLAGS:
547f0d16c93Smvs NET_LOCK();
548c97a905aSflorian if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
54918ae10f7Shenning ifp->if_flags |= IFF_RUNNING;
550339bbf62Smvs mtx_enter(&sc->sc_mtx);
551fa1d79b8Sbenno /* send templates on startup */
5528818ef4eSbenno if (sc->sc_version == PFLOW_PROTO_10)
553fa1d79b8Sbenno pflow_sendout_ipfix_tmpl(sc);
554339bbf62Smvs mtx_leave(&sc->sc_mtx);
55541cbda0dSgollo } else
55618ae10f7Shenning ifp->if_flags &= ~IFF_RUNNING;
5570b9ea278Smvs NET_UNLOCK();
55818ae10f7Shenning break;
5590b9ea278Smvs
56018ae10f7Shenning case SIOCSIFMTU:
5610b9ea278Smvs if (ifr->ifr_mtu < PFLOW_MINMTU) {
5620b9ea278Smvs error = EINVAL;
5630b9ea278Smvs goto out;
5640b9ea278Smvs }
56518ae10f7Shenning if (ifr->ifr_mtu > MCLBYTES)
56618ae10f7Shenning ifr->ifr_mtu = MCLBYTES;
5670b9ea278Smvs NET_LOCK();
56818ae10f7Shenning if (ifr->ifr_mtu < ifp->if_mtu)
569fa1d79b8Sbenno pflow_flush(sc);
570339bbf62Smvs mtx_enter(&sc->sc_mtx);
57118ae10f7Shenning pflow_setmtu(sc, ifr->ifr_mtu);
572339bbf62Smvs mtx_leave(&sc->sc_mtx);
5730b9ea278Smvs NET_UNLOCK();
57418ae10f7Shenning break;
57518ae10f7Shenning
57618ae10f7Shenning case SIOCGETPFLOW:
57718ae10f7Shenning bzero(&pflowr, sizeof(pflowr));
57818ae10f7Shenning
5793baed77aSflorian if (sc->sc_flowsrc != NULL)
5803baed77aSflorian memcpy(&pflowr.flowsrc, sc->sc_flowsrc,
5813baed77aSflorian sc->sc_flowsrc->sa_len);
5823baed77aSflorian if (sc->sc_flowdst != NULL)
5833baed77aSflorian memcpy(&pflowr.flowdst, sc->sc_flowdst,
5843baed77aSflorian sc->sc_flowdst->sa_len);
585339bbf62Smvs mtx_enter(&sc->sc_mtx);
586fa1d79b8Sbenno pflowr.version = sc->sc_version;
587339bbf62Smvs mtx_leave(&sc->sc_mtx);
58818ae10f7Shenning
5890b9ea278Smvs if ((error = copyout(&pflowr, ifr->ifr_data, sizeof(pflowr))))
5900b9ea278Smvs goto out;
59118ae10f7Shenning break;
59218ae10f7Shenning
59318ae10f7Shenning case SIOCSETPFLOW:
5943e676399Smpi if ((error = suser(p)) != 0)
5950b9ea278Smvs goto out;
5960b9ea278Smvs if ((error = copyin(ifr->ifr_data, &pflowr, sizeof(pflowr))))
5970b9ea278Smvs goto out;
598fa1d79b8Sbenno
5994da5ea9aSmpi error = pflow_set(sc, &pflowr);
6000b9ea278Smvs if (error != 0)
6010b9ea278Smvs goto out;
60218ae10f7Shenning
6030b9ea278Smvs NET_LOCK();
604c97a905aSflorian if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
60518ae10f7Shenning ifp->if_flags |= IFF_RUNNING;
606339bbf62Smvs mtx_enter(&sc->sc_mtx);
6078818ef4eSbenno if (sc->sc_version == PFLOW_PROTO_10)
6084d8db378Sflorian pflow_sendout_ipfix_tmpl(sc);
609339bbf62Smvs mtx_leave(&sc->sc_mtx);
61041cbda0dSgollo } else
61118ae10f7Shenning ifp->if_flags &= ~IFF_RUNNING;
6120b9ea278Smvs NET_UNLOCK();
61318ae10f7Shenning
61418ae10f7Shenning break;
61518ae10f7Shenning }
6160b9ea278Smvs
6170b9ea278Smvs out:
6180b9ea278Smvs rw_exit_write(&sc->sc_lock);
6190b9ea278Smvs NET_LOCK();
6200b9ea278Smvs
6210b9ea278Smvs return (error);
62218ae10f7Shenning }
62318ae10f7Shenning
624fa1d79b8Sbenno int
pflow_calc_mtu(struct pflow_softc * sc,int mtu,int hdrsz)625fa1d79b8Sbenno pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
626fa1d79b8Sbenno {
62758354163Sflorian sc->sc_maxcount4 = (mtu - hdrsz -
62858354163Sflorian sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
62958354163Sflorian sc->sc_maxcount6 = (mtu - hdrsz -
63058354163Sflorian sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
631fa1d79b8Sbenno if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
632fa1d79b8Sbenno sc->sc_maxcount4 = PFLOW_MAXFLOWS;
633fa1d79b8Sbenno if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
634fa1d79b8Sbenno sc->sc_maxcount6 = PFLOW_MAXFLOWS;
63558354163Sflorian return (hdrsz + sizeof(struct udpiphdr) +
63658354163Sflorian MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
63758354163Sflorian sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
638fa1d79b8Sbenno }
639fa1d79b8Sbenno
640fa1d79b8Sbenno void
pflow_setmtu(struct pflow_softc * sc,int mtu_req)64118ae10f7Shenning pflow_setmtu(struct pflow_softc *sc, int mtu_req)
64218ae10f7Shenning {
64318ae10f7Shenning int mtu;
64418ae10f7Shenning
64518ae10f7Shenning mtu = mtu_req;
64618ae10f7Shenning
647fa1d79b8Sbenno switch (sc->sc_version) {
648fa1d79b8Sbenno case PFLOW_PROTO_5:
64988e5d322Sgollo sc->sc_maxcount = (mtu - sizeof(struct pflow_header) -
65088e5d322Sgollo sizeof(struct udpiphdr)) / sizeof(struct pflow_flow);
65118ae10f7Shenning if (sc->sc_maxcount > PFLOW_MAXFLOWS)
65218ae10f7Shenning sc->sc_maxcount = PFLOW_MAXFLOWS;
65318ae10f7Shenning sc->sc_if.if_mtu = sizeof(struct pflow_header) +
65488e5d322Sgollo sizeof(struct udpiphdr) +
65518ae10f7Shenning sc->sc_maxcount * sizeof(struct pflow_flow);
656fa1d79b8Sbenno break;
657fa1d79b8Sbenno case PFLOW_PROTO_10:
658fa1d79b8Sbenno sc->sc_if.if_mtu =
659fa1d79b8Sbenno pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header));
660fa1d79b8Sbenno break;
661fa1d79b8Sbenno default: /* NOTREACHED */
662fa1d79b8Sbenno break;
663fa1d79b8Sbenno }
66418ae10f7Shenning }
66518ae10f7Shenning
66618ae10f7Shenning struct mbuf *
pflow_get_mbuf(struct pflow_softc * sc,u_int16_t set_id)667fa1d79b8Sbenno pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id)
66818ae10f7Shenning {
669fa1d79b8Sbenno struct pflow_set_header set_hdr;
67088e5d322Sgollo struct pflow_header h;
67188e5d322Sgollo struct mbuf *m;
67218ae10f7Shenning
673339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
674339bbf62Smvs
67518ae10f7Shenning MGETHDR(m, M_DONTWAIT, MT_DATA);
67618ae10f7Shenning if (m == NULL) {
677ccf5da69Smvs pflowstat_inc(pflow_onomem);
67818ae10f7Shenning return (NULL);
67918ae10f7Shenning }
68018ae10f7Shenning
68118ae10f7Shenning MCLGET(m, M_DONTWAIT);
68288e5d322Sgollo if ((m->m_flags & M_EXT) == 0) {
68318ae10f7Shenning m_free(m);
684ccf5da69Smvs pflowstat_inc(pflow_onomem);
68518ae10f7Shenning return (NULL);
68618ae10f7Shenning }
68718ae10f7Shenning
68888e5d322Sgollo m->m_len = m->m_pkthdr.len = 0;
689fb492c37Smpi m->m_pkthdr.ph_ifidx = 0;
69018ae10f7Shenning
691fa1d79b8Sbenno if (sc == NULL) /* get only a new empty mbuf */
692fa1d79b8Sbenno return (m);
693fa1d79b8Sbenno
69410989718Sjasper switch (sc->sc_version) {
69510989718Sjasper case PFLOW_PROTO_5:
69618ae10f7Shenning /* populate pflow_header */
69788e5d322Sgollo h.reserved1 = 0;
69888e5d322Sgollo h.reserved2 = 0;
69988e5d322Sgollo h.count = 0;
700fa1d79b8Sbenno h.version = htons(PFLOW_PROTO_5);
70188e5d322Sgollo h.flow_sequence = htonl(sc->sc_gcounter);
70288e5d322Sgollo h.engine_type = PFLOW_ENGINE_TYPE;
70388e5d322Sgollo h.engine_id = PFLOW_ENGINE_ID;
70441b18b7eSblambert m_copyback(m, 0, PFLOW_HDRLEN, &h, M_NOWAIT);
70518ae10f7Shenning
70618ae10f7Shenning sc->sc_count = 0;
70718ae10f7Shenning timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
70810989718Sjasper break;
70910989718Sjasper case PFLOW_PROTO_10:
710fa1d79b8Sbenno /* populate pflow_set_header */
711fa1d79b8Sbenno set_hdr.set_length = 0;
712fa1d79b8Sbenno set_hdr.set_id = htons(set_id);
713fa1d79b8Sbenno m_copyback(m, 0, PFLOW_SET_HDRLEN, &set_hdr, M_NOWAIT);
71410989718Sjasper break;
71510989718Sjasper default: /* NOTREACHED */
71610989718Sjasper break;
717fa1d79b8Sbenno }
718fa1d79b8Sbenno
71988e5d322Sgollo return (m);
72018ae10f7Shenning }
72118ae10f7Shenning
72218ae10f7Shenning void
copy_flow_data(struct pflow_flow * flow1,struct pflow_flow * flow2,struct pf_state * st,struct pf_state_key * sk,int src,int dst)72318ae10f7Shenning copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2,
724c07294cfSflorian struct pf_state *st, struct pf_state_key *sk, int src, int dst)
72518ae10f7Shenning {
72688e5d322Sgollo flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
72788e5d322Sgollo flow1->src_port = flow2->dest_port = sk->port[src];
72888e5d322Sgollo flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
72988e5d322Sgollo flow1->dest_port = flow2->src_port = sk->port[dst];
73018ae10f7Shenning
73118ae10f7Shenning flow1->dest_as = flow2->src_as =
73218ae10f7Shenning flow1->src_as = flow2->dest_as = 0;
7336e55bf81Sflorian flow1->if_index_in = htons(st->if_index_in);
7346e55bf81Sflorian flow1->if_index_out = htons(st->if_index_out);
7356e55bf81Sflorian flow2->if_index_in = htons(st->if_index_out);
7366e55bf81Sflorian flow2->if_index_out = htons(st->if_index_in);
73718ae10f7Shenning flow1->dest_mask = flow2->src_mask =
73818ae10f7Shenning flow1->src_mask = flow2->dest_mask = 0;
73918ae10f7Shenning
74018ae10f7Shenning flow1->flow_packets = htonl(st->packets[0]);
74118ae10f7Shenning flow2->flow_packets = htonl(st->packets[1]);
74218ae10f7Shenning flow1->flow_octets = htonl(st->bytes[0]);
74318ae10f7Shenning flow2->flow_octets = htonl(st->bytes[1]);
74418ae10f7Shenning
7455e6d0011Sflorian /*
7465e6d0011Sflorian * Pretend the flow was created or expired when the machine came up
7475e6d0011Sflorian * when creation is in the future of the last time a package was seen
7485e6d0011Sflorian * or was created / expired before this machine came up due to pfsync.
7495e6d0011Sflorian */
7505e6d0011Sflorian flow1->flow_start = flow2->flow_start = st->creation < 0 ||
7515e6d0011Sflorian st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000);
7525e6d0011Sflorian flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) :
7535e6d0011Sflorian htonl(st->expire * 1000);
75418ae10f7Shenning flow1->tcp_flags = flow2->tcp_flags = 0;
75518ae10f7Shenning flow1->protocol = flow2->protocol = sk->proto;
75618ae10f7Shenning flow1->tos = flow2->tos = st->rule.ptr->tos;
75718ae10f7Shenning }
75818ae10f7Shenning
759fa1d79b8Sbenno void
copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 * flow1,struct pflow_ipfix_flow4 * flow2,struct pf_state * st,struct pf_state_key * sk,struct pflow_softc * sc,int src,int dst)76058354163Sflorian copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1,
76158354163Sflorian struct pflow_ipfix_flow4 *flow2, struct pf_state *st,
76258354163Sflorian struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
76358354163Sflorian {
76458354163Sflorian flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
76558354163Sflorian flow1->src_port = flow2->dest_port = sk->port[src];
76658354163Sflorian flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
76758354163Sflorian flow1->dest_port = flow2->src_port = sk->port[dst];
76858354163Sflorian
76958354163Sflorian flow1->if_index_in = htonl(st->if_index_in);
77058354163Sflorian flow1->if_index_out = htonl(st->if_index_out);
77158354163Sflorian flow2->if_index_in = htonl(st->if_index_out);
77258354163Sflorian flow2->if_index_out = htonl(st->if_index_in);
77358354163Sflorian
77458354163Sflorian flow1->flow_packets = htobe64(st->packets[0]);
77558354163Sflorian flow2->flow_packets = htobe64(st->packets[1]);
77658354163Sflorian flow1->flow_octets = htobe64(st->bytes[0]);
77758354163Sflorian flow2->flow_octets = htobe64(st->bytes[1]);
77858354163Sflorian
77958354163Sflorian /*
78058354163Sflorian * Pretend the flow was created when the machine came up when creation
78158354163Sflorian * is in the future of the last time a package was seen due to pfsync.
78258354163Sflorian */
78358354163Sflorian if (st->creation > st->expire)
7843209772dScheloha flow1->flow_start = flow2->flow_start = htobe64((gettime() -
7853209772dScheloha getuptime())*1000);
78658354163Sflorian else
7873209772dScheloha flow1->flow_start = flow2->flow_start = htobe64((gettime() -
7883209772dScheloha (getuptime() - st->creation))*1000);
7893209772dScheloha flow1->flow_finish = flow2->flow_finish = htobe64((gettime() -
7903209772dScheloha (getuptime() - st->expire))*1000);
79158354163Sflorian
79258354163Sflorian flow1->protocol = flow2->protocol = sk->proto;
79358354163Sflorian flow1->tos = flow2->tos = st->rule.ptr->tos;
79458354163Sflorian }
79558354163Sflorian
79658354163Sflorian void
copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 * flow1,struct pflow_ipfix_flow6 * flow2,struct pf_state * st,struct pf_state_key * sk,struct pflow_softc * sc,int src,int dst)79758354163Sflorian copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1,
79858354163Sflorian struct pflow_ipfix_flow6 *flow2, struct pf_state *st,
79958354163Sflorian struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
80058354163Sflorian {
80158354163Sflorian bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip));
80258354163Sflorian bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip));
80358354163Sflorian flow1->src_port = flow2->dest_port = sk->port[src];
80458354163Sflorian bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip));
80558354163Sflorian bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip));
80658354163Sflorian flow1->dest_port = flow2->src_port = sk->port[dst];
80758354163Sflorian
80858354163Sflorian flow1->if_index_in = htonl(st->if_index_in);
80958354163Sflorian flow1->if_index_out = htonl(st->if_index_out);
81058354163Sflorian flow2->if_index_in = htonl(st->if_index_out);
81158354163Sflorian flow2->if_index_out = htonl(st->if_index_in);
81258354163Sflorian
81358354163Sflorian flow1->flow_packets = htobe64(st->packets[0]);
81458354163Sflorian flow2->flow_packets = htobe64(st->packets[1]);
81558354163Sflorian flow1->flow_octets = htobe64(st->bytes[0]);
81658354163Sflorian flow2->flow_octets = htobe64(st->bytes[1]);
81758354163Sflorian
81858354163Sflorian /*
81958354163Sflorian * Pretend the flow was created when the machine came up when creation
82058354163Sflorian * is in the future of the last time a package was seen due to pfsync.
82158354163Sflorian */
82258354163Sflorian if (st->creation > st->expire)
8233209772dScheloha flow1->flow_start = flow2->flow_start = htobe64((gettime() -
8243209772dScheloha getuptime())*1000);
82558354163Sflorian else
8263209772dScheloha flow1->flow_start = flow2->flow_start = htobe64((gettime() -
8273209772dScheloha (getuptime() - st->creation))*1000);
8283209772dScheloha flow1->flow_finish = flow2->flow_finish = htobe64((gettime() -
8293209772dScheloha (getuptime() - st->expire))*1000);
83058354163Sflorian
831fa1d79b8Sbenno flow1->protocol = flow2->protocol = sk->proto;
832fa1d79b8Sbenno flow1->tos = flow2->tos = st->rule.ptr->tos;
833fa1d79b8Sbenno }
834fa1d79b8Sbenno
83518ae10f7Shenning int
export_pflow(struct pf_state * st)83618ae10f7Shenning export_pflow(struct pf_state *st)
83718ae10f7Shenning {
838d9bf6ab7Sgollo struct pflow_softc *sc = NULL;
839c07294cfSflorian struct pf_state_key *sk;
840c07294cfSflorian
841c07294cfSflorian sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK];
84288e5d322Sgollo
84363a0cdecSmvs SMR_SLIST_FOREACH(sc, &pflowif_list, sc_next) {
844339bbf62Smvs mtx_enter(&sc->sc_mtx);
845fa1d79b8Sbenno switch (sc->sc_version) {
846fa1d79b8Sbenno case PFLOW_PROTO_5:
847fa1d79b8Sbenno if (sk->af == AF_INET)
848c07294cfSflorian export_pflow_if(st, sk, sc);
849fa1d79b8Sbenno break;
850ab60931cSflorian case PFLOW_PROTO_10:
851fa1d79b8Sbenno if (sk->af == AF_INET || sk->af == AF_INET6)
852c07294cfSflorian export_pflow_if(st, sk, sc);
853fa1d79b8Sbenno break;
854fa1d79b8Sbenno default: /* NOTREACHED */
855fa1d79b8Sbenno break;
856fa1d79b8Sbenno }
857339bbf62Smvs mtx_leave(&sc->sc_mtx);
858d9bf6ab7Sgollo }
859d9bf6ab7Sgollo
860d9bf6ab7Sgollo return (0);
861d9bf6ab7Sgollo }
862d9bf6ab7Sgollo
863d9bf6ab7Sgollo int
export_pflow_if(struct pf_state * st,struct pf_state_key * sk,struct pflow_softc * sc)864c07294cfSflorian export_pflow_if(struct pf_state *st, struct pf_state_key *sk,
865c07294cfSflorian struct pflow_softc *sc)
866d9bf6ab7Sgollo {
86718ae10f7Shenning struct pf_state pfs_copy;
86888e5d322Sgollo struct ifnet *ifp = &sc->sc_if;
86918ae10f7Shenning u_int64_t bytes[2];
87018ae10f7Shenning int ret = 0;
87118ae10f7Shenning
872d9bf6ab7Sgollo if (!(ifp->if_flags & IFF_RUNNING))
87318ae10f7Shenning return (0);
87418ae10f7Shenning
87558354163Sflorian if (sc->sc_version == PFLOW_PROTO_10)
876c07294cfSflorian return (pflow_pack_flow_ipfix(st, sk, sc));
877fa1d79b8Sbenno
878fa1d79b8Sbenno /* PFLOW_PROTO_5 */
87918ae10f7Shenning if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
88018ae10f7Shenning && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES))
881c07294cfSflorian return (pflow_pack_flow(st, sk, sc));
88218ae10f7Shenning
88318ae10f7Shenning /* flow > PFLOW_MAXBYTES need special handling */
88418ae10f7Shenning bcopy(st, &pfs_copy, sizeof(pfs_copy));
88518ae10f7Shenning bytes[0] = pfs_copy.bytes[0];
88618ae10f7Shenning bytes[1] = pfs_copy.bytes[1];
88718ae10f7Shenning
88818ae10f7Shenning while (bytes[0] > PFLOW_MAXBYTES) {
88918ae10f7Shenning pfs_copy.bytes[0] = PFLOW_MAXBYTES;
89018ae10f7Shenning pfs_copy.bytes[1] = 0;
89118ae10f7Shenning
892c07294cfSflorian if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
89318ae10f7Shenning return (ret);
89418ae10f7Shenning if ((bytes[0] - PFLOW_MAXBYTES) > 0)
89518ae10f7Shenning bytes[0] -= PFLOW_MAXBYTES;
89618ae10f7Shenning }
89718ae10f7Shenning
89818ae10f7Shenning while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) {
89918ae10f7Shenning pfs_copy.bytes[1] = PFLOW_MAXBYTES;
90018ae10f7Shenning pfs_copy.bytes[0] = 0;
90118ae10f7Shenning
902c07294cfSflorian if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
90318ae10f7Shenning return (ret);
90418ae10f7Shenning if ((bytes[1] - PFLOW_MAXBYTES) > 0)
90518ae10f7Shenning bytes[1] -= PFLOW_MAXBYTES;
90618ae10f7Shenning }
90718ae10f7Shenning
90818ae10f7Shenning pfs_copy.bytes[0] = bytes[0];
90918ae10f7Shenning pfs_copy.bytes[1] = bytes[1];
91018ae10f7Shenning
911c07294cfSflorian return (pflow_pack_flow(&pfs_copy, sk, sc));
91218ae10f7Shenning }
91318ae10f7Shenning
91418ae10f7Shenning int
copy_flow_to_m(struct pflow_flow * flow,struct pflow_softc * sc)91588e5d322Sgollo copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc)
91618ae10f7Shenning {
9178818ef4eSbenno int ret = 0;
91818ae10f7Shenning
919339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
920339bbf62Smvs
92118ae10f7Shenning if (sc->sc_mbuf == NULL) {
9228818ef4eSbenno if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL)
92388e5d322Sgollo return (ENOBUFS);
92418ae10f7Shenning }
92588e5d322Sgollo m_copyback(sc->sc_mbuf, PFLOW_HDRLEN +
92688e5d322Sgollo (sc->sc_count * sizeof(struct pflow_flow)),
92741b18b7eSblambert sizeof(struct pflow_flow), flow, M_NOWAIT);
92818ae10f7Shenning
929ccf5da69Smvs pflowstat_inc(pflow_flows);
93018ae10f7Shenning sc->sc_gcounter++;
93118ae10f7Shenning sc->sc_count++;
93218ae10f7Shenning
93388e5d322Sgollo if (sc->sc_count >= sc->sc_maxcount)
934fa1d79b8Sbenno ret = pflow_sendout_v5(sc);
935fa1d79b8Sbenno
936fa1d79b8Sbenno return(ret);
937fa1d79b8Sbenno }
938fa1d79b8Sbenno
939fa1d79b8Sbenno int
copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 * flow,struct pflow_softc * sc)94058354163Sflorian copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc)
94158354163Sflorian {
9428818ef4eSbenno int ret = 0;
94358354163Sflorian
944339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
945339bbf62Smvs
94658354163Sflorian if (sc->sc_mbuf == NULL) {
94758354163Sflorian if ((sc->sc_mbuf =
94858354163Sflorian pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) {
94958354163Sflorian return (ENOBUFS);
95058354163Sflorian }
95158354163Sflorian sc->sc_count4 = 0;
95258354163Sflorian timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
95358354163Sflorian }
95458354163Sflorian m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN +
95558354163Sflorian (sc->sc_count4 * sizeof(struct pflow_ipfix_flow4)),
95658354163Sflorian sizeof(struct pflow_ipfix_flow4), flow, M_NOWAIT);
957fa1d79b8Sbenno
958ccf5da69Smvs pflowstat_inc(pflow_flows);
959fa1d79b8Sbenno sc->sc_gcounter++;
960fa1d79b8Sbenno sc->sc_count4++;
961fa1d79b8Sbenno
962fa1d79b8Sbenno if (sc->sc_count4 >= sc->sc_maxcount4)
963fa1d79b8Sbenno ret = pflow_sendout_ipfix(sc, AF_INET);
964fa1d79b8Sbenno return(ret);
965fa1d79b8Sbenno }
966fa1d79b8Sbenno
967fa1d79b8Sbenno int
copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 * flow,struct pflow_softc * sc)96858354163Sflorian copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc)
969fa1d79b8Sbenno {
9708818ef4eSbenno int ret = 0;
971fa1d79b8Sbenno
972339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
973339bbf62Smvs
974fa1d79b8Sbenno if (sc->sc_mbuf6 == NULL) {
975fa1d79b8Sbenno if ((sc->sc_mbuf6 =
97658354163Sflorian pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) {
977fa1d79b8Sbenno return (ENOBUFS);
978fa1d79b8Sbenno }
979fa1d79b8Sbenno sc->sc_count6 = 0;
980fa1d79b8Sbenno timeout_add_sec(&sc->sc_tmo6, PFLOW_TIMEOUT);
981fa1d79b8Sbenno }
982fa1d79b8Sbenno m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN +
98358354163Sflorian (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)),
98458354163Sflorian sizeof(struct pflow_ipfix_flow6), flow, M_NOWAIT);
985fa1d79b8Sbenno
986ccf5da69Smvs pflowstat_inc(pflow_flows);
987fa1d79b8Sbenno sc->sc_gcounter++;
988fa1d79b8Sbenno sc->sc_count6++;
989fa1d79b8Sbenno
990fa1d79b8Sbenno if (sc->sc_count6 >= sc->sc_maxcount6)
991fa1d79b8Sbenno ret = pflow_sendout_ipfix(sc, AF_INET6);
99288e5d322Sgollo
99388e5d322Sgollo return(ret);
99488e5d322Sgollo }
99588e5d322Sgollo
99688e5d322Sgollo int
pflow_pack_flow(struct pf_state * st,struct pf_state_key * sk,struct pflow_softc * sc)997c07294cfSflorian pflow_pack_flow(struct pf_state *st, struct pf_state_key *sk,
998c07294cfSflorian struct pflow_softc *sc)
99988e5d322Sgollo {
100088e5d322Sgollo struct pflow_flow flow1;
100188e5d322Sgollo struct pflow_flow flow2;
100288e5d322Sgollo int ret = 0;
100388e5d322Sgollo
100488e5d322Sgollo bzero(&flow1, sizeof(flow1));
100518ae10f7Shenning bzero(&flow2, sizeof(flow2));
100618ae10f7Shenning
100718ae10f7Shenning if (st->direction == PF_OUT)
1008c07294cfSflorian copy_flow_data(&flow1, &flow2, st, sk, 1, 0);
100918ae10f7Shenning else
1010c07294cfSflorian copy_flow_data(&flow1, &flow2, st, sk, 0, 1);
101118ae10f7Shenning
101288e5d322Sgollo if (st->bytes[0] != 0) /* first flow from state */
101388e5d322Sgollo ret = copy_flow_to_m(&flow1, sc);
101418ae10f7Shenning
101588e5d322Sgollo if (st->bytes[1] != 0) /* second flow from state */
101688e5d322Sgollo ret = copy_flow_to_m(&flow2, sc);
101718ae10f7Shenning
101818ae10f7Shenning return (ret);
101918ae10f7Shenning }
102018ae10f7Shenning
1021fa1d79b8Sbenno int
pflow_pack_flow_ipfix(struct pf_state * st,struct pf_state_key * sk,struct pflow_softc * sc)102258354163Sflorian pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk,
102358354163Sflorian struct pflow_softc *sc)
102458354163Sflorian {
102558354163Sflorian struct pflow_ipfix_flow4 flow4_1, flow4_2;
102658354163Sflorian struct pflow_ipfix_flow6 flow6_1, flow6_2;
102758354163Sflorian int ret = 0;
102858354163Sflorian if (sk->af == AF_INET) {
102958354163Sflorian bzero(&flow4_1, sizeof(flow4_1));
103058354163Sflorian bzero(&flow4_2, sizeof(flow4_2));
103158354163Sflorian
103258354163Sflorian if (st->direction == PF_OUT)
103358354163Sflorian copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
103458354163Sflorian 1, 0);
103558354163Sflorian else
103658354163Sflorian copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
103758354163Sflorian 0, 1);
103858354163Sflorian
103958354163Sflorian if (st->bytes[0] != 0) /* first flow from state */
104058354163Sflorian ret = copy_flow_ipfix_4_to_m(&flow4_1, sc);
104158354163Sflorian
104258354163Sflorian if (st->bytes[1] != 0) /* second flow from state */
104358354163Sflorian ret = copy_flow_ipfix_4_to_m(&flow4_2, sc);
104458354163Sflorian } else if (sk->af == AF_INET6) {
104558354163Sflorian bzero(&flow6_1, sizeof(flow6_1));
104658354163Sflorian bzero(&flow6_2, sizeof(flow6_2));
104758354163Sflorian
104858354163Sflorian if (st->direction == PF_OUT)
104958354163Sflorian copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
105058354163Sflorian 1, 0);
105158354163Sflorian else
105258354163Sflorian copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
105358354163Sflorian 0, 1);
105458354163Sflorian
105558354163Sflorian if (st->bytes[0] != 0) /* first flow from state */
105658354163Sflorian ret = copy_flow_ipfix_6_to_m(&flow6_1, sc);
105758354163Sflorian
105858354163Sflorian if (st->bytes[1] != 0) /* second flow from state */
105958354163Sflorian ret = copy_flow_ipfix_6_to_m(&flow6_2, sc);
1060fa1d79b8Sbenno }
1061fa1d79b8Sbenno return (ret);
1062fa1d79b8Sbenno }
1063fa1d79b8Sbenno
106418ae10f7Shenning void
pflow_timeout(void * v)106518ae10f7Shenning pflow_timeout(void *v)
106618ae10f7Shenning {
106718ae10f7Shenning struct pflow_softc *sc = v;
106818ae10f7Shenning
1069339bbf62Smvs mtx_enter(&sc->sc_mtx);
1070fa1d79b8Sbenno switch (sc->sc_version) {
1071fa1d79b8Sbenno case PFLOW_PROTO_5:
1072fa1d79b8Sbenno pflow_sendout_v5(sc);
1073fa1d79b8Sbenno break;
1074fa1d79b8Sbenno case PFLOW_PROTO_10:
1075fa1d79b8Sbenno pflow_sendout_ipfix(sc, AF_INET);
107658354163Sflorian break;
1077fa1d79b8Sbenno default: /* NOTREACHED */
1078fa1d79b8Sbenno break;
1079fa1d79b8Sbenno }
1080339bbf62Smvs mtx_leave(&sc->sc_mtx);
1081fa1d79b8Sbenno }
1082fa1d79b8Sbenno
1083fa1d79b8Sbenno void
pflow_timeout6(void * v)1084fa1d79b8Sbenno pflow_timeout6(void *v)
1085fa1d79b8Sbenno {
1086fa1d79b8Sbenno struct pflow_softc *sc = v;
1087fa1d79b8Sbenno
1088339bbf62Smvs mtx_enter(&sc->sc_mtx);
1089fa1d79b8Sbenno pflow_sendout_ipfix(sc, AF_INET6);
1090339bbf62Smvs mtx_leave(&sc->sc_mtx);
1091fa1d79b8Sbenno }
1092fa1d79b8Sbenno
1093fa1d79b8Sbenno void
pflow_timeout_tmpl(void * v)1094fa1d79b8Sbenno pflow_timeout_tmpl(void *v)
1095fa1d79b8Sbenno {
1096fa1d79b8Sbenno struct pflow_softc *sc = v;
1097fa1d79b8Sbenno
1098339bbf62Smvs mtx_enter(&sc->sc_mtx);
1099fa1d79b8Sbenno pflow_sendout_ipfix_tmpl(sc);
1100339bbf62Smvs mtx_leave(&sc->sc_mtx);
110118ae10f7Shenning }
110218ae10f7Shenning
1103fa1d79b8Sbenno void
pflow_flush(struct pflow_softc * sc)1104fa1d79b8Sbenno pflow_flush(struct pflow_softc *sc)
1105fa1d79b8Sbenno {
1106339bbf62Smvs mtx_enter(&sc->sc_mtx);
1107fa1d79b8Sbenno switch (sc->sc_version) {
1108fa1d79b8Sbenno case PFLOW_PROTO_5:
1109fa1d79b8Sbenno pflow_sendout_v5(sc);
1110fa1d79b8Sbenno break;
1111fa1d79b8Sbenno case PFLOW_PROTO_10:
1112fa1d79b8Sbenno pflow_sendout_ipfix(sc, AF_INET);
1113fa1d79b8Sbenno pflow_sendout_ipfix(sc, AF_INET6);
1114fa1d79b8Sbenno break;
1115fa1d79b8Sbenno default: /* NOTREACHED */
1116fa1d79b8Sbenno break;
1117fa1d79b8Sbenno }
1118339bbf62Smvs mtx_leave(&sc->sc_mtx);
1119fa1d79b8Sbenno }
1120fa1d79b8Sbenno
112118ae10f7Shenning int
pflow_sendout_v5(struct pflow_softc * sc)1122fa1d79b8Sbenno pflow_sendout_v5(struct pflow_softc *sc)
112318ae10f7Shenning {
11249e200726Sgollo struct mbuf *m = sc->sc_mbuf;
112518ae10f7Shenning struct pflow_header *h;
112618ae10f7Shenning struct ifnet *ifp = &sc->sc_if;
11277ea7180bSdlg struct timespec tv;
112818ae10f7Shenning
1129339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1130339bbf62Smvs
113118ae10f7Shenning timeout_del(&sc->sc_tmo);
113218ae10f7Shenning
11339e200726Sgollo if (m == NULL)
113418ae10f7Shenning return (0);
113518ae10f7Shenning
11369e200726Sgollo sc->sc_mbuf = NULL;
113718ae10f7Shenning if (!(ifp->if_flags & IFF_RUNNING)) {
113818ae10f7Shenning m_freem(m);
113918ae10f7Shenning return (0);
114018ae10f7Shenning }
114118ae10f7Shenning
1142ccf5da69Smvs pflowstat_inc(pflow_packets);
114318ae10f7Shenning h = mtod(m, struct pflow_header *);
114418ae10f7Shenning h->count = htons(sc->sc_count);
114518ae10f7Shenning
114618ae10f7Shenning /* populate pflow_header */
11473209772dScheloha h->uptime_ms = htonl(getuptime() * 1000);
11487ea7180bSdlg
11497ea7180bSdlg getnanotime(&tv);
115058354163Sflorian h->time_sec = htonl(tv.tv_sec); /* XXX 2038 */
11517ea7180bSdlg h->time_nanosec = htonl(tv.tv_nsec);
1152b52009cbSvisa if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
115393865884Ssashan task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
11548818ef4eSbenno return (0);
115518ae10f7Shenning }
115618ae10f7Shenning
1157fa1d79b8Sbenno int
pflow_sendout_ipfix(struct pflow_softc * sc,sa_family_t af)115858354163Sflorian pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
115958354163Sflorian {
116058354163Sflorian struct mbuf *m;
116158354163Sflorian struct pflow_v10_header *h10;
116258354163Sflorian struct pflow_set_header *set_hdr;
116358354163Sflorian struct ifnet *ifp = &sc->sc_if;
1164990339f0Sblambert u_int32_t count;
116558354163Sflorian int set_length;
116658354163Sflorian
1167339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1168339bbf62Smvs
116958354163Sflorian switch (af) {
117058354163Sflorian case AF_INET:
117158354163Sflorian m = sc->sc_mbuf;
117258354163Sflorian timeout_del(&sc->sc_tmo);
117358354163Sflorian if (m == NULL)
117458354163Sflorian return (0);
117558354163Sflorian sc->sc_mbuf = NULL;
1176990339f0Sblambert count = sc->sc_count4;
117758354163Sflorian set_length = sizeof(struct pflow_set_header)
117858354163Sflorian + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
1179fa1d79b8Sbenno break;
118058354163Sflorian case AF_INET6:
118158354163Sflorian m = sc->sc_mbuf6;
118258354163Sflorian timeout_del(&sc->sc_tmo6);
118358354163Sflorian if (m == NULL)
118458354163Sflorian return (0);
118558354163Sflorian sc->sc_mbuf6 = NULL;
1186990339f0Sblambert count = sc->sc_count6;
118758354163Sflorian set_length = sizeof(struct pflow_set_header)
118858354163Sflorian + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
118958354163Sflorian break;
1190ba413839Sjsg default:
1191ba413839Sjsg unhandled_af(af);
119258354163Sflorian }
119358354163Sflorian
119458354163Sflorian if (!(ifp->if_flags & IFF_RUNNING)) {
119558354163Sflorian m_freem(m);
119658354163Sflorian return (0);
119758354163Sflorian }
119858354163Sflorian
1199ccf5da69Smvs pflowstat_inc(pflow_packets);
120058354163Sflorian set_hdr = mtod(m, struct pflow_set_header *);
120158354163Sflorian set_hdr->set_length = htons(set_length);
120258354163Sflorian
1203fa1d79b8Sbenno /* populate pflow_header */
1204fa1d79b8Sbenno M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
1205fa1d79b8Sbenno if (m == NULL) {
1206ccf5da69Smvs pflowstat_inc(pflow_onomem);
1207fa1d79b8Sbenno return (ENOBUFS);
1208fa1d79b8Sbenno }
1209fa1d79b8Sbenno h10 = mtod(m, struct pflow_v10_header *);
1210fa1d79b8Sbenno h10->version = htons(PFLOW_PROTO_10);
121158354163Sflorian h10->length = htons(PFLOW_IPFIX_HDRLEN + set_length);
12123209772dScheloha h10->time_sec = htonl(gettime()); /* XXX 2038 */
1213990339f0Sblambert h10->flow_sequence = htonl(sc->sc_sequence);
1214990339f0Sblambert sc->sc_sequence += count;
1215fa1d79b8Sbenno h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
1216b52009cbSvisa if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
121793865884Ssashan task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
12188818ef4eSbenno return (0);
1219fa1d79b8Sbenno }
122058354163Sflorian
122158354163Sflorian int
pflow_sendout_ipfix_tmpl(struct pflow_softc * sc)1222fa1d79b8Sbenno pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
1223fa1d79b8Sbenno {
1224fa1d79b8Sbenno struct mbuf *m;
1225fa1d79b8Sbenno struct pflow_v10_header *h10;
1226fa1d79b8Sbenno struct ifnet *ifp = &sc->sc_if;
1227fa1d79b8Sbenno
1228339bbf62Smvs MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
1229339bbf62Smvs
1230fa1d79b8Sbenno timeout_del(&sc->sc_tmo_tmpl);
1231fa1d79b8Sbenno
1232fa1d79b8Sbenno if (!(ifp->if_flags & IFF_RUNNING)) {
1233fa1d79b8Sbenno return (0);
1234fa1d79b8Sbenno }
1235339bbf62Smvs m = pflow_get_mbuf(sc, 0);
1236fa1d79b8Sbenno if (m == NULL)
1237fa1d79b8Sbenno return (0);
123858354163Sflorian if (m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl),
123958354163Sflorian &sc->sc_tmpl_ipfix, M_NOWAIT)) {
1240fa1d79b8Sbenno m_freem(m);
1241fa1d79b8Sbenno return (0);
1242fa1d79b8Sbenno }
1243ccf5da69Smvs pflowstat_inc(pflow_packets);
124458354163Sflorian
1245fa1d79b8Sbenno /* populate pflow_header */
1246fa1d79b8Sbenno M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
1247fa1d79b8Sbenno if (m == NULL) {
1248ccf5da69Smvs pflowstat_inc(pflow_onomem);
1249fa1d79b8Sbenno return (ENOBUFS);
1250fa1d79b8Sbenno }
1251fa1d79b8Sbenno h10 = mtod(m, struct pflow_v10_header *);
1252fa1d79b8Sbenno h10->version = htons(PFLOW_PROTO_10);
125358354163Sflorian h10->length = htons(PFLOW_IPFIX_HDRLEN + sizeof(struct
125458354163Sflorian pflow_ipfix_tmpl));
12553209772dScheloha h10->time_sec = htonl(gettime()); /* XXX 2038 */
1256990339f0Sblambert h10->flow_sequence = htonl(sc->sc_sequence);
1257fa1d79b8Sbenno h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
125858354163Sflorian
1259fa1d79b8Sbenno timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
1260b52009cbSvisa if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
126193865884Ssashan task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
12628818ef4eSbenno return (0);
1263fa1d79b8Sbenno }
1264fa1d79b8Sbenno
126518ae10f7Shenning int
pflow_sendout_mbuf(struct pflow_softc * sc,struct mbuf * m)126618ae10f7Shenning pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
126718ae10f7Shenning {
1268339bbf62Smvs rw_assert_anylock(&sc->sc_lock);
1269339bbf62Smvs
1270f0d16c93Smvs counters_pkt(sc->sc_if.if_counters,
1271f0d16c93Smvs ifc_opackets, ifc_obytes, m->m_pkthdr.len);
127288e5d322Sgollo
1273416aa928Sflorian if (sc->so == NULL) {
1274416aa928Sflorian m_freem(m);
1275416aa928Sflorian return (EINVAL);
127688e5d322Sgollo }
1277416aa928Sflorian return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
127818ae10f7Shenning }
12790aaca726Sgollo
12800aaca726Sgollo int
pflow_sysctl(int * name,u_int namelen,void * oldp,size_t * oldlenp,void * newp,size_t newlen)12810aaca726Sgollo pflow_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
12820aaca726Sgollo void *newp, size_t newlen)
12830aaca726Sgollo {
12840aaca726Sgollo if (namelen != 1)
12850aaca726Sgollo return (ENOTDIR);
12860aaca726Sgollo
12870aaca726Sgollo switch (name[0]) {
1288ccf5da69Smvs case NET_PFLOW_STATS: {
1289ccf5da69Smvs uint64_t counters[pflow_ncounters];
1290ccf5da69Smvs struct pflowstats pflowstats;
1291ccf5da69Smvs
12920aaca726Sgollo if (newp != NULL)
12930aaca726Sgollo return (EPERM);
1294ccf5da69Smvs
1295ccf5da69Smvs counters_read(pflow_counters, counters, pflow_ncounters, NULL);
1296ccf5da69Smvs
1297ccf5da69Smvs pflowstats.pflow_flows = counters[pflow_flows];
1298ccf5da69Smvs pflowstats.pflow_packets = counters[pflow_packets];
1299ccf5da69Smvs pflowstats.pflow_onomem = counters[pflow_onomem];
1300ccf5da69Smvs pflowstats.pflow_oerrors = counters[pflow_oerrors];
1301ccf5da69Smvs
13020aaca726Sgollo return (sysctl_struct(oldp, oldlenp, newp, newlen,
13030aaca726Sgollo &pflowstats, sizeof(pflowstats)));
1304ccf5da69Smvs }
13050aaca726Sgollo default:
13060aaca726Sgollo return (EOPNOTSUPP);
13070aaca726Sgollo }
13080aaca726Sgollo return (0);
13090aaca726Sgollo }
1310