aboutsummaryrefslogtreecommitdiff
path: root/lib/libpfctl/libpfctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libpfctl/libpfctl.c')
-rw-r--r--lib/libpfctl/libpfctl.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index e93c79758428..d84a66063647 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -3188,3 +3188,139 @@ pfctl_del_table(struct pfctl_handle *h, struct pfr_table *table,
return (e.error);
}
+static bool
+snl_attr_get_uint64_into_int_array(struct snl_state *ss, struct nlattr *nla,
+ const void *arg, void *target)
+{
+ uint64_t *u64target;
+ struct snl_uint64_array a = {
+ .count = 0,
+ .max = (size_t)arg,
+ };
+ bool error;
+
+ u64target = malloc(a.max * sizeof(uint64_t));
+ a.array = u64target;
+
+ error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &array_parser, &a);
+ if (! error)
+ return (error);
+
+ for (size_t i = 0; i < a.count; i++)
+ ((int *)target)[i] = (int)u64target[i];
+
+ free(u64target);
+
+ return (true);
+}
+
+#define _OUT(_field) offsetof(struct pfr_table, _field)
+static const struct snl_attr_parser ap_table[] = {
+ { .type = PF_T_ANCHOR, .off = _OUT(pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = snl_attr_copy_string },
+ { .type = PF_T_NAME, .off = _OUT(pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb =snl_attr_copy_string },
+ { .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrt_flags), .cb = snl_attr_get_uint32 },
+};
+#undef _OUT
+SNL_DECLARE_ATTR_PARSER(table_parser, ap_table);
+#define _OUT(_field) offsetof(struct pfr_tstats, _field)
+static struct snl_attr_parser ap_tstats[] = {
+ { .type = PF_TS_TABLE, .off = _OUT(pfrts_t), .arg = &table_parser, .cb = snl_attr_get_nested },
+ { .type = PF_TS_PACKETS, .off = _OUT(pfrts_packets), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array},
+ { .type = PF_TS_BYTES, .off = _OUT(pfrts_bytes), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array },
+ { .type = PF_TS_MATCH, .off = _OUT(pfrts_match), .cb = snl_attr_get_uint64 },
+ {. type = PF_TS_NOMATCH, .off = _OUT(pfrts_nomatch), .cb = snl_attr_get_uint64 },
+ { .type = PF_TS_TZERO, .off = _OUT(pfrts_tzero), .cb = snl_attr_get_uint64 },
+ { .type = PF_TS_REFCNT, .off = _OUT(pfrts_cnt), . arg = (void *)PFR_REFCNT_MAX, .cb = snl_attr_get_uint64_into_int_array },
+};
+#undef _OUT
+SNL_DECLARE_PARSER(tstats_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats);
+
+int
+pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+ pfctl_get_tstats_fn fn, void *arg)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint32_t seq_id;
+ int family_id;
+ int ret;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GET_TSTATS);
+
+ snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
+ snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
+ snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (!snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ struct pfr_tstats tstats = {};
+
+ if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_parser, &tstats))
+ continue;
+
+ ret = fn(&tstats, arg);
+ if (ret != 0)
+ break;
+ }
+
+ return (e.error);
+}
+
+static struct snl_attr_parser ap_tstats_clr[] = {
+ { .type = PF_TS_NZERO, .off = 0, .cb = snl_attr_get_uint64 },
+};
+SNL_DECLARE_PARSER(tstats_clr_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats_clr);
+
+int
+pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+ int *nzero, int flags)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint64_t zero;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_TSTATS);
+
+ snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
+ snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
+ snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
+ snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (!snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &zero))
+ continue;
+ if (nzero)
+ *nzero = (uint32_t)zero;
+ }
+
+ return (e.error);
+}