summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sbin/ifconfig/ifconfig.812
-rw-r--r--sbin/ifconfig/ifconfig.c35
-rw-r--r--share/man/man4/pflow.425
-rw-r--r--sys/net/if_pflow.c655
-rw-r--r--sys/net/if_pflow.h161
5 files changed, 835 insertions, 53 deletions
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 64fb7d106a0..ca3c7b82d0f 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ifconfig.8,v 1.225 2011/12/04 06:26:10 haesbaert Exp $
+.\" $OpenBSD: ifconfig.8,v 1.226 2012/02/02 12:34:37 benno Exp $
.\" $NetBSD: ifconfig.8,v 1.11 1996/01/04 21:27:29 pk Exp $
.\" $FreeBSD: ifconfig.8,v 1.16 1998/02/01 07:03:29 steve Exp $
.\"
@@ -31,7 +31,7 @@
.\"
.\" @(#)ifconfig.8 8.4 (Berkeley) 6/1/94
.\"
-.Dd $Mdocdate: December 4 2011 $
+.Dd $Mdocdate: February 2 2012 $
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -1186,10 +1186,15 @@ packets entering the MPLS domain.
.El
.\" PFLOW
.Sh PFLOW
+.nr nS 1
+.Bk -words
.Nm ifconfig
.Ar pflow-interface
.Op Oo Fl Oc Ns Cm flowdst Ar addr : Ns Ar port
.Op Oo Fl Oc Ns Cm flowsrc Ar addr
+.Op Cm pflowproto Ar n
+.Ek
+.nr nS 0
.Pp
The following options are available for a
.Xr pflow 4
@@ -1214,6 +1219,9 @@ is the IP address used as sender of the UDP packets and may be used to
identify the source of the data on the pflow collector.
.It Fl flowsrc
Unset the source address.
+.It Cm pflowproto Ar n
+Set the protocol version.
+The default is version 5.
.El
.\" PFSYNC
.Sh PFSYNC
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index 5477b590c77..53e69e931ea 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ifconfig.c,v 1.253 2011/12/04 06:26:10 haesbaert Exp $ */
+/* $OpenBSD: ifconfig.c,v 1.254 2012/02/02 12:34:37 benno Exp $ */
/* $NetBSD: ifconfig.c,v 1.40 1997/10/01 02:19:43 enami Exp $ */
/*
@@ -248,6 +248,7 @@ void setpflow_sender(const char *, int);
void unsetpflow_sender(const char *, int);
void setpflow_receiver(const char *, int);
void unsetpflow_receiver(const char *, int);
+void setpflowproto(const char *, int);
void list_cloners(void);
void setifipdst(const char *, int);
void setifdesc(const char *, int);
@@ -405,6 +406,7 @@ const struct cmd {
{ "-flowsrc", 1, 0, unsetpflow_sender },
{ "flowdst", NEXTARG, 0, setpflow_receiver },
{ "-flowdst", 1, 0, unsetpflow_receiver },
+ { "pflowproto", NEXTARG, 0, setpflowproto },
{ "-inet6", IFXF_NOINET6, 0, setifxflags } ,
{ "keepalive", NEXTARG2, 0, NULL, setkeepalive },
{ "-keepalive", 1, 0, unsetkeepalive },
@@ -3811,8 +3813,9 @@ pflow_status(void)
return;
printf("\tpflow: sender: %s ", inet_ntoa(preq.sender_ip));
- printf("receiver: %s:%u\n", inet_ntoa(preq.receiver_ip),
+ printf("receiver: %s:%u ", inet_ntoa(preq.receiver_ip),
ntohs(preq.receiver_port));
+ printf("version: %d\n", preq.version);
}
/* ARGSUSED */
@@ -3913,6 +3916,34 @@ unsetpflow_receiver(const char *val, int d)
err(1, "SIOCSETPFLOW");
}
+/* PFLOWPROTO XXX */
+void
+setpflowproto(const char *val, int d)
+{
+ struct pflow_protos ppr[] = PFLOW_PROTOS;
+ struct pflowreq preq;
+ int i;
+
+ bzero(&preq, sizeof(preq));
+ preq.version = PFLOW_PROTO_MAX;
+
+ for (i = 0; i < (sizeof(ppr) / sizeof(ppr[0])); i++) {
+ if (strcmp(val, ppr[i].ppr_name) == 0) {
+ preq.version = ppr[i].ppr_proto;
+ break;
+ }
+ }
+ if (preq.version == PFLOW_PROTO_MAX)
+ errx(1, "Invalid pflow protocol: %s", val);
+
+ preq.addrmask |= PFLOW_MASK_VERSION;
+
+ ifr.ifr_data = (caddr_t)&preq;
+
+ if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
+ err(1, "SIOCSETPFLOW");
+}
+
void
pppoe_status(void)
{
diff --git a/share/man/man4/pflow.4 b/share/man/man4/pflow.4
index 450eaefbe13..cc72690fe59 100644
--- a/share/man/man4/pflow.4
+++ b/share/man/man4/pflow.4
@@ -1,4 +1,4 @@
-.\" $OpenBSD: pflow.4,v 1.10 2009/11/27 17:56:48 jmc Exp $
+.\" $OpenBSD: pflow.4,v 1.11 2012/02/02 12:34:37 benno Exp $
.\"
.\" Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
.\" Copyright (c) 2008 Joerg Goltermann <jg@osn.de>
@@ -15,7 +15,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 27 2009 $
+.Dd $Mdocdate: February 2 2012 $
.Dt PFLOW 4
.Os
.Sh NAME
@@ -32,7 +32,7 @@ accounting data from the kernel using
.Xr udp 4
packets.
.Nm
-is compatible with netflow v5.
+is compatible with netflow version 5, 9, and IPFIX (10).
The data is extracted from the
.Xr pf 4
state table.
@@ -99,6 +99,11 @@ and 10.0.0.2:1234 as destination:
.Bd -literal -offset indent
# ifconfig pflow0 flowsrc 10.0.0.1 flowdst 10.0.0.2:1234
.Ed
+.Pp
+The protocol is set to IPFIX with the following command:
+.Bd -literal -offset indent
+# ifconfig pflow0 pflowproto 10
+.Ed
.Sh SEE ALSO
.Xr netintro 4 ,
.Xr pf 4 ,
@@ -106,8 +111,22 @@ and 10.0.0.2:1234 as destination:
.Xr pf.conf 5 ,
.Xr ifconfig 8 ,
.Xr tcpdump 8
+.Rs
+.%R RFC 3954
+.%T "Cisco Systems NetFlow Services Export Version 9"
+.%D October 2004
+.Re
+.Rs
+.%R RFC 5101
+.%T "Specification of the IP Flow Information Export (IPFIX) Protocol for the Exchange of IP Traffic Flow Information"
+.%D January 2008
+.Re
.Sh HISTORY
The
.Nm
device first appeared in
.Ox 4.5 .
+.Sh BUGS
+The IPFIX implementation is incomplete:
+The required transport protocol SCTP is not supported.
+Transport over TCP and DTLS protected flow export is also not supported.
diff --git a/sys/net/if_pflow.c b/sys/net/if_pflow.c
index 9524609c18d..45b24b9037d 100644
--- a/sys/net/if_pflow.c
+++ b/sys/net/if_pflow.c
@@ -1,6 +1,8 @@
-/* $OpenBSD: if_pflow.c,v 1.18 2011/11/25 12:52:10 dlg Exp $ */
+/* $OpenBSD: if_pflow.c,v 1.19 2012/02/02 12:34:37 benno Exp $ */
/*
+ * Copyright (c) 2011 Florian Obser <florian@narrans.de>
+ * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de>
* Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
* Copyright (c) 2008 Joerg Goltermann <jg@osn.de>
*
@@ -69,22 +71,36 @@ struct pflowstats pflowstats;
void pflowattach(int);
int pflow_clone_create(struct if_clone *, int);
int pflow_clone_destroy(struct ifnet *);
+void pflow_init_timeouts(struct pflow_softc *);
+int pflow_calc_mtu(struct pflow_softc *, int, int);
void pflow_setmtu(struct pflow_softc *, int);
int pflowoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *);
int pflowioctl(struct ifnet *, u_long, caddr_t);
void pflowstart(struct ifnet *);
-struct mbuf *pflow_get_mbuf(struct pflow_softc *);
-int pflow_sendout(struct pflow_softc *);
+struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
+void pflow_flush(struct pflow_softc *);
+int pflow_sendout_v5(struct pflow_softc *);
+int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
+int pflow_sendout_ipfix_tmpl(struct pflow_softc *);
int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
void pflow_timeout(void *);
+void pflow_timeout6(void *);
+void pflow_timeout_tmpl(void *);
void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
struct pf_state *, int, int);
+void copy_flow4_data(struct pflow_flow4 *, struct pflow_flow4 *,
+ struct pf_state *, int, int);
+void copy_flow6_data(struct pflow_flow6 *, struct pflow_flow6 *,
+ struct pf_state *, int, int);
int pflow_pack_flow(struct pf_state *, struct pflow_softc *);
+int pflow_pack_flow_ipfix(struct pf_state *, struct pflow_softc *);
int pflow_get_dynport(void);
int export_pflow_if(struct pf_state*, struct pflow_softc *);
int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
+int copy_flow4_to_m(struct pflow_flow4 *flow, struct pflow_softc *sc);
+int copy_flow6_to_m(struct pflow_flow6 *flow, struct pflow_softc *sc);
struct if_clone pflow_cloner =
IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
@@ -117,9 +133,6 @@ pflow_clone_create(struct if_clone *ifc, int unit)
M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
return (ENOMEM);
- pflowif->sc_sender_ip.s_addr = INADDR_ANY;
- pflowif->sc_sender_port = pflow_get_dynport();
-
pflowif->sc_imo.imo_membership = malloc(
(sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
M_WAITOK|M_ZERO);
@@ -128,6 +141,84 @@ pflow_clone_create(struct if_clone *ifc, int unit)
pflowif->sc_receiver_port = 0;
pflowif->sc_sender_ip.s_addr = INADDR_ANY;
pflowif->sc_sender_port = pflow_get_dynport();
+ pflowif->sc_version = PFLOW_PROTO_DEFAULT;
+ bzero(&pflowif->sc_tmpl,sizeof(pflowif->sc_tmpl));
+ pflowif->sc_tmpl.set_header.set_id =
+ htons(pflowif->sc_version == PFLOW_PROTO_9?
+ PFLOW_V9_TMPL_SET_ID:PFLOW_V10_TMPL_SET_ID);
+ pflowif->sc_tmpl.set_header.set_length =
+ htons(sizeof(struct pflow_tmpl));
+
+ /* v9/v10 IPv4 template */
+ pflowif->sc_tmpl.ipv4_tmpl.h.tmpl_id = htons(PFLOW_TMPL_IPV4_ID);
+ pflowif->sc_tmpl.ipv4_tmpl.h.field_count
+ = htons(PFLOW_TMPL_IPV4_FIELD_COUNT);
+ pflowif->sc_tmpl.ipv4_tmpl.src_ip.field_id =
+ htons(PFIX_IE_sourceIPv4Address);
+ pflowif->sc_tmpl.ipv4_tmpl.src_ip.len = htons(4);
+ pflowif->sc_tmpl.ipv4_tmpl.dest_ip.field_id =
+ htons(PFIX_IE_destinationIPv4Address);
+ pflowif->sc_tmpl.ipv4_tmpl.dest_ip.len = htons(4);
+ pflowif->sc_tmpl.ipv4_tmpl.packets.field_id =
+ htons(PFIX_IE_packetDeltaCount);
+ pflowif->sc_tmpl.ipv4_tmpl.packets.len = htons(8);
+ pflowif->sc_tmpl.ipv4_tmpl.octets.field_id =
+ htons(PFIX_IE_octetDeltaCount);
+ pflowif->sc_tmpl.ipv4_tmpl.octets.len = htons(8);
+ pflowif->sc_tmpl.ipv4_tmpl.start.field_id =
+ htons(PFIX_IE_flowStartSysUpTime);
+ pflowif->sc_tmpl.ipv4_tmpl.start.len = htons(4);
+ pflowif->sc_tmpl.ipv4_tmpl.finish.field_id =
+ htons(PFIX_IE_flowEndSysUpTime);
+ pflowif->sc_tmpl.ipv4_tmpl.finish.len = htons(4);
+ pflowif->sc_tmpl.ipv4_tmpl.src_port.field_id =
+ htons(PFIX_IE_sourceTransportPort);
+ pflowif->sc_tmpl.ipv4_tmpl.src_port.len = htons(2);
+ pflowif->sc_tmpl.ipv4_tmpl.dest_port.field_id =
+ htons(PFIX_IE_destinationTransportPort);
+ pflowif->sc_tmpl.ipv4_tmpl.dest_port.len = htons(2);
+ pflowif->sc_tmpl.ipv4_tmpl.tos.field_id =
+ htons(PFIX_IE_ipClassOfService);
+ pflowif->sc_tmpl.ipv4_tmpl.tos.len = htons(1);
+ pflowif->sc_tmpl.ipv4_tmpl.protocol.field_id =
+ htons(PFIX_IE_protocolIdentifier);
+ pflowif->sc_tmpl.ipv4_tmpl.protocol.len = htons(1);
+
+ /* v9/v10 IPv6 template */
+ pflowif->sc_tmpl.ipv6_tmpl.h.tmpl_id = htons(PFLOW_TMPL_IPV6_ID);
+ pflowif->sc_tmpl.ipv6_tmpl.h.field_count =
+ htons(PFLOW_TMPL_IPV6_FIELD_COUNT);
+ pflowif->sc_tmpl.ipv6_tmpl.src_ip.field_id =
+ htons(PFIX_IE_sourceIPv6Address);
+ pflowif->sc_tmpl.ipv6_tmpl.src_ip.len = htons(16);
+ pflowif->sc_tmpl.ipv6_tmpl.dest_ip.field_id =
+ htons(PFIX_IE_destinationIPv6Address);
+ pflowif->sc_tmpl.ipv6_tmpl.dest_ip.len = htons(16);
+ pflowif->sc_tmpl.ipv6_tmpl.packets.field_id =
+ htons(PFIX_IE_packetDeltaCount);
+ pflowif->sc_tmpl.ipv6_tmpl.packets.len = htons(8);
+ pflowif->sc_tmpl.ipv6_tmpl.octets.field_id =
+ htons(PFIX_IE_octetDeltaCount);
+ pflowif->sc_tmpl.ipv6_tmpl.octets.len = htons(8);
+ pflowif->sc_tmpl.ipv6_tmpl.start.field_id =
+ htons(PFIX_IE_flowStartSysUpTime);
+ pflowif->sc_tmpl.ipv6_tmpl.start.len = htons(4);
+ pflowif->sc_tmpl.ipv6_tmpl.finish.field_id =
+ htons(PFIX_IE_flowEndSysUpTime);
+ pflowif->sc_tmpl.ipv6_tmpl.finish.len = htons(4);
+ pflowif->sc_tmpl.ipv6_tmpl.src_port.field_id =
+ htons(PFIX_IE_sourceTransportPort);
+ pflowif->sc_tmpl.ipv6_tmpl.src_port.len = htons(2);
+ pflowif->sc_tmpl.ipv6_tmpl.dest_port.field_id =
+ htons(PFIX_IE_destinationTransportPort);
+ pflowif->sc_tmpl.ipv6_tmpl.dest_port.len = htons(2);
+ pflowif->sc_tmpl.ipv6_tmpl.tos.field_id =
+ htons(PFIX_IE_ipClassOfService);
+ pflowif->sc_tmpl.ipv6_tmpl.tos.len = htons(1);
+ pflowif->sc_tmpl.ipv6_tmpl.protocol.field_id =
+ htons(PFIX_IE_protocolIdentifier);
+ pflowif->sc_tmpl.ipv6_tmpl.protocol.len = htons(1);
+
ifp = &pflowif->sc_if;
snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit);
ifp->if_softc = pflowif;
@@ -140,7 +231,7 @@ pflow_clone_create(struct if_clone *ifc, int unit)
ifp->if_flags = IFF_UP;
ifp->if_flags &= ~IFF_RUNNING; /* not running, need receiver */
pflow_setmtu(pflowif, ETHERMTU);
- timeout_set(&pflowif->sc_tmo, pflow_timeout, pflowif);
+ pflow_init_timeouts(pflowif);
if_attach(ifp);
if_alloc_sadl(ifp);
@@ -160,7 +251,7 @@ pflow_clone_destroy(struct ifnet *ifp)
int s;
s = splnet();
- pflow_sendout(sc);
+ pflow_flush(sc);
if_detach(ifp);
SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
free(sc->sc_imo.imo_membership, M_IPMOPTS);
@@ -218,6 +309,13 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_receiver_port != 0) {
ifp->if_flags |= IFF_RUNNING;
sc->sc_gcounter=pflowstats.pflow_flows;
+ /* send templates on startup */
+ if (sc->sc_version == PFLOW_PROTO_9
+ || sc->sc_version == PFLOW_PROTO_10) {
+ s = splnet();
+ pflow_sendout_ipfix_tmpl(sc);
+ splx(s);
+ }
} else
ifp->if_flags &= ~IFF_RUNNING;
break;
@@ -228,7 +326,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
ifr->ifr_mtu = MCLBYTES;
s = splnet();
if (ifr->ifr_mtu < ifp->if_mtu)
- pflow_sendout(sc);
+ pflow_flush(sc);
pflow_setmtu(sc, ifr->ifr_mtu);
splx(s);
break;
@@ -239,6 +337,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
pflowr.sender_ip = sc->sc_sender_ip;
pflowr.receiver_ip = sc->sc_receiver_ip;
pflowr.receiver_port = sc->sc_receiver_port;
+ pflowr.version = sc->sc_version;
if ((error = copyout(&pflowr, ifr->ifr_data,
sizeof(pflowr))))
@@ -251,10 +350,19 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
if ((error = copyin(ifr->ifr_data, &pflowr,
sizeof(pflowr))))
return (error);
-
+ if (pflowr.addrmask & PFLOW_MASK_VERSION) {
+ switch(pflowr.version) {
+ case PFLOW_PROTO_5:
+ case PFLOW_PROTO_9:
+ case PFLOW_PROTO_10:
+ break;
+ default:
+ return(EINVAL);
+ }
+ }
s = splnet();
- pflow_sendout(sc);
- splx(s);
+
+ pflow_flush(sc);
if (pflowr.addrmask & PFLOW_MASK_DSTIP)
sc->sc_receiver_ip = pflowr.receiver_ip;
@@ -262,6 +370,22 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sc->sc_receiver_port = pflowr.receiver_port;
if (pflowr.addrmask & PFLOW_MASK_SRCIP)
sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr;
+ /* error check is above */
+ if (pflowr.addrmask & PFLOW_MASK_VERSION)
+ sc->sc_version = pflowr.version;
+
+ pflow_setmtu(sc, ETHERMTU);
+ pflow_init_timeouts(sc);
+
+ if (sc->sc_version == PFLOW_PROTO_9
+ || sc->sc_version == PFLOW_PROTO_10) {
+ sc->sc_tmpl.set_header.set_id =
+ htons(sc->sc_version == PFLOW_PROTO_9?
+ PFLOW_V9_TMPL_SET_ID:PFLOW_V10_TMPL_SET_ID);
+ pflow_sendout_ipfix_tmpl(sc);
+ }
+
+ splx(s);
if ((ifp->if_flags & IFF_UP) &&
sc->sc_receiver_ip.s_addr != 0 &&
@@ -280,6 +404,51 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
}
void
+pflow_init_timeouts(struct pflow_softc *sc)
+{
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ if (timeout_initialized(&sc->sc_tmo6))
+ timeout_del(&sc->sc_tmo6);
+ if (timeout_initialized(&sc->sc_tmo_tmpl))
+ timeout_del(&sc->sc_tmo_tmpl);
+ if (!timeout_initialized(&sc->sc_tmo))
+ timeout_set(&sc->sc_tmo, pflow_timeout, sc);
+ break;
+ case PFLOW_PROTO_9:
+ case PFLOW_PROTO_10:
+ if (!timeout_initialized(&sc->sc_tmo_tmpl))
+ timeout_set(&sc->sc_tmo_tmpl, pflow_timeout_tmpl, sc);
+ if (!timeout_initialized(&sc->sc_tmo))
+ timeout_set(&sc->sc_tmo, pflow_timeout, sc);
+ if (!timeout_initialized(&sc->sc_tmo6))
+ timeout_set(&sc->sc_tmo6, pflow_timeout6, sc);
+
+ timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+}
+
+int
+pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
+{
+ sc->sc_maxcount4 = (mtu - hdrsz -
+ sizeof(struct udpiphdr)) / sizeof(struct pflow_flow4);
+ if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
+ sc->sc_maxcount4 = PFLOW_MAXFLOWS;
+ sc->sc_maxcount6 = (mtu - hdrsz -
+ sizeof(struct udpiphdr)) / sizeof(struct pflow_flow6);
+ if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
+ sc->sc_maxcount6 = PFLOW_MAXFLOWS;
+
+ return (hdrsz + sizeof(struct udpiphdr) +
+ MIN(sc->sc_maxcount4 * sizeof(struct pflow_flow4),
+ sc->sc_maxcount6 * sizeof(struct pflow_flow6)));
+}
+
+void
pflow_setmtu(struct pflow_softc *sc, int mtu_req)
{
int mtu;
@@ -289,18 +458,33 @@ pflow_setmtu(struct pflow_softc *sc, int mtu_req)
else
mtu = mtu_req;
- sc->sc_maxcount = (mtu - sizeof(struct pflow_header) -
- sizeof (struct udpiphdr)) / sizeof(struct pflow_flow);
- if (sc->sc_maxcount > PFLOW_MAXFLOWS)
- sc->sc_maxcount = PFLOW_MAXFLOWS;
- sc->sc_if.if_mtu = sizeof(struct pflow_header) +
- sizeof (struct udpiphdr) +
- sc->sc_maxcount * sizeof(struct pflow_flow);
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ sc->sc_maxcount = (mtu - sizeof(struct pflow_header) -
+ sizeof(struct udpiphdr)) / sizeof(struct pflow_flow);
+ if (sc->sc_maxcount > PFLOW_MAXFLOWS)
+ sc->sc_maxcount = PFLOW_MAXFLOWS;
+ sc->sc_if.if_mtu = sizeof(struct pflow_header) +
+ sizeof(struct udpiphdr) +
+ sc->sc_maxcount * sizeof(struct pflow_flow);
+ break;
+ case PFLOW_PROTO_9:
+ sc->sc_if.if_mtu =
+ pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v9_header));
+ break;
+ case PFLOW_PROTO_10:
+ sc->sc_if.if_mtu =
+ pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header));
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
}
struct mbuf *
-pflow_get_mbuf(struct pflow_softc *sc)
+pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id)
{
+ struct pflow_set_header set_hdr;
struct pflow_header h;
struct mbuf *m;
@@ -320,18 +504,29 @@ pflow_get_mbuf(struct pflow_softc *sc)
m->m_len = m->m_pkthdr.len = 0;
m->m_pkthdr.rcvif = NULL;
- /* populate pflow_header */
- h.reserved1 = 0;
- h.reserved2 = 0;
- h.count = 0;
- h.version = htons(PFLOW_VERSION);
- h.flow_sequence = htonl(sc->sc_gcounter);
- h.engine_type = PFLOW_ENGINE_TYPE;
- h.engine_id = PFLOW_ENGINE_ID;
- m_copyback(m, 0, PFLOW_HDRLEN, &h, M_NOWAIT);
-
- sc->sc_count = 0;
- timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
+ if (sc == NULL) /* get only a new empty mbuf */
+ return (m);
+
+ if (sc->sc_version == PFLOW_PROTO_5) {
+ /* populate pflow_header */
+ h.reserved1 = 0;
+ h.reserved2 = 0;
+ h.count = 0;
+ h.version = htons(PFLOW_PROTO_5);
+ h.flow_sequence = htonl(sc->sc_gcounter);
+ h.engine_type = PFLOW_ENGINE_TYPE;
+ h.engine_id = PFLOW_ENGINE_ID;
+ m_copyback(m, 0, PFLOW_HDRLEN, &h, M_NOWAIT);
+
+ sc->sc_count = 0;
+ timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
+ } else {
+ /* populate pflow_set_header */
+ set_hdr.set_length = 0;
+ set_hdr.set_id = htons(set_id);
+ m_copyback(m, 0, PFLOW_SET_HDRLEN, &set_hdr, M_NOWAIT);
+ }
+
return (m);
}
@@ -369,17 +564,82 @@ copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2,
flow1->tos = flow2->tos = st->rule.ptr->tos;
}
+void
+copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2,
+ struct pf_state *st, int src, int dst)
+{
+ struct pf_state_key *sk = st->key[PF_SK_WIRE];
+
+ flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
+ flow1->src_port = flow2->dest_port = sk->port[src];
+ flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
+ flow1->dest_port = flow2->src_port = sk->port[dst];
+
+ flow1->flow_packets = htobe64(st->packets[0]);
+ flow2->flow_packets = htobe64(st->packets[1]);
+ flow1->flow_octets = htobe64(st->bytes[0]);
+ flow2->flow_octets = htobe64(st->bytes[1]);
+
+ flow1->flow_start = flow2->flow_start =
+ htonl(st->creation * 1000);
+ flow1->flow_finish = flow2->flow_finish =
+ htonl((time_uptime - (st->rule.ptr->timeout[st->timeout] ?
+ st->rule.ptr->timeout[st->timeout] :
+ pf_default_rule.timeout[st->timeout])) * 1000);
+
+ flow1->protocol = flow2->protocol = sk->proto;
+ flow1->tos = flow2->tos = st->rule.ptr->tos;
+}
+
+void
+copy_flow6_data(struct pflow_flow6 *flow1, struct pflow_flow6 *flow2,
+ struct pf_state *st, int src, int dst)
+{
+ struct pf_state_key *sk = st->key[PF_SK_WIRE];
+ bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip));
+ bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip));
+ flow1->src_port = flow2->dest_port = sk->port[src];
+ bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip));
+ bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip));
+ flow1->dest_port = flow2->src_port = sk->port[dst];
+
+ flow1->flow_packets = htobe64(st->packets[0]);
+ flow2->flow_packets = htobe64(st->packets[1]);
+ flow1->flow_octets = htobe64(st->bytes[0]);
+ flow2->flow_octets = htobe64(st->bytes[1]);
+
+ flow1->flow_start = flow2->flow_start =
+ htonl(st->creation * 1000);
+ flow1->flow_finish = flow2->flow_finish =
+ htonl((time_uptime - (st->rule.ptr->timeout[st->timeout] ?
+ st->rule.ptr->timeout[st->timeout] :
+ pf_default_rule.timeout[st->timeout])) * 1000);
+
+ flow1->protocol = flow2->protocol = sk->proto;
+ flow1->tos = flow2->tos = st->rule.ptr->tos;
+}
+
int
export_pflow(struct pf_state *st)
{
struct pflow_softc *sc = NULL;
struct pf_state_key *sk = st->key[PF_SK_WIRE];
- if (sk->af != AF_INET)
- return (0);
-
SLIST_FOREACH(sc, &pflowif_list, sc_next) {
- export_pflow_if(st, sc);
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ if( sk->af == AF_INET )
+ export_pflow_if(st, sc);
+ break;
+ case PFLOW_PROTO_9:
+ /* ... fall through ... */
+ case PFLOW_PROTO_10:
+ if( sk->af == AF_INET || sk->af == AF_INET6 )
+ export_pflow_if(st, sc);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
}
return (0);
@@ -396,6 +656,10 @@ export_pflow_if(struct pf_state *st, struct pflow_softc *sc)
if (!(ifp->if_flags & IFF_RUNNING))
return (0);
+ if (sc->sc_version == PFLOW_PROTO_9 || sc->sc_version == PFLOW_PROTO_10)
+ return (pflow_pack_flow_ipfix(st, sc));
+
+ /* PFLOW_PROTO_5 */
if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
&& (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES))
return (pflow_pack_flow(st, sc));
@@ -438,14 +702,14 @@ copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc)
s = splnet();
if (sc->sc_mbuf == NULL) {
- if ((sc->sc_mbuf = pflow_get_mbuf(sc)) == NULL) {
+ if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL) {
splx(s);
return (ENOBUFS);
}
}
m_copyback(sc->sc_mbuf, PFLOW_HDRLEN +
- (sc->sc_count * sizeof (struct pflow_flow)),
- sizeof (struct pflow_flow), flow, M_NOWAIT);
+ (sc->sc_count * sizeof(struct pflow_flow)),
+ sizeof(struct pflow_flow), flow, M_NOWAIT);
if (pflowstats.pflow_flows == sc->sc_gcounter)
pflowstats.pflow_flows++;
@@ -453,7 +717,68 @@ copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc)
sc->sc_count++;
if (sc->sc_count >= sc->sc_maxcount)
- ret = pflow_sendout(sc);
+ ret = pflow_sendout_v5(sc);
+
+ splx(s);
+ return(ret);
+}
+
+int
+copy_flow4_to_m(struct pflow_flow4 *flow, struct pflow_softc *sc)
+{
+ int s, ret = 0;
+
+ s = splnet();
+ if (sc->sc_mbuf == NULL) {
+ if ((sc->sc_mbuf =
+ pflow_get_mbuf(sc, PFLOW_TMPL_IPV4_ID)) == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+ sc->sc_count4 = 0;
+ timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
+ }
+ m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN +
+ (sc->sc_count4 * sizeof(struct pflow_flow4)),
+ sizeof(struct pflow_flow4), flow, M_NOWAIT);
+
+ if (pflowstats.pflow_flows == sc->sc_gcounter)
+ pflowstats.pflow_flows++;
+ sc->sc_gcounter++;
+ sc->sc_count4++;
+
+ if (sc->sc_count4 >= sc->sc_maxcount4)
+ ret = pflow_sendout_ipfix(sc, AF_INET);
+ splx(s);
+ return(ret);
+}
+
+int
+copy_flow6_to_m(struct pflow_flow6 *flow, struct pflow_softc *sc)
+{
+ int s, ret = 0;
+
+ s = splnet();
+ if (sc->sc_mbuf6 == NULL) {
+ if ((sc->sc_mbuf6 =
+ pflow_get_mbuf(sc, PFLOW_TMPL_IPV6_ID)) == NULL) {
+ splx(s);
+ return (ENOBUFS);
+ }
+ sc->sc_count6 = 0;
+ timeout_add_sec(&sc->sc_tmo6, PFLOW_TIMEOUT);
+ }
+ m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN +
+ (sc->sc_count6 * sizeof(struct pflow_flow6)),
+ sizeof(struct pflow_flow6), flow, M_NOWAIT);
+
+ if (pflowstats.pflow_flows == sc->sc_gcounter)
+ pflowstats.pflow_flows++;
+ sc->sc_gcounter++;
+ sc->sc_count6++;
+
+ if (sc->sc_count6 >= sc->sc_maxcount6)
+ ret = pflow_sendout_ipfix(sc, AF_INET6);
splx(s);
return(ret);
@@ -483,6 +808,45 @@ pflow_pack_flow(struct pf_state *st, struct pflow_softc *sc)
return (ret);
}
+int
+pflow_pack_flow_ipfix(struct pf_state *st, struct pflow_softc *sc)
+{
+ struct pf_state_key *sk = st->key[PF_SK_WIRE];
+ struct pflow_flow4 flow4_1, flow4_2;
+ struct pflow_flow6 flow6_1, flow6_2;
+ int ret = 0;
+ if (sk->af == AF_INET) {
+ bzero(&flow4_1, sizeof(flow4_1));
+ bzero(&flow4_2, sizeof(flow4_2));
+
+ if (st->direction == PF_OUT)
+ copy_flow4_data(&flow4_1, &flow4_2, st, 1, 0);
+ else
+ copy_flow4_data(&flow4_1, &flow4_2, st, 0, 1);
+
+ if (st->bytes[0] != 0) /* first flow from state */
+ ret = copy_flow4_to_m(&flow4_1, sc);
+
+ if (st->bytes[1] != 0) /* second flow from state */
+ ret = copy_flow4_to_m(&flow4_2, sc);
+ } else if (sk->af == AF_INET6) {
+ bzero(&flow6_1, sizeof(flow6_1));
+ bzero(&flow6_2, sizeof(flow6_2));
+
+ if (st->direction == PF_OUT)
+ copy_flow6_data(&flow6_1, &flow6_2, st, 1, 0);
+ else
+ copy_flow6_data(&flow6_1, &flow6_2, st, 0, 1);
+
+ if (st->bytes[0] != 0) /* first flow from state */
+ ret = copy_flow6_to_m(&flow6_1, sc);
+
+ if (st->bytes[1] != 0) /* second flow from state */
+ ret = copy_flow6_to_m(&flow6_2, sc);
+ }
+ return (ret);
+}
+
void
pflow_timeout(void *v)
{
@@ -490,13 +854,64 @@ pflow_timeout(void *v)
int s;
s = splnet();
- pflow_sendout(sc);
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ pflow_sendout_v5(sc);
+ break;
+ case PFLOW_PROTO_9:
+ /* ... fall through ... */
+ case PFLOW_PROTO_10:
+ pflow_sendout_ipfix(sc, AF_INET);
+ default: /* NOTREACHED */
+ break;
+ }
splx(s);
}
+void
+pflow_timeout6(void *v)
+{
+ struct pflow_softc *sc = v;
+ int s;
+
+ s = splnet();
+ pflow_sendout_ipfix(sc, AF_INET6);
+ splx(s);
+}
+
+void
+pflow_timeout_tmpl(void *v)
+{
+ struct pflow_softc *sc = v;
+ int s;
+
+ s = splnet();
+ pflow_sendout_ipfix_tmpl(sc);
+ splx(s);
+}
+
+/* This must be called in splnet() */
+void
+pflow_flush(struct pflow_softc *sc)
+{
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ pflow_sendout_v5(sc);
+ break;
+ case PFLOW_PROTO_9:
+ case PFLOW_PROTO_10:
+ pflow_sendout_ipfix(sc, AF_INET);
+ pflow_sendout_ipfix(sc, AF_INET6);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+}
+
+
/* This must be called in splnet() */
int
-pflow_sendout(struct pflow_softc *sc)
+pflow_sendout_v5(struct pflow_softc *sc)
{
struct mbuf *m = sc->sc_mbuf;
struct pflow_header *h;
@@ -525,6 +940,158 @@ pflow_sendout(struct pflow_softc *sc)
return (pflow_sendout_mbuf(sc, m));
}
+/* This must be called in splnet() */
+int
+pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
+{
+ struct mbuf *m;
+ struct pflow_v9_header *h9;
+ struct pflow_v10_header *h10;
+ struct pflow_set_header *set_hdr;
+ struct ifnet *ifp = &sc->sc_if;
+ int set_length;
+
+ switch (af) {
+ case AF_INET:
+ m = sc->sc_mbuf;
+ timeout_del(&sc->sc_tmo);
+ if (m == NULL)
+ return (0);
+ sc->sc_mbuf = NULL;
+ break;
+ case AF_INET6:
+ m = sc->sc_mbuf6;
+ timeout_del(&sc->sc_tmo6);
+ if (m == NULL)
+ return (0);
+ sc->sc_mbuf6 = NULL;
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ m_freem(m);
+ return (0);
+ }
+
+ pflowstats.pflow_packets++;
+ set_hdr = mtod(m, struct pflow_set_header *);
+ switch (af) {
+ case AF_INET:
+ set_length = sizeof(struct pflow_set_header)
+ + sc->sc_count4 * sizeof(struct pflow_flow4);
+ break;
+ case AF_INET6:
+ set_length = sizeof(struct pflow_set_header)
+ + sc->sc_count6 * sizeof(struct pflow_flow6);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+ set_hdr->set_length = htons(set_length);
+
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_9:
+ /* populate pflow_header */
+ M_PREPEND(m, sizeof(struct pflow_v9_header), M_DONTWAIT);
+ if (m == NULL) {
+ pflowstats.pflow_onomem++;
+ return (ENOBUFS);
+ }
+ h9 = mtod(m, struct pflow_v9_header *);
+ h9->version = htons(PFLOW_PROTO_9);
+ h9->count = htons(1);
+ h9->uptime_ms = htonl(time_uptime * 1000);
+ h9->time_sec = htonl(time_second);
+ /* XXX correct mod 2^32 semantics? */
+ h9->flow_sequence = htonl(sc->sc_gcounter);
+ h9->observation_dom = htonl(PFLOW_ENGINE_TYPE);
+ break;
+ case PFLOW_PROTO_10:
+ /* populate pflow_header */
+ M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
+ if (m == NULL) {
+ pflowstats.pflow_onomem++;
+ return (ENOBUFS);
+ }
+ h10 = mtod(m, struct pflow_v10_header *);
+ h10->version = htons(PFLOW_PROTO_10);
+ h10->length = htons(PFLOW_V10_HDRLEN + set_length);
+ h10->time_sec = htonl(time_second);
+ /* XXX correct mod 2^32 semantics? */
+ h10->flow_sequence = htonl(sc->sc_gcounter);
+ h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+ return (pflow_sendout_mbuf(sc, m));
+}
+
+/* This must be called in splnet() */
+int
+pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
+{
+ struct mbuf *m;
+ struct pflow_v9_header *h9;
+ struct pflow_v10_header *h10;
+ struct ifnet *ifp = &sc->sc_if;
+
+ timeout_del(&sc->sc_tmo_tmpl);
+
+ if (!(ifp->if_flags & IFF_RUNNING)) {
+ return (0);
+ }
+ m = pflow_get_mbuf(NULL, 0);
+ if (m == NULL)
+ return (0);
+ if (m_copyback(m, 0, sizeof(struct pflow_tmpl),
+ &sc->sc_tmpl, M_NOWAIT)) {
+ m_freem(m);
+ return (0);
+ }
+ pflowstats.pflow_packets++;
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_9:
+ /* populate pflow_header */
+ M_PREPEND(m, sizeof(struct pflow_v9_header), M_DONTWAIT);
+ if (m == NULL) {
+ pflowstats.pflow_onomem++;
+ return (ENOBUFS);
+ }
+ h9 = mtod(m, struct pflow_v9_header *);
+ h9->version = htons(PFLOW_PROTO_9);
+ h9->count = htons(1);
+ h9->uptime_ms = htonl(time_uptime * 1000);
+ h9->time_sec = htonl(time_second);
+ /* XXX correct mod 2^32 semantics? */
+ h9->flow_sequence = htonl(sc->sc_gcounter);
+ h9->observation_dom = htonl(PFLOW_ENGINE_TYPE);
+ break;
+ case PFLOW_PROTO_10:
+ /* populate pflow_header */
+ M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
+ if (m == NULL) {
+ pflowstats.pflow_onomem++;
+ return (ENOBUFS);
+ }
+ h10 = mtod(m, struct pflow_v10_header *);
+ h10->version = htons(PFLOW_PROTO_10);
+ h10->length = htons(PFLOW_V10_HDRLEN
+ + sizeof(struct pflow_tmpl));
+ h10->time_sec = htonl(time_second);
+ /* XXX correct mod 2^32 semantics? */
+ h10->flow_sequence = htonl(sc->sc_gcounter);
+ h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+ timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
+ return (pflow_sendout_mbuf(sc, m));
+}
+
int
pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
{
@@ -547,7 +1114,7 @@ pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
ui->ui_sport = sc->sc_sender_port;
ui->ui_dst = sc->sc_receiver_ip;
ui->ui_dport = sc->sc_receiver_port;
- ui->ui_ulen = htons(sizeof (struct udphdr) + len);
+ ui->ui_ulen = htons(sizeof(struct udphdr) + len);
ip = (struct ip *)ui;
ip->ip_v = IPVERSION;
@@ -556,7 +1123,7 @@ pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
ip->ip_off = htons(IP_DF);
ip->ip_tos = IPTOS_LOWDELAY;
ip->ip_ttl = IPDEFTTL;
- ip->ip_len = htons(sizeof (struct udpiphdr) + len);
+ ip->ip_len = htons(sizeof(struct udpiphdr) + len);
/*
* Compute the pseudo-header checksum; defer further checksumming
diff --git a/sys/net/if_pflow.h b/sys/net/if_pflow.h
index 51dc017ae5a..b39e491cecf 100644
--- a/sys/net/if_pflow.h
+++ b/sys/net/if_pflow.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_pflow.h,v 1.5 2009/02/27 11:09:36 gollo Exp $ */
+/* $OpenBSD: if_pflow.h,v 1.6 2012/02/02 12:34:37 benno Exp $ */
/*
* Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
@@ -23,11 +23,29 @@
#define PFLOW_ID_LEN sizeof(u_int64_t)
#define PFLOW_MAXFLOWS 30
-#define PFLOW_VERSION 5
#define PFLOW_ENGINE_TYPE 42
#define PFLOW_ENGINE_ID 42
#define PFLOW_MAXBYTES 0xffffffff
#define PFLOW_TIMEOUT 30
+#define PFLOW_TMPL_TIMEOUT 30 /* rfc 5101 10.3.6 (p.40) recommends 600 */
+
+#define PFLOW_V9_TMPL_SET_ID 0
+#define PFLOW_V10_TMPL_SET_ID 2
+
+/* RFC 5102 Information Element Identifiers */
+
+#define PFIX_IE_octetDeltaCount 1
+#define PFIX_IE_packetDeltaCount 2
+#define PFIX_IE_protocolIdentifier 4
+#define PFIX_IE_ipClassOfService 5
+#define PFIX_IE_sourceTransportPort 7
+#define PFIX_IE_sourceIPv4Address 8
+#define PFIX_IE_destinationTransportPort 11
+#define PFIX_IE_destinationIPv4Address 12
+#define PFIX_IE_flowEndSysUpTime 21
+#define PFIX_IE_flowStartSysUpTime 22
+#define PFIX_IE_sourceIPv6Address 27
+#define PFIX_IE_destinationIPv6Address 28
struct pflow_flow {
u_int32_t src_ip;
@@ -52,6 +70,93 @@ struct pflow_flow {
u_int16_t pad2;
} __packed;
+struct pflow_set_header {
+ u_int16_t set_id;
+ u_int16_t set_length; /* total length of the set,
+ in octets, including the set header */
+} __packed;
+
+#define PFLOW_SET_HDRLEN sizeof(struct pflow_set_header)
+
+struct pflow_tmpl_hdr {
+ u_int16_t tmpl_id;
+ u_int16_t field_count;
+} __packed;
+
+/* field specifier rfc5101 sec 3.2, v9 uses the same format*/
+struct pflow_tmpl_fspec {
+ u_int16_t field_id;
+ u_int16_t len;
+} __packed;
+
+/* update pflow_clone_create() when changing pflow_v10_tmpl_v4 */
+struct pflow_tmpl_ipv4 {
+ struct pflow_tmpl_hdr h;
+ struct pflow_tmpl_fspec src_ip;
+ struct pflow_tmpl_fspec dest_ip;
+ struct pflow_tmpl_fspec packets;
+ struct pflow_tmpl_fspec octets;
+ struct pflow_tmpl_fspec start;
+ struct pflow_tmpl_fspec finish;
+ struct pflow_tmpl_fspec src_port;
+ struct pflow_tmpl_fspec dest_port;
+ struct pflow_tmpl_fspec tos;
+ struct pflow_tmpl_fspec protocol;
+#define PFLOW_TMPL_IPV4_FIELD_COUNT 10
+#define PFLOW_TMPL_IPV4_ID 256
+} __packed;
+
+/* update pflow_clone_create() when changing pflow_v10_tmpl_v6 */
+struct pflow_tmpl_ipv6 {
+ struct pflow_tmpl_hdr h;
+ struct pflow_tmpl_fspec src_ip;
+ struct pflow_tmpl_fspec dest_ip;
+ struct pflow_tmpl_fspec packets;
+ struct pflow_tmpl_fspec octets;
+ struct pflow_tmpl_fspec start;
+ struct pflow_tmpl_fspec finish;
+ struct pflow_tmpl_fspec src_port;
+ struct pflow_tmpl_fspec dest_port;
+ struct pflow_tmpl_fspec tos;
+ struct pflow_tmpl_fspec protocol;
+#define PFLOW_TMPL_IPV6_FIELD_COUNT 10
+#define PFLOW_TMPL_IPV6_ID 257
+} __packed;
+
+struct pflow_tmpl {
+ struct pflow_set_header set_header;
+ struct pflow_tmpl_ipv4 ipv4_tmpl;
+ struct pflow_tmpl_ipv6 ipv6_tmpl;
+} __packed;
+
+struct pflow_flow4 {
+ u_int32_t src_ip; /* sourceIPv4Address*/
+ u_int32_t dest_ip; /* destinationIPv4Address */
+ u_int64_t flow_packets; /* packetDeltaCount */
+ u_int64_t flow_octets; /* octetDeltaCount */
+ u_int32_t flow_start; /* flowStartSysUpTime */
+ u_int32_t flow_finish; /* flowEndSysUpTime */
+ u_int16_t src_port; /* sourceTransportPort */
+ u_int16_t dest_port; /* destinationTransportPort */
+ u_int8_t tos; /* ipClassOfService */
+ u_int8_t protocol; /* protocolIdentifier */
+ /* XXX padding needed? */
+} __packed;
+
+struct pflow_flow6 {
+ struct in6_addr src_ip; /* sourceIPv6Address */
+ struct in6_addr dest_ip; /* destinationIPv6Address */
+ u_int64_t flow_packets; /* packetDeltaCount */
+ u_int64_t flow_octets; /* octetDeltaCount */
+ u_int32_t flow_start; /* flowStartSysUpTime */
+ u_int32_t flow_finish; /* flowEndSysUpTime */
+ u_int16_t src_port; /* sourceTransportPort */
+ u_int16_t dest_port; /* destinationTransportPort */
+ u_int8_t tos; /* ipClassOfService */
+ u_int8_t protocol; /* protocolIdentifier */
+ /* XXX padding needed? */
+} __packed;
+
#ifdef _KERNEL
extern int pflow_ok;
@@ -61,15 +166,25 @@ struct pflow_softc {
struct ifnet *sc_pflow_ifp;
unsigned int sc_count;
+ unsigned int sc_count4;
+ unsigned int sc_count6;
unsigned int sc_maxcount;
+ unsigned int sc_maxcount4;
+ unsigned int sc_maxcount6;
u_int64_t sc_gcounter;
struct ip_moptions sc_imo;
struct timeout sc_tmo;
+ struct timeout sc_tmo6;
+ struct timeout sc_tmo_tmpl;
struct in_addr sc_sender_ip;
u_int16_t sc_sender_port;
struct in_addr sc_receiver_ip;
u_int16_t sc_receiver_port;
+ u_char sc_send_templates;
+ struct pflow_tmpl sc_tmpl;
+ u_int8_t sc_version;
struct mbuf *sc_mbuf; /* current cumulative mbuf */
+ struct mbuf *sc_mbuf6; /* current cumulative mbuf */
SLIST_ENTRY(pflow_softc) sc_next;
};
@@ -92,6 +207,27 @@ struct pflow_header {
#define PFLOW_HDRLEN sizeof(struct pflow_header)
+struct pflow_v10_header {
+ u_int16_t version;
+ u_int16_t length;
+ u_int32_t time_sec;
+ u_int32_t flow_sequence;
+ u_int32_t observation_dom;
+} __packed;
+
+#define PFLOW_V10_HDRLEN sizeof(struct pflow_v10_header)
+
+struct pflow_v9_header {
+ u_int16_t version;
+ u_int16_t count;
+ u_int32_t uptime_ms;
+ u_int32_t time_sec;
+ u_int32_t flow_sequence;
+ u_int32_t observation_dom;
+} __packed;
+
+#define PFLOW_V9_HDRLEN sizeof(struct pflow_v9_header)
+
struct pflowstats {
u_int64_t pflow_flows;
u_int64_t pflow_packets;
@@ -99,6 +235,25 @@ struct pflowstats {
u_int64_t pflow_oerrors;
};
+/* Supported flow protocols */
+#define PFLOW_PROTO_5 5 /* original pflow */
+#define PFLOW_PROTO_9 9 /* version 9 */
+#define PFLOW_PROTO_10 10 /* ipfix */
+#define PFLOW_PROTO_MAX 11
+
+#define PFLOW_PROTO_DEFAULT PFLOW_PROTO_5
+
+struct pflow_protos {
+ const char *ppr_name;
+ u_int8_t ppr_proto;
+};
+
+#define PFLOW_PROTOS { \
+ { "5", PFLOW_PROTO_5 }, \
+ { "9", PFLOW_PROTO_9 }, \
+ { "10", PFLOW_PROTO_10 }, \
+}
+
/*
* Configuration structure for SIOCSETPFLOW SIOCGETPFLOW
*/
@@ -107,9 +262,11 @@ struct pflowreq {
struct in_addr receiver_ip;
u_int16_t receiver_port;
u_int16_t addrmask;
+ u_int8_t version;
#define PFLOW_MASK_SRCIP 0x01
#define PFLOW_MASK_DSTIP 0x02
#define PFLOW_MASK_DSTPRT 0x04
+#define PFLOW_MASK_VERSION 0x08
};
#ifdef _KERNEL