Page MenuHomeFreeBSD

D45928.id140965.diff
No OneTemporary

D45928.id140965.diff

diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -4151,6 +4151,7 @@
net/bpf_filter.c optional bpf | netgraph_bpf
net/bpf_zerocopy.c optional bpf
net/bridgestp.c optional bridge | if_bridge
+net/dummymbuf.c optional dummymbuf
net/ieee8023ad_lacp.c optional lagg
net/if.c standard
net/ifq.c standard
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -101,6 +101,7 @@
${_dpdk_lpm4} \
${_dpdk_lpm6} \
${_dpms} \
+ dummymbuf \
dummynet \
${_dwwdt} \
${_e6000sw} \
diff --git a/sys/modules/dummymbuf/Makefile b/sys/modules/dummymbuf/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/dummymbuf/Makefile
@@ -0,0 +1,9 @@
+.PATH: ${SRCTOP}/sys/net
+
+KMOD= dummymbuf
+SRCS= dummymbuf.c
+SRCS+= opt_inet.h opt_inet6.h
+
+EXPORT_SYMS= YES
+
+.include <bsd.kmod.mk>
diff --git a/sys/net/dummymbuf.c b/sys/net/dummymbuf.c
new file mode 100644
--- /dev/null
+++ b/sys/net/dummymbuf.c
@@ -0,0 +1,328 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2024 Igor Ostapenko <pm@igoro.pro>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <machine/atomic.h>
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/socket.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/vnet.h>
+#include <net/pfil.h>
+
+SYSCTL_NODE(_net, OID_AUTO, dummymbuf, 0, NULL,
+ "Dummy mbuf sysctl");
+
+#define RULES_MAXLEN 512
+VNET_DEFINE_STATIC(char, rules[RULES_MAXLEN]) = "";
+#define V_rules VNET(rules)
+SYSCTL_STRING(_net_dummymbuf, OID_AUTO, rules, CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(rules), RULES_MAXLEN,
+ "{inet | inet6 | ether} {in | out} <ifname> <opname>[ opargs...];"
+ " ...;");
+
+VNET_DEFINE_STATIC(counter_u64_t, hits);
+#define V_hits VNET(hits)
+SYSCTL_PROC(_net_dummymbuf, OID_AUTO, hits,
+ CTLTYPE_U64 | CTLFLAG_MPSAFE | CTLFLAG_STATS | CTLFLAG_RW | CTLFLAG_VNET,
+ &VNET_NAME(hits), 0, sysctl_handle_counter_u64,
+ "QU", "Number of times a rule has been applied");
+
+VNET_DEFINE_STATIC(bool, dmb_pfil_inited);
+#define V_dmb_pfil_inited VNET(dmb_pfil_inited)
+
+VNET_DEFINE_STATIC(pfil_hook_t, dmb_pfil_inet_hook);
+#define V_dmb_pfil_inet_hook VNET(dmb_pfil_inet_hook)
+
+struct rule;
+typedef struct mbuf * (*op_t)(struct mbuf *, struct rule *);
+struct rule {
+ const char *syntax_begin;
+ int syntax_len;
+ int pfil_type;
+ int pfil_dir;
+ char ifname[IFNAMSIZ];
+ op_t op;
+ const char *opargs;
+};
+
+#define FEEDBACK(pfil_type_str, pfil_flags, ifp, rule, msg) \
+ printf("dummymbuf: %s %b %s: %s: %.*s\n", \
+ (pfil_type_str), \
+ (pfil_flags), "\20\21PFIL_IN\22PFIL_OUT", \
+ (ifp)->if_xname, \
+ (msg), \
+ (rule).syntax_len, (rule).syntax_begin \
+ )
+
+static struct mbuf *
+dmb_m_pull_head(struct mbuf *m, struct rule *rule)
+{
+ struct mbuf *n;
+ int count;
+
+ count = (int)strtol(rule->opargs, NULL, 10);
+ if (count < 0 || count > MCLBYTES)
+ goto bad;
+
+ if (!(m->m_flags & M_PKTHDR))
+ goto bad;
+ if (m->m_pkthdr.len <= 0)
+ return (m);
+ if (count > m->m_pkthdr.len)
+ count = m->m_pkthdr.len;
+
+ if ((n = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR)) == NULL)
+ goto bad;
+
+ m_move_pkthdr(n, m);
+ m_copydata(m, 0, count, n->m_ext.ext_buf);
+ n->m_len = count;
+
+ m_adj(m, count);
+ n->m_next = m;
+
+ return (n);
+
+bad:
+ m_freem(m);
+ return (NULL);
+}
+
+static bool
+read_rule(const char **cur, struct rule *rule)
+{
+ // {inet | inet6 | ether} {in | out} <ifname> <opname>[ opargs...];
+
+ // syntax_begin
+ while (**cur == ' ')
+ (*cur)++;
+ rule->syntax_begin = *cur;
+
+ // syntax_len
+ rule->syntax_len = 0;
+ char *delim = strchr(*cur, ';');
+ if (delim == NULL)
+ return (false);
+ rule->syntax_len = (int)(delim - *cur + 1);
+
+ // pfil_type
+ if (strstr(*cur, "inet6") == *cur) {
+ rule->pfil_type = PFIL_TYPE_IP6;
+ *cur += strlen("inet6");
+ } else if (strstr(*cur, "inet") == *cur) {
+ rule->pfil_type = PFIL_TYPE_IP4;
+ *cur += strlen("inet");
+ } else if (strstr(*cur, "ethernet")) {
+ rule->pfil_type = PFIL_TYPE_ETHERNET;
+ *cur += strlen("ethernet");
+ } else {
+ return (false);
+ }
+ while (**cur == ' ')
+ (*cur)++;
+
+ // pfil_dir
+ if (strstr(*cur, "in") == *cur) {
+ rule->pfil_dir = PFIL_IN;
+ *cur += strlen("in");
+ } else if (strstr(*cur, "out") == *cur) {
+ rule->pfil_dir = PFIL_OUT;
+ *cur += strlen("out");
+ } else {
+ return (false);
+ }
+ while (**cur == ' ')
+ (*cur)++;
+
+ // ifname
+ char *sp = strchr(*cur, ' ');
+ if (sp == NULL || sp > delim)
+ return (false);
+ size_t len = sp - *cur;
+ if (len >= sizeof(rule->ifname))
+ return (false);
+ strncpy(rule->ifname, *cur, len);
+ rule->ifname[len] = 0;
+ *cur = sp;
+ while (**cur == ' ')
+ (*cur)++;
+
+ // opname
+ if (strstr(*cur, "pull-head") == *cur) {
+ rule->op = dmb_m_pull_head;
+ *cur += strlen("pull-head");
+ } else {
+ return (false);
+ }
+ while (**cur == ' ')
+ (*cur)++;
+
+ // opargs
+ if (*cur > delim)
+ return (false);
+ rule->opargs = *cur;
+
+ *cur = delim + 1;
+
+ return (true);
+}
+
+static pfil_return_t
+dmb_pfil_inet_mbuf_chk(struct mbuf **mp, struct ifnet *ifp, int flags,
+ void *ruleset, struct inpcb *inp)
+{
+ // TODO: serialize read/write of the rules
+ struct mbuf *m = *mp;
+ const char *cursor = V_rules;
+ bool parsed;
+ struct rule rule;
+
+ while ((parsed = read_rule(&cursor, &rule))) {
+ if (rule.pfil_type == PFIL_TYPE_IP4 &&
+ rule.pfil_dir == (flags & rule.pfil_dir) &&
+ strcmp(rule.ifname, ifp->if_xname) == 0) {
+ m = rule.op(m, &rule);
+ if (m == NULL) {
+ FEEDBACK("PFIL_TYPE_IP4", flags, ifp, rule,
+ "mbuf operation failed");
+ break;
+ }
+ counter_u64_add(V_hits, 1);
+ }
+ if (strlen(cursor) == 0)
+ break;
+ }
+ if (!parsed) {
+ FEEDBACK("PFIL_TYPE_IP4", flags, ifp, rule,
+ "rule parsing failed");
+ m_freem(m);
+ m = NULL;
+ }
+ if (m == NULL) {
+ *mp = NULL;
+ return (PFIL_DROPPED);
+ }
+
+ if (m != *mp) {
+ *mp = m;
+ return (PFIL_REALLOCED);
+ }
+
+ return (PFIL_PASS);
+}
+
+static void
+dmb_pfil_init(void)
+{
+ if (atomic_load_bool(&V_dmb_pfil_inited))
+ return;
+
+#ifdef INET
+ struct pfil_hook_args pha = {
+ .pa_version = PFIL_VERSION,
+ .pa_modname = "dummymbuf",
+ .pa_type = PFIL_TYPE_IP4,
+ .pa_flags = PFIL_IN | PFIL_OUT,
+ .pa_mbuf_chk = dmb_pfil_inet_mbuf_chk,
+ .pa_rulname = "inet",
+ };
+ V_dmb_pfil_inet_hook = pfil_add_hook(&pha);
+#endif
+
+ atomic_store_bool(&V_dmb_pfil_inited, true);
+}
+
+static void
+dmb_pfil_uninit(void)
+{
+ if (!atomic_load_bool(&V_dmb_pfil_inited))
+ return;
+
+#ifdef INET
+ pfil_remove_hook(V_dmb_pfil_inet_hook);
+#endif
+
+ atomic_store_bool(&V_dmb_pfil_inited, false);
+}
+
+static void
+dmb_vnet_init(void *unused __unused)
+{
+ V_hits = counter_u64_alloc(M_WAITOK);
+ dmb_pfil_init();
+}
+VNET_SYSINIT(dmb_vnet_init, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
+ dmb_vnet_init, NULL);
+
+static void
+dmb_vnet_uninit(void *unused __unused)
+{
+ dmb_pfil_uninit();
+ counter_u64_free(V_hits);
+}
+VNET_SYSUNINIT(dmb_vnet_uninit, SI_SUB_PROTO_PFIL, SI_ORDER_ANY,
+ dmb_vnet_uninit, NULL);
+
+static int
+dmb_modevent(module_t mod __unused, int event, void *arg __unused)
+{
+ int error = 0;
+
+ switch (event) {
+ case MOD_LOAD:
+ case MOD_UNLOAD:
+ case MOD_SHUTDOWN:
+ case MOD_QUIESCE:
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ return (error);
+}
+
+static moduledata_t dmb_mod = {
+ "dummymbuf",
+ dmb_modevent,
+ NULL
+};
+
+// TODO: inet6 support
+// TODO: ethernet support
+// TODO: man 4 dummymbuf
+DECLARE_MODULE(dummymbuf, dmb_mod, SI_SUB_PROTO_PFIL, SI_ORDER_ANY);
+MODULE_VERSION(dummymbuf, 1);

File Metadata

Mime Type
text/plain
Expires
Thu, Jul 23, 4:38 PM (9 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
35408269
Default Alt Text
D45928.id140965.diff (8 KB)

Event Timeline