1f92d9b1aSKristof Provost /* $OpenBSD: if_pflow.c,v 1.100 2023/11/09 08:53:20 mvs Exp $ */ 2f92d9b1aSKristof Provost 3f92d9b1aSKristof Provost /* 4f92d9b1aSKristof Provost * Copyright (c) 2023 Rubicon Communications, LLC (Netgate) 5f92d9b1aSKristof Provost * Copyright (c) 2011 Florian Obser <florian@narrans.de> 6f92d9b1aSKristof Provost * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de> 7f92d9b1aSKristof Provost * Copyright (c) 2008 Henning Brauer <henning@openbsd.org> 8f92d9b1aSKristof Provost * Copyright (c) 2008 Joerg Goltermann <jg@osn.de> 9f92d9b1aSKristof Provost * 10f92d9b1aSKristof Provost * Permission to use, copy, modify, and distribute this software for any 11f92d9b1aSKristof Provost * purpose with or without fee is hereby granted, provided that the above 12f92d9b1aSKristof Provost * copyright notice and this permission notice appear in all copies. 13f92d9b1aSKristof Provost * 14f92d9b1aSKristof Provost * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 15f92d9b1aSKristof Provost * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 16f92d9b1aSKristof Provost * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 17f92d9b1aSKristof Provost * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18f92d9b1aSKristof Provost * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN 19f92d9b1aSKristof Provost * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20f92d9b1aSKristof Provost * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21f92d9b1aSKristof Provost */ 22f92d9b1aSKristof Provost 23f92d9b1aSKristof Provost #include <sys/cdefs.h> 24f92d9b1aSKristof Provost #include <sys/param.h> 25f92d9b1aSKristof Provost #include <sys/bus.h> 26f92d9b1aSKristof Provost #include <sys/callout.h> 27f92d9b1aSKristof Provost #include <sys/endian.h> 28f92d9b1aSKristof Provost #include <sys/interrupt.h> 29f92d9b1aSKristof Provost #include <sys/kernel.h> 30f92d9b1aSKristof Provost #include <sys/malloc.h> 31f92d9b1aSKristof Provost #include <sys/module.h> 32f92d9b1aSKristof Provost #include <sys/mbuf.h> 33f92d9b1aSKristof Provost #include <sys/socket.h> 34f92d9b1aSKristof Provost #include <sys/socketvar.h> 35f92d9b1aSKristof Provost #include <sys/sockio.h> 36f92d9b1aSKristof Provost #include <sys/sysctl.h> 37f92d9b1aSKristof Provost #include <sys/systm.h> 38f92d9b1aSKristof Provost #include <sys/priv.h> 39f92d9b1aSKristof Provost 40f92d9b1aSKristof Provost #include <net/if.h> 41f92d9b1aSKristof Provost #include <net/if_types.h> 42f92d9b1aSKristof Provost #include <net/bpf.h> 43f92d9b1aSKristof Provost #include <net/route.h> 44f92d9b1aSKristof Provost #include <netinet/in.h> 45f92d9b1aSKristof Provost #include <netinet/if_ether.h> 46f92d9b1aSKristof Provost #include <netinet/tcp.h> 47f92d9b1aSKristof Provost 48f92d9b1aSKristof Provost #include <netinet/ip.h> 49f92d9b1aSKristof Provost #include <netinet/ip_icmp.h> 50f92d9b1aSKristof Provost #include <netinet/ip_var.h> 51f92d9b1aSKristof Provost #include <netinet/udp.h> 52f92d9b1aSKristof Provost #include <netinet/udp_var.h> 53f92d9b1aSKristof Provost #include <netinet/in_pcb.h> 54f92d9b1aSKristof Provost 55f92d9b1aSKristof Provost #include <netlink/netlink.h> 56f92d9b1aSKristof Provost #include <netlink/netlink_ctl.h> 57f92d9b1aSKristof Provost #include <netlink/netlink_generic.h> 58f92d9b1aSKristof Provost #include <netlink/netlink_message_writer.h> 59f92d9b1aSKristof Provost 60f92d9b1aSKristof Provost #include <net/pfvar.h> 61f92d9b1aSKristof Provost #include <net/pflow.h> 62f92d9b1aSKristof Provost #include "net/if_var.h" 63f92d9b1aSKristof Provost 64f92d9b1aSKristof Provost #define PFLOW_MINMTU \ 65f92d9b1aSKristof Provost (sizeof(struct pflow_header) + sizeof(struct pflow_flow)) 66f92d9b1aSKristof Provost 67f92d9b1aSKristof Provost #ifdef PFLOWDEBUG 68f92d9b1aSKristof Provost #define DPRINTF(x) do { printf x ; } while (0) 69f92d9b1aSKristof Provost #else 70f92d9b1aSKristof Provost #define DPRINTF(x) 71f92d9b1aSKristof Provost #endif 72f92d9b1aSKristof Provost 73f92d9b1aSKristof Provost static void pflow_output_process(void *); 74f92d9b1aSKristof Provost static int pflow_create(int); 75f92d9b1aSKristof Provost static int pflow_destroy(int, bool); 76f92d9b1aSKristof Provost static int pflow_calc_mtu(struct pflow_softc *, int, int); 77f92d9b1aSKristof Provost static void pflow_setmtu(struct pflow_softc *, int); 78f92d9b1aSKristof Provost static int pflowvalidsockaddr(const struct sockaddr *, int); 79f92d9b1aSKristof Provost 80f92d9b1aSKristof Provost static struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t); 81f92d9b1aSKristof Provost static void pflow_flush(struct pflow_softc *); 82f92d9b1aSKristof Provost static int pflow_sendout_v5(struct pflow_softc *); 83f92d9b1aSKristof Provost static int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t); 84f92d9b1aSKristof Provost static int pflow_sendout_ipfix_tmpl(struct pflow_softc *); 85f92d9b1aSKristof Provost static int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *); 86f92d9b1aSKristof Provost static void pflow_timeout(void *); 87f92d9b1aSKristof Provost static void pflow_timeout6(void *); 88f92d9b1aSKristof Provost static void pflow_timeout_tmpl(void *); 89f92d9b1aSKristof Provost static void copy_flow_data(struct pflow_flow *, struct pflow_flow *, 90f92d9b1aSKristof Provost struct pf_kstate *, struct pf_state_key *, int, int); 91f92d9b1aSKristof Provost static void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *, 92f92d9b1aSKristof Provost struct pflow_ipfix_flow4 *, struct pf_kstate *, struct pf_state_key *, 93f92d9b1aSKristof Provost struct pflow_softc *, int, int); 94f92d9b1aSKristof Provost static void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *, 95f92d9b1aSKristof Provost struct pflow_ipfix_flow6 *, struct pf_kstate *, struct pf_state_key *, 96f92d9b1aSKristof Provost struct pflow_softc *, int, int); 97f92d9b1aSKristof Provost static int pflow_pack_flow(struct pf_kstate *, struct pf_state_key *, 98f92d9b1aSKristof Provost struct pflow_softc *); 99f92d9b1aSKristof Provost static int pflow_pack_flow_ipfix(struct pf_kstate *, struct pf_state_key *, 100f92d9b1aSKristof Provost struct pflow_softc *); 101f92d9b1aSKristof Provost static int export_pflow_if(struct pf_kstate*, struct pf_state_key *, 102f92d9b1aSKristof Provost struct pflow_softc *); 103f92d9b1aSKristof Provost static int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc); 104f92d9b1aSKristof Provost static int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, 105f92d9b1aSKristof Provost struct pflow_softc *sc); 106f92d9b1aSKristof Provost static int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, 107f92d9b1aSKristof Provost struct pflow_softc *sc); 108f92d9b1aSKristof Provost 109f92d9b1aSKristof Provost static const char pflowname[] = "pflow"; 110f92d9b1aSKristof Provost 111f92d9b1aSKristof Provost /** 112f92d9b1aSKristof Provost * Locking concept 113f92d9b1aSKristof Provost * 114f92d9b1aSKristof Provost * The list of pflow devices (V_pflowif_list) is managed through epoch. 115f92d9b1aSKristof Provost * It is safe to read the list without locking (while in NET_EPOCH). 116f92d9b1aSKristof Provost * There may only be one simultaneous modifier, hence we need V_pflow_list_mtx 117f92d9b1aSKristof Provost * on every add/delete. 118f92d9b1aSKristof Provost * 119f92d9b1aSKristof Provost * Each pflow interface protects its own data with the sc_lock mutex. 120f92d9b1aSKristof Provost * 121f92d9b1aSKristof Provost * We do not require any pf locks, and in fact expect to be called without 122f92d9b1aSKristof Provost * hashrow locks held. 123f92d9b1aSKristof Provost **/ 124f92d9b1aSKristof Provost 125f92d9b1aSKristof Provost VNET_DEFINE(struct unrhdr *, pflow_unr); 126f92d9b1aSKristof Provost #define V_pflow_unr VNET(pflow_unr) 127f92d9b1aSKristof Provost VNET_DEFINE(CK_LIST_HEAD(, pflow_softc), pflowif_list); 128f92d9b1aSKristof Provost #define V_pflowif_list VNET(pflowif_list) 129f92d9b1aSKristof Provost VNET_DEFINE(struct mtx, pflowif_list_mtx); 130f92d9b1aSKristof Provost #define V_pflowif_list_mtx VNET(pflowif_list_mtx) 131*5dea523bSKristof Provost VNET_DEFINE(struct pflowstats, pflowstat); 132*5dea523bSKristof Provost #define V_pflowstats VNET(pflowstat) 133f92d9b1aSKristof Provost 134f92d9b1aSKristof Provost #define PFLOW_LOCK(_sc) mtx_lock(&(_sc)->sc_lock) 135f92d9b1aSKristof Provost #define PFLOW_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_lock) 136f92d9b1aSKristof Provost #define PFLOW_ASSERT(_sc) mtx_assert(&(_sc)->sc_lock, MA_OWNED) 137f92d9b1aSKristof Provost 138*5dea523bSKristof Provost SYSCTL_NODE(_net, OID_AUTO, pflow, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 139*5dea523bSKristof Provost "PFLOW"); 140*5dea523bSKristof Provost SYSCTL_STRUCT(_net_pflow, OID_AUTO, stats, CTLFLAG_VNET | CTLFLAG_RW, 141*5dea523bSKristof Provost &VNET_NAME(pflowstat), pflowstats, 142*5dea523bSKristof Provost "PFLOW statistics (struct pflowstats, net/if_pflow.h)"); 143*5dea523bSKristof Provost 144f92d9b1aSKristof Provost static void 145f92d9b1aSKristof Provost vnet_pflowattach(void) 146f92d9b1aSKristof Provost { 147f92d9b1aSKristof Provost CK_LIST_INIT(&V_pflowif_list); 148f92d9b1aSKristof Provost mtx_init(&V_pflowif_list_mtx, "pflow interface list mtx", NULL, MTX_DEF); 149f92d9b1aSKristof Provost 150f92d9b1aSKristof Provost V_pflow_unr = new_unrhdr(0, INT_MAX, &V_pflowif_list_mtx); 151f92d9b1aSKristof Provost } 152f92d9b1aSKristof Provost VNET_SYSINIT(vnet_pflowattach, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY, 153f92d9b1aSKristof Provost vnet_pflowattach, NULL); 154f92d9b1aSKristof Provost 155f92d9b1aSKristof Provost static void 156f92d9b1aSKristof Provost vnet_pflowdetach(void) 157f92d9b1aSKristof Provost { 158f92d9b1aSKristof Provost struct pflow_softc *sc; 159f92d9b1aSKristof Provost 160f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 161f92d9b1aSKristof Provost pflow_destroy(sc->sc_id, false); 162f92d9b1aSKristof Provost } 163f92d9b1aSKristof Provost 164f92d9b1aSKristof Provost MPASS(CK_LIST_EMPTY(&V_pflowif_list)); 165f92d9b1aSKristof Provost delete_unrhdr(V_pflow_unr); 166f92d9b1aSKristof Provost mtx_destroy(&V_pflowif_list_mtx); 167f92d9b1aSKristof Provost } 168f92d9b1aSKristof Provost VNET_SYSUNINIT(vnet_pflowdetach, SI_SUB_PROTO_FIREWALL, SI_ORDER_FOURTH, 169f92d9b1aSKristof Provost vnet_pflowdetach, NULL); 170f92d9b1aSKristof Provost 171f92d9b1aSKristof Provost static void 172f92d9b1aSKristof Provost vnet_pflow_finalise(void) 173f92d9b1aSKristof Provost { 174f92d9b1aSKristof Provost /* 175f92d9b1aSKristof Provost * Ensure we've freed all interfaces, and do not have pending 176f92d9b1aSKristof Provost * epoch cleanup calls. 177f92d9b1aSKristof Provost */ 178f92d9b1aSKristof Provost NET_EPOCH_DRAIN_CALLBACKS(); 179f92d9b1aSKristof Provost } 180f92d9b1aSKristof Provost VNET_SYSUNINIT(vnet_pflow_finalise, SI_SUB_PROTO_FIREWALL, SI_ORDER_THIRD, 181f92d9b1aSKristof Provost vnet_pflow_finalise, NULL); 182f92d9b1aSKristof Provost 183f92d9b1aSKristof Provost static void 184f92d9b1aSKristof Provost pflow_output_process(void *arg) 185f92d9b1aSKristof Provost { 186f92d9b1aSKristof Provost struct mbufq ml; 187f92d9b1aSKristof Provost struct pflow_softc *sc = arg; 188f92d9b1aSKristof Provost struct mbuf *m; 189f92d9b1aSKristof Provost 190f92d9b1aSKristof Provost mbufq_init(&ml, 0); 191f92d9b1aSKristof Provost 192f92d9b1aSKristof Provost PFLOW_LOCK(sc); 193f92d9b1aSKristof Provost mbufq_concat(&ml, &sc->sc_outputqueue); 194f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 195f92d9b1aSKristof Provost 196f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 197f92d9b1aSKristof Provost while ((m = mbufq_dequeue(&ml)) != NULL) { 198f92d9b1aSKristof Provost pflow_sendout_mbuf(sc, m); 199f92d9b1aSKristof Provost } 200f92d9b1aSKristof Provost CURVNET_RESTORE(); 201f92d9b1aSKristof Provost } 202f92d9b1aSKristof Provost 203f92d9b1aSKristof Provost static int 204f92d9b1aSKristof Provost pflow_create(int unit) 205f92d9b1aSKristof Provost { 206f92d9b1aSKristof Provost struct pflow_softc *pflowif; 207f92d9b1aSKristof Provost int error; 208f92d9b1aSKristof Provost 209f92d9b1aSKristof Provost pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO); 210f92d9b1aSKristof Provost mtx_init(&pflowif->sc_lock, "pflowlk", NULL, MTX_DEF); 211f92d9b1aSKristof Provost pflowif->sc_version = PFLOW_PROTO_DEFAULT; 212f92d9b1aSKristof Provost 213f92d9b1aSKristof Provost /* ipfix template init */ 214f92d9b1aSKristof Provost bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix)); 215f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.set_header.set_id = 216f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_SET_ID); 217f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.set_header.set_length = 218f92d9b1aSKristof Provost htons(sizeof(struct pflow_ipfix_tmpl)); 219f92d9b1aSKristof Provost 220f92d9b1aSKristof Provost /* ipfix IPv4 template */ 221f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id = 222f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV4_ID); 223f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count 224f92d9b1aSKristof Provost = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT); 225f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id = 226f92d9b1aSKristof Provost htons(PFIX_IE_sourceIPv4Address); 227f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4); 228f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id = 229f92d9b1aSKristof Provost htons(PFIX_IE_destinationIPv4Address); 230f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4); 231f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id = 232f92d9b1aSKristof Provost htons(PFIX_IE_ingressInterface); 233f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4); 234f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id = 235f92d9b1aSKristof Provost htons(PFIX_IE_egressInterface); 236f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4); 237f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.field_id = 238f92d9b1aSKristof Provost htons(PFIX_IE_packetDeltaCount); 239f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8); 240f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id = 241f92d9b1aSKristof Provost htons(PFIX_IE_octetDeltaCount); 242f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8); 243f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id = 244f92d9b1aSKristof Provost htons(PFIX_IE_flowStartMilliseconds); 245f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8); 246f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id = 247f92d9b1aSKristof Provost htons(PFIX_IE_flowEndMilliseconds); 248f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8); 249f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.field_id = 250f92d9b1aSKristof Provost htons(PFIX_IE_sourceTransportPort); 251f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2); 252f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.field_id = 253f92d9b1aSKristof Provost htons(PFIX_IE_destinationTransportPort); 254f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2); 255f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.field_id = 256f92d9b1aSKristof Provost htons(PFIX_IE_ipClassOfService); 257f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1); 258f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id = 259f92d9b1aSKristof Provost htons(PFIX_IE_protocolIdentifier); 260f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1); 261f92d9b1aSKristof Provost 262f92d9b1aSKristof Provost /* ipfix IPv6 template */ 263f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id = 264f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV6_ID); 265f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count = 266f92d9b1aSKristof Provost htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT); 267f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id = 268f92d9b1aSKristof Provost htons(PFIX_IE_sourceIPv6Address); 269f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16); 270f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id = 271f92d9b1aSKristof Provost htons(PFIX_IE_destinationIPv6Address); 272f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16); 273f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id = 274f92d9b1aSKristof Provost htons(PFIX_IE_ingressInterface); 275f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4); 276f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id = 277f92d9b1aSKristof Provost htons(PFIX_IE_egressInterface); 278f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4); 279f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id = 280f92d9b1aSKristof Provost htons(PFIX_IE_packetDeltaCount); 281f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8); 282f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id = 283f92d9b1aSKristof Provost htons(PFIX_IE_octetDeltaCount); 284f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8); 285f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id = 286f92d9b1aSKristof Provost htons(PFIX_IE_flowStartMilliseconds); 287f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8); 288f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id = 289f92d9b1aSKristof Provost htons(PFIX_IE_flowEndMilliseconds); 290f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8); 291f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id = 292f92d9b1aSKristof Provost htons(PFIX_IE_sourceTransportPort); 293f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2); 294f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id = 295f92d9b1aSKristof Provost htons(PFIX_IE_destinationTransportPort); 296f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2); 297f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id = 298f92d9b1aSKristof Provost htons(PFIX_IE_ipClassOfService); 299f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1); 300f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id = 301f92d9b1aSKristof Provost htons(PFIX_IE_protocolIdentifier); 302f92d9b1aSKristof Provost pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1); 303f92d9b1aSKristof Provost 304f92d9b1aSKristof Provost pflowif->sc_id = unit; 305f92d9b1aSKristof Provost pflowif->sc_vnet = curvnet; 306f92d9b1aSKristof Provost 307f92d9b1aSKristof Provost mbufq_init(&pflowif->sc_outputqueue, 8192); 308f92d9b1aSKristof Provost pflow_setmtu(pflowif, ETHERMTU); 309f92d9b1aSKristof Provost 310f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo, &pflowif->sc_lock, 0); 311f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo6, &pflowif->sc_lock, 0); 312f92d9b1aSKristof Provost callout_init_mtx(&pflowif->sc_tmo_tmpl, &pflowif->sc_lock, 0); 313f92d9b1aSKristof Provost 314f92d9b1aSKristof Provost error = swi_add(&pflowif->sc_swi_ie, pflowname, pflow_output_process, 315f92d9b1aSKristof Provost pflowif, SWI_NET, INTR_MPSAFE, &pflowif->sc_swi_cookie); 316f92d9b1aSKristof Provost if (error) { 317f92d9b1aSKristof Provost free(pflowif, M_DEVBUF); 318f92d9b1aSKristof Provost return (error); 319f92d9b1aSKristof Provost } 320f92d9b1aSKristof Provost 321f92d9b1aSKristof Provost /* Insert into list of pflows */ 322f92d9b1aSKristof Provost mtx_lock(&V_pflowif_list_mtx); 323f92d9b1aSKristof Provost CK_LIST_INSERT_HEAD(&V_pflowif_list, pflowif, sc_next); 324f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 325f92d9b1aSKristof Provost 326f92d9b1aSKristof Provost return (0); 327f92d9b1aSKristof Provost } 328f92d9b1aSKristof Provost 329f92d9b1aSKristof Provost static void 330f92d9b1aSKristof Provost pflow_free_cb(struct epoch_context *ctx) 331f92d9b1aSKristof Provost { 332f92d9b1aSKristof Provost struct pflow_softc *sc; 333f92d9b1aSKristof Provost 334f92d9b1aSKristof Provost sc = __containerof(ctx, struct pflow_softc, sc_epoch_ctx); 335f92d9b1aSKristof Provost 336f92d9b1aSKristof Provost free(sc, M_DEVBUF); 337f92d9b1aSKristof Provost } 338f92d9b1aSKristof Provost 339f92d9b1aSKristof Provost static int 340f92d9b1aSKristof Provost pflow_destroy(int unit, bool drain) 341f92d9b1aSKristof Provost { 342f92d9b1aSKristof Provost struct pflow_softc *sc; 343f92d9b1aSKristof Provost int error __diagused; 344f92d9b1aSKristof Provost 345f92d9b1aSKristof Provost mtx_lock(&V_pflowif_list_mtx); 346f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 347f92d9b1aSKristof Provost if (sc->sc_id == unit) 348f92d9b1aSKristof Provost break; 349f92d9b1aSKristof Provost } 350f92d9b1aSKristof Provost if (sc == NULL) { 351f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 352f92d9b1aSKristof Provost return (ENOENT); 353f92d9b1aSKristof Provost } 354f92d9b1aSKristof Provost CK_LIST_REMOVE(sc, sc_next); 355f92d9b1aSKristof Provost mtx_unlock(&V_pflowif_list_mtx); 356f92d9b1aSKristof Provost 357f92d9b1aSKristof Provost sc->sc_dying = 1; 358f92d9b1aSKristof Provost 359f92d9b1aSKristof Provost if (drain) { 360f92d9b1aSKristof Provost /* Let's be sure no one is using this interface any more. */ 361f92d9b1aSKristof Provost NET_EPOCH_DRAIN_CALLBACKS(); 362f92d9b1aSKristof Provost } 363f92d9b1aSKristof Provost 364f92d9b1aSKristof Provost error = swi_remove(sc->sc_swi_cookie); 365f92d9b1aSKristof Provost MPASS(error == 0); 366f92d9b1aSKristof Provost error = intr_event_destroy(sc->sc_swi_ie); 367f92d9b1aSKristof Provost MPASS(error == 0); 368f92d9b1aSKristof Provost 369f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo); 370f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo6); 371f92d9b1aSKristof Provost callout_drain(&sc->sc_tmo_tmpl); 372f92d9b1aSKristof Provost 373f92d9b1aSKristof Provost m_freem(sc->sc_mbuf); 374f92d9b1aSKristof Provost m_freem(sc->sc_mbuf6); 375f92d9b1aSKristof Provost 376f92d9b1aSKristof Provost PFLOW_LOCK(sc); 377f92d9b1aSKristof Provost mbufq_drain(&sc->sc_outputqueue); 378f92d9b1aSKristof Provost if (sc->so != NULL) { 379f92d9b1aSKristof Provost soclose(sc->so); 380f92d9b1aSKristof Provost sc->so = NULL; 381f92d9b1aSKristof Provost } 382f92d9b1aSKristof Provost if (sc->sc_flowdst != NULL) 383f92d9b1aSKristof Provost free(sc->sc_flowdst, M_DEVBUF); 384f92d9b1aSKristof Provost if (sc->sc_flowsrc != NULL) 385f92d9b1aSKristof Provost free(sc->sc_flowsrc, M_DEVBUF); 386f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 387f92d9b1aSKristof Provost 388f92d9b1aSKristof Provost mtx_destroy(&sc->sc_lock); 389f92d9b1aSKristof Provost 390f92d9b1aSKristof Provost free_unr(V_pflow_unr, unit); 391f92d9b1aSKristof Provost 392f92d9b1aSKristof Provost NET_EPOCH_CALL(pflow_free_cb, &sc->sc_epoch_ctx); 393f92d9b1aSKristof Provost 394f92d9b1aSKristof Provost return (0); 395f92d9b1aSKristof Provost } 396f92d9b1aSKristof Provost 397f92d9b1aSKristof Provost static int 398f92d9b1aSKristof Provost pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port) 399f92d9b1aSKristof Provost { 400f92d9b1aSKristof Provost const struct sockaddr_in6 *sin6; 401f92d9b1aSKristof Provost const struct sockaddr_in *sin; 402f92d9b1aSKristof Provost 403f92d9b1aSKristof Provost if (sa == NULL) 404f92d9b1aSKristof Provost return (0); 405f92d9b1aSKristof Provost switch(sa->sa_family) { 406f92d9b1aSKristof Provost case AF_INET: 407f92d9b1aSKristof Provost sin = (const struct sockaddr_in *)sa; 408f92d9b1aSKristof Provost return (sin->sin_addr.s_addr != INADDR_ANY && 409f92d9b1aSKristof Provost (ignore_port || sin->sin_port != 0)); 410f92d9b1aSKristof Provost case AF_INET6: 411f92d9b1aSKristof Provost sin6 = (const struct sockaddr_in6 *)sa; 412f92d9b1aSKristof Provost return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) && 413f92d9b1aSKristof Provost (ignore_port || sin6->sin6_port != 0)); 414f92d9b1aSKristof Provost default: 415f92d9b1aSKristof Provost return (0); 416f92d9b1aSKristof Provost } 417f92d9b1aSKristof Provost } 418f92d9b1aSKristof Provost 419f92d9b1aSKristof Provost static int 420f92d9b1aSKristof Provost pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz) 421f92d9b1aSKristof Provost { 422f92d9b1aSKristof Provost 423f92d9b1aSKristof Provost sc->sc_maxcount4 = (mtu - hdrsz - 424f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4); 425f92d9b1aSKristof Provost sc->sc_maxcount6 = (mtu - hdrsz - 426f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6); 427f92d9b1aSKristof Provost if (sc->sc_maxcount4 > PFLOW_MAXFLOWS) 428f92d9b1aSKristof Provost sc->sc_maxcount4 = PFLOW_MAXFLOWS; 429f92d9b1aSKristof Provost if (sc->sc_maxcount6 > PFLOW_MAXFLOWS) 430f92d9b1aSKristof Provost sc->sc_maxcount6 = PFLOW_MAXFLOWS; 431f92d9b1aSKristof Provost return (hdrsz + sizeof(struct udpiphdr) + 432f92d9b1aSKristof Provost MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4), 433f92d9b1aSKristof Provost sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6))); 434f92d9b1aSKristof Provost } 435f92d9b1aSKristof Provost 436f92d9b1aSKristof Provost static void 437f92d9b1aSKristof Provost pflow_setmtu(struct pflow_softc *sc, int mtu_req) 438f92d9b1aSKristof Provost { 439f92d9b1aSKristof Provost int mtu; 440f92d9b1aSKristof Provost 441f92d9b1aSKristof Provost mtu = mtu_req; 442f92d9b1aSKristof Provost 443f92d9b1aSKristof Provost switch (sc->sc_version) { 444f92d9b1aSKristof Provost case PFLOW_PROTO_5: 445f92d9b1aSKristof Provost sc->sc_maxcount = (mtu - sizeof(struct pflow_header) - 446f92d9b1aSKristof Provost sizeof(struct udpiphdr)) / sizeof(struct pflow_flow); 447f92d9b1aSKristof Provost if (sc->sc_maxcount > PFLOW_MAXFLOWS) 448f92d9b1aSKristof Provost sc->sc_maxcount = PFLOW_MAXFLOWS; 449f92d9b1aSKristof Provost break; 450f92d9b1aSKristof Provost case PFLOW_PROTO_10: 451f92d9b1aSKristof Provost pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header)); 452f92d9b1aSKristof Provost break; 453f92d9b1aSKristof Provost default: /* NOTREACHED */ 454f92d9b1aSKristof Provost break; 455f92d9b1aSKristof Provost } 456f92d9b1aSKristof Provost } 457f92d9b1aSKristof Provost 458f92d9b1aSKristof Provost static struct mbuf * 459f92d9b1aSKristof Provost pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id) 460f92d9b1aSKristof Provost { 461f92d9b1aSKristof Provost struct pflow_set_header set_hdr; 462f92d9b1aSKristof Provost struct pflow_header h; 463f92d9b1aSKristof Provost struct mbuf *m; 464f92d9b1aSKristof Provost 465f92d9b1aSKristof Provost MGETHDR(m, M_NOWAIT, MT_DATA); 466f92d9b1aSKristof Provost if (m == NULL) { 467f92d9b1aSKristof Provost V_pflowstats.pflow_onomem++; 468f92d9b1aSKristof Provost return (NULL); 469f92d9b1aSKristof Provost } 470f92d9b1aSKristof Provost 471f92d9b1aSKristof Provost MCLGET(m, M_NOWAIT); 472f92d9b1aSKristof Provost if ((m->m_flags & M_EXT) == 0) { 473f92d9b1aSKristof Provost m_free(m); 474f92d9b1aSKristof Provost V_pflowstats.pflow_onomem++; 475f92d9b1aSKristof Provost return (NULL); 476f92d9b1aSKristof Provost } 477f92d9b1aSKristof Provost 478f92d9b1aSKristof Provost m->m_len = m->m_pkthdr.len = 0; 479f92d9b1aSKristof Provost 480f92d9b1aSKristof Provost if (sc == NULL) /* get only a new empty mbuf */ 481f92d9b1aSKristof Provost return (m); 482f92d9b1aSKristof Provost 483f92d9b1aSKristof Provost switch (sc->sc_version) { 484f92d9b1aSKristof Provost case PFLOW_PROTO_5: 485f92d9b1aSKristof Provost /* populate pflow_header */ 486f92d9b1aSKristof Provost h.reserved1 = 0; 487f92d9b1aSKristof Provost h.reserved2 = 0; 488f92d9b1aSKristof Provost h.count = 0; 489f92d9b1aSKristof Provost h.version = htons(PFLOW_PROTO_5); 490f92d9b1aSKristof Provost h.flow_sequence = htonl(sc->sc_gcounter); 491f92d9b1aSKristof Provost h.engine_type = PFLOW_ENGINE_TYPE; 492f92d9b1aSKristof Provost h.engine_id = PFLOW_ENGINE_ID; 493f92d9b1aSKristof Provost m_copyback(m, 0, PFLOW_HDRLEN, (caddr_t)&h); 494f92d9b1aSKristof Provost 495f92d9b1aSKristof Provost sc->sc_count = 0; 496f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz, 497f92d9b1aSKristof Provost pflow_timeout, sc); 498f92d9b1aSKristof Provost break; 499f92d9b1aSKristof Provost case PFLOW_PROTO_10: 500f92d9b1aSKristof Provost /* populate pflow_set_header */ 501f92d9b1aSKristof Provost set_hdr.set_length = 0; 502f92d9b1aSKristof Provost set_hdr.set_id = htons(set_id); 503f92d9b1aSKristof Provost m_copyback(m, 0, PFLOW_SET_HDRLEN, (caddr_t)&set_hdr); 504f92d9b1aSKristof Provost break; 505f92d9b1aSKristof Provost default: /* NOTREACHED */ 506f92d9b1aSKristof Provost break; 507f92d9b1aSKristof Provost } 508f92d9b1aSKristof Provost 509f92d9b1aSKristof Provost return (m); 510f92d9b1aSKristof Provost } 511f92d9b1aSKristof Provost 512f92d9b1aSKristof Provost static void 513f92d9b1aSKristof Provost copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, 514f92d9b1aSKristof Provost struct pf_kstate *st, struct pf_state_key *sk, int src, int dst) 515f92d9b1aSKristof Provost { 516f92d9b1aSKristof Provost flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; 517f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 518f92d9b1aSKristof Provost flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr; 519f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 520f92d9b1aSKristof Provost 521f92d9b1aSKristof Provost flow1->dest_as = flow2->src_as = 522f92d9b1aSKristof Provost flow1->src_as = flow2->dest_as = 0; 523f92d9b1aSKristof Provost flow1->if_index_in = htons(st->if_index_in); 524f92d9b1aSKristof Provost flow1->if_index_out = htons(st->if_index_out); 525f92d9b1aSKristof Provost flow2->if_index_in = htons(st->if_index_out); 526f92d9b1aSKristof Provost flow2->if_index_out = htons(st->if_index_in); 527f92d9b1aSKristof Provost flow1->dest_mask = flow2->src_mask = 528f92d9b1aSKristof Provost flow1->src_mask = flow2->dest_mask = 0; 529f92d9b1aSKristof Provost 530f92d9b1aSKristof Provost flow1->flow_packets = htonl(st->packets[0]); 531f92d9b1aSKristof Provost flow2->flow_packets = htonl(st->packets[1]); 532f92d9b1aSKristof Provost flow1->flow_octets = htonl(st->bytes[0]); 533f92d9b1aSKristof Provost flow2->flow_octets = htonl(st->bytes[1]); 534f92d9b1aSKristof Provost 535f92d9b1aSKristof Provost /* 536f92d9b1aSKristof Provost * Pretend the flow was created or expired when the machine came up 537f92d9b1aSKristof Provost * when creation is in the future of the last time a package was seen 538f92d9b1aSKristof Provost * or was created / expired before this machine came up due to pfsync. 539f92d9b1aSKristof Provost */ 540f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = st->creation < 0 || 541f92d9b1aSKristof Provost st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000); 542f92d9b1aSKristof Provost flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) : 543f92d9b1aSKristof Provost htonl(st->expire * 1000); 544f92d9b1aSKristof Provost flow1->tcp_flags = flow2->tcp_flags = 0; 545f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 546f92d9b1aSKristof Provost flow1->tos = flow2->tos = st->rule.ptr->tos; 547f92d9b1aSKristof Provost } 548f92d9b1aSKristof Provost 549f92d9b1aSKristof Provost static void 550f92d9b1aSKristof Provost copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1, 551f92d9b1aSKristof Provost struct pflow_ipfix_flow4 *flow2, struct pf_kstate *st, 552f92d9b1aSKristof Provost struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) 553f92d9b1aSKristof Provost { 554f92d9b1aSKristof Provost flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr; 555f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 556f92d9b1aSKristof Provost flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr; 557f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 558f92d9b1aSKristof Provost 559f92d9b1aSKristof Provost flow1->if_index_in = htonl(st->if_index_in); 560f92d9b1aSKristof Provost flow1->if_index_out = htonl(st->if_index_out); 561f92d9b1aSKristof Provost flow2->if_index_in = htonl(st->if_index_out); 562f92d9b1aSKristof Provost flow2->if_index_out = htonl(st->if_index_in); 563f92d9b1aSKristof Provost 564f92d9b1aSKristof Provost flow1->flow_packets = htobe64(st->packets[0]); 565f92d9b1aSKristof Provost flow2->flow_packets = htobe64(st->packets[1]); 566f92d9b1aSKristof Provost flow1->flow_octets = htobe64(st->bytes[0]); 567f92d9b1aSKristof Provost flow2->flow_octets = htobe64(st->bytes[1]); 568f92d9b1aSKristof Provost 569f92d9b1aSKristof Provost /* 570f92d9b1aSKristof Provost * Pretend the flow was created when the machine came up when creation 571f92d9b1aSKristof Provost * is in the future of the last time a package was seen due to pfsync. 572f92d9b1aSKristof Provost */ 573f92d9b1aSKristof Provost if (st->creation > st->expire) 574f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 575f92d9b1aSKristof Provost time_uptime)*1000); 576f92d9b1aSKristof Provost else 577f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 578f92d9b1aSKristof Provost (time_uptime - st->creation))*1000); 579f92d9b1aSKristof Provost flow1->flow_finish = flow2->flow_finish = htobe64((time_second - 580f92d9b1aSKristof Provost (time_uptime - st->expire))*1000); 581f92d9b1aSKristof Provost 582f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 583f92d9b1aSKristof Provost flow1->tos = flow2->tos = st->rule.ptr->tos; 584f92d9b1aSKristof Provost } 585f92d9b1aSKristof Provost 586f92d9b1aSKristof Provost static void 587f92d9b1aSKristof Provost copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1, 588f92d9b1aSKristof Provost struct pflow_ipfix_flow6 *flow2, struct pf_kstate *st, 589f92d9b1aSKristof Provost struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) 590f92d9b1aSKristof Provost { 591f92d9b1aSKristof Provost bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip)); 592f92d9b1aSKristof Provost bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip)); 593f92d9b1aSKristof Provost flow1->src_port = flow2->dest_port = sk->port[src]; 594f92d9b1aSKristof Provost bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip)); 595f92d9b1aSKristof Provost bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip)); 596f92d9b1aSKristof Provost flow1->dest_port = flow2->src_port = sk->port[dst]; 597f92d9b1aSKristof Provost 598f92d9b1aSKristof Provost flow1->if_index_in = htonl(st->if_index_in); 599f92d9b1aSKristof Provost flow1->if_index_out = htonl(st->if_index_out); 600f92d9b1aSKristof Provost flow2->if_index_in = htonl(st->if_index_out); 601f92d9b1aSKristof Provost flow2->if_index_out = htonl(st->if_index_in); 602f92d9b1aSKristof Provost 603f92d9b1aSKristof Provost flow1->flow_packets = htobe64(st->packets[0]); 604f92d9b1aSKristof Provost flow2->flow_packets = htobe64(st->packets[1]); 605f92d9b1aSKristof Provost flow1->flow_octets = htobe64(st->bytes[0]); 606f92d9b1aSKristof Provost flow2->flow_octets = htobe64(st->bytes[1]); 607f92d9b1aSKristof Provost 608f92d9b1aSKristof Provost /* 609f92d9b1aSKristof Provost * Pretend the flow was created when the machine came up when creation 610f92d9b1aSKristof Provost * is in the future of the last time a package was seen due to pfsync. 611f92d9b1aSKristof Provost */ 612f92d9b1aSKristof Provost if (st->creation > st->expire) 613f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 614f92d9b1aSKristof Provost time_uptime)*1000); 615f92d9b1aSKristof Provost else 616f92d9b1aSKristof Provost flow1->flow_start = flow2->flow_start = htobe64((time_second - 617f92d9b1aSKristof Provost (time_uptime - st->creation))*1000); 618f92d9b1aSKristof Provost flow1->flow_finish = flow2->flow_finish = htobe64((time_second - 619f92d9b1aSKristof Provost (time_uptime - st->expire))*1000); 620f92d9b1aSKristof Provost 621f92d9b1aSKristof Provost flow1->protocol = flow2->protocol = sk->proto; 622f92d9b1aSKristof Provost flow1->tos = flow2->tos = st->rule.ptr->tos; 623f92d9b1aSKristof Provost } 624f92d9b1aSKristof Provost 625f92d9b1aSKristof Provost int 626f92d9b1aSKristof Provost export_pflow(struct pf_kstate *st) 627f92d9b1aSKristof Provost { 628f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 629f92d9b1aSKristof Provost struct pf_state_key *sk; 630f92d9b1aSKristof Provost 631f92d9b1aSKristof Provost NET_EPOCH_ASSERT(); 632f92d9b1aSKristof Provost 633f92d9b1aSKristof Provost sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK]; 634f92d9b1aSKristof Provost 635f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 636f92d9b1aSKristof Provost PFLOW_LOCK(sc); 637f92d9b1aSKristof Provost switch (sc->sc_version) { 638f92d9b1aSKristof Provost case PFLOW_PROTO_5: 639f92d9b1aSKristof Provost if (sk->af == AF_INET) 640f92d9b1aSKristof Provost export_pflow_if(st, sk, sc); 641f92d9b1aSKristof Provost break; 642f92d9b1aSKristof Provost case PFLOW_PROTO_10: 643f92d9b1aSKristof Provost if (sk->af == AF_INET || sk->af == AF_INET6) 644f92d9b1aSKristof Provost export_pflow_if(st, sk, sc); 645f92d9b1aSKristof Provost break; 646f92d9b1aSKristof Provost default: /* NOTREACHED */ 647f92d9b1aSKristof Provost break; 648f92d9b1aSKristof Provost } 649f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 650f92d9b1aSKristof Provost } 651f92d9b1aSKristof Provost 652f92d9b1aSKristof Provost return (0); 653f92d9b1aSKristof Provost } 654f92d9b1aSKristof Provost 655f92d9b1aSKristof Provost static int 656f92d9b1aSKristof Provost export_pflow_if(struct pf_kstate *st, struct pf_state_key *sk, 657f92d9b1aSKristof Provost struct pflow_softc *sc) 658f92d9b1aSKristof Provost { 659f92d9b1aSKristof Provost struct pf_kstate pfs_copy; 660f92d9b1aSKristof Provost u_int64_t bytes[2]; 661f92d9b1aSKristof Provost int ret = 0; 662f92d9b1aSKristof Provost 663f92d9b1aSKristof Provost if (sc->sc_version == PFLOW_PROTO_10) 664f92d9b1aSKristof Provost return (pflow_pack_flow_ipfix(st, sk, sc)); 665f92d9b1aSKristof Provost 666f92d9b1aSKristof Provost /* PFLOW_PROTO_5 */ 667f92d9b1aSKristof Provost if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES) 668f92d9b1aSKristof Provost && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES)) 669f92d9b1aSKristof Provost return (pflow_pack_flow(st, sk, sc)); 670f92d9b1aSKristof Provost 671f92d9b1aSKristof Provost /* flow > PFLOW_MAXBYTES need special handling */ 672f92d9b1aSKristof Provost bcopy(st, &pfs_copy, sizeof(pfs_copy)); 673f92d9b1aSKristof Provost bytes[0] = pfs_copy.bytes[0]; 674f92d9b1aSKristof Provost bytes[1] = pfs_copy.bytes[1]; 675f92d9b1aSKristof Provost 676f92d9b1aSKristof Provost while (bytes[0] > PFLOW_MAXBYTES) { 677f92d9b1aSKristof Provost pfs_copy.bytes[0] = PFLOW_MAXBYTES; 678f92d9b1aSKristof Provost pfs_copy.bytes[1] = 0; 679f92d9b1aSKristof Provost 680f92d9b1aSKristof Provost if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0) 681f92d9b1aSKristof Provost return (ret); 682f92d9b1aSKristof Provost if ((bytes[0] - PFLOW_MAXBYTES) > 0) 683f92d9b1aSKristof Provost bytes[0] -= PFLOW_MAXBYTES; 684f92d9b1aSKristof Provost } 685f92d9b1aSKristof Provost 686f92d9b1aSKristof Provost while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) { 687f92d9b1aSKristof Provost pfs_copy.bytes[1] = PFLOW_MAXBYTES; 688f92d9b1aSKristof Provost pfs_copy.bytes[0] = 0; 689f92d9b1aSKristof Provost 690f92d9b1aSKristof Provost if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0) 691f92d9b1aSKristof Provost return (ret); 692f92d9b1aSKristof Provost if ((bytes[1] - PFLOW_MAXBYTES) > 0) 693f92d9b1aSKristof Provost bytes[1] -= PFLOW_MAXBYTES; 694f92d9b1aSKristof Provost } 695f92d9b1aSKristof Provost 696f92d9b1aSKristof Provost pfs_copy.bytes[0] = bytes[0]; 697f92d9b1aSKristof Provost pfs_copy.bytes[1] = bytes[1]; 698f92d9b1aSKristof Provost 699f92d9b1aSKristof Provost return (pflow_pack_flow(&pfs_copy, sk, sc)); 700f92d9b1aSKristof Provost } 701f92d9b1aSKristof Provost 702f92d9b1aSKristof Provost static int 703f92d9b1aSKristof Provost copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc) 704f92d9b1aSKristof Provost { 705f92d9b1aSKristof Provost int ret = 0; 706f92d9b1aSKristof Provost 707f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 708f92d9b1aSKristof Provost 709f92d9b1aSKristof Provost if (sc->sc_mbuf == NULL) { 710f92d9b1aSKristof Provost if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL) 711f92d9b1aSKristof Provost return (ENOBUFS); 712f92d9b1aSKristof Provost } 713f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf, PFLOW_HDRLEN + 714f92d9b1aSKristof Provost (sc->sc_count * sizeof(struct pflow_flow)), 715f92d9b1aSKristof Provost sizeof(struct pflow_flow), (caddr_t)flow); 716f92d9b1aSKristof Provost 717f92d9b1aSKristof Provost if (V_pflowstats.pflow_flows == sc->sc_gcounter) 718f92d9b1aSKristof Provost V_pflowstats.pflow_flows++; 719f92d9b1aSKristof Provost sc->sc_gcounter++; 720f92d9b1aSKristof Provost sc->sc_count++; 721f92d9b1aSKristof Provost 722f92d9b1aSKristof Provost if (sc->sc_count >= sc->sc_maxcount) 723f92d9b1aSKristof Provost ret = pflow_sendout_v5(sc); 724f92d9b1aSKristof Provost 725f92d9b1aSKristof Provost return(ret); 726f92d9b1aSKristof Provost } 727f92d9b1aSKristof Provost 728f92d9b1aSKristof Provost static int 729f92d9b1aSKristof Provost copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc) 730f92d9b1aSKristof Provost { 731f92d9b1aSKristof Provost int ret = 0; 732f92d9b1aSKristof Provost 733f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 734f92d9b1aSKristof Provost 735f92d9b1aSKristof Provost if (sc->sc_mbuf == NULL) { 736f92d9b1aSKristof Provost if ((sc->sc_mbuf = 737f92d9b1aSKristof Provost pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) { 738f92d9b1aSKristof Provost return (ENOBUFS); 739f92d9b1aSKristof Provost } 740f92d9b1aSKristof Provost sc->sc_count4 = 0; 741f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo, PFLOW_TIMEOUT * hz, 742f92d9b1aSKristof Provost pflow_timeout, sc); 743f92d9b1aSKristof Provost } 744f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN + 745f92d9b1aSKristof Provost (sc->sc_count4 * sizeof(struct pflow_ipfix_flow4)), 746f92d9b1aSKristof Provost sizeof(struct pflow_ipfix_flow4), (caddr_t)flow); 747f92d9b1aSKristof Provost 748f92d9b1aSKristof Provost if (V_pflowstats.pflow_flows == sc->sc_gcounter) 749f92d9b1aSKristof Provost V_pflowstats.pflow_flows++; 750f92d9b1aSKristof Provost sc->sc_gcounter++; 751f92d9b1aSKristof Provost sc->sc_count4++; 752f92d9b1aSKristof Provost 753f92d9b1aSKristof Provost if (sc->sc_count4 >= sc->sc_maxcount4) 754f92d9b1aSKristof Provost ret = pflow_sendout_ipfix(sc, AF_INET); 755f92d9b1aSKristof Provost return(ret); 756f92d9b1aSKristof Provost } 757f92d9b1aSKristof Provost 758f92d9b1aSKristof Provost static int 759f92d9b1aSKristof Provost copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc) 760f92d9b1aSKristof Provost { 761f92d9b1aSKristof Provost int ret = 0; 762f92d9b1aSKristof Provost 763f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 764f92d9b1aSKristof Provost 765f92d9b1aSKristof Provost if (sc->sc_mbuf6 == NULL) { 766f92d9b1aSKristof Provost if ((sc->sc_mbuf6 = 767f92d9b1aSKristof Provost pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) { 768f92d9b1aSKristof Provost return (ENOBUFS); 769f92d9b1aSKristof Provost } 770f92d9b1aSKristof Provost sc->sc_count6 = 0; 771f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo6, PFLOW_TIMEOUT * hz, 772f92d9b1aSKristof Provost pflow_timeout6, sc); 773f92d9b1aSKristof Provost } 774f92d9b1aSKristof Provost m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN + 775f92d9b1aSKristof Provost (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)), 776f92d9b1aSKristof Provost sizeof(struct pflow_ipfix_flow6), (caddr_t)flow); 777f92d9b1aSKristof Provost 778f92d9b1aSKristof Provost if (V_pflowstats.pflow_flows == sc->sc_gcounter) 779f92d9b1aSKristof Provost V_pflowstats.pflow_flows++; 780f92d9b1aSKristof Provost sc->sc_gcounter++; 781f92d9b1aSKristof Provost sc->sc_count6++; 782f92d9b1aSKristof Provost 783f92d9b1aSKristof Provost if (sc->sc_count6 >= sc->sc_maxcount6) 784f92d9b1aSKristof Provost ret = pflow_sendout_ipfix(sc, AF_INET6); 785f92d9b1aSKristof Provost 786f92d9b1aSKristof Provost return(ret); 787f92d9b1aSKristof Provost } 788f92d9b1aSKristof Provost 789f92d9b1aSKristof Provost static int 790f92d9b1aSKristof Provost pflow_pack_flow(struct pf_kstate *st, struct pf_state_key *sk, 791f92d9b1aSKristof Provost struct pflow_softc *sc) 792f92d9b1aSKristof Provost { 793f92d9b1aSKristof Provost struct pflow_flow flow1; 794f92d9b1aSKristof Provost struct pflow_flow flow2; 795f92d9b1aSKristof Provost int ret = 0; 796f92d9b1aSKristof Provost 797f92d9b1aSKristof Provost bzero(&flow1, sizeof(flow1)); 798f92d9b1aSKristof Provost bzero(&flow2, sizeof(flow2)); 799f92d9b1aSKristof Provost 800f92d9b1aSKristof Provost if (st->direction == PF_OUT) 801f92d9b1aSKristof Provost copy_flow_data(&flow1, &flow2, st, sk, 1, 0); 802f92d9b1aSKristof Provost else 803f92d9b1aSKristof Provost copy_flow_data(&flow1, &flow2, st, sk, 0, 1); 804f92d9b1aSKristof Provost 805f92d9b1aSKristof Provost if (st->bytes[0] != 0) /* first flow from state */ 806f92d9b1aSKristof Provost ret = copy_flow_to_m(&flow1, sc); 807f92d9b1aSKristof Provost 808f92d9b1aSKristof Provost if (st->bytes[1] != 0) /* second flow from state */ 809f92d9b1aSKristof Provost ret = copy_flow_to_m(&flow2, sc); 810f92d9b1aSKristof Provost 811f92d9b1aSKristof Provost return (ret); 812f92d9b1aSKristof Provost } 813f92d9b1aSKristof Provost 814f92d9b1aSKristof Provost static int 815f92d9b1aSKristof Provost pflow_pack_flow_ipfix(struct pf_kstate *st, struct pf_state_key *sk, 816f92d9b1aSKristof Provost struct pflow_softc *sc) 817f92d9b1aSKristof Provost { 818f92d9b1aSKristof Provost struct pflow_ipfix_flow4 flow4_1, flow4_2; 819f92d9b1aSKristof Provost struct pflow_ipfix_flow6 flow6_1, flow6_2; 820f92d9b1aSKristof Provost int ret = 0; 821f92d9b1aSKristof Provost if (sk->af == AF_INET) { 822f92d9b1aSKristof Provost bzero(&flow4_1, sizeof(flow4_1)); 823f92d9b1aSKristof Provost bzero(&flow4_2, sizeof(flow4_2)); 824f92d9b1aSKristof Provost 825f92d9b1aSKristof Provost if (st->direction == PF_OUT) 826f92d9b1aSKristof Provost copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, 827f92d9b1aSKristof Provost 1, 0); 828f92d9b1aSKristof Provost else 829f92d9b1aSKristof Provost copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, 830f92d9b1aSKristof Provost 0, 1); 831f92d9b1aSKristof Provost 832f92d9b1aSKristof Provost if (st->bytes[0] != 0) /* first flow from state */ 833f92d9b1aSKristof Provost ret = copy_flow_ipfix_4_to_m(&flow4_1, sc); 834f92d9b1aSKristof Provost 835f92d9b1aSKristof Provost if (st->bytes[1] != 0) /* second flow from state */ 836f92d9b1aSKristof Provost ret = copy_flow_ipfix_4_to_m(&flow4_2, sc); 837f92d9b1aSKristof Provost } else if (sk->af == AF_INET6) { 838f92d9b1aSKristof Provost bzero(&flow6_1, sizeof(flow6_1)); 839f92d9b1aSKristof Provost bzero(&flow6_2, sizeof(flow6_2)); 840f92d9b1aSKristof Provost 841f92d9b1aSKristof Provost if (st->direction == PF_OUT) 842f92d9b1aSKristof Provost copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, 843f92d9b1aSKristof Provost 1, 0); 844f92d9b1aSKristof Provost else 845f92d9b1aSKristof Provost copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, 846f92d9b1aSKristof Provost 0, 1); 847f92d9b1aSKristof Provost 848f92d9b1aSKristof Provost if (st->bytes[0] != 0) /* first flow from state */ 849f92d9b1aSKristof Provost ret = copy_flow_ipfix_6_to_m(&flow6_1, sc); 850f92d9b1aSKristof Provost 851f92d9b1aSKristof Provost if (st->bytes[1] != 0) /* second flow from state */ 852f92d9b1aSKristof Provost ret = copy_flow_ipfix_6_to_m(&flow6_2, sc); 853f92d9b1aSKristof Provost } 854f92d9b1aSKristof Provost return (ret); 855f92d9b1aSKristof Provost } 856f92d9b1aSKristof Provost 857f92d9b1aSKristof Provost static void 858f92d9b1aSKristof Provost pflow_timeout(void *v) 859f92d9b1aSKristof Provost { 860f92d9b1aSKristof Provost struct pflow_softc *sc = v; 861f92d9b1aSKristof Provost 862f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 863f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 864f92d9b1aSKristof Provost 865f92d9b1aSKristof Provost switch (sc->sc_version) { 866f92d9b1aSKristof Provost case PFLOW_PROTO_5: 867f92d9b1aSKristof Provost pflow_sendout_v5(sc); 868f92d9b1aSKristof Provost break; 869f92d9b1aSKristof Provost case PFLOW_PROTO_10: 870f92d9b1aSKristof Provost pflow_sendout_ipfix(sc, AF_INET); 871f92d9b1aSKristof Provost break; 872f92d9b1aSKristof Provost default: /* NOTREACHED */ 873f92d9b1aSKristof Provost panic("Unsupported version %d", sc->sc_version); 874f92d9b1aSKristof Provost break; 875f92d9b1aSKristof Provost } 876f92d9b1aSKristof Provost 877f92d9b1aSKristof Provost CURVNET_RESTORE(); 878f92d9b1aSKristof Provost } 879f92d9b1aSKristof Provost 880f92d9b1aSKristof Provost static void 881f92d9b1aSKristof Provost pflow_timeout6(void *v) 882f92d9b1aSKristof Provost { 883f92d9b1aSKristof Provost struct pflow_softc *sc = v; 884f92d9b1aSKristof Provost 885f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 886f92d9b1aSKristof Provost 887f92d9b1aSKristof Provost if (sc->sc_version != PFLOW_PROTO_10) 888f92d9b1aSKristof Provost return; 889f92d9b1aSKristof Provost 890f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 891f92d9b1aSKristof Provost pflow_sendout_ipfix(sc, AF_INET6); 892f92d9b1aSKristof Provost CURVNET_RESTORE(); 893f92d9b1aSKristof Provost } 894f92d9b1aSKristof Provost 895f92d9b1aSKristof Provost static void 896f92d9b1aSKristof Provost pflow_timeout_tmpl(void *v) 897f92d9b1aSKristof Provost { 898f92d9b1aSKristof Provost struct pflow_softc *sc = v; 899f92d9b1aSKristof Provost 900f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 901f92d9b1aSKristof Provost 902f92d9b1aSKristof Provost if (sc->sc_version != PFLOW_PROTO_10) 903f92d9b1aSKristof Provost return; 904f92d9b1aSKristof Provost 905f92d9b1aSKristof Provost CURVNET_SET(sc->sc_vnet); 906f92d9b1aSKristof Provost pflow_sendout_ipfix_tmpl(sc); 907f92d9b1aSKristof Provost CURVNET_RESTORE(); 908f92d9b1aSKristof Provost } 909f92d9b1aSKristof Provost 910f92d9b1aSKristof Provost static void 911f92d9b1aSKristof Provost pflow_flush(struct pflow_softc *sc) 912f92d9b1aSKristof Provost { 913f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 914f92d9b1aSKristof Provost 915f92d9b1aSKristof Provost switch (sc->sc_version) { 916f92d9b1aSKristof Provost case PFLOW_PROTO_5: 917f92d9b1aSKristof Provost pflow_sendout_v5(sc); 918f92d9b1aSKristof Provost break; 919f92d9b1aSKristof Provost case PFLOW_PROTO_10: 920f92d9b1aSKristof Provost pflow_sendout_ipfix(sc, AF_INET); 921f92d9b1aSKristof Provost pflow_sendout_ipfix(sc, AF_INET6); 922f92d9b1aSKristof Provost break; 923f92d9b1aSKristof Provost default: /* NOTREACHED */ 924f92d9b1aSKristof Provost break; 925f92d9b1aSKristof Provost } 926f92d9b1aSKristof Provost } 927f92d9b1aSKristof Provost 928f92d9b1aSKristof Provost static int 929f92d9b1aSKristof Provost pflow_sendout_v5(struct pflow_softc *sc) 930f92d9b1aSKristof Provost { 931f92d9b1aSKristof Provost struct mbuf *m = sc->sc_mbuf; 932f92d9b1aSKristof Provost struct pflow_header *h; 933f92d9b1aSKristof Provost struct timespec tv; 934f92d9b1aSKristof Provost 935f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 936f92d9b1aSKristof Provost 937f92d9b1aSKristof Provost if (m == NULL) 938f92d9b1aSKristof Provost return (0); 939f92d9b1aSKristof Provost 940f92d9b1aSKristof Provost sc->sc_mbuf = NULL; 941f92d9b1aSKristof Provost 942f92d9b1aSKristof Provost V_pflowstats.pflow_packets++; 943f92d9b1aSKristof Provost h = mtod(m, struct pflow_header *); 944f92d9b1aSKristof Provost h->count = htons(sc->sc_count); 945f92d9b1aSKristof Provost 946f92d9b1aSKristof Provost /* populate pflow_header */ 947f92d9b1aSKristof Provost h->uptime_ms = htonl(time_uptime * 1000); 948f92d9b1aSKristof Provost 949f92d9b1aSKristof Provost getnanotime(&tv); 950f92d9b1aSKristof Provost h->time_sec = htonl(tv.tv_sec); /* XXX 2038 */ 951f92d9b1aSKristof Provost h->time_nanosec = htonl(tv.tv_nsec); 952f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 953f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 954f92d9b1aSKristof Provost 955f92d9b1aSKristof Provost return (0); 956f92d9b1aSKristof Provost } 957f92d9b1aSKristof Provost 958f92d9b1aSKristof Provost static int 959f92d9b1aSKristof Provost pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) 960f92d9b1aSKristof Provost { 961f92d9b1aSKristof Provost struct mbuf *m; 962f92d9b1aSKristof Provost struct pflow_v10_header *h10; 963f92d9b1aSKristof Provost struct pflow_set_header *set_hdr; 964f92d9b1aSKristof Provost u_int32_t count; 965f92d9b1aSKristof Provost int set_length; 966f92d9b1aSKristof Provost 967f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 968f92d9b1aSKristof Provost 969f92d9b1aSKristof Provost switch (af) { 970f92d9b1aSKristof Provost case AF_INET: 971f92d9b1aSKristof Provost m = sc->sc_mbuf; 972f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo); 973f92d9b1aSKristof Provost if (m == NULL) 974f92d9b1aSKristof Provost return (0); 975f92d9b1aSKristof Provost sc->sc_mbuf = NULL; 976f92d9b1aSKristof Provost count = sc->sc_count4; 977f92d9b1aSKristof Provost set_length = sizeof(struct pflow_set_header) 978f92d9b1aSKristof Provost + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4); 979f92d9b1aSKristof Provost break; 980f92d9b1aSKristof Provost case AF_INET6: 981f92d9b1aSKristof Provost m = sc->sc_mbuf6; 982f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo6); 983f92d9b1aSKristof Provost if (m == NULL) 984f92d9b1aSKristof Provost return (0); 985f92d9b1aSKristof Provost sc->sc_mbuf6 = NULL; 986f92d9b1aSKristof Provost count = sc->sc_count6; 987f92d9b1aSKristof Provost set_length = sizeof(struct pflow_set_header) 988f92d9b1aSKristof Provost + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6); 989f92d9b1aSKristof Provost break; 990f92d9b1aSKristof Provost default: 991f92d9b1aSKristof Provost panic("Unsupported AF %d", af); 992f92d9b1aSKristof Provost } 993f92d9b1aSKristof Provost 994f92d9b1aSKristof Provost V_pflowstats.pflow_packets++; 995f92d9b1aSKristof Provost set_hdr = mtod(m, struct pflow_set_header *); 996f92d9b1aSKristof Provost set_hdr->set_length = htons(set_length); 997f92d9b1aSKristof Provost 998f92d9b1aSKristof Provost /* populate pflow_header */ 999f92d9b1aSKristof Provost M_PREPEND(m, sizeof(struct pflow_v10_header), M_NOWAIT); 1000f92d9b1aSKristof Provost if (m == NULL) { 1001f92d9b1aSKristof Provost V_pflowstats.pflow_onomem++; 1002f92d9b1aSKristof Provost return (ENOBUFS); 1003f92d9b1aSKristof Provost } 1004f92d9b1aSKristof Provost h10 = mtod(m, struct pflow_v10_header *); 1005f92d9b1aSKristof Provost h10->version = htons(PFLOW_PROTO_10); 1006f92d9b1aSKristof Provost h10->length = htons(PFLOW_IPFIX_HDRLEN + set_length); 1007f92d9b1aSKristof Provost h10->time_sec = htonl(time_second); /* XXX 2038 */ 1008f92d9b1aSKristof Provost h10->flow_sequence = htonl(sc->sc_sequence); 1009f92d9b1aSKristof Provost sc->sc_sequence += count; 1010f92d9b1aSKristof Provost h10->observation_dom = htonl(PFLOW_ENGINE_TYPE); 1011f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 1012f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 1013f92d9b1aSKristof Provost 1014f92d9b1aSKristof Provost return (0); 1015f92d9b1aSKristof Provost } 1016f92d9b1aSKristof Provost 1017f92d9b1aSKristof Provost static int 1018f92d9b1aSKristof Provost pflow_sendout_ipfix_tmpl(struct pflow_softc *sc) 1019f92d9b1aSKristof Provost { 1020f92d9b1aSKristof Provost struct mbuf *m; 1021f92d9b1aSKristof Provost struct pflow_v10_header *h10; 1022f92d9b1aSKristof Provost 1023f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1024f92d9b1aSKristof Provost 1025f92d9b1aSKristof Provost m = pflow_get_mbuf(sc, 0); 1026f92d9b1aSKristof Provost if (m == NULL) 1027f92d9b1aSKristof Provost return (0); 1028f92d9b1aSKristof Provost m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl), 1029f92d9b1aSKristof Provost (caddr_t)&sc->sc_tmpl_ipfix); 1030f92d9b1aSKristof Provost 1031f92d9b1aSKristof Provost V_pflowstats.pflow_packets++; 1032f92d9b1aSKristof Provost 1033f92d9b1aSKristof Provost /* populate pflow_header */ 1034f92d9b1aSKristof Provost M_PREPEND(m, sizeof(struct pflow_v10_header), M_NOWAIT); 1035f92d9b1aSKristof Provost if (m == NULL) { 1036f92d9b1aSKristof Provost V_pflowstats.pflow_onomem++; 1037f92d9b1aSKristof Provost return (ENOBUFS); 1038f92d9b1aSKristof Provost } 1039f92d9b1aSKristof Provost h10 = mtod(m, struct pflow_v10_header *); 1040f92d9b1aSKristof Provost h10->version = htons(PFLOW_PROTO_10); 1041f92d9b1aSKristof Provost h10->length = htons(PFLOW_IPFIX_HDRLEN + sizeof(struct 1042f92d9b1aSKristof Provost pflow_ipfix_tmpl)); 1043f92d9b1aSKristof Provost h10->time_sec = htonl(time_second); /* XXX 2038 */ 1044f92d9b1aSKristof Provost h10->flow_sequence = htonl(sc->sc_sequence); 1045f92d9b1aSKristof Provost h10->observation_dom = htonl(PFLOW_ENGINE_TYPE); 1046f92d9b1aSKristof Provost 1047f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT * hz, 1048f92d9b1aSKristof Provost pflow_timeout_tmpl, sc); 1049f92d9b1aSKristof Provost if (mbufq_enqueue(&sc->sc_outputqueue, m) == 0) 1050f92d9b1aSKristof Provost swi_sched(sc->sc_swi_cookie, 0); 1051f92d9b1aSKristof Provost 1052f92d9b1aSKristof Provost return (0); 1053f92d9b1aSKristof Provost } 1054f92d9b1aSKristof Provost 1055f92d9b1aSKristof Provost static int 1056f92d9b1aSKristof Provost pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m) 1057f92d9b1aSKristof Provost { 1058f92d9b1aSKristof Provost if (sc->so == NULL) { 1059f92d9b1aSKristof Provost m_freem(m); 1060f92d9b1aSKristof Provost return (EINVAL); 1061f92d9b1aSKristof Provost } 1062f92d9b1aSKristof Provost return (sosend(sc->so, sc->sc_flowdst, NULL, m, NULL, 0, curthread)); 1063f92d9b1aSKristof Provost } 1064f92d9b1aSKristof Provost 1065f92d9b1aSKristof Provost static int 1066f92d9b1aSKristof Provost pflow_nl_list(struct nlmsghdr *hdr, struct nl_pstate *npt) 1067f92d9b1aSKristof Provost { 1068f92d9b1aSKristof Provost struct epoch_tracker et; 1069f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1070f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1071f92d9b1aSKristof Provost int error = 0; 1072f92d9b1aSKristof Provost 1073f92d9b1aSKristof Provost hdr->nlmsg_flags |= NLM_F_MULTI; 1074f92d9b1aSKristof Provost 1075f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1076f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1077f92d9b1aSKristof Provost if (!nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1078f92d9b1aSKristof Provost error = ENOMEM; 1079f92d9b1aSKristof Provost goto out; 1080f92d9b1aSKristof Provost } 1081f92d9b1aSKristof Provost 1082f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1083f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_LIST; 1084f92d9b1aSKristof Provost ghdr_new->version = 0; 1085f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1086f92d9b1aSKristof Provost 1087f92d9b1aSKristof Provost nlattr_add_u32(nw, PFLOWNL_L_ID, sc->sc_id); 1088f92d9b1aSKristof Provost 1089f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1090f92d9b1aSKristof Provost error = ENOMEM; 1091f92d9b1aSKristof Provost goto out; 1092f92d9b1aSKristof Provost } 1093f92d9b1aSKristof Provost } 1094f92d9b1aSKristof Provost 1095f92d9b1aSKristof Provost out: 1096f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1097f92d9b1aSKristof Provost 1098f92d9b1aSKristof Provost if (error != 0) 1099f92d9b1aSKristof Provost nlmsg_abort(nw); 1100f92d9b1aSKristof Provost 1101f92d9b1aSKristof Provost return (error); 1102f92d9b1aSKristof Provost } 1103f92d9b1aSKristof Provost 1104f92d9b1aSKristof Provost static int 1105f92d9b1aSKristof Provost pflow_nl_create(struct nlmsghdr *hdr, struct nl_pstate *npt) 1106f92d9b1aSKristof Provost { 1107f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1108f92d9b1aSKristof Provost int error = 0; 1109f92d9b1aSKristof Provost int unit; 1110f92d9b1aSKristof Provost 1111f92d9b1aSKristof Provost if (! nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1112f92d9b1aSKristof Provost return (ENOMEM); 1113f92d9b1aSKristof Provost } 1114f92d9b1aSKristof Provost 1115f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1116f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_CREATE; 1117f92d9b1aSKristof Provost ghdr_new->version = 0; 1118f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1119f92d9b1aSKristof Provost 1120f92d9b1aSKristof Provost unit = alloc_unr(V_pflow_unr); 1121f92d9b1aSKristof Provost 1122f92d9b1aSKristof Provost error = pflow_create(unit); 1123f92d9b1aSKristof Provost if (error != 0) { 1124f92d9b1aSKristof Provost free_unr(V_pflow_unr, unit); 1125f92d9b1aSKristof Provost nlmsg_abort(nw); 1126f92d9b1aSKristof Provost return (error); 1127f92d9b1aSKristof Provost } 1128f92d9b1aSKristof Provost 1129f92d9b1aSKristof Provost nlattr_add_s32(nw, PFLOWNL_CREATE_ID, unit); 1130f92d9b1aSKristof Provost 1131f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1132f92d9b1aSKristof Provost pflow_destroy(unit, true); 1133f92d9b1aSKristof Provost return (ENOMEM); 1134f92d9b1aSKristof Provost } 1135f92d9b1aSKristof Provost 1136f92d9b1aSKristof Provost return (0); 1137f92d9b1aSKristof Provost } 1138f92d9b1aSKristof Provost 1139f92d9b1aSKristof Provost struct pflow_parsed_del { 1140f92d9b1aSKristof Provost int id; 1141f92d9b1aSKristof Provost }; 1142f92d9b1aSKristof Provost #define _IN(_field) offsetof(struct genlmsghdr, _field) 1143f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_del, _field) 1144f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_del[] = { 1145f92d9b1aSKristof Provost { .type = PFLOWNL_DEL_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1146f92d9b1aSKristof Provost }; 1147f92d9b1aSKristof Provost static const struct nlfield_parser nlf_p_del[] = {}; 1148f92d9b1aSKristof Provost #undef _IN 1149f92d9b1aSKristof Provost #undef _OUT 1150f92d9b1aSKristof Provost NL_DECLARE_PARSER(del_parser, struct genlmsghdr, nlf_p_del, nla_p_del); 1151f92d9b1aSKristof Provost 1152f92d9b1aSKristof Provost static int 1153f92d9b1aSKristof Provost pflow_nl_del(struct nlmsghdr *hdr, struct nl_pstate *npt) 1154f92d9b1aSKristof Provost { 1155f92d9b1aSKristof Provost struct pflow_parsed_del d = {}; 1156f92d9b1aSKristof Provost int error; 1157f92d9b1aSKristof Provost 1158f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &del_parser, npt, &d); 1159f92d9b1aSKristof Provost if (error != 0) 1160f92d9b1aSKristof Provost return (error); 1161f92d9b1aSKristof Provost 1162f92d9b1aSKristof Provost error = pflow_destroy(d.id, true); 1163f92d9b1aSKristof Provost 1164f92d9b1aSKristof Provost return (error); 1165f92d9b1aSKristof Provost } 1166f92d9b1aSKristof Provost 1167f92d9b1aSKristof Provost struct pflow_parsed_get { 1168f92d9b1aSKristof Provost int id; 1169f92d9b1aSKristof Provost }; 1170f92d9b1aSKristof Provost #define _IN(_field) offsetof(struct genlmsghdr, _field) 1171f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_get, _field) 1172f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_get[] = { 1173f92d9b1aSKristof Provost { .type = PFLOWNL_GET_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1174f92d9b1aSKristof Provost }; 1175f92d9b1aSKristof Provost static const struct nlfield_parser nlf_p_get[] = {}; 1176f92d9b1aSKristof Provost #undef _IN 1177f92d9b1aSKristof Provost #undef _OUT 1178f92d9b1aSKristof Provost NL_DECLARE_PARSER(get_parser, struct genlmsghdr, nlf_p_get, nla_p_get); 1179f92d9b1aSKristof Provost 1180f92d9b1aSKristof Provost static bool 1181f92d9b1aSKristof Provost nlattr_add_sockaddr(struct nl_writer *nw, int attr, const struct sockaddr *s) 1182f92d9b1aSKristof Provost { 1183f92d9b1aSKristof Provost int off = nlattr_add_nested(nw, attr); 1184f92d9b1aSKristof Provost if (off == 0) 1185f92d9b1aSKristof Provost return (false); 1186f92d9b1aSKristof Provost 1187f92d9b1aSKristof Provost nlattr_add_u8(nw, PFLOWNL_ADDR_FAMILY, s->sa_family); 1188f92d9b1aSKristof Provost 1189f92d9b1aSKristof Provost switch (s->sa_family) { 1190f92d9b1aSKristof Provost case AF_INET: { 1191f92d9b1aSKristof Provost const struct sockaddr_in *in = (const struct sockaddr_in *)s; 1192f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_ADDR_PORT, in->sin_port); 1193f92d9b1aSKristof Provost nlattr_add_in_addr(nw, PFLOWNL_ADDR_IP, &in->sin_addr); 1194f92d9b1aSKristof Provost break; 1195f92d9b1aSKristof Provost } 1196f92d9b1aSKristof Provost case AF_INET6: { 1197f92d9b1aSKristof Provost const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)s; 1198f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_ADDR_PORT, in6->sin6_port); 1199f92d9b1aSKristof Provost nlattr_add_in6_addr(nw, PFLOWNL_ADDR_IP6, &in6->sin6_addr); 1200f92d9b1aSKristof Provost break; 1201f92d9b1aSKristof Provost } 1202f92d9b1aSKristof Provost default: 1203f92d9b1aSKristof Provost panic("Unknown address family %d", s->sa_family); 1204f92d9b1aSKristof Provost } 1205f92d9b1aSKristof Provost 1206f92d9b1aSKristof Provost nlattr_set_len(nw, off); 1207f92d9b1aSKristof Provost return (true); 1208f92d9b1aSKristof Provost } 1209f92d9b1aSKristof Provost 1210f92d9b1aSKristof Provost static int 1211f92d9b1aSKristof Provost pflow_nl_get(struct nlmsghdr *hdr, struct nl_pstate *npt) 1212f92d9b1aSKristof Provost { 1213f92d9b1aSKristof Provost struct epoch_tracker et; 1214f92d9b1aSKristof Provost struct pflow_parsed_get g = {}; 1215f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1216f92d9b1aSKristof Provost struct nl_writer *nw = npt->nw; 1217f92d9b1aSKristof Provost struct genlmsghdr *ghdr_new; 1218f92d9b1aSKristof Provost int error; 1219f92d9b1aSKristof Provost 1220f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &get_parser, npt, &g); 1221f92d9b1aSKristof Provost if (error != 0) 1222f92d9b1aSKristof Provost return (error); 1223f92d9b1aSKristof Provost 1224f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1225f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1226f92d9b1aSKristof Provost if (sc->sc_id == g.id) 1227f92d9b1aSKristof Provost break; 1228f92d9b1aSKristof Provost } 1229f92d9b1aSKristof Provost if (sc == NULL) { 1230f92d9b1aSKristof Provost error = ENOENT; 1231f92d9b1aSKristof Provost goto out; 1232f92d9b1aSKristof Provost } 1233f92d9b1aSKristof Provost 1234f92d9b1aSKristof Provost if (! nlmsg_reply(nw, hdr, sizeof(struct genlmsghdr))) { 1235f92d9b1aSKristof Provost nlmsg_abort(nw); 1236f92d9b1aSKristof Provost error = ENOMEM; 1237f92d9b1aSKristof Provost goto out; 1238f92d9b1aSKristof Provost } 1239f92d9b1aSKristof Provost 1240f92d9b1aSKristof Provost ghdr_new = nlmsg_reserve_object(nw, struct genlmsghdr); 1241f92d9b1aSKristof Provost if (ghdr_new == NULL) { 1242f92d9b1aSKristof Provost nlmsg_abort(nw); 1243f92d9b1aSKristof Provost error = ENOMEM; 1244f92d9b1aSKristof Provost goto out; 1245f92d9b1aSKristof Provost } 1246f92d9b1aSKristof Provost 1247f92d9b1aSKristof Provost ghdr_new->cmd = PFLOWNL_CMD_GET; 1248f92d9b1aSKristof Provost ghdr_new->version = 0; 1249f92d9b1aSKristof Provost ghdr_new->reserved = 0; 1250f92d9b1aSKristof Provost 1251f92d9b1aSKristof Provost nlattr_add_u32(nw, PFLOWNL_GET_ID, sc->sc_id); 1252f92d9b1aSKristof Provost nlattr_add_u16(nw, PFLOWNL_GET_VERSION, sc->sc_version); 1253f92d9b1aSKristof Provost if (sc->sc_flowsrc) 1254f92d9b1aSKristof Provost nlattr_add_sockaddr(nw, PFLOWNL_GET_SRC, sc->sc_flowsrc); 1255f92d9b1aSKristof Provost if (sc->sc_flowdst) 1256f92d9b1aSKristof Provost nlattr_add_sockaddr(nw, PFLOWNL_GET_DST, sc->sc_flowdst); 1257f92d9b1aSKristof Provost 1258f92d9b1aSKristof Provost if (! nlmsg_end(nw)) { 1259f92d9b1aSKristof Provost nlmsg_abort(nw); 1260f92d9b1aSKristof Provost error = ENOMEM; 1261f92d9b1aSKristof Provost } 1262f92d9b1aSKristof Provost 1263f92d9b1aSKristof Provost out: 1264f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1265f92d9b1aSKristof Provost 1266f92d9b1aSKristof Provost return (error); 1267f92d9b1aSKristof Provost } 1268f92d9b1aSKristof Provost 1269f92d9b1aSKristof Provost struct pflow_sockaddr { 1270f92d9b1aSKristof Provost union { 1271f92d9b1aSKristof Provost struct sockaddr_in in; 1272f92d9b1aSKristof Provost struct sockaddr_in6 in6; 1273f92d9b1aSKristof Provost struct sockaddr_storage storage; 1274f92d9b1aSKristof Provost }; 1275f92d9b1aSKristof Provost }; 1276f92d9b1aSKristof Provost static bool 1277f92d9b1aSKristof Provost pflow_postparse_sockaddr(void *parsed_args, struct nl_pstate *npt __unused) 1278f92d9b1aSKristof Provost { 1279f92d9b1aSKristof Provost struct pflow_sockaddr *s = (struct pflow_sockaddr *)parsed_args; 1280f92d9b1aSKristof Provost 1281f92d9b1aSKristof Provost if (s->storage.ss_family == AF_INET) 1282f92d9b1aSKristof Provost s->storage.ss_len = sizeof(struct sockaddr_in); 1283f92d9b1aSKristof Provost else if (s->storage.ss_family == AF_INET6) 1284f92d9b1aSKristof Provost s->storage.ss_len = sizeof(struct sockaddr_in6); 1285f92d9b1aSKristof Provost else 1286f92d9b1aSKristof Provost return (false); 1287f92d9b1aSKristof Provost 1288f92d9b1aSKristof Provost return (true); 1289f92d9b1aSKristof Provost } 1290f92d9b1aSKristof Provost 1291f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_sockaddr, _field) 1292f92d9b1aSKristof Provost static struct nlattr_parser nla_p_sockaddr[] = { 1293f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_FAMILY, .off = _OUT(in.sin_family), .cb = nlattr_get_uint8 }, 1294f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_PORT, .off = _OUT(in.sin_port), .cb = nlattr_get_uint16 }, 1295f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_IP, .off = _OUT(in.sin_addr), .cb = nlattr_get_in_addr }, 1296f92d9b1aSKristof Provost { .type = PFLOWNL_ADDR_IP6, .off = _OUT(in6.sin6_addr), .cb = nlattr_get_in6_addr }, 1297f92d9b1aSKristof Provost }; 1298f92d9b1aSKristof Provost NL_DECLARE_ATTR_PARSER_EXT(addr_parser, nla_p_sockaddr, pflow_postparse_sockaddr); 1299f92d9b1aSKristof Provost #undef _OUT 1300f92d9b1aSKristof Provost 1301f92d9b1aSKristof Provost struct pflow_parsed_set { 1302f92d9b1aSKristof Provost int id; 1303f92d9b1aSKristof Provost uint16_t version; 1304f92d9b1aSKristof Provost struct sockaddr_storage src; 1305f92d9b1aSKristof Provost struct sockaddr_storage dst; 1306f92d9b1aSKristof Provost }; 1307f92d9b1aSKristof Provost #define _IN(_field) offsetof(struct genlmsghdr, _field) 1308f92d9b1aSKristof Provost #define _OUT(_field) offsetof(struct pflow_parsed_set, _field) 1309f92d9b1aSKristof Provost static const struct nlattr_parser nla_p_set[] = { 1310f92d9b1aSKristof Provost { .type = PFLOWNL_SET_ID, .off = _OUT(id), .cb = nlattr_get_uint32 }, 1311f92d9b1aSKristof Provost { .type = PFLOWNL_SET_VERSION, .off = _OUT(version), .cb = nlattr_get_uint16 }, 1312f92d9b1aSKristof Provost { .type = PFLOWNL_SET_SRC, .off = _OUT(src), .arg = &addr_parser, .cb = nlattr_get_nested }, 1313f92d9b1aSKristof Provost { .type = PFLOWNL_SET_DST, .off = _OUT(dst), .arg = &addr_parser, .cb = nlattr_get_nested }, 1314f92d9b1aSKristof Provost }; 1315f92d9b1aSKristof Provost static const struct nlfield_parser nlf_p_set[] = {}; 1316f92d9b1aSKristof Provost #undef _IN 1317f92d9b1aSKristof Provost #undef _OUT 1318f92d9b1aSKristof Provost NL_DECLARE_PARSER(set_parser, struct genlmsghdr, nlf_p_set, nla_p_set); 1319f92d9b1aSKristof Provost 1320f92d9b1aSKristof Provost static int 1321f92d9b1aSKristof Provost pflow_set(struct pflow_softc *sc, const struct pflow_parsed_set *pflowr, struct ucred *cred) 1322f92d9b1aSKristof Provost { 1323f92d9b1aSKristof Provost struct thread *td; 1324f92d9b1aSKristof Provost struct socket *so; 1325f92d9b1aSKristof Provost int error = 0; 1326f92d9b1aSKristof Provost 1327f92d9b1aSKristof Provost td = curthread; 1328f92d9b1aSKristof Provost 1329f92d9b1aSKristof Provost PFLOW_ASSERT(sc); 1330f92d9b1aSKristof Provost 1331f92d9b1aSKristof Provost if (pflowr->version != 0) { 1332f92d9b1aSKristof Provost switch(pflowr->version) { 1333f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1334f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1335f92d9b1aSKristof Provost break; 1336f92d9b1aSKristof Provost default: 1337f92d9b1aSKristof Provost return(EINVAL); 1338f92d9b1aSKristof Provost } 1339f92d9b1aSKristof Provost } 1340f92d9b1aSKristof Provost 1341f92d9b1aSKristof Provost pflow_flush(sc); 1342f92d9b1aSKristof Provost 1343f92d9b1aSKristof Provost if (pflowr->dst.ss_len != 0) { 1344f92d9b1aSKristof Provost if (sc->sc_flowdst != NULL && 1345f92d9b1aSKristof Provost sc->sc_flowdst->sa_family != pflowr->dst.ss_family) { 1346f92d9b1aSKristof Provost free(sc->sc_flowdst, M_DEVBUF); 1347f92d9b1aSKristof Provost sc->sc_flowdst = NULL; 1348f92d9b1aSKristof Provost if (sc->so != NULL) { 1349f92d9b1aSKristof Provost soclose(sc->so); 1350f92d9b1aSKristof Provost sc->so = NULL; 1351f92d9b1aSKristof Provost } 1352f92d9b1aSKristof Provost } 1353f92d9b1aSKristof Provost 1354f92d9b1aSKristof Provost switch (pflowr->dst.ss_family) { 1355f92d9b1aSKristof Provost case AF_INET: 1356f92d9b1aSKristof Provost if (sc->sc_flowdst == NULL) { 1357f92d9b1aSKristof Provost if ((sc->sc_flowdst = malloc( 1358f92d9b1aSKristof Provost sizeof(struct sockaddr_in), 1359f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1360f92d9b1aSKristof Provost return (ENOMEM); 1361f92d9b1aSKristof Provost } 1362f92d9b1aSKristof Provost memcpy(sc->sc_flowdst, &pflowr->dst, 1363f92d9b1aSKristof Provost sizeof(struct sockaddr_in)); 1364f92d9b1aSKristof Provost sc->sc_flowdst->sa_len = sizeof(struct 1365f92d9b1aSKristof Provost sockaddr_in); 1366f92d9b1aSKristof Provost break; 1367f92d9b1aSKristof Provost case AF_INET6: 1368f92d9b1aSKristof Provost if (sc->sc_flowdst == NULL) { 1369f92d9b1aSKristof Provost if ((sc->sc_flowdst = malloc( 1370f92d9b1aSKristof Provost sizeof(struct sockaddr_in6), 1371f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1372f92d9b1aSKristof Provost return (ENOMEM); 1373f92d9b1aSKristof Provost } 1374f92d9b1aSKristof Provost memcpy(sc->sc_flowdst, &pflowr->dst, 1375f92d9b1aSKristof Provost sizeof(struct sockaddr_in6)); 1376f92d9b1aSKristof Provost sc->sc_flowdst->sa_len = sizeof(struct 1377f92d9b1aSKristof Provost sockaddr_in6); 1378f92d9b1aSKristof Provost break; 1379f92d9b1aSKristof Provost default: 1380f92d9b1aSKristof Provost break; 1381f92d9b1aSKristof Provost } 1382f92d9b1aSKristof Provost } 1383f92d9b1aSKristof Provost 1384f92d9b1aSKristof Provost if (pflowr->src.ss_len != 0) { 1385f92d9b1aSKristof Provost if (sc->sc_flowsrc != NULL) 1386f92d9b1aSKristof Provost free(sc->sc_flowsrc, M_DEVBUF); 1387f92d9b1aSKristof Provost sc->sc_flowsrc = NULL; 1388f92d9b1aSKristof Provost if (sc->so != NULL) { 1389f92d9b1aSKristof Provost soclose(sc->so); 1390f92d9b1aSKristof Provost sc->so = NULL; 1391f92d9b1aSKristof Provost } 1392f92d9b1aSKristof Provost switch(pflowr->src.ss_family) { 1393f92d9b1aSKristof Provost case AF_INET: 1394f92d9b1aSKristof Provost if ((sc->sc_flowsrc = malloc( 1395f92d9b1aSKristof Provost sizeof(struct sockaddr_in), 1396f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1397f92d9b1aSKristof Provost return (ENOMEM); 1398f92d9b1aSKristof Provost memcpy(sc->sc_flowsrc, &pflowr->src, 1399f92d9b1aSKristof Provost sizeof(struct sockaddr_in)); 1400f92d9b1aSKristof Provost sc->sc_flowsrc->sa_len = sizeof(struct 1401f92d9b1aSKristof Provost sockaddr_in); 1402f92d9b1aSKristof Provost break; 1403f92d9b1aSKristof Provost case AF_INET6: 1404f92d9b1aSKristof Provost if ((sc->sc_flowsrc = malloc( 1405f92d9b1aSKristof Provost sizeof(struct sockaddr_in6), 1406f92d9b1aSKristof Provost M_DEVBUF, M_NOWAIT)) == NULL) 1407f92d9b1aSKristof Provost return (ENOMEM); 1408f92d9b1aSKristof Provost memcpy(sc->sc_flowsrc, &pflowr->src, 1409f92d9b1aSKristof Provost sizeof(struct sockaddr_in6)); 1410f92d9b1aSKristof Provost sc->sc_flowsrc->sa_len = sizeof(struct 1411f92d9b1aSKristof Provost sockaddr_in6); 1412f92d9b1aSKristof Provost break; 1413f92d9b1aSKristof Provost default: 1414f92d9b1aSKristof Provost break; 1415f92d9b1aSKristof Provost } 1416f92d9b1aSKristof Provost } 1417f92d9b1aSKristof Provost 1418f92d9b1aSKristof Provost if (sc->so == NULL) { 1419f92d9b1aSKristof Provost if (pflowvalidsockaddr(sc->sc_flowdst, 0)) { 1420f92d9b1aSKristof Provost error = socreate(sc->sc_flowdst->sa_family, 1421f92d9b1aSKristof Provost &so, SOCK_DGRAM, IPPROTO_UDP, cred, td); 1422f92d9b1aSKristof Provost if (error) 1423f92d9b1aSKristof Provost return (error); 1424f92d9b1aSKristof Provost if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) { 1425f92d9b1aSKristof Provost error = sobind(so, sc->sc_flowsrc, td); 1426f92d9b1aSKristof Provost if (error) { 1427f92d9b1aSKristof Provost soclose(so); 1428f92d9b1aSKristof Provost return (error); 1429f92d9b1aSKristof Provost } 1430f92d9b1aSKristof Provost } 1431f92d9b1aSKristof Provost sc->so = so; 1432f92d9b1aSKristof Provost } 1433f92d9b1aSKristof Provost } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) { 1434f92d9b1aSKristof Provost soclose(sc->so); 1435f92d9b1aSKristof Provost sc->so = NULL; 1436f92d9b1aSKristof Provost } 1437f92d9b1aSKristof Provost 1438f92d9b1aSKristof Provost /* error check is above */ 1439f92d9b1aSKristof Provost if (pflowr->version != 0) 1440f92d9b1aSKristof Provost sc->sc_version = pflowr->version; 1441f92d9b1aSKristof Provost 1442f92d9b1aSKristof Provost pflow_setmtu(sc, ETHERMTU); 1443f92d9b1aSKristof Provost 1444f92d9b1aSKristof Provost switch (sc->sc_version) { 1445f92d9b1aSKristof Provost case PFLOW_PROTO_5: 1446f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo6); 1447f92d9b1aSKristof Provost callout_stop(&sc->sc_tmo_tmpl); 1448f92d9b1aSKristof Provost break; 1449f92d9b1aSKristof Provost case PFLOW_PROTO_10: 1450f92d9b1aSKristof Provost callout_reset(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT * hz, 1451f92d9b1aSKristof Provost pflow_timeout_tmpl, sc); 1452f92d9b1aSKristof Provost break; 1453f92d9b1aSKristof Provost default: /* NOTREACHED */ 1454f92d9b1aSKristof Provost break; 1455f92d9b1aSKristof Provost } 1456f92d9b1aSKristof Provost 1457f92d9b1aSKristof Provost return (0); 1458f92d9b1aSKristof Provost } 1459f92d9b1aSKristof Provost 1460f92d9b1aSKristof Provost static int 1461f92d9b1aSKristof Provost pflow_nl_set(struct nlmsghdr *hdr, struct nl_pstate *npt) 1462f92d9b1aSKristof Provost { 1463f92d9b1aSKristof Provost struct epoch_tracker et; 1464f92d9b1aSKristof Provost struct pflow_parsed_set s = {}; 1465f92d9b1aSKristof Provost struct pflow_softc *sc = NULL; 1466f92d9b1aSKristof Provost int error; 1467f92d9b1aSKristof Provost 1468f92d9b1aSKristof Provost error = nl_parse_nlmsg(hdr, &set_parser, npt, &s); 1469f92d9b1aSKristof Provost if (error != 0) 1470f92d9b1aSKristof Provost return (error); 1471f92d9b1aSKristof Provost 1472f92d9b1aSKristof Provost NET_EPOCH_ENTER(et); 1473f92d9b1aSKristof Provost CK_LIST_FOREACH(sc, &V_pflowif_list, sc_next) { 1474f92d9b1aSKristof Provost if (sc->sc_id == s.id) 1475f92d9b1aSKristof Provost break; 1476f92d9b1aSKristof Provost } 1477f92d9b1aSKristof Provost if (sc == NULL) { 1478f92d9b1aSKristof Provost error = ENOENT; 1479f92d9b1aSKristof Provost goto out; 1480f92d9b1aSKristof Provost } 1481f92d9b1aSKristof Provost 1482f92d9b1aSKristof Provost PFLOW_LOCK(sc); 1483f92d9b1aSKristof Provost error = pflow_set(sc, &s, nlp_get_cred(npt->nlp)); 1484f92d9b1aSKristof Provost PFLOW_UNLOCK(sc); 1485f92d9b1aSKristof Provost 1486f92d9b1aSKristof Provost out: 1487f92d9b1aSKristof Provost NET_EPOCH_EXIT(et); 1488f92d9b1aSKristof Provost return (error); 1489f92d9b1aSKristof Provost } 1490f92d9b1aSKristof Provost 1491f92d9b1aSKristof Provost static const struct genl_cmd pflow_cmds[] = { 1492f92d9b1aSKristof Provost { 1493f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_LIST, 1494f92d9b1aSKristof Provost .cmd_name = "LIST", 1495f92d9b1aSKristof Provost .cmd_cb = pflow_nl_list, 1496f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1497f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1498f92d9b1aSKristof Provost }, 1499f92d9b1aSKristof Provost { 1500f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_CREATE, 1501f92d9b1aSKristof Provost .cmd_name = "CREATE", 1502f92d9b1aSKristof Provost .cmd_cb = pflow_nl_create, 1503f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1504f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1505f92d9b1aSKristof Provost }, 1506f92d9b1aSKristof Provost { 1507f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_DEL, 1508f92d9b1aSKristof Provost .cmd_name = "DEL", 1509f92d9b1aSKristof Provost .cmd_cb = pflow_nl_del, 1510f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1511f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1512f92d9b1aSKristof Provost }, 1513f92d9b1aSKristof Provost { 1514f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_GET, 1515f92d9b1aSKristof Provost .cmd_name = "GET", 1516f92d9b1aSKristof Provost .cmd_cb = pflow_nl_get, 1517f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1518f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1519f92d9b1aSKristof Provost }, 1520f92d9b1aSKristof Provost { 1521f92d9b1aSKristof Provost .cmd_num = PFLOWNL_CMD_SET, 1522f92d9b1aSKristof Provost .cmd_name = "SET", 1523f92d9b1aSKristof Provost .cmd_cb = pflow_nl_set, 1524f92d9b1aSKristof Provost .cmd_flags = GENL_CMD_CAP_DO | GENL_CMD_CAP_DUMP | GENL_CMD_CAP_HASPOL, 1525f92d9b1aSKristof Provost .cmd_priv = PRIV_NETINET_PF, 1526f92d9b1aSKristof Provost }, 1527f92d9b1aSKristof Provost }; 1528f92d9b1aSKristof Provost 1529f92d9b1aSKristof Provost static const struct nlhdr_parser *all_parsers[] = { 1530f92d9b1aSKristof Provost &del_parser, 1531f92d9b1aSKristof Provost &get_parser, 1532f92d9b1aSKristof Provost &set_parser, 1533f92d9b1aSKristof Provost }; 1534f92d9b1aSKristof Provost 1535f92d9b1aSKristof Provost static int 1536f92d9b1aSKristof Provost pflow_init(void) 1537f92d9b1aSKristof Provost { 1538f92d9b1aSKristof Provost bool ret; 1539f92d9b1aSKristof Provost int family_id __diagused; 1540f92d9b1aSKristof Provost 1541f92d9b1aSKristof Provost NL_VERIFY_PARSERS(all_parsers); 1542f92d9b1aSKristof Provost 1543f92d9b1aSKristof Provost family_id = genl_register_family(PFLOWNL_FAMILY_NAME, 0, 2, PFLOWNL_CMD_MAX); 1544f92d9b1aSKristof Provost MPASS(family_id != 0); 1545f92d9b1aSKristof Provost ret = genl_register_cmds(PFLOWNL_FAMILY_NAME, pflow_cmds, NL_ARRAY_LEN(pflow_cmds)); 1546f92d9b1aSKristof Provost 1547f92d9b1aSKristof Provost return (ret ? 0 : ENODEV); 1548f92d9b1aSKristof Provost } 1549f92d9b1aSKristof Provost 1550f92d9b1aSKristof Provost static void 1551f92d9b1aSKristof Provost pflow_uninit(void) 1552f92d9b1aSKristof Provost { 1553f92d9b1aSKristof Provost genl_unregister_family(PFLOWNL_FAMILY_NAME); 1554f92d9b1aSKristof Provost } 1555f92d9b1aSKristof Provost 1556f92d9b1aSKristof Provost static int 1557f92d9b1aSKristof Provost pflow_modevent(module_t mod, int type, void *data) 1558f92d9b1aSKristof Provost { 1559f92d9b1aSKristof Provost int error = 0; 1560f92d9b1aSKristof Provost 1561f92d9b1aSKristof Provost switch (type) { 1562f92d9b1aSKristof Provost case MOD_LOAD: 1563f92d9b1aSKristof Provost error = pflow_init(); 1564f92d9b1aSKristof Provost break; 1565f92d9b1aSKristof Provost case MOD_UNLOAD: 1566f92d9b1aSKristof Provost pflow_uninit(); 1567f92d9b1aSKristof Provost break; 1568f92d9b1aSKristof Provost default: 1569f92d9b1aSKristof Provost error = EINVAL; 1570f92d9b1aSKristof Provost break; 1571f92d9b1aSKristof Provost } 1572f92d9b1aSKristof Provost 1573f92d9b1aSKristof Provost return (error); 1574f92d9b1aSKristof Provost } 1575f92d9b1aSKristof Provost 1576f92d9b1aSKristof Provost static moduledata_t pflow_mod = { 1577f92d9b1aSKristof Provost pflowname, 1578f92d9b1aSKristof Provost pflow_modevent, 1579f92d9b1aSKristof Provost 0 1580f92d9b1aSKristof Provost }; 1581f92d9b1aSKristof Provost 1582f92d9b1aSKristof Provost DECLARE_MODULE(pflow, pflow_mod, SI_SUB_PROTO_FIREWALL, SI_ORDER_ANY); 1583f92d9b1aSKristof Provost MODULE_VERSION(pflow, 1); 1584f92d9b1aSKristof Provost MODULE_DEPEND(pflow, pf, PF_MODVER, PF_MODVER, PF_MODVER); 1585