diff options
author | Florian Obser <florian@cvs.openbsd.org> | 2013-08-13 08:44:06 +0000 |
---|---|---|
committer | Florian Obser <florian@cvs.openbsd.org> | 2013-08-13 08:44:06 +0000 |
commit | 0a059bc1c663c12221108b3e18bb10e9a25ff466 (patch) | |
tree | 2e178be5f7c2c0bca378542ea43267dc0ee34d14 | |
parent | a1bd9b00f4b2fdf76515f8d2e73164f76a30f2cb (diff) |
Split pflow version 9 and version 10 to be able to send 64 bit
time values for version 10.
While there mark places which will blow up in 2038.
OK benno@
-rw-r--r-- | sys/net/if_pflow.c | 841 | ||||
-rw-r--r-- | sys/net/if_pflow.h | 123 |
2 files changed, 677 insertions, 287 deletions
diff --git a/sys/net/if_pflow.c b/sys/net/if_pflow.c index 4b60bf18e12..ba51cb1849e 100644 --- a/sys/net/if_pflow.c +++ b/sys/net/if_pflow.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflow.c,v 1.33 2013/08/10 18:33:21 florian Exp $ */ +/* $OpenBSD: if_pflow.c,v 1.34 2013/08/13 08:44:05 florian Exp $ */ /* * Copyright (c) 2011 Florian Obser <florian@narrans.de> @@ -82,7 +82,9 @@ void pflowstart(struct ifnet *); 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_v9(struct pflow_softc *, sa_family_t); int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t); +int pflow_sendout_v9_tmpl(struct pflow_softc *); int pflow_sendout_ipfix_tmpl(struct pflow_softc *); int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *); void pflow_timeout(void *); @@ -90,22 +92,36 @@ void pflow_timeout6(void *); void pflow_timeout_tmpl(void *); void copy_flow_data(struct pflow_flow *, struct pflow_flow *, struct pf_state *, struct pf_state_key *, int, int); -void copy_flow4_data(struct pflow_flow4 *, struct pflow_flow4 *, +void copy_flow_v9_4_data(struct pflow_v9_flow4 *, struct pflow_v9_flow4 *, struct pf_state *, struct pf_state_key *, struct pflow_softc *, int, int); -void copy_flow6_data(struct pflow_flow6 *, struct pflow_flow6 *, +void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *, + struct pflow_ipfix_flow4 *, struct pf_state *, struct pf_state_key *, + struct pflow_softc *, int, int); +void copy_flow_v9_6_data(struct pflow_v9_flow6 *, struct pflow_v9_flow6 *, struct pf_state *, struct pf_state_key *, struct pflow_softc *, int, int); +void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *, + struct pflow_ipfix_flow6 *, struct pf_state *, struct pf_state_key *, + struct pflow_softc *, int, int); int pflow_pack_flow(struct pf_state *, struct pf_state_key *, struct pflow_softc *); +int pflow_pack_flow_v9(struct pf_state *, struct pf_state_key *, + struct pflow_softc *); int pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *, struct pflow_softc *); int pflow_get_dynport(void); int export_pflow_if(struct pf_state*, struct pf_state_key *, struct pflow_softc *); int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc); -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); +int copy_flow_v9_4_to_m(struct pflow_v9_flow4 *flow, struct pflow_softc + *sc); +int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, + struct pflow_softc *sc); +int copy_flow_v9_6_to_m(struct pflow_v9_flow6 *flow, struct pflow_softc + *sc); +int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, + struct pflow_softc *sc); struct if_clone pflow_cloner = IF_CLONE_INITIALIZER("pflow", pflow_clone_create, @@ -140,102 +156,185 @@ pflow_clone_create(struct if_clone *ifc, int unit) 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 = + + /* v9 template init */ + bzero(&pflowif->sc_tmpl_v9,sizeof(pflowif->sc_tmpl_v9)); + pflowif->sc_tmpl_v9.set_header.set_id = htons(PFLOW_V9_TMPL_SET_ID); + pflowif->sc_tmpl_v9.set_header.set_length = + htons(sizeof(struct pflow_v9_tmpl)); + + /* v9 IPv4 template */ + pflowif->sc_tmpl_v9.ipv4_tmpl.h.tmpl_id = htons(PFLOW_V9_TMPL_IPV4_ID); + pflowif->sc_tmpl_v9.ipv4_tmpl.h.field_count + = htons(PFLOW_V9_TMPL_IPV4_FIELD_COUNT); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv4_tmpl.src_ip.len = htons(4); + pflowif->sc_tmpl_v9.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.if_index_in.field_id = + pflowif->sc_tmpl_v9.ipv4_tmpl.dest_ip.len = htons(4); + pflowif->sc_tmpl_v9.ipv4_tmpl.if_index_in.field_id = htons(PFIX_IE_ingressInterface); - pflowif->sc_tmpl.ipv4_tmpl.if_index_in.len = htons(4); - pflowif->sc_tmpl.ipv4_tmpl.if_index_out.field_id = + pflowif->sc_tmpl_v9.ipv4_tmpl.if_index_in.len = htons(4); + pflowif->sc_tmpl_v9.ipv4_tmpl.if_index_out.field_id = htons(PFIX_IE_egressInterface); - pflowif->sc_tmpl.ipv4_tmpl.if_index_out.len = htons(4); - pflowif->sc_tmpl.ipv4_tmpl.packets.field_id = + pflowif->sc_tmpl_v9.ipv4_tmpl.if_index_out.len = htons(4); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv4_tmpl.packets.len = htons(8); + pflowif->sc_tmpl_v9.ipv4_tmpl.octets.field_id = htons(PFIX_IE_octetDeltaCount); - pflowif->sc_tmpl.ipv4_tmpl.octets.len = htons(8); - /* keep in sync with SIOCSETPFLOW */ - pflowif->sc_tmpl.ipv4_tmpl.start.field_id = - htons(pflowif->sc_version == PFLOW_PROTO_9? - PFIX_IE_flowStartSysUpTime:PFIX_IE_flowStartSeconds); - pflowif->sc_tmpl.ipv4_tmpl.start.len = htons(4); - /* keep in sync with SIOCSETPFLOW */ - pflowif->sc_tmpl.ipv4_tmpl.finish.field_id = - htons(pflowif->sc_version == PFLOW_PROTO_9? - PFIX_IE_flowEndSysUpTime:PFIX_IE_flowEndSeconds); - pflowif->sc_tmpl.ipv4_tmpl.finish.len = htons(4); - pflowif->sc_tmpl.ipv4_tmpl.src_port.field_id = + pflowif->sc_tmpl_v9.ipv4_tmpl.octets.len = htons(8); + pflowif->sc_tmpl_v9.ipv4_tmpl.start.field_id = + htons(PFIX_IE_flowStartSysUpTime); + pflowif->sc_tmpl_v9.ipv4_tmpl.start.len = htons(4); + pflowif->sc_tmpl_v9.ipv4_tmpl.finish.field_id = + htons(PFIX_IE_flowEndSysUpTime); + pflowif->sc_tmpl_v9.ipv4_tmpl.finish.len = htons(4); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv4_tmpl.src_port.len = htons(2); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv4_tmpl.dest_port.len = htons(2); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv4_tmpl.tos.len = htons(1); + pflowif->sc_tmpl_v9.ipv4_tmpl.protocol.field_id = htons(PFIX_IE_protocolIdentifier); - pflowif->sc_tmpl.ipv4_tmpl.protocol.len = htons(1); + pflowif->sc_tmpl_v9.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 = + /* v9 IPv6 template */ + pflowif->sc_tmpl_v9.ipv6_tmpl.h.tmpl_id = htons(PFLOW_V9_TMPL_IPV6_ID); + pflowif->sc_tmpl_v9.ipv6_tmpl.h.field_count = + htons(PFLOW_V9_TMPL_IPV6_FIELD_COUNT); + pflowif->sc_tmpl_v9.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 = + pflowif->sc_tmpl_v9.ipv6_tmpl.src_ip.len = htons(16); + pflowif->sc_tmpl_v9.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.if_index_in.field_id = + pflowif->sc_tmpl_v9.ipv6_tmpl.dest_ip.len = htons(16); + pflowif->sc_tmpl_v9.ipv6_tmpl.if_index_in.field_id = + htons(PFIX_IE_ingressInterface); + pflowif->sc_tmpl_v9.ipv6_tmpl.if_index_in.len = htons(4); + pflowif->sc_tmpl_v9.ipv6_tmpl.if_index_out.field_id = + htons(PFIX_IE_egressInterface); + pflowif->sc_tmpl_v9.ipv6_tmpl.if_index_out.len = htons(4); + pflowif->sc_tmpl_v9.ipv6_tmpl.packets.field_id = + htons(PFIX_IE_packetDeltaCount); + pflowif->sc_tmpl_v9.ipv6_tmpl.packets.len = htons(8); + pflowif->sc_tmpl_v9.ipv6_tmpl.octets.field_id = + htons(PFIX_IE_octetDeltaCount); + pflowif->sc_tmpl_v9.ipv6_tmpl.octets.len = htons(8); + pflowif->sc_tmpl_v9.ipv6_tmpl.start.field_id = + htons(PFIX_IE_flowStartSysUpTime); + pflowif->sc_tmpl_v9.ipv6_tmpl.start.len = htons(4); + pflowif->sc_tmpl_v9.ipv6_tmpl.finish.field_id = + htons(PFIX_IE_flowEndSysUpTime); + pflowif->sc_tmpl_v9.ipv6_tmpl.finish.len = htons(4); + pflowif->sc_tmpl_v9.ipv6_tmpl.src_port.field_id = + htons(PFIX_IE_sourceTransportPort); + pflowif->sc_tmpl_v9.ipv6_tmpl.src_port.len = htons(2); + pflowif->sc_tmpl_v9.ipv6_tmpl.dest_port.field_id = + htons(PFIX_IE_destinationTransportPort); + pflowif->sc_tmpl_v9.ipv6_tmpl.dest_port.len = htons(2); + pflowif->sc_tmpl_v9.ipv6_tmpl.tos.field_id = + htons(PFIX_IE_ipClassOfService); + pflowif->sc_tmpl_v9.ipv6_tmpl.tos.len = htons(1); + pflowif->sc_tmpl_v9.ipv6_tmpl.protocol.field_id = + htons(PFIX_IE_protocolIdentifier); + pflowif->sc_tmpl_v9.ipv6_tmpl.protocol.len = htons(1); + + /* ipfix template init */ + bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix)); + pflowif->sc_tmpl_ipfix.set_header.set_id = + htons(PFLOW_IPFIX_TMPL_SET_ID); + pflowif->sc_tmpl_ipfix.set_header.set_length = + htons(sizeof(struct pflow_ipfix_tmpl)); + + /* ipfix IPv4 template */ + pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id = + htons(PFLOW_IPFIX_TMPL_IPV4_ID); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count + = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id = + htons(PFIX_IE_sourceIPv4Address); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id = + htons(PFIX_IE_destinationIPv4Address); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id = htons(PFIX_IE_ingressInterface); - pflowif->sc_tmpl.ipv6_tmpl.if_index_in.len = htons(4); - pflowif->sc_tmpl.ipv6_tmpl.if_index_out.field_id = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id = htons(PFIX_IE_egressInterface); - pflowif->sc_tmpl.ipv6_tmpl.if_index_out.len = htons(4); - pflowif->sc_tmpl.ipv6_tmpl.packets.field_id = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv4_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 = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id = htons(PFIX_IE_octetDeltaCount); - pflowif->sc_tmpl.ipv6_tmpl.octets.len = htons(8); - /* keep in sync with SIOCSETPFLOW */ - pflowif->sc_tmpl.ipv6_tmpl.start.field_id = - htons(pflowif->sc_version == PFLOW_PROTO_9? - PFIX_IE_flowStartSysUpTime:PFIX_IE_flowStartSeconds); - pflowif->sc_tmpl.ipv6_tmpl.start.len = htons(4); - /* keep in sync with SIOCSETPFLOW */ - pflowif->sc_tmpl.ipv6_tmpl.finish.field_id = - htons(pflowif->sc_version == PFLOW_PROTO_9? - PFIX_IE_flowEndSysUpTime:PFIX_IE_flowEndSeconds); - pflowif->sc_tmpl.ipv6_tmpl.finish.len = htons(4); - pflowif->sc_tmpl.ipv6_tmpl.src_port.field_id = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id = + htons(PFIX_IE_flowStartMilliseconds); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id = + htons(PFIX_IE_flowEndMilliseconds); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv4_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 = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2); + pflowif->sc_tmpl_ipfix.ipv4_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 = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2); + pflowif->sc_tmpl_ipfix.ipv4_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 = + pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id = htons(PFIX_IE_protocolIdentifier); - pflowif->sc_tmpl.ipv6_tmpl.protocol.len = htons(1); + pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1); + + /* ipfix IPv6 template */ + pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id = + htons(PFLOW_IPFIX_TMPL_IPV6_ID); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count = + htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id = + htons(PFIX_IE_sourceIPv6Address); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id = + htons(PFIX_IE_destinationIPv6Address); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id = + htons(PFIX_IE_ingressInterface); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id = + htons(PFIX_IE_egressInterface); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id = + htons(PFIX_IE_packetDeltaCount); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id = + htons(PFIX_IE_octetDeltaCount); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id = + htons(PFIX_IE_flowStartMilliseconds); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id = + htons(PFIX_IE_flowEndMilliseconds); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id = + htons(PFIX_IE_sourceTransportPort); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id = + htons(PFIX_IE_destinationTransportPort); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id = + htons(PFIX_IE_ipClassOfService); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id = + htons(PFIX_IE_protocolIdentifier); + pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1); ifp = &pflowif->sc_if; snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit); @@ -334,8 +433,11 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 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) { + if (sc->sc_version == PFLOW_PROTO_9) { + s = splnet(); + pflow_sendout_v9_tmpl(sc); + splx(s); + } else if (sc->sc_version == PFLOW_PROTO_10) { s = splnet(); pflow_sendout_ipfix_tmpl(sc); splx(s); @@ -401,32 +503,10 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data) pflow_setmtu(sc, ETHERMTU); pflow_init_timeouts(sc); - switch (sc->sc_version) { - case PFLOW_PROTO_9: - sc->sc_tmpl.set_header.set_id = - htons(PFLOW_V9_TMPL_SET_ID); - sc->sc_tmpl.ipv4_tmpl.start.field_id = - sc->sc_tmpl.ipv6_tmpl.start.field_id = - htons(PFIX_IE_flowStartSysUpTime); - sc->sc_tmpl.ipv4_tmpl.finish.field_id = - sc->sc_tmpl.ipv6_tmpl.finish.field_id = - htons(PFIX_IE_flowEndSysUpTime); + if (sc->sc_version == PFLOW_PROTO_9) + pflow_sendout_v9_tmpl(sc); + else if (sc->sc_version == PFLOW_PROTO_10) pflow_sendout_ipfix_tmpl(sc); - break; - case PFLOW_PROTO_10: - sc->sc_tmpl.set_header.set_id = - htons(PFLOW_V10_TMPL_SET_ID); - sc->sc_tmpl.ipv4_tmpl.start.field_id = - sc->sc_tmpl.ipv6_tmpl.start.field_id = - htons(PFIX_IE_flowStartSeconds); - sc->sc_tmpl.ipv4_tmpl.finish.field_id = - sc->sc_tmpl.ipv6_tmpl.finish.field_id = - htons(PFIX_IE_flowEndSeconds); - pflow_sendout_ipfix_tmpl(sc); - break; - default: - break; - } splx(s); @@ -477,18 +557,29 @@ pflow_init_timeouts(struct pflow_softc *sc) 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_version == PFLOW_PROTO_9) { + sc->sc_maxcount4 = (mtu - hdrsz - + sizeof(struct udpiphdr)) / sizeof(struct pflow_v9_flow4); + sc->sc_maxcount6 = (mtu - hdrsz - + sizeof(struct udpiphdr)) / sizeof(struct pflow_v9_flow6); + } else { + sc->sc_maxcount4 = (mtu - hdrsz - + sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4); + sc->sc_maxcount6 = (mtu - hdrsz - + sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6); + } 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))); + if (sc->sc_version == PFLOW_PROTO_9) + return (hdrsz + sizeof(struct udpiphdr) + + MIN(sc->sc_maxcount4 * sizeof(struct pflow_v9_flow4), + sc->sc_maxcount6 * sizeof(struct pflow_v9_flow6))); + else + return (hdrsz + sizeof(struct udpiphdr) + + MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4), + sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6))); } void @@ -611,7 +702,7 @@ copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2, } void -copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2, +copy_flow_v9_4_data(struct pflow_v9_flow4 *flow1, struct pflow_v9_flow4 *flow2, struct pf_state *st, struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) { @@ -630,36 +721,24 @@ copy_flow4_data(struct pflow_flow4 *flow1, struct pflow_flow4 *flow2, flow1->flow_octets = htobe64(st->bytes[0]); flow2->flow_octets = htobe64(st->bytes[1]); - switch (sc->sc_version) { - case PFLOW_PROTO_9: - /* - * Pretend the flow was created or expired when the machine came - * up when creation is in the future of the last time a package - * was seen or was created / expired before this machine came up - * due to pfsync. - */ - flow1->flow_start = flow2->flow_start = st->creation < 0 || - st->creation > st->expire ? htonl(0) : htonl(st->creation * - 1000); - flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? - htonl(0) : htonl(st->expire * 1000); - break; - case PFLOW_PROTO_10: - flow1->flow_start = flow2->flow_start = htonl(time_second - - (time_uptime - st->creation)); - flow1->flow_finish = flow2->flow_finish = htonl(time_second - - (time_uptime - st->expire)); - break; - default: /* NOTREACHED */ - break; - } + /* + * Pretend the flow was created or expired when the machine came + * up when creation is in the future of the last time a package + * was seen or was created / expired before this machine came up + * due to pfsync. + */ + flow1->flow_start = flow2->flow_start = st->creation < 0 || + st->creation > st->expire ? htonl(0) : htonl(st->creation * + 1000); + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? + htonl(0) : htonl(st->expire * 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, +copy_flow_v9_6_data(struct pflow_v9_flow6 *flow1, struct pflow_v9_flow6 *flow2, struct pf_state *st, struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) { @@ -680,29 +759,93 @@ copy_flow6_data(struct pflow_flow6 *flow1, struct pflow_flow6 *flow2, flow1->flow_octets = htobe64(st->bytes[0]); flow2->flow_octets = htobe64(st->bytes[1]); - switch (sc->sc_version) { - case PFLOW_PROTO_9: - /* - * Pretend the flow was created or expired when the machine came - * up when creation is in the future of the last time a package - * was seen or was created / expired before this machine came up - * due to pfsync. - */ - flow1->flow_start = flow2->flow_start = st->creation < 0 || - st->creation > st->expire ? htonl(0) : htonl(st->creation * - 1000); - flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? - htonl(0) : htonl(st->expire * 1000); - break; - case PFLOW_PROTO_10: - flow1->flow_start = flow2->flow_start = htonl(time_second - - (time_uptime - st->creation)); - flow1->flow_finish = flow2->flow_finish = htonl(time_second - - (time_uptime - st->expire)); - break; - default: /* NOTREACHED */ - break; - } + /* + * Pretend the flow was created or expired when the machine came + * up when creation is in the future of the last time a package + * was seen or was created / expired before this machine came up + * due to pfsync. + */ + flow1->flow_start = flow2->flow_start = st->creation < 0 || + st->creation > st->expire ? htonl(0) : htonl(st->creation * + 1000); + flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? + htonl(0) : htonl(st->expire * 1000); + + flow1->protocol = flow2->protocol = sk->proto; + flow1->tos = flow2->tos = st->rule.ptr->tos; +} + +void +copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1, + struct pflow_ipfix_flow4 *flow2, struct pf_state *st, + struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) +{ + 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->if_index_in = htonl(st->if_index_in); + flow1->if_index_out = htonl(st->if_index_out); + flow2->if_index_in = htonl(st->if_index_out); + flow2->if_index_out = htonl(st->if_index_in); + + 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]); + + /* + * Pretend the flow was created when the machine came up when creation + * is in the future of the last time a package was seen due to pfsync. + */ + if (st->creation > st->expire) + flow1->flow_start = flow2->flow_start = htobe64((time_second - + time_uptime)*1000); + else + flow1->flow_start = flow2->flow_start = htobe64((time_second - + (time_uptime - st->creation))*1000); + flow1->flow_finish = flow2->flow_finish = htobe64((time_second - + (time_uptime - st->expire))*1000); + + flow1->protocol = flow2->protocol = sk->proto; + flow1->tos = flow2->tos = st->rule.ptr->tos; +} + +void +copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1, + struct pflow_ipfix_flow6 *flow2, struct pf_state *st, + struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst) +{ + 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->if_index_in = htonl(st->if_index_in); + flow1->if_index_out = htonl(st->if_index_out); + flow2->if_index_in = htonl(st->if_index_out); + flow2->if_index_out = htonl(st->if_index_in); + + 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]); + + /* + * Pretend the flow was created when the machine came up when creation + * is in the future of the last time a package was seen due to pfsync. + */ + if (st->creation > st->expire) + flow1->flow_start = flow2->flow_start = htobe64((time_second - + time_uptime)*1000); + else + flow1->flow_start = flow2->flow_start = htobe64((time_second - + (time_uptime - st->creation))*1000); + flow1->flow_finish = flow2->flow_finish = htobe64((time_second - + (time_uptime - st->expire))*1000); flow1->protocol = flow2->protocol = sk->proto; flow1->tos = flow2->tos = st->rule.ptr->tos; @@ -748,7 +891,9 @@ export_pflow_if(struct pf_state *st, struct pf_state_key *sk, if (!(ifp->if_flags & IFF_RUNNING)) return (0); - if (sc->sc_version == PFLOW_PROTO_9 || sc->sc_version == PFLOW_PROTO_10) + if (sc->sc_version == PFLOW_PROTO_9) + return (pflow_pack_flow_v9(st, sk, sc)); + if (sc->sc_version == PFLOW_PROTO_10) return (pflow_pack_flow_ipfix(st, sk, sc)); /* PFLOW_PROTO_5 */ @@ -816,14 +961,14 @@ 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) +copy_flow_v9_4_to_m(struct pflow_v9_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) { + pflow_get_mbuf(sc, PFLOW_V9_TMPL_IPV4_ID)) == NULL) { splx(s); return (ENOBUFS); } @@ -831,8 +976,69 @@ copy_flow4_to_m(struct pflow_flow4 *flow, struct pflow_softc *sc) 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); + (sc->sc_count4 * sizeof(struct pflow_v9_flow4)), + sizeof(struct pflow_v9_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_v9(sc, AF_INET); + splx(s); + return(ret); +} + +int +copy_flow_v9_6_to_m(struct pflow_v9_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_V9_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_v9_flow6)), + sizeof(struct pflow_v9_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_v9(sc, AF_INET6); + + splx(s); + return(ret); +} + +int +copy_flow_ipfix_4_to_m(struct pflow_ipfix_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_IPFIX_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_ipfix_flow4)), + sizeof(struct pflow_ipfix_flow4), flow, M_NOWAIT); if (pflowstats.pflow_flows == sc->sc_gcounter) pflowstats.pflow_flows++; @@ -846,14 +1052,14 @@ 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) +copy_flow_ipfix_6_to_m(struct pflow_ipfix_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) { + pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) { splx(s); return (ENOBUFS); } @@ -861,8 +1067,8 @@ copy_flow6_to_m(struct pflow_flow6 *flow, struct pflow_softc *sc) 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); + (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)), + sizeof(struct pflow_ipfix_flow6), flow, M_NOWAIT); if (pflowstats.pflow_flows == sc->sc_gcounter) pflowstats.pflow_flows++; @@ -902,40 +1108,87 @@ pflow_pack_flow(struct pf_state *st, struct pf_state_key *sk, } int -pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk, +pflow_pack_flow_v9(struct pf_state *st, struct pf_state_key *sk, struct pflow_softc *sc) { - struct pflow_flow4 flow4_1, flow4_2; - struct pflow_flow6 flow6_1, flow6_2; + struct pflow_v9_flow4 flow4_1, flow4_2; + struct pflow_v9_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, sk, sc, 1, 0); + copy_flow_v9_4_data(&flow4_1, &flow4_2, st, sk, sc, 1, + 0); else - copy_flow4_data(&flow4_1, &flow4_2, st, sk, sc, 0, 1); + copy_flow_v9_4_data(&flow4_1, &flow4_2, st, sk, sc, 0, + 1); if (st->bytes[0] != 0) /* first flow from state */ - ret = copy_flow4_to_m(&flow4_1, sc); + ret = copy_flow_v9_4_to_m(&flow4_1, sc); if (st->bytes[1] != 0) /* second flow from state */ - ret = copy_flow4_to_m(&flow4_2, sc); + ret = copy_flow_v9_4_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, sk, sc, 1, 0); + copy_flow_v9_6_data(&flow6_1, &flow6_2, st, sk, sc, 1, + 0); else - copy_flow6_data(&flow6_1, &flow6_2, st, sk, sc, 0, 1); + copy_flow_v9_6_data(&flow6_1, &flow6_2, st, sk, sc, 0, + 1); if (st->bytes[0] != 0) /* first flow from state */ - ret = copy_flow6_to_m(&flow6_1, sc); + ret = copy_flow_v9_6_to_m(&flow6_1, sc); if (st->bytes[1] != 0) /* second flow from state */ - ret = copy_flow6_to_m(&flow6_2, sc); + ret = copy_flow_v9_6_to_m(&flow6_2, sc); + } + return (ret); +} + +int +pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk, + struct pflow_softc *sc) +{ + struct pflow_ipfix_flow4 flow4_1, flow4_2; + struct pflow_ipfix_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_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, + 1, 0); + else + copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc, + 0, 1); + + if (st->bytes[0] != 0) /* first flow from state */ + ret = copy_flow_ipfix_4_to_m(&flow4_1, sc); + + if (st->bytes[1] != 0) /* second flow from state */ + ret = copy_flow_ipfix_4_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_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, + 1, 0); + else + copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc, + 0, 1); + + if (st->bytes[0] != 0) /* first flow from state */ + ret = copy_flow_ipfix_6_to_m(&flow6_1, sc); + + if (st->bytes[1] != 0) /* second flow from state */ + ret = copy_flow_ipfix_6_to_m(&flow6_2, sc); } return (ret); } @@ -952,9 +1205,11 @@ pflow_timeout(void *v) pflow_sendout_v5(sc); break; case PFLOW_PROTO_9: - /* ... fall through ... */ + pflow_sendout_v9(sc, AF_INET); + break; case PFLOW_PROTO_10: pflow_sendout_ipfix(sc, AF_INET); + break; default: /* NOTREACHED */ break; } @@ -968,7 +1223,16 @@ pflow_timeout6(void *v) int s; s = splnet(); - pflow_sendout_ipfix(sc, AF_INET6); + switch (sc->sc_version) { + case PFLOW_PROTO_9: + pflow_sendout_v9(sc, AF_INET6); + break; + case PFLOW_PROTO_10: + pflow_sendout_ipfix(sc, AF_INET6); + break; + default: /* NOTREACHED */ + break; + } splx(s); } @@ -979,7 +1243,10 @@ pflow_timeout_tmpl(void *v) int s; s = splnet(); - pflow_sendout_ipfix_tmpl(sc); + if (sc->sc_version == PFLOW_PROTO_9) + pflow_sendout_v9_tmpl(sc); + else if (sc->sc_version == PFLOW_PROTO_10) + pflow_sendout_ipfix_tmpl(sc); splx(s); } @@ -992,6 +1259,9 @@ pflow_flush(struct pflow_softc *sc) pflow_sendout_v5(sc); break; case PFLOW_PROTO_9: + pflow_sendout_v9(sc, AF_INET); + pflow_sendout_v9(sc, AF_INET6); + break; case PFLOW_PROTO_10: pflow_sendout_ipfix(sc, AF_INET); pflow_sendout_ipfix(sc, AF_INET6); @@ -1030,7 +1300,7 @@ pflow_sendout_v5(struct pflow_softc *sc) h->uptime_ms = htonl(time_uptime * 1000); getnanotime(&tv); - h->time_sec = htonl(tv.tv_sec); + h->time_sec = htonl(tv.tv_sec); /* XXX 2038 */ h->time_nanosec = htonl(tv.tv_nsec); return (pflow_sendout_mbuf(sc, m)); @@ -1038,11 +1308,10 @@ pflow_sendout_v5(struct pflow_softc *sc) /* This must be called in splnet() */ int -pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) +pflow_sendout_v9(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; @@ -1054,6 +1323,8 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) if (m == NULL) return (0); sc->sc_mbuf = NULL; + set_length = sizeof(struct pflow_set_header) + + sc->sc_count4 * sizeof(struct pflow_v9_flow4); break; case AF_INET6: m = sc->sc_mbuf6; @@ -1061,6 +1332,8 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) if (m == NULL) return (0); sc->sc_mbuf6 = NULL; + set_length = sizeof(struct pflow_set_header) + + sc->sc_count6 * sizeof(struct pflow_v9_flow6); break; default: /* NOTREACHED */ break; @@ -1073,64 +1346,127 @@ pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af) pflowstats.pflow_packets++; set_hdr = mtod(m, struct pflow_set_header *); + set_hdr->set_length = htons(set_length); + + /* 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 2038 */ + h9->flow_sequence = htonl(sc->sc_gcounter); + h9->observation_dom = htonl(PFLOW_ENGINE_TYPE); + 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_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; set_length = sizeof(struct pflow_set_header) - + sc->sc_count4 * sizeof(struct pflow_flow4); + + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4); break; case AF_INET6: + m = sc->sc_mbuf6; + timeout_del(&sc->sc_tmo6); + if (m == NULL) + return (0); + sc->sc_mbuf6 = NULL; set_length = sizeof(struct pflow_set_header) - + sc->sc_count6 * sizeof(struct pflow_flow6); + + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6); 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 *); 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; + /* 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_IPFIX_HDRLEN + set_length); + h10->time_sec = htonl(time_second); /* XXX 2038 */ + h10->flow_sequence = htonl(sc->sc_gcounter); + h10->observation_dom = htonl(PFLOW_ENGINE_TYPE); return (pflow_sendout_mbuf(sc, m)); } /* This must be called in splnet() */ int -pflow_sendout_ipfix_tmpl(struct pflow_softc *sc) +pflow_sendout_v9_tmpl(struct pflow_softc *sc) { struct mbuf *m; struct pflow_v9_header *h9; + 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_v9_tmpl), + &sc->sc_tmpl_v9, M_NOWAIT)) { + m_freem(m); + return (0); + } + pflowstats.pflow_packets++; + + /* 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 2038 */ + h9->flow_sequence = htonl(sc->sc_gcounter); + h9->observation_dom = htonl(PFLOW_ENGINE_TYPE); + + timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT); + 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_v10_header *h10; struct ifnet *ifp = &sc->sc_if; @@ -1142,48 +1478,27 @@ pflow_sendout_ipfix_tmpl(struct pflow_softc *sc) 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)) { + if (m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl), + &sc->sc_tmpl_ipfix, 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; + + /* 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_IPFIX_HDRLEN + sizeof(struct + pflow_ipfix_tmpl)); + h10->time_sec = htonl(time_second); /* XXX 2038 */ + h10->flow_sequence = htonl(sc->sc_gcounter); + h10->observation_dom = htonl(PFLOW_ENGINE_TYPE); + timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT); return (pflow_sendout_mbuf(sc, m)); } diff --git a/sys/net/if_pflow.h b/sys/net/if_pflow.h index 250ff7e47ef..1676ec8d016 100644 --- a/sys/net/if_pflow.h +++ b/sys/net/if_pflow.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_pflow.h,v 1.8 2013/05/03 15:33:47 florian Exp $ */ +/* $OpenBSD: if_pflow.h,v 1.9 2013/08/13 08:44:05 florian Exp $ */ /* * Copyright (c) 2008 Henning Brauer <henning@openbsd.org> @@ -30,7 +30,7 @@ #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 +#define PFLOW_IPFIX_TMPL_SET_ID 2 /* RFC 5102 Information Element Identifiers */ @@ -48,8 +48,8 @@ #define PFIX_IE_flowStartSysUpTime 22 #define PFIX_IE_sourceIPv6Address 27 #define PFIX_IE_destinationIPv6Address 28 -#define PFIX_IE_flowStartSeconds 150 -#define PFIX_IE_flowEndSeconds 151 +#define PFIX_IE_flowStartMilliseconds 152 +#define PFIX_IE_flowEndMilliseconds 153 struct pflow_flow { u_int32_t src_ip; @@ -93,8 +93,8 @@ struct pflow_tmpl_fspec { u_int16_t len; } __packed; -/* update pflow_clone_create() when changing pflow_tmpl_ipv4 */ -struct pflow_tmpl_ipv4 { +/* update pflow_clone_create() when changing pflow_v9_tmpl_ipv4 */ +struct pflow_v9_tmpl_ipv4 { struct pflow_tmpl_hdr h; struct pflow_tmpl_fspec src_ip; struct pflow_tmpl_fspec dest_ip; @@ -108,12 +108,12 @@ struct pflow_tmpl_ipv4 { struct pflow_tmpl_fspec dest_port; struct pflow_tmpl_fspec tos; struct pflow_tmpl_fspec protocol; -#define PFLOW_TMPL_IPV4_FIELD_COUNT 12 -#define PFLOW_TMPL_IPV4_ID 256 +#define PFLOW_V9_TMPL_IPV4_FIELD_COUNT 12 +#define PFLOW_V9_TMPL_IPV4_ID 256 } __packed; -/* update pflow_clone_create() when changing pflow_tmpl_v6 */ -struct pflow_tmpl_ipv6 { +/* update pflow_clone_create() when changing pflow_v9_tmpl_v6 */ +struct pflow_v9_tmpl_ipv6 { struct pflow_tmpl_hdr h; struct pflow_tmpl_fspec src_ip; struct pflow_tmpl_fspec dest_ip; @@ -127,17 +127,62 @@ struct pflow_tmpl_ipv6 { struct pflow_tmpl_fspec dest_port; struct pflow_tmpl_fspec tos; struct pflow_tmpl_fspec protocol; -#define PFLOW_TMPL_IPV6_FIELD_COUNT 12 -#define PFLOW_TMPL_IPV6_ID 257 +#define PFLOW_V9_TMPL_IPV6_FIELD_COUNT 12 +#define PFLOW_V9_TMPL_IPV6_ID 257 } __packed; -struct pflow_tmpl { +struct pflow_v9_tmpl { struct pflow_set_header set_header; - struct pflow_tmpl_ipv4 ipv4_tmpl; - struct pflow_tmpl_ipv6 ipv6_tmpl; + struct pflow_v9_tmpl_ipv4 ipv4_tmpl; + struct pflow_v9_tmpl_ipv6 ipv6_tmpl; } __packed; -struct pflow_flow4 { + +/* update pflow_clone_create() when changing pflow_ipfix_tmpl_ipv4 */ +struct pflow_ipfix_tmpl_ipv4 { + struct pflow_tmpl_hdr h; + struct pflow_tmpl_fspec src_ip; + struct pflow_tmpl_fspec dest_ip; + struct pflow_tmpl_fspec if_index_in; + struct pflow_tmpl_fspec if_index_out; + 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_IPFIX_TMPL_IPV4_FIELD_COUNT 12 +#define PFLOW_IPFIX_TMPL_IPV4_ID 256 +} __packed; + +/* update pflow_clone_create() when changing pflow_ipfix_tmpl_v6 */ +struct pflow_ipfix_tmpl_ipv6 { + struct pflow_tmpl_hdr h; + struct pflow_tmpl_fspec src_ip; + struct pflow_tmpl_fspec dest_ip; + struct pflow_tmpl_fspec if_index_in; + struct pflow_tmpl_fspec if_index_out; + 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_IPFIX_TMPL_IPV6_FIELD_COUNT 12 +#define PFLOW_IPFIX_TMPL_IPV6_ID 257 +} __packed; + +struct pflow_ipfix_tmpl { + struct pflow_set_header set_header; + struct pflow_ipfix_tmpl_ipv4 ipv4_tmpl; + struct pflow_ipfix_tmpl_ipv6 ipv6_tmpl; +} __packed; + +struct pflow_v9_flow4 { u_int32_t src_ip; /* sourceIPv4Address*/ u_int32_t dest_ip; /* destinationIPv4Address */ u_int32_t if_index_in; /* ingressInterface */ @@ -153,18 +198,47 @@ struct pflow_flow4 { /* XXX padding needed? */ } __packed; -struct pflow_flow6 { +struct pflow_v9_flow6 { + struct in6_addr src_ip; /* sourceIPv6Address */ + struct in6_addr dest_ip; /* destinationIPv6Address */ + u_int32_t if_index_in; /* ingressInterface */ + u_int32_t if_index_out; /* egressInterface */ + 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_ipfix_flow4 { + u_int32_t src_ip; /* sourceIPv4Address*/ + u_int32_t dest_ip; /* destinationIPv4Address */ + u_int32_t if_index_in; /* ingressInterface */ + u_int32_t if_index_out; /* egressInterface */ + u_int64_t flow_packets; /* packetDeltaCount */ + u_int64_t flow_octets; /* octetDeltaCount */ + int64_t flow_start; /* flowStartMilliseconds */ + int64_t flow_finish; /* flowEndMilliseconds */ + 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_ipfix_flow6 { struct in6_addr src_ip; /* sourceIPv6Address */ struct in6_addr dest_ip; /* destinationIPv6Address */ u_int32_t if_index_in; /* ingressInterface */ u_int32_t if_index_out; /* egressInterface */ u_int64_t flow_packets; /* packetDeltaCount */ u_int64_t flow_octets; /* octetDeltaCount */ - u_int32_t flow_start; /* - * flowStartSysUpTime / - * flowStartSeconds - */ - u_int32_t flow_finish; /* flowEndSysUpTime / flowEndSeconds */ + int64_t flow_start; /* flowStartMilliseconds */ + int64_t flow_finish; /* flowEndMilliseconds */ u_int16_t src_port; /* sourceTransportPort */ u_int16_t dest_port; /* destinationTransportPort */ u_int8_t tos; /* ipClassOfService */ @@ -196,7 +270,8 @@ struct pflow_softc { struct in_addr sc_receiver_ip; u_int16_t sc_receiver_port; u_char sc_send_templates; - struct pflow_tmpl sc_tmpl; + struct pflow_v9_tmpl sc_tmpl_v9; + struct pflow_ipfix_tmpl sc_tmpl_ipfix; u_int8_t sc_version; struct mbuf *sc_mbuf; /* current cumulative mbuf */ struct mbuf *sc_mbuf6; /* current cumulative mbuf */ @@ -230,7 +305,7 @@ struct pflow_v10_header { u_int32_t observation_dom; } __packed; -#define PFLOW_V10_HDRLEN sizeof(struct pflow_v10_header) +#define PFLOW_IPFIX_HDRLEN sizeof(struct pflow_v10_header) struct pflow_v9_header { u_int16_t version; |