Download raw body.
if_pflow IPFIX NAT support
And, here's a version without my debug printfs.
Index: if_pflow.c
===================================================================
RCS file: /cvs/src/sys/net/if_pflow.c,v
retrieving revision 1.111
diff -u -p -u -r1.111 if_pflow.c
--- if_pflow.c 7 Jul 2025 02:28:50 -0000 1.111
+++ if_pflow.c 23 Sep 2025 17:00:00 -0000
@@ -89,29 +89,34 @@ int pflowioctl(struct ifnet *, u_long, c
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(struct pflow_softc *, sa_family_t, size_t, u_int16_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 pflow_timeout_nat(void *);
void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
struct pf_state *, struct pf_state_key *, int, int);
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_ipfix_nat_4_data(struct pflow_ipfix_nat_flow4 *,
+ struct pflow_ipfix_nat_flow4 *, struct pf_state *,
+ struct pf_state_key *, 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_ipfix(struct pf_state *, struct pf_state_key *,
- struct pflow_softc *);
+ struct pf_state_key *, struct pflow_softc *);
int export_pflow_if(struct pf_state*, struct pf_state_key *,
- struct pflow_softc *);
+ struct pf_state_key *, struct pflow_softc *);
int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
-int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow,
- struct pflow_softc *sc);
+int copy_flow_ipfix_4_to_m(void *flow, size_t size,
+ struct pflow_softc *sc, u_int16_t tmpl);
int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
struct pflow_softc *sc);
@@ -172,8 +177,8 @@ pflow_clone_create(struct if_clone *ifc,
/* 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.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);
@@ -211,6 +216,60 @@ pflow_clone_create(struct if_clone *ifc,
htons(PFIX_IE_protocolIdentifier);
pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1);
+ /* ipfix IPv4 NAT template */
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.h.tmpl_id =
+ htons(PFLOW_IPFIX_TMPL_NAT_IPV4_ID);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.h.field_count =
+ htons(PFLOW_IPFIX_TMPL_NAT_IPV4_FIELD_COUNT);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.src_ip.field_id =
+ htons(PFIX_IE_sourceIPv4Address);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.src_ip.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.dest_ip.field_id =
+ htons(PFIX_IE_destinationIPv4Address);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.dest_ip.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.if_index_in.field_id =
+ htons(PFIX_IE_ingressInterface);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.if_index_in.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.if_index_out.field_id =
+ htons(PFIX_IE_egressInterface);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.if_index_out.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.packets.field_id =
+ htons(PFIX_IE_packetDeltaCount);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.packets.len = htons(8);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.octets.field_id =
+ htons(PFIX_IE_octetDeltaCount);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.octets.len = htons(8);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.start.field_id =
+ htons(PFIX_IE_flowStartMilliseconds);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.start.len = htons(8);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.finish.field_id =
+ htons(PFIX_IE_flowEndMilliseconds);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.finish.len = htons(8);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_src_ip.field_id =
+ htons(PFIX_IE_postNATSourceIPv4Address);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_src_ip.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_dest_ip.field_id =
+ htons(PFIX_IE_postNATDestinationIPv4Address);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_dest_ip.len = htons(4);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_src_port.field_id =
+ htons(PFIX_IE_postNAPTSourceTransportPort);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_src_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_dest_port.field_id =
+ htons(PFIX_IE_postNAPTDestinationTransportPort);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.post_dest_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.src_port.field_id =
+ htons(PFIX_IE_sourceTransportPort);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.src_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.dest_port.field_id =
+ htons(PFIX_IE_destinationTransportPort);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.dest_port.len = htons(2);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.tos.field_id =
+ htons(PFIX_IE_ipClassOfService);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.tos.len = htons(1);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.protocol.field_id =
+ htons(PFIX_IE_protocolIdentifier);
+ pflowif->sc_tmpl_ipfix.ipv4_nat_tmpl.protocol.len = htons(1);
+
/* ipfix IPv6 template */
pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id =
htons(PFLOW_IPFIX_TMPL_IPV6_ID);
@@ -270,6 +329,7 @@ pflow_clone_create(struct if_clone *ifc,
timeout_set_proc(&pflowif->sc_tmo, pflow_timeout, pflowif);
timeout_set_proc(&pflowif->sc_tmo6, pflow_timeout6, pflowif);
timeout_set_proc(&pflowif->sc_tmo_tmpl, pflow_timeout_tmpl, pflowif);
+ timeout_set_proc(&pflowif->sc_tmo_nat, pflow_timeout_nat, pflowif);
task_set(&pflowif->sc_outputtask, pflow_output_process, pflowif);
@@ -302,6 +362,7 @@ pflow_clone_destroy(struct ifnet *ifp)
timeout_del(&sc->sc_tmo);
timeout_del(&sc->sc_tmo6);
timeout_del(&sc->sc_tmo_tmpl);
+ timeout_del(&sc->sc_tmo_nat);
pflow_flush(sc);
taskq_del_barrier(net_tq(ifp->if_index), &sc->sc_outputtask);
@@ -618,7 +679,7 @@ int
pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
{
sc->sc_maxcount4 = (mtu - hdrsz -
- sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
+ sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_nat_flow4);
sc->sc_maxcount6 = (mtu - hdrsz -
sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
@@ -626,7 +687,7 @@ pflow_calc_mtu(struct pflow_softc *sc, i
if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
sc->sc_maxcount6 = PFLOW_MAXFLOWS;
return (hdrsz + sizeof(struct udpiphdr) +
- MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
+ MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_nat_flow4),
sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
}
@@ -787,6 +848,59 @@ copy_flow_ipfix_4_data(struct pflow_ipfi
}
void
+copy_flow_ipfix_nat_4_data(struct pflow_ipfix_nat_flow4 *flow1,
+ struct pflow_ipfix_nat_flow4 *flow2, struct pf_state *st,
+ struct pf_state_key *sk, struct pf_state_key *skw,
+ struct pflow_softc *sc, int src, int dst)
+{
+ flow1->src_ip = sk->addr[src].v4.s_addr;
+ flow1->dest_ip = sk->addr[dst].v4.s_addr;
+ flow2->src_ip = sk->addr[dst].v4.s_addr;
+ flow2->dest_ip = sk->addr[src].v4.s_addr;
+
+ flow1->post_src_ip = skw->addr[src].v4.s_addr;
+ flow1->post_dest_ip = skw->addr[dst].v4.s_addr;
+ flow1->post_src_port = skw->port[src];
+ flow1->post_dest_port = skw->port[dst];
+
+ flow2->post_src_ip = skw->addr[dst].v4.s_addr;
+ flow2->post_dest_ip = skw->addr[src].v4.s_addr;
+ flow2->post_src_port = skw->port[dst];
+ flow2->post_dest_port = skw->port[src];
+
+ 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((gettime() -
+ getuptime())*1000);
+ else
+ flow1->flow_start = flow2->flow_start = htobe64((gettime() -
+ (getuptime() - st->creation))*1000);
+ flow1->flow_finish = flow2->flow_finish = htobe64((gettime() -
+ (getuptime() - st->expire))*1000);
+
+ flow1->src_port = sk->port[src];
+ flow1->dest_port = sk->port[dst];
+ flow2->src_port = sk->port[dst];
+ flow2->dest_port = sk->port[src];
+
+ flow1->protocol = flow2->protocol = sk->proto;
+ flow1->tos = flow2->tos = st->rule.ptr ? st->rule.ptr->tos : 0;
+}
+
+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)
@@ -829,20 +943,21 @@ int
export_pflow(struct pf_state *st)
{
struct pflow_softc *sc = NULL;
- struct pf_state_key *sk;
+ struct pf_state_key *sk, *skw;
sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK];
+ skw = st->key[st->direction == PF_OUT ? PF_SK_WIRE : PF_SK_STACK];
SMR_SLIST_FOREACH(sc, &pflowif_list, sc_next) {
mtx_enter(&sc->sc_mtx);
switch (sc->sc_version) {
case PFLOW_PROTO_5:
if (sk->af == AF_INET)
- export_pflow_if(st, sk, sc);
+ export_pflow_if(st, sk, skw, sc);
break;
case PFLOW_PROTO_10:
if (sk->af == AF_INET || sk->af == AF_INET6)
- export_pflow_if(st, sk, sc);
+ export_pflow_if(st, sk, skw, sc);
break;
default: /* NOTREACHED */
break;
@@ -855,7 +970,7 @@ export_pflow(struct pf_state *st)
int
export_pflow_if(struct pf_state *st, struct pf_state_key *sk,
- struct pflow_softc *sc)
+ struct pf_state_key *skw, struct pflow_softc *sc)
{
struct pf_state pfs_copy;
struct ifnet *ifp = &sc->sc_if;
@@ -866,7 +981,7 @@ export_pflow_if(struct pf_state *st, str
return (0);
if (sc->sc_version == PFLOW_PROTO_10)
- return (pflow_pack_flow_ipfix(st, sk, sc));
+ return (pflow_pack_flow_ipfix(st, sk, skw, sc));
/* PFLOW_PROTO_5 */
if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
@@ -930,30 +1045,45 @@ copy_flow_to_m(struct pflow_flow *flow,
}
int
-copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc)
+copy_flow_ipfix_4_to_m(void *flow, size_t size, struct pflow_softc *sc,
+ u_int16_t tmpl)
{
int ret = 0;
MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
- if (sc->sc_mbuf == NULL) {
- if ((sc->sc_mbuf =
- pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) {
- return (ENOBUFS);
+ if (tmpl == PFLOW_IPFIX_TMPL_NAT_IPV4_ID) {
+ if (sc->sc_mbuf_nat == NULL) {
+ if ((sc->sc_mbuf_nat = pflow_get_mbuf(sc, tmpl)) == NULL)
+ return (ENOBUFS);
+ sc->sc_count4_nat = 0;
+ timeout_add_sec(&sc->sc_tmo_nat, PFLOW_TIMEOUT);
}
- 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);
-
- pflowstat_inc(pflow_flows);
- sc->sc_gcounter++;
- sc->sc_count4++;
+ m_copyback(sc->sc_mbuf_nat, PFLOW_SET_HDRLEN +
+ (sc->sc_count4_nat * size), size, flow, M_NOWAIT);
+ pflowstat_inc(pflow_flows);
+ sc->sc_gcounter++;
+ sc->sc_count4_nat++;
+
+ if (sc->sc_count4_nat >= sc->sc_maxcount4)
+ ret = pflow_sendout_ipfix(sc, AF_INET, size, tmpl);
+ } else {
+ if (sc->sc_mbuf == NULL) {
+ if ((sc->sc_mbuf = pflow_get_mbuf(sc, tmpl)) == NULL)
+ 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 * size), size, flow, M_NOWAIT);
+ pflowstat_inc(pflow_flows);
+ sc->sc_gcounter++;
+ sc->sc_count4++;
- if (sc->sc_count4 >= sc->sc_maxcount4)
- ret = pflow_sendout_ipfix(sc, AF_INET);
+ if (sc->sc_count4 >= sc->sc_maxcount4)
+ ret = pflow_sendout_ipfix(sc, AF_INET, size, tmpl);
+ }
+
return(ret);
}
@@ -961,6 +1091,7 @@ int
copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc)
{
int ret = 0;
+ int size = sizeof(struct pflow_ipfix_flow6);
MUTEX_ASSERT_LOCKED(&sc->sc_mtx);
@@ -973,15 +1104,15 @@ copy_flow_ipfix_6_to_m(struct pflow_ipfi
timeout_add_sec(&sc->sc_tmo6, PFLOW_TIMEOUT);
}
m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN +
- (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)),
- sizeof(struct pflow_ipfix_flow6), flow, M_NOWAIT);
+ (sc->sc_count6 * size), size, flow, M_NOWAIT);
pflowstat_inc(pflow_flows);
sc->sc_gcounter++;
sc->sc_count6++;
if (sc->sc_count6 >= sc->sc_maxcount6)
- ret = pflow_sendout_ipfix(sc, AF_INET6);
+ ret = pflow_sendout_ipfix(sc, AF_INET6, size,
+ PFLOW_IPFIX_TMPL_IPV6_ID);
return(ret);
}
@@ -1013,27 +1144,58 @@ pflow_pack_flow(struct pf_state *st, str
int
pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk,
- struct pflow_softc *sc)
+ struct pf_state_key *skw, struct pflow_softc *sc)
{
struct pflow_ipfix_flow4 flow4_1, flow4_2;
+ struct pflow_ipfix_nat_flow4 natflow4_1, natflow4_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));
+ int is_nat = (sk != skw);
- 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);
+ if (sk->af == AF_INET) {
+ if (is_nat) {
+ bzero(&natflow4_1, sizeof(natflow4_1));
+ bzero(&natflow4_2, sizeof(natflow4_2));
+
+ if (st->direction == PF_OUT)
+ copy_flow_ipfix_nat_4_data(&natflow4_1,
+ &natflow4_2, st, sk, skw, sc, 1, 0);
+ else
+ copy_flow_ipfix_nat_4_data(&natflow4_1,
+ &natflow4_2, st, sk, skw, sc, 0, 1);
+
+ if (st->bytes[0] != 0) /* first flow from state */
+ ret = copy_flow_ipfix_4_to_m(
+ (void *)&natflow4_1,
+ sizeof(natflow4_1), sc,
+ PFLOW_IPFIX_TMPL_NAT_IPV4_ID);
+ if (st->bytes[1] != 0) /* second flow from state */
+ ret = copy_flow_ipfix_4_to_m(
+ (void *)&natflow4_2,
+ sizeof(natflow4_2), sc,
+ PFLOW_IPFIX_TMPL_NAT_IPV4_ID);
+ } else {
+ 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(
+ (void *)&flow4_1,
+ sizeof(flow4_1), sc,
+ PFLOW_IPFIX_TMPL_IPV4_ID);
+ if (st->bytes[1] != 0) /* second flow from state */
+ ret = copy_flow_ipfix_4_to_m(
+ (void *)&flow4_2,
+ sizeof(flow4_2), sc,
+ PFLOW_IPFIX_TMPL_IPV4_ID);
+ }
} else if (sk->af == AF_INET6) {
bzero(&flow6_1, sizeof(flow6_1));
bzero(&flow6_2, sizeof(flow6_2));
@@ -1054,6 +1216,26 @@ pflow_pack_flow_ipfix(struct pf_state *s
return (ret);
}
+void pflow_timeout_nat(void *v)
+{
+ struct pflow_softc *sc = v;
+
+ mtx_enter(&sc->sc_mtx);
+ switch (sc->sc_version) {
+ case PFLOW_PROTO_5:
+ pflow_sendout_v5(sc);
+ break;
+ case PFLOW_PROTO_10:
+ pflow_sendout_ipfix(sc, AF_INET,
+ sizeof(struct pflow_ipfix_nat_flow4),
+ PFLOW_IPFIX_TMPL_NAT_IPV4_ID);
+ break;
+ default: /* NOTREACHED */
+ break;
+ }
+ mtx_leave(&sc->sc_mtx);
+}
+
void
pflow_timeout(void *v)
{
@@ -1065,7 +1247,9 @@ pflow_timeout(void *v)
pflow_sendout_v5(sc);
break;
case PFLOW_PROTO_10:
- pflow_sendout_ipfix(sc, AF_INET);
+ pflow_sendout_ipfix(sc, AF_INET,
+ sizeof(struct pflow_ipfix_flow4),
+ PFLOW_IPFIX_TMPL_IPV4_ID);
break;
default: /* NOTREACHED */
break;
@@ -1079,7 +1263,9 @@ pflow_timeout6(void *v)
struct pflow_softc *sc = v;
mtx_enter(&sc->sc_mtx);
- pflow_sendout_ipfix(sc, AF_INET6);
+ pflow_sendout_ipfix(sc, AF_INET6,
+ sizeof(struct pflow_ipfix_flow6),
+ PFLOW_IPFIX_TMPL_IPV6_ID);
mtx_leave(&sc->sc_mtx);
}
@@ -1102,8 +1288,15 @@ pflow_flush(struct pflow_softc *sc)
pflow_sendout_v5(sc);
break;
case PFLOW_PROTO_10:
- pflow_sendout_ipfix(sc, AF_INET);
- pflow_sendout_ipfix(sc, AF_INET6);
+ pflow_sendout_ipfix(sc, AF_INET,
+ sizeof(struct pflow_ipfix_nat_flow4),
+ PFLOW_IPFIX_TMPL_NAT_IPV4_ID);
+ pflow_sendout_ipfix(sc, AF_INET,
+ sizeof(struct pflow_ipfix_flow4),
+ PFLOW_IPFIX_TMPL_IPV4_ID);
+ pflow_sendout_ipfix(sc, AF_INET6,
+ sizeof(struct pflow_ipfix_flow6),
+ PFLOW_IPFIX_TMPL_IPV6_ID);
break;
default: /* NOTREACHED */
break;
@@ -1148,7 +1341,7 @@ pflow_sendout_v5(struct pflow_softc *sc)
}
int
-pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
+pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af, size_t size, u_int16_t tmpl)
{
struct mbuf *m;
struct pflow_v10_header *h10;
@@ -1161,14 +1354,23 @@ pflow_sendout_ipfix(struct pflow_softc *
switch (af) {
case AF_INET:
- m = sc->sc_mbuf;
- timeout_del(&sc->sc_tmo);
- if (m == NULL)
- return (0);
- sc->sc_mbuf = NULL;
- count = sc->sc_count4;
+ if (tmpl == PFLOW_IPFIX_TMPL_NAT_IPV4_ID) {
+ m = sc->sc_mbuf_nat;
+ timeout_del(&sc->sc_tmo_nat);
+ if (m == NULL)
+ return (0);
+ sc->sc_mbuf_nat = NULL;
+ count = sc->sc_count4_nat;
+ } else {
+ m = sc->sc_mbuf;
+ timeout_del(&sc->sc_tmo);
+ if (m == NULL)
+ return (0);
+ sc->sc_mbuf = NULL;
+ count = sc->sc_count4;
+ }
set_length = sizeof(struct pflow_set_header)
- + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
+ + count * size;
break;
case AF_INET6:
m = sc->sc_mbuf6;
@@ -1178,7 +1380,7 @@ pflow_sendout_ipfix(struct pflow_softc *
sc->sc_mbuf6 = NULL;
count = sc->sc_count6;
set_length = sizeof(struct pflow_set_header)
- + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
+ + sc->sc_count6 * size;
break;
default:
unhandled_af(af);
Index: if_pflow.h
===================================================================
RCS file: /cvs/src/sys/net/if_pflow.h,v
retrieving revision 1.23
diff -u -p -u -r1.23 if_pflow.h
--- if_pflow.h 16 Dec 2023 22:16:02 -0000 1.23
+++ if_pflow.h 23 Sep 2025 17:00:00 -0000
@@ -33,22 +33,26 @@
/* 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_ingressInterface 10
-#define PFIX_IE_destinationTransportPort 11
-#define PFIX_IE_destinationIPv4Address 12
-#define PFIX_IE_egressInterface 14
-#define PFIX_IE_flowEndSysUpTime 21
-#define PFIX_IE_flowStartSysUpTime 22
-#define PFIX_IE_sourceIPv6Address 27
-#define PFIX_IE_destinationIPv6Address 28
-#define PFIX_IE_flowStartMilliseconds 152
-#define PFIX_IE_flowEndMilliseconds 153
+#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_ingressInterface 10
+#define PFIX_IE_destinationTransportPort 11
+#define PFIX_IE_destinationIPv4Address 12
+#define PFIX_IE_egressInterface 14
+#define PFIX_IE_flowEndSysUpTime 21
+#define PFIX_IE_flowStartSysUpTime 22
+#define PFIX_IE_sourceIPv6Address 27
+#define PFIX_IE_destinationIPv6Address 28
+#define PFIX_IE_flowStartMilliseconds 152
+#define PFIX_IE_flowEndMilliseconds 153
+#define PFIX_IE_postNATSourceIPv4Address 225
+#define PFIX_IE_postNATDestinationIPv4Address 226
+#define PFIX_IE_postNAPTSourceTransportPort 227
+#define PFIX_IE_postNAPTDestinationTransportPort 228
struct pflow_flow {
u_int32_t src_ip;
@@ -110,6 +114,28 @@ struct pflow_ipfix_tmpl_ipv4 {
#define PFLOW_IPFIX_TMPL_IPV4_ID 256
} __packed;
+struct pflow_ipfix_tmpl_nat_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 post_src_ip;
+ struct pflow_tmpl_fspec post_dest_ip;
+ struct pflow_tmpl_fspec post_src_port;
+ struct pflow_tmpl_fspec post_dest_port;
+ 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_NAT_IPV4_FIELD_COUNT 16
+#define PFLOW_IPFIX_TMPL_NAT_IPV4_ID 257
+} __packed;
+
/* update pflow_clone_create() when changing pflow_ipfix_tmpl_v6 */
struct pflow_ipfix_tmpl_ipv6 {
struct pflow_tmpl_hdr h;
@@ -126,13 +152,14 @@ struct pflow_ipfix_tmpl_ipv6 {
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
+#define PFLOW_IPFIX_TMPL_IPV6_ID 258
} __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;
+ struct pflow_ipfix_tmpl_ipv4 ipv4_tmpl;
+ struct pflow_ipfix_tmpl_nat_ipv4 ipv4_nat_tmpl;
+ struct pflow_ipfix_tmpl_ipv6 ipv6_tmpl;
} __packed;
struct pflow_ipfix_flow4 {
@@ -151,6 +178,26 @@ struct pflow_ipfix_flow4 {
/* XXX padding needed? */
} __packed;
+struct pflow_ipfix_nat_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_int32_t post_src_ip; /* postNATSourceIPv4Address */
+ u_int32_t post_dest_ip; /* postNATDestinationIPv4Address */
+ u_int16_t post_src_port; /* postNAPTSourceTransportPort */
+ u_int16_t post_dest_port; /* postNAPTDestinationTransportPort */
+ 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 */
@@ -187,6 +234,7 @@ struct pflow_softc {
unsigned int sc_count; /* [m] */
unsigned int sc_count4; /* [m] */
+ unsigned int sc_count4_nat; /* [m] */
unsigned int sc_count6; /* [m] */
unsigned int sc_maxcount; /* [m] */
unsigned int sc_maxcount4; /* [m] */
@@ -196,6 +244,7 @@ struct pflow_softc {
struct timeout sc_tmo;
struct timeout sc_tmo6;
struct timeout sc_tmo_tmpl;
+ struct timeout sc_tmo_nat;
struct mbuf_queue sc_outputqueue;
struct task sc_outputtask;
struct socket *so; /* [p] */
@@ -207,6 +256,8 @@ struct pflow_softc {
struct mbuf *sc_mbuf; /* [m] current cumulative
mbuf */
struct mbuf *sc_mbuf6; /* [m] current cumulative
+ mbuf */
+ struct mbuf *sc_mbuf_nat; /* [m] current cumulative
mbuf */
SMR_SLIST_ENTRY(pflow_softc) sc_next;
};
if_pflow IPFIX NAT support