* Re: [PATCH libnetfilter_queue 1/1] Convert libnetfilter_queue to use entirely libmnl functions
2024-02-14 10:47 ` Pablo Neira Ayuso
@ 2024-02-16 1:41 ` Duncan Roe
2024-02-19 2:27 ` Duncan Roe
2024-03-19 23:58 ` [PATCH libnetfilter_queue 00/32] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
2024-03-15 7:33 ` Duncan Roe
` (32 subsequent siblings)
33 siblings, 2 replies; 39+ messages in thread
From: Duncan Roe @ 2024-02-16 1:41 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development
Hi Pablo,
On Wed, Feb 14, 2024 at 11:47:30AM +0100, Pablo Neira Ayuso wrote:
> Hi Duncan,
[...]
> because this conversion to libmnl _cannot_ break existing userspace
> applications, that's the challenge.
>
Absolutely. utils/nfqnl_test.c builds and runs, are there any other examples I
could try?
Userspace applications *will* break if they either
1. Call libnfnetlink nfnl_* functions directly (other than nfnl_rcvbufsiz())
OR
2. Call nfq_open_nfnl()
Is that acceptable?
Cheers ... Duncan.
^ permalink raw reply [flat|nested] 39+ messages in thread* Re: [PATCH libnetfilter_queue 1/1] Convert libnetfilter_queue to use entirely libmnl functions
2024-02-16 1:41 ` Duncan Roe
@ 2024-02-19 2:27 ` Duncan Roe
2024-03-19 23:58 ` [PATCH libnetfilter_queue 00/32] Convert libnetfilter_queue to not need libnfnetlink Duncan Roe
1 sibling, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-02-19 2:27 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development
Hi Pablo,
On Fri, Feb 16, 2024 at 12:41:35PM +1100, Duncan Roe wrote:
[...]
> Userspace applications *will* break if they either
>
> 1. Call libnfnetlink nfnl_* functions directly (other than nfnl_rcvbufsiz())
>
> OR
>
> 2. Call nfq_open_nfnl()
>
> Is that acceptable?
>
If it's not acceptable then there's no point in my spending any more time on it.
So I won't post again until you reply.
Cheers ... Duncan.
^ permalink raw reply [flat|nested] 39+ messages in thread
* Re: [PATCH libnetfilter_queue 00/32] Convert libnetfilter_queue to not need libnfnetlink
2024-02-16 1:41 ` Duncan Roe
2024-02-19 2:27 ` Duncan Roe
@ 2024-03-19 23:58 ` Duncan Roe
1 sibling, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-19 23:58 UTC (permalink / raw)
To: Pablo Neira Ayuso; +Cc: Netfilter Development
Hi Pablo,
On Fri, Feb 16, 2024 at 12:41:35PM +1100, Duncan Roe wrote:
> Hi Pablo,
>
> On Wed, Feb 14, 2024 at 11:47:30AM +0100, Pablo Neira Ayuso wrote:
> > Hi Duncan,
> [...]
> > because this conversion to libmnl _cannot_ break existing userspace
> > applications, that's the challenge.
> >
> Absolutely. utils/nfqnl_test.c builds and runs, are there any other examples I
> could try?
>
> Userspace applications *will* break if they either
>
> 1. Call libnfnetlink nfnl_* functions directly (other than nfnl_rcvbufsiz())
>
> OR
>
> 2. Call nfq_open_nfnl()
>
> Is that acceptable?
>
> Cheers ... Duncan.
>
To clarify, the new patch series
https://patchwork.ozlabs.org/project/netfilter-devel/list/?series=399143
overcomes 1 and 2 above.
Existing userspace applications should *all* keep running.
Cheers ... Duncan.
^ permalink raw reply [flat|nested] 39+ messages in thread
* [PATCH libnetfilter_queue 00/32] Convert libnetfilter_queue to not need libnfnetlink
2024-02-14 10:47 ` Pablo Neira Ayuso
2024-02-16 1:41 ` Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 01/32] src: Convert nfq_open() to use libmnl Duncan Roe
` (31 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Hi Pablo,
On Wed, Feb 14, 2024 at 11:47:30AM +0100, Pablo Neira Ayuso wrote:
> Hi Duncan,
>
> On Wed, Feb 14, 2024 at 08:07:06AM +1100, Duncan Roe wrote:
> > And no libnfnetlink headers either.
> > Submitted as a single patch because the first change essentially broke
> > it until the job was nearly finished.
>
> This is too large. Can you start with smaller chunks?
>
> For example, use mnl_attr_get_*(), then pick the next target
> incrementally, so there is a chance of evaluating what could break,
> because this conversion to libmnl _cannot_ break existing userspace
> applications, that's the challenge.
>
[SNIP}
This series is a re-spin of
"Convert libnetfilter_queue to use entirely libmnl functions".
This time, I managed to convert nfq_open_nfnl(). Existing userspace
applications that use nfq_open_nfnl() or any other functions from
libnfnetlink should continue to run just fine.
However many patches you apply, the library will keep working with the
unpatched functions using libnfnetlink.
To assist with patch review, these patches don't contain any documentation
updates except for the nlif subsystem. I have plenty of documentation
updates ready to go but can defer them until you have committed the code.
Cheers ... Duncan.
Duncan Roe (32):
src: Convert nfq_open() to use libmnl
src: Convert nfq_open_nfnl() to use libmnl
src: Convert nfq_close() to use libmnl
src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() to
use libmnl
src: Convert nfq_set_queue_flags() & nfq_set_queue_maxlen() to use
libmnl
src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload()
and all the nfq_get_ functions to use libmnl
src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if
there is no data
src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue
src: Convert nfq_fd() to use libmnl
src: Convert remaining nfq_* functions to use libmnl
src: Fix checkpatch whitespace and block comment warnings
src: Copy nlif-related code from libnfnetlink
include: Cherry-pick macros and functions that nlif will need
doc: Add linux_list.h to the doxygen system
doc: Eliminate doxygen warnings from linux_list.h
doc: Eliminate doxygen warnings from iftable.c
whitespace: remove trailing spaces from iftable.c
include: Use libmnl.h instead of libnfnetlink.h
src: Convert all nlif_* functions to use libmnl
src: Delete rtnl.c
build: Remove libnfnetlink from the build
include: Remove the last remaining use of a libnfnetlink header
doc: Get doxygen to document useful static inline functions
doc: SYNOPSIS of linux_list.h nominates
libnetfilter_queue/libnetfilter_queue.h
doc: Move nlif usage description from libnetfilter_queue.c to
iftable.c
build: Shave some time off build
doc: Resolve most issues with man page generated from linux_list.h
build: Get real & user times back to what they were
doc: Cater for doxygen variants w.r.t. #define stmts
doc: Fix list_empty() doxygen comments
src: Use a cast in place of convoluted construct
whitespace: Fix more checkpatch errors & warnings
Make_global.am | 2 +-
configure.ac | 1 -
doxygen/Makefile.am | 5 +
doxygen/build_man.sh | 44 +-
doxygen/doxygen.cfg.in | 11 +-
.../libnetfilter_queue/libnetfilter_queue.h | 39 +-
include/libnetfilter_queue/linux_list.h | 192 +++++++
.../linux_nfnetlink_queue.h | 3 +-
libnetfilter_queue.pc.in | 2 -
src/Makefile.am | 3 +-
src/iftable.c | 376 +++++++++++++
src/libnetfilter_queue.c | 515 +++++++++++-------
12 files changed, 987 insertions(+), 206 deletions(-)
create mode 100644 include/libnetfilter_queue/linux_list.h
create mode 100644 src/iftable.c
--
2.35.8
^ permalink raw reply [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 01/32] src: Convert nfq_open() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
2024-02-16 1:41 ` Duncan Roe
2024-03-15 7:33 ` Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 02/32] src: Convert nfq_open_nfnl() " Duncan Roe
` (30 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Add copies of nfnl_handle, nfnl_subsys_handle & mnl_socket to
libnetfilter_queue.c. After calling mnl_socket_open() & mnl_socket_bind(),
it fills in the libnfnetlink structs as if nfnl_open() had been called.
The rest of the system still uses libnfnetlink functions but they keep
working.
Where possible, code is copied exactly from libnfnetlink. checkpatch
warns about space before tabs but these warnings are addressed in a
later commit.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/doxygen.cfg.in | 3 ++
src/libnetfilter_queue.c | 88 ++++++++++++++++++++++++++++++++++++----
2 files changed, 82 insertions(+), 9 deletions(-)
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 97174ff..6dd7017 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -13,6 +13,9 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfq_handle \
nfq_data \
nfq_q_handle \
+ nfnl_handle \
+ nfnl_subsys_handle \
+ mnl_socket \
tcp_flag_word
EXAMPLE_PATTERNS =
INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'"
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index bf67a19..2aba68d 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -31,6 +31,7 @@
#include <sys/socket.h>
#include <linux/netfilter/nfnetlink_queue.h>
+#include <libmnl/libmnl.h>
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -134,11 +135,43 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
* burst
*/
+/* Copy of private libnfnetlink structures */
+
+#define NFNL_MAX_SUBSYS 16
+
+struct nfnl_subsys_handle {
+ struct nfnl_handle *nfnlh;
+ uint32_t subscriptions;
+ uint8_t subsys_id;
+ uint8_t cb_count;
+ struct nfnl_callback *cb; /* array of callbacks */
+};
+
+struct nfnl_handle {
+ int fd;
+ struct sockaddr_nl local;
+ struct sockaddr_nl peer;
+ uint32_t subscriptions;
+ uint32_t seq;
+ uint32_t dump;
+ uint32_t rcv_buffer_size; /* for nfnl_catch */
+ uint32_t flags;
+ struct nlmsghdr *last_nlhdr;
+ struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
+};
+
+/* Copy of private libmnl structure */
+struct mnl_socket {
+ int fd;
+ struct sockaddr_nl addr;
+};
+
struct nfq_handle
{
struct nfnl_handle *nfnlh;
struct nfnl_subsys_handle *nfnlssh;
struct nfq_q_handle *qh_list;
+ struct mnl_socket *nl;
};
struct nfq_q_handle
@@ -383,20 +416,57 @@ int nfq_fd(struct nfq_handle *h)
EXPORT_SYMBOL
struct nfq_handle *nfq_open(void)
{
- struct nfnl_handle *nfnlh = nfnl_open();
- struct nfq_handle *qh;
+ struct nfnl_callback pkt_cb = {
+ .call = __nfq_rcv_pkt,
+ .attr_count = NFQA_MAX,
+ };
+ struct nfq_handle *h = malloc(sizeof(*h));
- if (!nfnlh)
+ if (!h)
return NULL;
+ memset(h, 0, sizeof(*h));
- /* unset netlink sequence tracking by default */
- nfnl_unset_sequence_tracking(nfnlh);
+ h->nfnlh = malloc(sizeof(*h->nfnlh));
+ if (!h->nfnlh)
+ goto err_free;
+ memset(h->nfnlh, 0, sizeof(*h->nfnlh));
+
+ h->nl = mnl_socket_open(NETLINK_NETFILTER);
+ if (!h->nl)
+ goto err_free2;
+
+ if (mnl_socket_bind(h->nl, 0, MNL_SOCKET_AUTOPID) < 0)
+ goto err_close;
+
+ /* Fill in nfnl handle */
+ h->nfnlh->fd = h->nl->fd;
+ h->nfnlh->local = h->nl->addr;
+ h->nfnlh->peer.nl_family = AF_NETLINK;
+ //h->nfnlh->seq = time(NULL);
+ h->nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
+
+ /* Fill in nfnl subsys handle with code adapted from libnfnetlink */
+ h->nfnlssh = &h->nfnlh->subsys[NFNL_SUBSYS_QUEUE];
+ h->nfnlssh->cb = calloc(NFQNL_MSG_MAX, sizeof(*(h->nfnlssh->cb)));
+ if (!h->nfnlssh->cb)
+ goto err_close;
+
+ h->nfnlssh->nfnlh = h->nfnlh;
+ h->nfnlssh->cb_count = NFQNL_MSG_MAX;
+ h->nfnlssh->subscriptions = 0;
+ h->nfnlssh->subsys_id = NFNL_SUBSYS_QUEUE;
+ pkt_cb.data = h;
+ memcpy(&h->nfnlssh->cb[NFQNL_MSG_PACKET], &pkt_cb, sizeof(pkt_cb));
- qh = nfq_open_nfnl(nfnlh);
- if (!qh)
- nfnl_close(nfnlh);
+ return h;
- return qh;
+err_close:
+ mnl_socket_close(h->nl);
+err_free2:
+ free(h->nfnlh);
+err_free:
+ free(h);
+ return NULL;
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 02/32] src: Convert nfq_open_nfnl() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (2 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 01/32] src: Convert nfq_open() to use libmnl Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 03/32] src: Convert nfq_close() " Duncan Roe
` (29 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Use copies of private libnfnetlink and libmnl structs to move required info
from one to the other.
Move (now) common code in nfq_open() and nfq_open_nfnl() to static
fill_nfnl_subsys_handle().
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 64 ++++++++++++++++++++--------------------
1 file changed, 32 insertions(+), 32 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 2aba68d..03c56ca 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -403,6 +403,27 @@ int nfq_fd(struct nfq_handle *h)
* @{
*/
+static bool fill_nfnl_subsys_handle(struct nfq_handle *h)
+{
+ struct nfnl_callback pkt_cb = {
+ .call = __nfq_rcv_pkt,
+ .attr_count = NFQA_MAX,
+ };
+
+ /* Fill in nfnl subsys handle with code adapted from libnfnetlink */
+ h->nfnlssh = &h->nfnlh->subsys[NFNL_SUBSYS_QUEUE];
+ h->nfnlssh->cb = calloc(NFQNL_MSG_MAX, sizeof(*(h->nfnlssh->cb)));
+ if (!h->nfnlssh->cb)
+ return false;
+ h->nfnlssh->nfnlh = h->nfnlh;
+ h->nfnlssh->cb_count = NFQNL_MSG_MAX;
+ h->nfnlssh->subscriptions = 0;
+ h->nfnlssh->subsys_id = NFNL_SUBSYS_QUEUE;
+ pkt_cb.data = h;
+ memcpy(&h->nfnlssh->cb[NFQNL_MSG_PACKET], &pkt_cb, sizeof(pkt_cb));
+ return true;
+}
+
/**
* nfq_open - open a nfqueue handler
*
@@ -416,10 +437,6 @@ int nfq_fd(struct nfq_handle *h)
EXPORT_SYMBOL
struct nfq_handle *nfq_open(void)
{
- struct nfnl_callback pkt_cb = {
- .call = __nfq_rcv_pkt,
- .attr_count = NFQA_MAX,
- };
struct nfq_handle *h = malloc(sizeof(*h));
if (!h)
@@ -442,22 +459,11 @@ struct nfq_handle *nfq_open(void)
h->nfnlh->fd = h->nl->fd;
h->nfnlh->local = h->nl->addr;
h->nfnlh->peer.nl_family = AF_NETLINK;
- //h->nfnlh->seq = time(NULL);
h->nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
- /* Fill in nfnl subsys handle with code adapted from libnfnetlink */
- h->nfnlssh = &h->nfnlh->subsys[NFNL_SUBSYS_QUEUE];
- h->nfnlssh->cb = calloc(NFQNL_MSG_MAX, sizeof(*(h->nfnlssh->cb)));
- if (!h->nfnlssh->cb)
+ if (!fill_nfnl_subsys_handle(h))
goto err_close;
- h->nfnlssh->nfnlh = h->nfnlh;
- h->nfnlssh->cb_count = NFQNL_MSG_MAX;
- h->nfnlssh->subscriptions = 0;
- h->nfnlssh->subsys_id = NFNL_SUBSYS_QUEUE;
- pkt_cb.data = h;
- memcpy(&h->nfnlssh->cb[NFQNL_MSG_PACKET], &pkt_cb, sizeof(pkt_cb));
-
return h;
err_close:
@@ -473,6 +479,7 @@ err_free:
* @}
*/
+#define NFNL_F_SEQTRACK_ENABLED (1 << 0)
/**
* nfq_open_nfnl - open a nfqueue handler from a existing nfnetlink handler
* \param nfnlh Netfilter netlink connection handle obtained by calling nfnl_open()
@@ -486,12 +493,7 @@ err_free:
EXPORT_SYMBOL
struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
{
- struct nfnl_callback pkt_cb = {
- .call = __nfq_rcv_pkt,
- .attr_count = NFQA_MAX,
- };
struct nfq_handle *h;
- int err;
h = malloc(sizeof(*h));
if (!h)
@@ -499,24 +501,22 @@ struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh)
memset(h, 0, sizeof(*h));
h->nfnlh = nfnlh;
+ h->nfnlh->seq = 0;
+ h->nfnlh->flags &= ~NFNL_F_SEQTRACK_ENABLED;
- h->nfnlssh = nfnl_subsys_open(h->nfnlh, NFNL_SUBSYS_QUEUE,
- NFQNL_MSG_MAX, 0);
- if (!h->nfnlssh) {
- /* FIXME: nfq_errno */
+ h->nl = malloc(sizeof(*h->nl));
+ if (!h->nl)
goto out_free;
- }
+ memset(h->nl, 0, sizeof(*h->nl));
+ h->nl->fd = h->nfnlh->fd;
+ h->nl->addr = h->nfnlh->local;
- pkt_cb.data = h;
- err = nfnl_callback_register(h->nfnlssh, NFQNL_MSG_PACKET, &pkt_cb);
- if (err < 0) {
- nfq_errno = err;
+ if (!fill_nfnl_subsys_handle(h))
goto out_close;
- }
return h;
out_close:
- nfnl_subsys_close(h->nfnlssh);
+ mnl_socket_close(h->nl);
out_free:
free(h);
return NULL;
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 03/32] src: Convert nfq_close() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (3 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 02/32] src: Convert nfq_open_nfnl() " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 04/32] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() " Duncan Roe
` (28 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 03c56ca..db31446 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -550,12 +550,20 @@ out_free:
EXPORT_SYMBOL
int nfq_close(struct nfq_handle *h)
{
- int ret;
+ struct nfq_q_handle *qh;
- ret = nfnl_close(h->nfnlh);
- if (ret == 0)
- free(h);
- return ret;
+ mnl_socket_close(h->nl);
+
+ while (h->qh_list) {
+ qh = h->qh_list;
+ h->qh_list = qh->next;
+ free(qh);
+ }
+ free(h->nfnlssh->cb);
+ free(h->nfnlh);
+ free(h);
+
+ return 0;
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 04/32] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (4 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 03/32] src: Convert nfq_close() " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 05/32] src: Convert nfq_set_queue_flags() & nfq_set_queue_maxlen() " Duncan Roe
` (27 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Convert static function __build_send_cfg_msg() to use libmnl.
This by itself converts the 3 public functions.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 32 +++++++++++++++++++-------------
1 file changed, 19 insertions(+), 13 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index db31446..1ef6fb8 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -227,27 +227,33 @@ static struct nfq_q_handle *find_qh(struct nfq_handle *h, uint16_t id)
return NULL;
}
+static int nfq_query(struct nfq_handle *h, struct nlmsghdr *nlh, char *buf,
+ size_t bufsiz)
+{
+ int ret;
+
+ ret = mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len);
+ if (ret != -1)
+ ret = mnl_socket_recvfrom(h->nl, buf, bufsiz);
+ if (ret != -1)
+ ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(h->nl),
+ NULL, NULL);
+ return ret;
+}
+
/* build a NFQNL_MSG_CONFIG message */
static int
__build_send_cfg_msg(struct nfq_handle *h, uint8_t command,
uint16_t queuenum, uint16_t pf)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_cmd))];
- struct nlmsghdr nmh;
- } u;
- struct nfqnl_msg_config_cmd cmd;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- nfnl_fill_hdr(h->nfnlssh, &u.nmh, 0, AF_UNSPEC, queuenum,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, queuenum, NLM_F_ACK);
- cmd._pad = 0;
- cmd.command = command;
- cmd.pf = htons(pf);
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_CMD, &cmd, sizeof(cmd));
+ nfq_nlmsg_cfg_put_cmd(nlh, AF_UNSPEC, command);
- return nfnl_query(h->nfnlh, &u.nmh);
+ return nfq_query(h, nlh, buf, sizeof(buf));
}
static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 05/32] src: Convert nfq_set_queue_flags() & nfq_set_queue_maxlen() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (5 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 04/32] src: Convert nfq_create_queue(), nfq_bind_pf() & nfq_unbind_pf() " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 06/32] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions " Duncan Roe
` (26 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Use a buffer of MNL_SOCKET_BUFFER_SIZE; no union required.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 1ef6fb8..28aa771 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -831,23 +831,18 @@ int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
EXPORT_SYMBOL
int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(mask)
- +NFA_LENGTH(sizeof(flags)))];
- struct nlmsghdr nmh;
- } u;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
mask = htonl(mask);
flags = htonl(flags);
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_FLAGS, flags);
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_CFG_MASK, mask);
+ mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, flags);
+ mnl_attr_put_u32(nlh, NFQA_CFG_MASK, mask);
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ return nfq_query(qh->h, nlh, buf, sizeof(buf));
}
/**
@@ -864,20 +859,14 @@ int nfq_set_queue_flags(struct nfq_q_handle *qh, uint32_t mask, uint32_t flags)
EXPORT_SYMBOL
int nfq_set_queue_maxlen(struct nfq_q_handle *qh, uint32_t queuelen)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
- struct nlmsghdr nmh;
- } u;
- uint32_t queue_maxlen = htonl(queuelen);
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_QUEUE_MAXLEN, &queue_maxlen,
- sizeof(queue_maxlen));
+ mnl_attr_put_u32(nlh, NFQA_CFG_QUEUE_MAXLEN, htonl(queuelen));
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ return nfq_query(qh->h, nlh, buf, sizeof(buf));
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 06/32] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (6 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 05/32] src: Convert nfq_set_queue_flags() & nfq_set_queue_maxlen() " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 07/32] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data Duncan Roe
` (25 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The opaque struct nfq_data is now an array of struct nlattr instead of
struct nfattr.
Because of using mnl_attr_parse(), the first array element is for
attribute 0 instaed of attribute 1 as previously. Because of this,
all the nfq_get_ functions have to be converted for this commit.
Functions now using libmnl exclusively: nfq_get_msg_packet_hdr(),
nfq_get_nfmark(), nfq_get_timestamp(), nfq_get_indev(),
nfq_get_physindev(), nfq_get_outdev(), nfq_get_physoutdev(),
nfqnl_msg_packet_hw(), nfq_get_uid() & nfq_get_gid().
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/doxygen.cfg.in | 1 +
src/libnetfilter_queue.c | 122 +++++++++++++++++++++++++++++----------
2 files changed, 91 insertions(+), 32 deletions(-)
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 6dd7017..fcfc045 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -16,6 +16,7 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfnl_handle \
nfnl_subsys_handle \
mnl_socket \
+ nfnl_callback2 \
tcp_flag_word
EXAMPLE_PATTERNS =
INPUT_FILTER = "sed 's/EXPORT_SYMBOL//g'"
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 28aa771..58875b1 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -32,6 +32,13 @@
#include <linux/netfilter/nfnetlink_queue.h>
#include <libmnl/libmnl.h>
+
+/* Use the real header since libnfnetlink is going away. */
+/* nfq_pkt_parse_attr_cb only knows attribates up to NFQA_SECCTX */
+/* so won't try to validate higher-numbered attrs but will store them. */
+/* mnl API programs will then be able to access them. */
+#include <linux/netfilter/nfnetlink.h>
+
#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -166,6 +173,13 @@ struct mnl_socket {
struct sockaddr_nl addr;
};
+/* Amended callback prototype */
+struct nfnl_callback2 {
+ int (*call)(struct nlmsghdr *nlh, struct nlattr *nfa[], void *data);
+ void *data;
+ uint16_t attr_count;
+};
+
struct nfq_handle
{
struct nfnl_handle *nfnlh;
@@ -185,7 +199,7 @@ struct nfq_q_handle
};
struct nfq_data {
- struct nfattr **data;
+ struct nlattr **data;
};
EXPORT_SYMBOL int nfq_errno;
@@ -256,7 +270,7 @@ __build_send_cfg_msg(struct nfq_handle *h, uint8_t command,
return nfq_query(h, nlh, buf, sizeof(buf));
}
-static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nfattr *nfa[],
+static int __nfq_rcv_pkt(struct nlmsghdr *nlh, struct nlattr *nfa[],
void *data)
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
@@ -411,7 +425,7 @@ int nfq_fd(struct nfq_handle *h)
static bool fill_nfnl_subsys_handle(struct nfq_handle *h)
{
- struct nfnl_callback pkt_cb = {
+ struct nfnl_callback2 pkt_cb = {
.call = __nfq_rcv_pkt,
.attr_count = NFQA_MAX,
};
@@ -610,6 +624,25 @@ int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf)
* @}
*/
+ static int __nfq_handle_msg(const struct nlmsghdr *nlh, void *data)
+{
+ struct nfq_handle *h = data;
+ struct nfq_q_handle *qh;
+ struct nlattr *nfa[NFQA_MAX + 1] = {};
+ struct nfq_data nfad = {nfa};
+ struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
+
+ if (nfq_nlmsg_parse(nlh, nfa) < 0)
+ return MNL_CB_ERROR;
+
+ /* Find our queue handler (to get CB fn) */
+ qh = find_qh(h, ntohs(nfmsg->res_id));
+ if (!qh)
+ return MNL_CB_ERROR;
+
+ return qh->cb(qh, nfmsg, &nfad, qh->data);
+}
+
/**
* \addtogroup Queue
* @{
@@ -721,7 +754,8 @@ int nfq_destroy_queue(struct nfq_q_handle *qh)
EXPORT_SYMBOL
int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
{
- return nfnl_handle_packet(h->nfnlh, buf, len);
+ return mnl_cb_run(buf, len, 0, mnl_socket_get_portid(h->nl),
+ __nfq_handle_msg, h);
}
/**
@@ -891,7 +925,7 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
/* This must be declared here (and not inside the data
* handling block) because the iovec points to this. */
- struct nfattr data_attr;
+ struct nlattr data_attr;
memset(iov, 0, sizeof(iov));
@@ -912,15 +946,17 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
nvecs = 1;
if (data_len) {
- /* The typecast here is to cast away data's const-ness: */
- nfnl_build_nfa_iovec(&iov[1], &data_attr, NFQA_PAYLOAD,
- data_len, (unsigned char *) data);
+ /* Temporary cast until we get rid of nfnl_build_nfa_iovec() */
+ nfnl_build_nfa_iovec(&iov[1], (struct nfattr *)&data_attr,
+ //nfnl_build_nfa_iovec(&iov[1], &data_attr,
+ NFQA_PAYLOAD, data_len,
+ (unsigned char *) data);
nvecs += 2;
/* Add the length of the appended data to the message
* header. The size of the attribute is given in the
- * nfa_len field and is set in the nfnl_build_nfa_iovec()
+ * nla_len field and is set in the nfnl_build_nfa_iovec()
* function. */
- u.nmh.nlmsg_len += data_attr.nfa_len;
+ u.nmh.nlmsg_len += data_attr.nla_len;
}
return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
@@ -1084,8 +1120,10 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
EXPORT_SYMBOL
struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad)
{
- return nfnl_get_pointer_to_data(nfad->data, NFQA_PACKET_HDR,
- struct nfqnl_msg_packet_hdr);
+ if (!nfad->data[NFQA_PACKET_HDR])
+ return NULL;
+
+ return mnl_attr_get_payload(nfad->data[NFQA_PACKET_HDR]);
}
/**
@@ -1097,6 +1135,10 @@ struct nfqnl_msg_packet_hdr *nfq_get_msg_packet_hdr(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_nfmark(struct nfq_data *nfad)
{
+ if (!nfad->data[NFQA_MARK])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_MARK]));
return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t));
}
@@ -1113,11 +1155,12 @@ EXPORT_SYMBOL
int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv)
{
struct nfqnl_msg_packet_timestamp *qpt;
- qpt = nfnl_get_pointer_to_data(nfad->data, NFQA_TIMESTAMP,
- struct nfqnl_msg_packet_timestamp);
- if (!qpt)
+
+ if (!nfad->data[NFQA_TIMESTAMP])
return -1;
+ qpt = mnl_attr_get_payload(nfad->data[NFQA_TIMESTAMP]);
+
tv->tv_sec = __be64_to_cpu(qpt->sec);
tv->tv_usec = __be64_to_cpu(qpt->usec);
@@ -1138,7 +1181,10 @@ int nfq_get_timestamp(struct nfq_data *nfad, struct timeval *tv)
EXPORT_SYMBOL
uint32_t nfq_get_indev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_INDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_INDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_INDEV]));
}
/**
@@ -1152,7 +1198,10 @@ uint32_t nfq_get_indev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_physindev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSINDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_PHYSINDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_PHYSINDEV]));
}
/**
@@ -1166,7 +1215,10 @@ uint32_t nfq_get_physindev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_outdev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_OUTDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_OUTDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_OUTDEV]));
}
/**
@@ -1182,7 +1234,10 @@ uint32_t nfq_get_outdev(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
{
- return ntohl(nfnl_get_data(nfad->data, NFQA_IFINDEX_PHYSOUTDEV, uint32_t));
+ if (!nfad->data[NFQA_IFINDEX_PHYSOUTDEV])
+ return 0;
+
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_IFINDEX_PHYSOUTDEV]));
}
/**
@@ -1317,8 +1372,10 @@ int nfq_get_physoutdev_name(struct nlif_handle *nlif_handle,
EXPORT_SYMBOL
struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
{
- return nfnl_get_pointer_to_data(nfad->data, NFQA_HWADDR,
- struct nfqnl_msg_packet_hw);
+ if (!nfad->data[NFQA_HWADDR])
+ return NULL;
+
+ return mnl_attr_get_payload(nfad->data[NFQA_HWADDR]);
}
/**
@@ -1366,10 +1423,10 @@ uint32_t nfq_get_skbinfo(struct nfq_data *nfad)
EXPORT_SYMBOL
int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
{
- if (!nfnl_attr_present(nfad->data, NFQA_UID))
+ if (!nfad->data[NFQA_UID])
return 0;
- *uid = ntohl(nfnl_get_data(nfad->data, NFQA_UID, uint32_t));
+ *uid = ntohl(mnl_attr_get_u32(nfad->data[NFQA_UID]));
return 1;
}
@@ -1387,10 +1444,10 @@ int nfq_get_uid(struct nfq_data *nfad, uint32_t *uid)
EXPORT_SYMBOL
int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid)
{
- if (!nfnl_attr_present(nfad->data, NFQA_GID))
+ if (!nfad->data[NFQA_GID])
return 0;
- *gid = ntohl(nfnl_get_data(nfad->data, NFQA_GID, uint32_t));
+ *gid = ntohl(mnl_attr_get_u32(nfad->data[NFQA_GID]));
return 1;
}
@@ -1408,14 +1465,13 @@ int nfq_get_gid(struct nfq_data *nfad, uint32_t *gid)
EXPORT_SYMBOL
int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
{
- if (!nfnl_attr_present(nfad->data, NFQA_SECCTX))
+ if (!nfad->data[NFQA_SECCTX])
return -1;
- *secdata = (unsigned char *)nfnl_get_pointer_to_data(nfad->data,
- NFQA_SECCTX, char);
+ *secdata = mnl_attr_get_payload(nfad->data[NFQA_SECCTX]);
if (*secdata)
- return NFA_PAYLOAD(nfad->data[NFQA_SECCTX-1]);
+ return mnl_attr_get_payload_len(nfad->data[NFQA_SECCTX]);
return 0;
}
@@ -1434,10 +1490,12 @@ int nfq_get_secctx(struct nfq_data *nfad, unsigned char **secdata)
EXPORT_SYMBOL
int nfq_get_payload(struct nfq_data *nfad, unsigned char **data)
{
- *data = (unsigned char *)
- nfnl_get_pointer_to_data(nfad->data, NFQA_PAYLOAD, char);
+ if (!nfad->data[NFQA_PAYLOAD])
+ return -1;
+
+ *data = mnl_attr_get_payload(nfad->data[NFQA_PAYLOAD]);
if (*data)
- return NFA_PAYLOAD(nfad->data[NFQA_PAYLOAD-1]);
+ return mnl_attr_get_payload_len(nfad->data[NFQA_PAYLOAD]);
return -1;
}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 07/32] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data
2024-02-14 10:47 ` Pablo Neira Ayuso
` (7 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 06/32] src: Convert nfq_handle_packet(), nfq_get_secctx(), nfq_get_payload() and all the nfq_get_ functions " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 08/32] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue Duncan Roe
` (24 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
static __set_verdict() uses mnl-API calls in enough places that the path
for no (mangled) data doesn't use any nfnl-API functions.
With no data, __set_verdict() uses sendto() (faster than sendmsg()).
nfq_set_verdict2() must not use htonl() on the packet mark.
checkpatch Block comments warning is fixed in a later commit.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 35 ++++++++++++++++-------------------
1 file changed, 16 insertions(+), 19 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 58875b1..17fe879 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -38,8 +38,8 @@
/* so won't try to validate higher-numbered attrs but will store them. */
/* mnl API programs will then be able to access them. */
#include <linux/netfilter/nfnetlink.h>
+#include <linux/netfilter/nfnetlink_compat.h>
-#include <libnfnetlink/libnfnetlink.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include "internal.h"
@@ -912,13 +912,8 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
uint32_t data_len, const unsigned char *data,
enum nfqnl_msg_types type)
{
- struct nfqnl_msg_verdict_hdr vh;
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(mark))
- +NFA_LENGTH(sizeof(vh))];
- struct nlmsghdr nmh;
- } u;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
struct iovec iov[3];
int nvecs;
@@ -929,20 +924,22 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
memset(iov, 0, sizeof(iov));
- vh.verdict = htonl(verdict);
- vh.id = htonl(id);
-
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- type, NLM_F_REQUEST);
+ nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qh->id);
/* add verdict header */
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_VERDICT_HDR, &vh, sizeof(vh));
+ nfq_nlmsg_verdict_put(nlh, id, verdict);
if (set_mark)
- nfnl_addattr32(&u.nmh, sizeof(u), NFQA_MARK, mark);
+ nfq_nlmsg_verdict_put_mark(nlh, mark);
+
+ /* Efficiency gain: when there is only 1 iov,
+ * sendto() is faster than sendmsg() because the kernel only has
+ * 1 userspace address to validate instead of 2. */
+ if (!data_len)
+ return mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
- iov[0].iov_base = &u.nmh;
- iov[0].iov_len = NLMSG_TAIL(&u.nmh) - (void *)&u.nmh;
+ iov[0].iov_base = nlh;
+ iov[0].iov_len = NLMSG_TAIL(nlh) - (void *)nlh;
nvecs = 1;
if (data_len) {
@@ -956,7 +953,7 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
* header. The size of the attribute is given in the
* nla_len field and is set in the nfnl_build_nfa_iovec()
* function. */
- u.nmh.nlmsg_len += data_attr.nla_len;
+ nlh->nlmsg_len += data_attr.nla_len;
}
return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
@@ -1013,7 +1010,7 @@ int nfq_set_verdict2(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark,
uint32_t data_len, const unsigned char *buf)
{
- return __set_verdict(qh, id, verdict, htonl(mark), 1, data_len,
+ return __set_verdict(qh, id, verdict, mark, 1, data_len,
buf, NFQNL_MSG_VERDICT);
}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 08/32] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue
2024-02-14 10:47 ` Pablo Neira Ayuso
` (8 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 07/32] src: Convert nfq_set_verdict() and nfq_set_verdict2() to use libmnl if there is no data Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 09/32] src: Convert nfq_fd() to use libmnl Duncan Roe
` (23 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
nfnl_rcvbufsiz() is the first bullet point in the Performance section
of the libnetfilter_queue HTML main page.
We have to assume people have used it,
so supply a version that uses libmnl.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
.../libnetfilter_queue/libnetfilter_queue.h | 2 ++
src/libnetfilter_queue.c | 34 +++++++++++++++++++
2 files changed, 36 insertions(+)
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index f7e68d8..9327f8c 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -35,6 +35,8 @@ typedef int nfq_callback(struct nfq_q_handle *gh, struct nfgenmsg *nfmsg,
struct nfq_data *nfad, void *data);
+extern unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h,
+ unsigned int size);
extern struct nfq_handle *nfq_open(void);
extern struct nfq_handle *nfq_open_nfnl(struct nfnl_handle *nfnlh);
extern int nfq_close(struct nfq_handle *h);
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 17fe879..2051aca 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -559,6 +559,40 @@ out_free:
* @{
*/
+/**
+ * nfnl_rcvbufsiz - set the socket buffer size
+ * \param h nfnetlink connection handle obtained via call to \b nfq_nfnlh()
+ * \param size size of the buffer we want to set
+ *
+ * This nfnl-API function sets the new size of the socket buffer.
+ * Use this setting
+ * to increase the socket buffer size if your system is reporting ENOBUFS
+ * errors.
+ *
+ * \return new size of kernel socket buffer
+ */
+
+EXPORT_SYMBOL
+unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
+{
+ int status;
+ socklen_t socklen = sizeof(size);
+ unsigned int read_size = 0;
+
+ /* first we try the FORCE option, which is introduced in kernel
+ * 2.6.14 to give "root" the ability to override the system wide
+ * maximum */
+ status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
+ if (status < 0) {
+ /* if this didn't work, we try at least to get the system
+ * wide maximum (or whatever the user requested) */
+ setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
+ }
+ getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
+
+ return read_size;
+}
+
/**
* nfq_close - close a nfqueue handler
* \param h Netfilter queue connection handle obtained via call to nfq_open()
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 09/32] src: Convert nfq_fd() to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (9 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 08/32] src: Incorporate nfnl_rcvbufsiz() in libnetfilter_queue Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 10/32] src: Convert remaining nfq_* functions " Duncan Roe
` (22 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
struct nfq_handle has a struct mnl_socket * now, use that.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 2051aca..5e09eb7 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -381,7 +381,7 @@ struct nfnl_handle *nfq_nfnlh(struct nfq_handle *h)
EXPORT_SYMBOL
int nfq_fd(struct nfq_handle *h)
{
- return nfnl_fd(nfq_nfnlh(h));
+ return mnl_socket_get_fd(h->nl);
}
/**
* @}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 10/32] src: Convert remaining nfq_* functions to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (10 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 09/32] src: Convert nfq_fd() to use libmnl Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 11/32] src: Fix checkpatch whitespace and block comment warnings Duncan Roe
` (21 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Converted: nfq_set_verdict2(), nfq_set_verdict_batch2(),
nfq_set_verdict_mark(), nfq_get_nfmark() [again],
nfq_get_skbinfo() & nfq_set_mode().
We only use 2 iovecs instead of 3
by tacking the data attribute onto the end of the first iovec buffer.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 98 ++++++++++++++++++++--------------------
1 file changed, 50 insertions(+), 48 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 5e09eb7..56d51ca 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -810,22 +810,21 @@ int nfq_handle_packet(struct nfq_handle *h, char *buf, int len)
EXPORT_SYMBOL
int nfq_set_mode(struct nfq_q_handle *qh, uint8_t mode, uint32_t range)
{
- union {
- char buf[NFNL_HEADER_LEN
- +NFA_LENGTH(sizeof(struct nfqnl_msg_config_params))];
- struct nlmsghdr nmh;
- } u;
- struct nfqnl_msg_config_params params;
-
- nfnl_fill_hdr(qh->h->nfnlssh, &u.nmh, 0, AF_UNSPEC, qh->id,
- NFQNL_MSG_CONFIG, NLM_F_REQUEST|NLM_F_ACK);
-
- params.copy_range = htonl(range);
- params.copy_mode = mode;
- nfnl_addattr_l(&u.nmh, sizeof(u), NFQA_CFG_PARAMS, ¶ms,
- sizeof(params));
-
- return nfnl_query(qh->h->nfnlh, &u.nmh);
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ int ret;
+
+ nlh = nfq_nlmsg_put2(buf, NFQNL_MSG_CONFIG, qh->id, NLM_F_ACK);
+
+ nfq_nlmsg_cfg_put_params(nlh, mode, range);
+
+ ret = mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
+ if (ret != -1)
+ ret = mnl_socket_recvfrom(qh->h->nl, buf, sizeof(buf));
+ if (ret != -1)
+ ret = mnl_cb_run(buf, ret, 0, mnl_socket_get_portid(qh->h->nl),
+ NULL, NULL);
+ return ret;
}
/**
@@ -948,17 +947,9 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
+ static struct sockaddr_nl snl = {.nl_family = AF_NETLINK };
- struct iovec iov[3];
- int nvecs;
-
- /* This must be declared here (and not inside the data
- * handling block) because the iovec points to this. */
- struct nlattr data_attr;
-
- memset(iov, 0, sizeof(iov));
-
- nlh = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, qh->id);
+ nlh = nfq_nlmsg_put(buf, type, qh->id);
/* add verdict header */
nfq_nlmsg_verdict_put(nlh, id, verdict);
@@ -971,26 +962,38 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
* 1 userspace address to validate instead of 2. */
if (!data_len)
return mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
+ {
+ struct iovec iov[2];
+ struct nlattr *data_attr = mnl_nlmsg_get_payload_tail(nlh);
+ const struct msghdr msg = {
+ .msg_name = &snl,
+ .msg_namelen = sizeof snl,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ mnl_attr_put(nlh, NFQA_PAYLOAD, 0, NULL);
+
+ iov[0].iov_base = nlh;
+ iov[0].iov_len = nlh->nlmsg_len;
+ /* The typecast here is to cast away data's const-ness: */
+ iov[1].iov_base = (unsigned char *)data;
+ iov[1].iov_len = data_len;
- iov[0].iov_base = nlh;
- iov[0].iov_len = NLMSG_TAIL(nlh) - (void *)nlh;
- nvecs = 1;
-
- if (data_len) {
- /* Temporary cast until we get rid of nfnl_build_nfa_iovec() */
- nfnl_build_nfa_iovec(&iov[1], (struct nfattr *)&data_attr,
- //nfnl_build_nfa_iovec(&iov[1], &data_attr,
- NFQA_PAYLOAD, data_len,
- (unsigned char *) data);
- nvecs += 2;
/* Add the length of the appended data to the message
- * header. The size of the attribute is given in the
- * nla_len field and is set in the nfnl_build_nfa_iovec()
- * function. */
- nlh->nlmsg_len += data_attr.nla_len;
- }
+ * header and attribute length.
+ * No padding is needed: this is the end of the message.
+ */
+
+ nlh->nlmsg_len += data_len;
- return nfnl_sendiov(qh->h->nfnlh, iov, nvecs, 0);
+ data_attr->nla_len += data_len;
+
+ return sendmsg(qh->h->nfnlh->fd, &msg, 0);
+ }
}
/**
@@ -1079,7 +1082,7 @@ EXPORT_SYMBOL
int nfq_set_verdict_batch2(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark)
{
- return __set_verdict(qh, id, verdict, htonl(mark), 1, 0,
+ return __set_verdict(qh, id, verdict, mark, 1, 0,
NULL, NFQNL_MSG_VERDICT_BATCH);
}
@@ -1102,7 +1105,7 @@ int nfq_set_verdict_mark(struct nfq_q_handle *qh, uint32_t id,
uint32_t verdict, uint32_t mark,
uint32_t data_len, const unsigned char *buf)
{
- return __set_verdict(qh, id, verdict, mark, 1, data_len, buf,
+ return __set_verdict(qh, id, verdict, ntohl(mark), 1, data_len, buf,
NFQNL_MSG_VERDICT);
}
@@ -1170,7 +1173,6 @@ uint32_t nfq_get_nfmark(struct nfq_data *nfad)
return 0;
return ntohl(mnl_attr_get_u32(nfad->data[NFQA_MARK]));
- return ntohl(nfnl_get_data(nfad->data, NFQA_MARK, uint32_t));
}
/**
@@ -1434,10 +1436,10 @@ struct nfqnl_msg_packet_hw *nfq_get_packet_hw(struct nfq_data *nfad)
EXPORT_SYMBOL
uint32_t nfq_get_skbinfo(struct nfq_data *nfad)
{
- if (!nfnl_attr_present(nfad->data, NFQA_SKB_INFO))
+ if (!nfad->data[NFQA_SKB_INFO])
return 0;
- return ntohl(nfnl_get_data(nfad->data, NFQA_SKB_INFO, uint32_t));
+ return ntohl(mnl_attr_get_u32(nfad->data[NFQA_SKB_INFO]));
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 11/32] src: Fix checkpatch whitespace and block comment warnings
2024-02-14 10:47 ` Pablo Neira Ayuso
` (11 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 10/32] src: Convert remaining nfq_* functions " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 12/32] src: Copy nlif-related code from libnfnetlink Duncan Roe
` (20 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The original patchset changed as little as possible from the original.
Whitespace fixes in particular are confusing during patch review
so leave them until now.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/libnetfilter_queue.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 56d51ca..2f50b47 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -147,11 +147,11 @@ gcc -g3 -ggdb -Wall -lmnl -lnetfilter_queue -o nf-queue nf-queue.c
#define NFNL_MAX_SUBSYS 16
struct nfnl_subsys_handle {
- struct nfnl_handle *nfnlh;
+ struct nfnl_handle *nfnlh;
uint32_t subscriptions;
uint8_t subsys_id;
uint8_t cb_count;
- struct nfnl_callback *cb; /* array of callbacks */
+ struct nfnl_callback *cb; /* array of callbacks */
};
struct nfnl_handle {
@@ -163,13 +163,13 @@ struct nfnl_handle {
uint32_t dump;
uint32_t rcv_buffer_size; /* for nfnl_catch */
uint32_t flags;
- struct nlmsghdr *last_nlhdr;
+ struct nlmsghdr *last_nlhdr;
struct nfnl_subsys_handle subsys[NFNL_MAX_SUBSYS+1];
};
/* Copy of private libmnl structure */
struct mnl_socket {
- int fd;
+ int fd;
struct sockaddr_nl addr;
};
@@ -581,11 +581,13 @@ unsigned int nfnl_rcvbufsiz(const struct nfnl_handle *h, unsigned int size)
/* first we try the FORCE option, which is introduced in kernel
* 2.6.14 to give "root" the ability to override the system wide
- * maximum */
+ * maximum
+ */
status = setsockopt(h->fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, socklen);
if (status < 0) {
/* if this didn't work, we try at least to get the system
- * wide maximum (or whatever the user requested) */
+ * wide maximum (or whatever the user requested)
+ */
setsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &size, socklen);
}
getsockopt(h->fd, SOL_SOCKET, SO_RCVBUF, &read_size, &socklen);
@@ -658,7 +660,7 @@ int nfq_unbind_pf(struct nfq_handle *h, uint16_t pf)
* @}
*/
- static int __nfq_handle_msg(const struct nlmsghdr *nlh, void *data)
+static int __nfq_handle_msg(const struct nlmsghdr *nlh, void *data)
{
struct nfq_handle *h = data;
struct nfq_q_handle *qh;
@@ -959,7 +961,8 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
/* Efficiency gain: when there is only 1 iov,
* sendto() is faster than sendmsg() because the kernel only has
- * 1 userspace address to validate instead of 2. */
+ * 1 userspace address to validate instead of 2.
+ */
if (!data_len)
return mnl_socket_sendto(qh->h->nl, nlh, nlh->nlmsg_len);
{
@@ -967,7 +970,7 @@ static int __set_verdict(struct nfq_q_handle *qh, uint32_t id,
struct nlattr *data_attr = mnl_nlmsg_get_payload_tail(nlh);
const struct msghdr msg = {
.msg_name = &snl,
- .msg_namelen = sizeof snl,
+ .msg_namelen = sizeof(snl),
.msg_iov = iov,
.msg_iovlen = 2,
.msg_control = NULL,
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 12/32] src: Copy nlif-related code from libnfnetlink
2024-02-14 10:47 ` Pablo Neira Ayuso
` (12 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 11/32] src: Fix checkpatch whitespace and block comment warnings Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 13/32] include: Cherry-pick macros and functions that nlif will need Duncan Roe
` (19 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
These sources are for reviewer's reference. In particular, the libmnl
updates to rtnl.c are slated to be done in iftable.c so rtnl.c will be
removed after the libmnl updates are done.
linux_list.h raises a number of checkpatch errors.
These will be addresses in a later commit.
This patch doesn't actually do anything with the new files.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/linux_list.h | 727 ++++++++++++++++++++++++
src/iftable.c | 348 ++++++++++++
src/rtnl.c | 283 +++++++++
3 files changed, 1358 insertions(+)
create mode 100644 include/libnetfilter_queue/linux_list.h
create mode 100644 src/iftable.c
create mode 100644 src/rtnl.c
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
new file mode 100644
index 0000000..cf71837
--- /dev/null
+++ b/include/libnetfilter_queue/linux_list.h
@@ -0,0 +1,727 @@
+#ifndef _LINUX_LIST_H
+#define _LINUX_LIST_H
+
+#include <stddef.h>
+
+#undef offsetof
+#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+
+/**
+ * container_of - cast a member of a structure out to the containing structure
+ *
+ * @ptr: the pointer to the member.
+ * @type: the type of the container struct this is embedded in.
+ * @member: the name of the member within the struct.
+ *
+ */
+#define container_of(ptr, type, member) ({ \
+ typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
+
+/*
+ * Check at compile time that something is of a particular type.
+ * Always evaluates to 1 so you may use it easily in comparisons.
+ */
+#define typecheck(type,x) \
+({ type __dummy; \
+ typeof(x) __dummy2; \
+ (void)(&__dummy == &__dummy2); \
+ 1; \
+})
+
+#define prefetch(x) ((void)0)
+
+/* empty define to make this work in userspace -HW */
+#ifndef smp_wmb
+#define smp_wmb()
+#endif
+
+/*
+ * These are non-NULL pointers that will result in page faults
+ * under normal circumstances, used to verify that nobody uses
+ * non-initialized list entries.
+ */
+#define LIST_POISON1 ((void *) 0x00100100)
+#define LIST_POISON2 ((void *) 0x00200200)
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+ struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+ struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+ (ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add(struct list_head *new,
+ struct list_head *prev,
+ struct list_head *next)
+{
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static inline void list_add(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static inline void list_add_tail(struct list_head *new, struct list_head *head)
+{
+ __list_add(new, head->prev, head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_add_rcu(struct list_head * new,
+ struct list_head * prev, struct list_head * next)
+{
+ new->next = next;
+ new->prev = prev;
+ smp_wmb();
+ next->prev = new;
+ prev->next = new;
+}
+
+/**
+ * list_add_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_rcu(struct list_head *new, struct list_head *head)
+{
+ __list_add_rcu(new, head, head->next);
+}
+
+/**
+ * list_add_tail_rcu - add a new entry to rcu-protected list
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_add_tail_rcu()
+ * or list_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ */
+static inline void list_add_tail_rcu(struct list_head *new,
+ struct list_head *head)
+{
+ __list_add_rcu(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static inline void __list_del(struct list_head * prev, struct list_head * next)
+{
+ next->prev = prev;
+ prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is
+ * in an undefined state.
+ */
+static inline void list_del(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->next = LIST_POISON1;
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_rcu - deletes entry from list without re-initialization
+ * @entry: the element to delete from the list.
+ *
+ * Note: list_empty on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as list_del_rcu()
+ * or list_add_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * list_for_each_entry_rcu().
+ *
+ * Note that the caller is not permitted to immediately free
+ * the newly deleted entry. Instead, either synchronize_kernel()
+ * or call_rcu() must be used to defer freeing until an RCU
+ * grace period has elapsed.
+ */
+static inline void list_del_rcu(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ entry->prev = LIST_POISON2;
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static inline void list_del_init(struct list_head *entry)
+{
+ __list_del(entry->prev, entry->next);
+ INIT_LIST_HEAD(entry);
+}
+
+/**
+ * list_move - delete from one list and add as another's head
+ * @list: the entry to move
+ * @head: the head that will precede our entry
+ */
+static inline void list_move(struct list_head *list, struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add(list, head);
+}
+
+/**
+ * list_move_tail - delete from one list and add as another's tail
+ * @list: the entry to move
+ * @head: the head that will follow our entry
+ */
+static inline void list_move_tail(struct list_head *list,
+ struct list_head *head)
+{
+ __list_del(list->prev, list->next);
+ list_add_tail(list, head);
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static inline int list_empty(const struct list_head *head)
+{
+ return head->next == head;
+}
+
+/**
+ * list_empty_careful - tests whether a list is
+ * empty _and_ checks that no other CPU might be
+ * in the process of still modifying either member
+ *
+ * NOTE: using list_empty_careful() without synchronization
+ * can only be safe if the only activity that can happen
+ * to the list entry is list_del_init(). Eg. it cannot be used
+ * if another CPU could re-list_add() it.
+ *
+ * @head: the list to test.
+ */
+static inline int list_empty_careful(const struct list_head *head)
+{
+ struct list_head *next = head->next;
+ return (next == head) && (next == head->prev);
+}
+
+static inline void __list_splice(struct list_head *list,
+ struct list_head *head)
+{
+ struct list_head *first = list->next;
+ struct list_head *last = list->prev;
+ struct list_head *at = head->next;
+
+ first->prev = head;
+ head->next = first;
+
+ last->next = at;
+ at->prev = last;
+}
+
+/**
+ * list_splice - join two lists
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ */
+static inline void list_splice(struct list_head *list, struct list_head *head)
+{
+ if (!list_empty(list))
+ __list_splice(list, head);
+}
+
+/**
+ * list_splice_init - join two lists and reinitialise the emptied list.
+ * @list: the new list to add.
+ * @head: the place to add it in the first list.
+ *
+ * The list at @list is reinitialised
+ */
+static inline void list_splice_init(struct list_head *list,
+ struct list_head *head)
+{
+ if (!list_empty(list)) {
+ __list_splice(list, head);
+ INIT_LIST_HEAD(list);
+ }
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr: the &struct list_head pointer.
+ * @type: the type of the struct this is embedded in.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+/**
+ * list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, prefetch(pos->next))
+
+/**
+ * __list_for_each - iterate over a list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This variant differs from list_for_each() in that it's the
+ * simplest possible list iteration code, no prefetching is done.
+ * Use this for code that knows the list to be very short (empty
+ * or 1 entry) most of the time.
+ */
+#define __list_for_each(pos, head) \
+ for (pos = (head)->next; pos != (head); pos = pos->next)
+
+/**
+ * list_for_each_prev - iterate over a list backwards
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ */
+#define list_for_each_prev(pos, head) \
+ for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
+ pos = pos->prev, prefetch(pos->prev))
+
+/**
+ * list_for_each_safe - iterate over a list safe against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, n = pos->next)
+
+/**
+ * list_for_each_entry - iterate over list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_reverse - iterate backwards over list of given type.
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_reverse(pos, head, member) \
+ for (pos = list_entry((head)->prev, typeof(*pos), member), \
+ prefetch(pos->member.prev); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.prev, typeof(*pos), member), \
+ prefetch(pos->member.prev))
+
+/**
+ * list_prepare_entry - prepare a pos entry for use as a start point in
+ * list_for_each_entry_continue
+ * @pos: the type * to use as a start point
+ * @head: the head of the list
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_prepare_entry(pos, head, member) \
+ ((pos) ? : list_entry(head, typeof(*pos), member))
+
+/**
+ * list_for_each_entry_continue - iterate over list of given type
+ * continuing after existing point
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_continue(pos, head, member) \
+ for (pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ prefetch(pos->member.next))
+
+/**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos: the type * to use as a loop counter.
+ * @n: another type * to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ n = list_entry(pos->member.next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
+ * list_for_each_rcu - iterate over an rcu-protected list
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_rcu(pos, head) \
+ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
+
+#define __list_for_each_rcu(pos, head) \
+ for (pos = (head)->next; pos != (head); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
+
+/**
+ * list_for_each_safe_rcu - iterate over an rcu-protected list safe
+ * against removal of list entry
+ * @pos: the &struct list_head to use as a loop counter.
+ * @n: another &struct list_head to use as temporary storage
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_safe_rcu(pos, n, head) \
+ for (pos = (head)->next, n = pos->next; pos != (head); \
+ pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
+
+/**
+ * list_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the list_struct within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_entry_rcu(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member), \
+ prefetch(pos->member.next); \
+ &pos->member != (head); \
+ pos = list_entry(pos->member.next, typeof(*pos), member), \
+ ({ smp_read_barrier_depends(); 0;}), \
+ prefetch(pos->member.next))
+
+
+/**
+ * list_for_each_continue_rcu - iterate over an rcu-protected list
+ * continuing after existing point.
+ * @pos: the &struct list_head to use as a loop counter.
+ * @head: the head for your list.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as list_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define list_for_each_continue_rcu(pos, head) \
+ for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
+ (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
+
+/*
+ * Double linked lists with a single pointer list head.
+ * Mostly useful for hash tables where the two pointer list head is
+ * too wasteful.
+ * You lose the ability to access the tail in O(1).
+ */
+
+struct hlist_head {
+ struct hlist_node *first;
+};
+
+struct hlist_node {
+ struct hlist_node *next, **pprev;
+};
+
+#define HLIST_HEAD_INIT { .first = NULL }
+#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
+#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
+#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
+
+static inline int hlist_unhashed(const struct hlist_node *h)
+{
+ return !h->pprev;
+}
+
+static inline int hlist_empty(const struct hlist_head *h)
+{
+ return !h->first;
+}
+
+static inline void __hlist_del(struct hlist_node *n)
+{
+ struct hlist_node *next = n->next;
+ struct hlist_node **pprev = n->pprev;
+ *pprev = next;
+ if (next)
+ next->pprev = pprev;
+}
+
+static inline void hlist_del(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->next = LIST_POISON1;
+ n->pprev = LIST_POISON2;
+}
+
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @n: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry().
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
+
+static inline void hlist_del_init(struct hlist_node *n)
+{
+ if (n->pprev) {
+ __hlist_del(n);
+ INIT_HLIST_NODE(n);
+ }
+}
+
+#define hlist_del_rcu_init hlist_del_init
+
+static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+ n->pprev = &h->first;
+}
+
+
+/**
+ * hlist_add_head_rcu - adds the specified element to the specified hlist,
+ * while permitting racing traversals.
+ * @n: the element to add to the hash list.
+ * @h: the list to add to.
+ *
+ * The caller must take whatever precautions are necessary
+ * (such as holding appropriate locks) to avoid racing
+ * with another list-mutation primitive, such as hlist_add_head_rcu()
+ * or hlist_del_rcu(), running on this same list.
+ * However, it is perfectly legal to run concurrently with
+ * the _rcu list-traversal primitives, such as
+ * hlist_for_each_entry(), but only if smp_read_barrier_depends()
+ * is used to prevent memory-consistency problems on Alpha CPUs.
+ * Regardless of the type of CPU, the list-traversal primitive
+ * must be guarded by rcu_read_lock().
+ *
+ * OK, so why don't we have an hlist_for_each_entry_rcu()???
+ */
+static inline void hlist_add_head_rcu(struct hlist_node *n,
+ struct hlist_head *h)
+{
+ struct hlist_node *first = h->first;
+ n->next = first;
+ n->pprev = &h->first;
+ smp_wmb();
+ if (first)
+ first->pprev = &n->next;
+ h->first = n;
+}
+
+/* next must be != NULL */
+static inline void hlist_add_before(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ n->pprev = next->pprev;
+ n->next = next;
+ next->pprev = &n->next;
+ *(n->pprev) = n;
+}
+
+static inline void hlist_add_after(struct hlist_node *n,
+ struct hlist_node *next)
+{
+ next->next = n->next;
+ n->next = next;
+ next->pprev = &n->next;
+
+ if(next->next)
+ next->next->pprev = &next->next;
+}
+
+#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
+
+#define hlist_for_each(pos, head) \
+ for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
+ pos = pos->next)
+
+#define hlist_for_each_safe(pos, n, head) \
+ for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry - iterate over list of given type
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_continue(tpos, pos, member) \
+ for (pos = (pos)->next; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_from(tpos, pos, member) \
+ for (; pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next)
+
+/**
+ * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @tpos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @n: another &struct hlist_node to use as temporary storage
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ n = pos->next; 1; }) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = n)
+
+/**
+ * hlist_for_each_entry_rcu - iterate over rcu list of given type
+ * @pos: the type * to use as a loop counter.
+ * @pos: the &struct hlist_node to use as a loop counter.
+ * @head: the head for your list.
+ * @member: the name of the hlist_node within the struct.
+ *
+ * This list-traversal primitive may safely run concurrently with
+ * the _rcu list-mutation primitives such as hlist_add_rcu()
+ * as long as the traversal is guarded by rcu_read_lock().
+ */
+#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
+ for (pos = (head)->first; \
+ pos && ({ prefetch(pos->next); 1;}) && \
+ ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
+ pos = pos->next, ({ smp_read_barrier_depends(); 0; }) )
+
+#endif
diff --git a/src/iftable.c b/src/iftable.c
new file mode 100644
index 0000000..aab59b3
--- /dev/null
+++ b/src/iftable.c
@@ -0,0 +1,348 @@
+/* iftable - table of network interfaces
+ *
+ * (C) 2004 by Astaro AG, written by Harald Welte <hwelte@astaro.com>
+ * (C) 2008 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * This software is Free Software and licensed under GNU GPLv2+.
+ */
+
+/* IFINDEX handling */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <linux/netdevice.h>
+
+#include <libnfnetlink/libnfnetlink.h>
+#include "rtnl.h"
+#include "linux_list.h"
+
+/**
+ * \defgroup iftable Functions in iftable.c [DEPRECATED]
+ * This documentation is provided for the benefit of maintainers of legacy code.
+ *
+ * New applications should use
+ * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/).
+ * @{
+ */
+
+struct ifindex_node {
+ struct list_head head;
+
+ uint32_t index;
+ uint32_t type;
+ uint32_t alen;
+ uint32_t flags;
+ char addr[8];
+ char name[16];
+};
+
+struct nlif_handle {
+ struct list_head ifindex_hash[16];
+ struct rtnl_handle *rtnl_handle;
+ struct rtnl_handler ifadd_handler;
+ struct rtnl_handler ifdel_handler;
+};
+
+/* iftable_add - Add/Update an entry to/in the interface table
+ * @n: netlink message header of a RTM_NEWLINK message
+ * @arg: not used
+ *
+ * This function adds/updates an entry in the intrface table.
+ * Returns -1 on error, 1 on success.
+ */
+static int iftable_add(struct nlmsghdr *n, void *arg)
+{
+ unsigned int hash, found = 0;
+ struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
+ struct ifindex_node *this;
+ struct rtattr *cb[IFLA_MAX+1];
+ struct nlif_handle *h = arg;
+
+ if (n->nlmsg_type != RTM_NEWLINK)
+ return -1;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
+ return -1;
+
+ rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
+
+ if (!cb[IFLA_IFNAME])
+ return -1;
+
+ hash = ifi_msg->ifi_index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ this = malloc(sizeof(*this));
+ if (!this)
+ return -1;
+
+ this->index = ifi_msg->ifi_index;
+ }
+
+ this->type = ifi_msg->ifi_type;
+ this->flags = ifi_msg->ifi_flags;
+ if (cb[IFLA_ADDRESS]) {
+ unsigned int alen;
+ this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]);
+ if (alen > sizeof(this->addr))
+ alen = sizeof(this->addr);
+ memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen);
+ } else {
+ this->alen = 0;
+ memset(this->addr, 0, sizeof(this->addr));
+ }
+ strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME]));
+
+ if (!found)
+ list_add(&this->head, &h->ifindex_hash[hash]);
+
+ return 1;
+}
+
+/* iftable_del - Delete an entry from the interface table
+ * @n: netlink message header of a RTM_DELLINK nlmsg
+ * @arg: not used
+ *
+ * Delete an entry from the interface table.
+ * Returns -1 on error, 0 if no matching entry was found or 1 on success.
+ */
+static int iftable_del(struct nlmsghdr *n, void *arg)
+{
+ struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
+ struct rtattr *cb[IFLA_MAX+1];
+ struct nlif_handle *h = arg;
+ struct ifindex_node *this, *tmp;
+ unsigned int hash;
+
+ if (n->nlmsg_type != RTM_DELLINK)
+ return -1;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
+ return -1;
+
+ rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
+
+ hash = ifi_msg->ifi_index & 0xF;
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index) {
+ list_del(&this->head);
+ free(this);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/** Get the name for an ifindex
+ *
+ * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param index ifindex to be resolved
+ * \param name interface name, pass a buffer of IFNAMSIZ size
+ * \return -1 on error, 1 on success
+ */
+int nlif_index2name(struct nlif_handle *h,
+ unsigned int index,
+ char *name)
+{
+ unsigned int hash;
+ struct ifindex_node *this;
+
+ assert(h != NULL);
+ assert(name != NULL);
+
+ if (index == 0) {
+ strcpy(name, "*");
+ return 1;
+ }
+
+ hash = index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == index) {
+ strcpy(name, this->name);
+ return 1;
+ }
+ }
+
+ errno = ENOENT;
+ return -1;
+}
+
+/** Get the flags for an ifindex
+ *
+ * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param index ifindex to be resolved
+ * \param flags pointer to variable used to store the interface flags
+ * \return -1 on error, 1 on success
+ */
+int nlif_get_ifflags(const struct nlif_handle *h,
+ unsigned int index,
+ unsigned int *flags)
+{
+ unsigned int hash;
+ struct ifindex_node *this;
+
+ assert(h != NULL);
+ assert(flags != NULL);
+
+ if (index == 0) {
+ errno = ENOENT;
+ return -1;
+ }
+
+ hash = index & 0xF;
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == index) {
+ *flags = this->flags;
+ return 1;
+ }
+ }
+ errno = ENOENT;
+ return -1;
+}
+
+/** Initialize interface table
+ *
+ * Initialize rtnl interface and interface table
+ * Call this before any nlif_* function
+ *
+ * \return file descriptor to netlink socket
+ */
+struct nlif_handle *nlif_open(void)
+{
+ int i;
+ struct nlif_handle *h;
+
+ h = calloc(1, sizeof(struct nlif_handle));
+ if (h == NULL)
+ goto err;
+
+ for (i=0; i<16; i++)
+ INIT_LIST_HEAD(&h->ifindex_hash[i]);
+
+ h->ifadd_handler.nlmsg_type = RTM_NEWLINK;
+ h->ifadd_handler.handlefn = iftable_add;
+ h->ifadd_handler.arg = h;
+ h->ifdel_handler.nlmsg_type = RTM_DELLINK;
+ h->ifdel_handler.handlefn = iftable_del;
+ h->ifdel_handler.arg = h;
+
+ h->rtnl_handle = rtnl_open();
+ if (h->rtnl_handle == NULL)
+ goto err;
+
+ if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0)
+ goto err_close;
+
+ if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0)
+ goto err_unregister;
+
+ return h;
+
+err_unregister:
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
+err_close:
+ rtnl_close(h->rtnl_handle);
+ free(h);
+err:
+ return NULL;
+}
+
+/** Destructor of interface table
+ *
+ * \param nlif_handle A pointer to a ::nlif_handle created
+ * via nlif_open()
+ */
+void nlif_close(struct nlif_handle *h)
+{
+ int i;
+ struct ifindex_node *this, *tmp;
+
+ assert(h != NULL);
+
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
+ rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler);
+ rtnl_close(h->rtnl_handle);
+
+ for (i=0; i<16; i++) {
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
+ list_del(&this->head);
+ free(this);
+ }
+ }
+
+ free(h);
+ h = NULL; /* bugtrap */
+}
+
+/** Receive message from netlink and update interface table
+ *
+ * \param nlif_handle A pointer to a ::nlif_handle created
+ * \return 0 if OK
+ */
+int nlif_catch(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return rtnl_receive(h->rtnl_handle);
+
+ return -1;
+}
+
+static int nlif_catch_multi(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return rtnl_receive_multi(h->rtnl_handle);
+
+ return -1;
+}
+
+/**
+ * nlif_query - request a dump of interfaces available in the system
+ * @h: pointer to a valid nlif_handler
+ */
+int nlif_query(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0)
+ return -1;
+
+ return nlif_catch_multi(h);
+}
+
+/** Returns socket descriptor for the netlink socket
+ *
+ * \param nlif_handle A pointer to a ::nlif_handle created
+ * \return The fd or -1 if there's an error
+ */
+int nlif_fd(struct nlif_handle *h)
+{
+ assert(h != NULL);
+
+ if (h->rtnl_handle)
+ return h->rtnl_handle->rtnl_fd;
+
+ return -1;
+}
+
+/**
+ * @}
+ */
diff --git a/src/rtnl.c b/src/rtnl.c
new file mode 100644
index 0000000..dff3bef
--- /dev/null
+++ b/src/rtnl.c
@@ -0,0 +1,283 @@
+/* rtnl - rtnetlink utility functions
+ *
+ * (C) 2004 by Astaro AG, written by Harald Welte <hwelte@astaro.com>
+ *
+ * Adapted to nfnetlink by Eric Leblond <eric@inl.fr>
+ *
+ * This software is free software and licensed under GNU GPLv2+.
+ *
+ */
+
+/* rtnetlink - routing table netlink interface */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+
+#include <netinet/in.h>
+
+#include <linux/types.h>
+#include <sys/socket.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+#include "rtnl.h"
+
+#define rtnl_log(x, ...)
+
+static inline struct rtnl_handler *
+find_handler(struct rtnl_handle *rtnl_handle, uint16_t type)
+{
+ struct rtnl_handler *h;
+ for (h = rtnl_handle->handlers; h; h = h->next) {
+ if (h->nlmsg_type == type)
+ return h;
+ }
+ return NULL;
+}
+
+static int call_handler(struct rtnl_handle *rtnl_handle,
+ uint16_t type,
+ struct nlmsghdr *hdr)
+{
+ struct rtnl_handler *h = find_handler(rtnl_handle, type);
+
+ if (!h) {
+ rtnl_log(LOG_DEBUG, "no registered handler for type %u", type);
+ return 0;
+ }
+
+ return (h->handlefn)(hdr, h->arg);
+}
+
+/**
+ * \defgroup rtnetlink Functions in rtnl.c [DEPRECATED]
+ * This documentation is provided for the benefit of maintainers of legacy code.
+ *
+ * New applications should use
+ * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/).
+ * @{
+ */
+
+/**
+ * rtnl_handler_register - register handler for given nlmsg type
+ * \param: rtnl_handle: Handler ftom rtnl_open()
+ * \param: hdlr: callback handler structure
+ */
+int rtnl_handler_register(struct rtnl_handle *rtnl_handle,
+ struct rtnl_handler *hdlr)
+{
+ rtnl_log(LOG_DEBUG, "registering handler for type %u",
+ hdlr->nlmsg_type);
+ hdlr->next = rtnl_handle->handlers;
+ rtnl_handle->handlers = hdlr;
+ return 1;
+}
+
+/**
+ * rtnl_handler_unregister - unregister handler for given nlmst type
+ * \param: hdlr: callback handler structure
+ * \param: hdlr: handler structure
+ */
+int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle,
+ struct rtnl_handler *hdlr)
+{
+ struct rtnl_handler *h, *prev = NULL;
+
+ rtnl_log(LOG_DEBUG, "unregistering handler for type %u",
+ hdlr->nlmsg_type);
+
+ for (h = rtnl_handle->handlers; h; h = h->next) {
+ if (h == hdlr) {
+ if (prev)
+ prev->next = h->next;
+ else
+ rtnl_handle->handlers = h->next;
+ return 1;
+ }
+ prev = h;
+ }
+ return 0;
+}
+
+int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+ memset(tb, 0, sizeof(struct rtattr *) * max);
+
+ while (RTA_OK(rta, len)) {
+ if (rta->rta_type <= max)
+ tb[rta->rta_type] = rta;
+ rta = RTA_NEXT(rta,len);
+ }
+ if (len)
+ return -1;
+ return 0;
+}
+
+/* rtnl_dump_type - ask rtnetlink to dump a specific table
+ * \param: type: type of table to be dumped
+ */
+int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ } req;
+ struct sockaddr_nl nladdr;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ memset(&req, 0, sizeof(req));
+ nladdr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = type;
+ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq);
+ req.g.rtgen_family = AF_INET;
+
+ return sendto(rtnl_handle->rtnl_fd, &req, sizeof(req), 0,
+ (struct sockaddr*)&nladdr, sizeof(nladdr));
+}
+
+/* rtnl_receive - receive netlink packets from rtnetlink socket */
+int rtnl_receive(struct rtnl_handle *rtnl_handle)
+{
+ int status;
+ char buf[8192];
+ struct sockaddr_nl nladdr;
+ struct iovec iov = { buf, sizeof(buf) };
+ struct nlmsghdr *h;
+
+ struct msghdr msg = {
+ .msg_name = &nladdr,
+ .msg_namelen = sizeof(nladdr),
+ .msg_iov = &iov,
+ .msg_iovlen = 1,
+ };
+
+ status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0);
+ if (status < 0) {
+ if (errno == EINTR)
+ return 0;
+ rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket");
+ return -1;
+ }
+ if (status == 0) {
+ rtnl_log(LOG_ERROR, "EOF on rtnl socket");
+ return -1;
+ }
+ if (msg.msg_namelen != sizeof(nladdr)) {
+ rtnl_log(LOG_ERROR, "invalid address size");
+ return -1;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (NLMSG_OK(h, status)) {
+#if 0
+ if (h->nlmsg_pid != rtnl_local.nl_pid ||
+ h->nlmsg_seq != rtnl_dump) {
+ goto skip;
+ }
+#endif
+
+ if (h->nlmsg_type == NLMSG_DONE) {
+ rtnl_log(LOG_NOTICE, "NLMSG_DONE");
+ return 0;
+ }
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = NLMSG_DATA(h);
+ if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr)))
+ errno = -err->error;
+ rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d",
+ errno);
+ return -1;
+ }
+
+ if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0)
+ rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u",
+ h->nlmsg_type);
+ h = NLMSG_NEXT(h, status);
+ }
+ return 1;
+}
+
+int rtnl_receive_multi(struct rtnl_handle *rtnl_handle)
+{
+ while (1) {
+ if (rtnl_receive(rtnl_handle) <= 0)
+ break;
+ }
+ return 1;
+}
+
+/* rtnl_open - constructor of rtnetlink module */
+struct rtnl_handle *rtnl_open(void)
+{
+ socklen_t addrlen;
+ struct rtnl_handle *h;
+
+ h = calloc(1, sizeof(struct rtnl_handle));
+ if (!h)
+ return NULL;
+
+ addrlen = sizeof(h->rtnl_local);
+
+ h->rtnl_local.nl_pid = getpid();
+ h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (h->rtnl_fd < 0) {
+ rtnl_log(LOG_ERROR, "unable to create rtnetlink socket");
+ goto err;
+ }
+
+ memset(&h->rtnl_local, 0, sizeof(h->rtnl_local));
+ h->rtnl_local.nl_family = AF_NETLINK;
+ h->rtnl_local.nl_groups = RTMGRP_LINK;
+ if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) {
+ rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket");
+ goto err_close;
+ }
+
+ if (getsockname(h->rtnl_fd,
+ (struct sockaddr *) &h->rtnl_local,
+ &addrlen) < 0) {
+ rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)");
+ goto err_close;
+ }
+
+ if (addrlen != sizeof(h->rtnl_local)) {
+ rtnl_log(LOG_ERROR, "invalid address size %u", addr_len);
+ goto err_close;
+ }
+
+ if (h->rtnl_local.nl_family != AF_NETLINK) {
+ rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family);
+ goto err_close;
+ }
+
+ h->rtnl_seq = time(NULL);
+
+ return h;
+
+err_close:
+ close(h->rtnl_fd);
+err:
+ free(h);
+ return NULL;
+}
+
+/* rtnl_close - destructor of rtnetlink module */
+void rtnl_close(struct rtnl_handle *rtnl_handle)
+{
+ close(rtnl_handle->rtnl_fd);
+ free(rtnl_handle);
+ return;
+}
+
+/**
+ * @}
+ */
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 13/32] include: Cherry-pick macros and functions that nlif will need
2024-02-14 10:47 ` Pablo Neira Ayuso
` (13 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 12/32] src: Copy nlif-related code from libnfnetlink Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 14/32] doc: Add linux_list.h to the doxygen system Duncan Roe
` (18 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
linux_list.h has macros and functions that mnl-api programs may want to
use. Will have to add linux_list.h to the doxygen system,
so cut out stuff we don't need to document.
Update libnetfilter_queue.h to include linux_list.h.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
.../libnetfilter_queue/libnetfilter_queue.h | 1 +
include/libnetfilter_queue/linux_list.h | 586 +-----------------
2 files changed, 7 insertions(+), 580 deletions(-)
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index 9327f8c..9bd9c43 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -16,6 +16,7 @@
#include <sys/time.h>
#include <libnfnetlink/libnfnetlink.h>
+#include <libnetfilter_queue/linux_list.h>
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
#ifdef __cplusplus
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index cf71837..eaa9c07 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -6,6 +6,12 @@
#undef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
+/*
+ * This is a cut-down copy of libnfnetlink/include/linux_list.h which is itself
+ * an old snapshot of linux/include/linux/list.h.
+ * This file only contains what we use.
+ */
+
/**
* container_of - cast a member of a structure out to the containing structure
*
@@ -18,24 +24,8 @@
typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
-/*
- * Check at compile time that something is of a particular type.
- * Always evaluates to 1 so you may use it easily in comparisons.
- */
-#define typecheck(type,x) \
-({ type __dummy; \
- typeof(x) __dummy2; \
- (void)(&__dummy == &__dummy2); \
- 1; \
-})
-
#define prefetch(x) ((void)0)
-/* empty define to make this work in userspace -HW */
-#ifndef smp_wmb
-#define smp_wmb()
-#endif
-
/*
* These are non-NULL pointers that will result in page faults
* under normal circumstances, used to verify that nobody uses
@@ -58,11 +48,6 @@ struct list_head {
struct list_head *next, *prev;
};
-#define LIST_HEAD_INIT(name) { &(name), &(name) }
-
-#define LIST_HEAD(name) \
- struct list_head name = LIST_HEAD_INIT(name)
-
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
@@ -96,78 +81,6 @@ static inline void list_add(struct list_head *new, struct list_head *head)
__list_add(new, head, head->next);
}
-/**
- * list_add_tail - add a new entry
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
-}
-
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add_rcu(struct list_head * new,
- struct list_head * prev, struct list_head * next)
-{
- new->next = next;
- new->prev = prev;
- smp_wmb();
- next->prev = new;
- prev->next = new;
-}
-
-/**
- * list_add_rcu - add a new entry to rcu-protected list
- * @new: new entry to be added
- * @head: list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- *
- * The caller must take whatever precautions are necessary
- * (such as holding appropriate locks) to avoid racing
- * with another list-mutation primitive, such as list_add_rcu()
- * or list_del_rcu(), running on this same list.
- * However, it is perfectly legal to run concurrently with
- * the _rcu list-traversal primitives, such as
- * list_for_each_entry_rcu().
- */
-static inline void list_add_rcu(struct list_head *new, struct list_head *head)
-{
- __list_add_rcu(new, head, head->next);
-}
-
-/**
- * list_add_tail_rcu - add a new entry to rcu-protected list
- * @new: new entry to be added
- * @head: list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- *
- * The caller must take whatever precautions are necessary
- * (such as holding appropriate locks) to avoid racing
- * with another list-mutation primitive, such as list_add_tail_rcu()
- * or list_del_rcu(), running on this same list.
- * However, it is perfectly legal to run concurrently with
- * the _rcu list-traversal primitives, such as
- * list_for_each_entry_rcu().
- */
-static inline void list_add_tail_rcu(struct list_head *new,
- struct list_head *head)
-{
- __list_add_rcu(new, head->prev, head);
-}
-
/*
* Delete a list entry by making the prev/next entries
* point to each other.
@@ -194,69 +107,6 @@ static inline void list_del(struct list_head *entry)
entry->prev = LIST_POISON2;
}
-/**
- * list_del_rcu - deletes entry from list without re-initialization
- * @entry: the element to delete from the list.
- *
- * Note: list_empty on entry does not return true after this,
- * the entry is in an undefined state. It is useful for RCU based
- * lockfree traversal.
- *
- * In particular, it means that we can not poison the forward
- * pointers that may still be used for walking the list.
- *
- * The caller must take whatever precautions are necessary
- * (such as holding appropriate locks) to avoid racing
- * with another list-mutation primitive, such as list_del_rcu()
- * or list_add_rcu(), running on this same list.
- * However, it is perfectly legal to run concurrently with
- * the _rcu list-traversal primitives, such as
- * list_for_each_entry_rcu().
- *
- * Note that the caller is not permitted to immediately free
- * the newly deleted entry. Instead, either synchronize_kernel()
- * or call_rcu() must be used to defer freeing until an RCU
- * grace period has elapsed.
- */
-static inline void list_del_rcu(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- entry->prev = LIST_POISON2;
-}
-
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @entry: the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
-{
- __list_del(entry->prev, entry->next);
- INIT_LIST_HEAD(entry);
-}
-
-/**
- * list_move - delete from one list and add as another's head
- * @list: the entry to move
- * @head: the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add(list, head);
-}
-
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @list: the entry to move
- * @head: the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
- struct list_head *head)
-{
- __list_del(list->prev, list->next);
- list_add_tail(list, head);
-}
-
/**
* list_empty - tests whether a list is empty
* @head: the list to test.
@@ -265,66 +115,6 @@ static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
-
-/**
- * list_empty_careful - tests whether a list is
- * empty _and_ checks that no other CPU might be
- * in the process of still modifying either member
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- *
- * @head: the list to test.
- */
-static inline int list_empty_careful(const struct list_head *head)
-{
- struct list_head *next = head->next;
- return (next == head) && (next == head->prev);
-}
-
-static inline void __list_splice(struct list_head *list,
- struct list_head *head)
-{
- struct list_head *first = list->next;
- struct list_head *last = list->prev;
- struct list_head *at = head->next;
-
- first->prev = head;
- head->next = first;
-
- last->next = at;
- at->prev = last;
-}
-
-/**
- * list_splice - join two lists
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- */
-static inline void list_splice(struct list_head *list, struct list_head *head)
-{
- if (!list_empty(list))
- __list_splice(list, head);
-}
-
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @list: the new list to add.
- * @head: the place to add it in the first list.
- *
- * The list at @list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list)) {
- __list_splice(list, head);
- INIT_LIST_HEAD(list);
- }
-}
-
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
@@ -334,47 +124,6 @@ static inline void list_splice_init(struct list_head *list,
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
-/**
- * list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next, prefetch(pos->next); pos != (head); \
- pos = pos->next, prefetch(pos->next))
-
-/**
- * __list_for_each - iterate over a list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- *
- * This variant differs from list_for_each() in that it's the
- * simplest possible list iteration code, no prefetching is done.
- * Use this for code that knows the list to be very short (empty
- * or 1 entry) most of the time.
- */
-#define __list_for_each(pos, head) \
- for (pos = (head)->next; pos != (head); pos = pos->next)
-
-/**
- * list_for_each_prev - iterate over a list backwards
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- */
-#define list_for_each_prev(pos, head) \
- for (pos = (head)->prev, prefetch(pos->prev); pos != (head); \
- pos = pos->prev, prefetch(pos->prev))
-
-/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop counter.
@@ -388,43 +137,6 @@ static inline void list_splice_init(struct list_head *list,
pos = list_entry(pos->member.next, typeof(*pos), member), \
prefetch(pos->member.next))
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member) \
- for (pos = list_entry((head)->prev, typeof(*pos), member), \
- prefetch(pos->member.prev); \
- &pos->member != (head); \
- pos = list_entry(pos->member.prev, typeof(*pos), member), \
- prefetch(pos->member.prev))
-
-/**
- * list_prepare_entry - prepare a pos entry for use as a start point in
- * list_for_each_entry_continue
- * @pos: the type * to use as a start point
- * @head: the head of the list
- * @member: the name of the list_struct within the struct.
- */
-#define list_prepare_entry(pos, head, member) \
- ((pos) ? : list_entry(head, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue - iterate over list of given type
- * continuing after existing point
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- */
-#define list_for_each_entry_continue(pos, head, member) \
- for (pos = list_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next))
-
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
* @pos: the type * to use as a loop counter.
@@ -438,290 +150,4 @@ static inline void list_splice_init(struct list_head *list,
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
-/**
- * list_for_each_rcu - iterate over an rcu-protected list
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as list_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define list_for_each_rcu(pos, head) \
- for (pos = (head)->next, prefetch(pos->next); pos != (head); \
- pos = pos->next, ({ smp_read_barrier_depends(); 0;}), prefetch(pos->next))
-
-#define __list_for_each_rcu(pos, head) \
- for (pos = (head)->next; pos != (head); \
- pos = pos->next, ({ smp_read_barrier_depends(); 0;}))
-
-/**
- * list_for_each_safe_rcu - iterate over an rcu-protected list safe
- * against removal of list entry
- * @pos: the &struct list_head to use as a loop counter.
- * @n: another &struct list_head to use as temporary storage
- * @head: the head for your list.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as list_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define list_for_each_safe_rcu(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, ({ smp_read_barrier_depends(); 0;}), n = pos->next)
-
-/**
- * list_for_each_entry_rcu - iterate over rcu list of given type
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as list_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define list_for_each_entry_rcu(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- prefetch(pos->member.next); \
- &pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member), \
- ({ smp_read_barrier_depends(); 0;}), \
- prefetch(pos->member.next))
-
-
-/**
- * list_for_each_continue_rcu - iterate over an rcu-protected list
- * continuing after existing point.
- * @pos: the &struct list_head to use as a loop counter.
- * @head: the head for your list.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as list_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define list_for_each_continue_rcu(pos, head) \
- for ((pos) = (pos)->next, prefetch((pos)->next); (pos) != (head); \
- (pos) = (pos)->next, ({ smp_read_barrier_depends(); 0;}), prefetch((pos)->next))
-
-/*
- * Double linked lists with a single pointer list head.
- * Mostly useful for hash tables where the two pointer list head is
- * too wasteful.
- * You lose the ability to access the tail in O(1).
- */
-
-struct hlist_head {
- struct hlist_node *first;
-};
-
-struct hlist_node {
- struct hlist_node *next, **pprev;
-};
-
-#define HLIST_HEAD_INIT { .first = NULL }
-#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
-#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
-#define INIT_HLIST_NODE(ptr) ((ptr)->next = NULL, (ptr)->pprev = NULL)
-
-static inline int hlist_unhashed(const struct hlist_node *h)
-{
- return !h->pprev;
-}
-
-static inline int hlist_empty(const struct hlist_head *h)
-{
- return !h->first;
-}
-
-static inline void __hlist_del(struct hlist_node *n)
-{
- struct hlist_node *next = n->next;
- struct hlist_node **pprev = n->pprev;
- *pprev = next;
- if (next)
- next->pprev = pprev;
-}
-
-static inline void hlist_del(struct hlist_node *n)
-{
- __hlist_del(n);
- n->next = LIST_POISON1;
- n->pprev = LIST_POISON2;
-}
-
-/**
- * hlist_del_rcu - deletes entry from hash list without re-initialization
- * @n: the element to delete from the hash list.
- *
- * Note: list_unhashed() on entry does not return true after this,
- * the entry is in an undefined state. It is useful for RCU based
- * lockfree traversal.
- *
- * In particular, it means that we can not poison the forward
- * pointers that may still be used for walking the hash list.
- *
- * The caller must take whatever precautions are necessary
- * (such as holding appropriate locks) to avoid racing
- * with another list-mutation primitive, such as hlist_add_head_rcu()
- * or hlist_del_rcu(), running on this same list.
- * However, it is perfectly legal to run concurrently with
- * the _rcu list-traversal primitives, such as
- * hlist_for_each_entry().
- */
-static inline void hlist_del_rcu(struct hlist_node *n)
-{
- __hlist_del(n);
- n->pprev = LIST_POISON2;
-}
-
-static inline void hlist_del_init(struct hlist_node *n)
-{
- if (n->pprev) {
- __hlist_del(n);
- INIT_HLIST_NODE(n);
- }
-}
-
-#define hlist_del_rcu_init hlist_del_init
-
-static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
-{
- struct hlist_node *first = h->first;
- n->next = first;
- if (first)
- first->pprev = &n->next;
- h->first = n;
- n->pprev = &h->first;
-}
-
-
-/**
- * hlist_add_head_rcu - adds the specified element to the specified hlist,
- * while permitting racing traversals.
- * @n: the element to add to the hash list.
- * @h: the list to add to.
- *
- * The caller must take whatever precautions are necessary
- * (such as holding appropriate locks) to avoid racing
- * with another list-mutation primitive, such as hlist_add_head_rcu()
- * or hlist_del_rcu(), running on this same list.
- * However, it is perfectly legal to run concurrently with
- * the _rcu list-traversal primitives, such as
- * hlist_for_each_entry(), but only if smp_read_barrier_depends()
- * is used to prevent memory-consistency problems on Alpha CPUs.
- * Regardless of the type of CPU, the list-traversal primitive
- * must be guarded by rcu_read_lock().
- *
- * OK, so why don't we have an hlist_for_each_entry_rcu()???
- */
-static inline void hlist_add_head_rcu(struct hlist_node *n,
- struct hlist_head *h)
-{
- struct hlist_node *first = h->first;
- n->next = first;
- n->pprev = &h->first;
- smp_wmb();
- if (first)
- first->pprev = &n->next;
- h->first = n;
-}
-
-/* next must be != NULL */
-static inline void hlist_add_before(struct hlist_node *n,
- struct hlist_node *next)
-{
- n->pprev = next->pprev;
- n->next = next;
- next->pprev = &n->next;
- *(n->pprev) = n;
-}
-
-static inline void hlist_add_after(struct hlist_node *n,
- struct hlist_node *next)
-{
- next->next = n->next;
- n->next = next;
- next->pprev = &n->next;
-
- if(next->next)
- next->next->pprev = &next->next;
-}
-
-#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
-
-#define hlist_for_each(pos, head) \
- for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
- pos = pos->next)
-
-#define hlist_for_each_safe(pos, n, head) \
- for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
- pos = n)
-
-/**
- * hlist_for_each_entry - iterate over list of given type
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry(tpos, pos, head, member) \
- for (pos = (head)->first; \
- pos && ({ prefetch(pos->next); 1;}) && \
- ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
- pos = pos->next)
-
-/**
- * hlist_for_each_entry_continue - iterate over a hlist continuing after existing point
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
- * @member: the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_continue(tpos, pos, member) \
- for (pos = (pos)->next; \
- pos && ({ prefetch(pos->next); 1;}) && \
- ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
- pos = pos->next)
-
-/**
- * hlist_for_each_entry_from - iterate over a hlist continuing from existing point
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
- * @member: the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_from(tpos, pos, member) \
- for (; pos && ({ prefetch(pos->next); 1;}) && \
- ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
- pos = pos->next)
-
-/**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @tpos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
- * @n: another &struct hlist_node to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the hlist_node within the struct.
- */
-#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
- for (pos = (head)->first; \
- pos && ({ n = pos->next; 1; }) && \
- ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
- pos = n)
-
-/**
- * hlist_for_each_entry_rcu - iterate over rcu list of given type
- * @pos: the type * to use as a loop counter.
- * @pos: the &struct hlist_node to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the hlist_node within the struct.
- *
- * This list-traversal primitive may safely run concurrently with
- * the _rcu list-mutation primitives such as hlist_add_rcu()
- * as long as the traversal is guarded by rcu_read_lock().
- */
-#define hlist_for_each_entry_rcu(tpos, pos, head, member) \
- for (pos = (head)->first; \
- pos && ({ prefetch(pos->next); 1;}) && \
- ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
- pos = pos->next, ({ smp_read_barrier_depends(); 0; }) )
-
#endif
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 14/32] doc: Add linux_list.h to the doxygen system
2024-02-14 10:47 ` Pablo Neira Ayuso
` (14 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 13/32] include: Cherry-pick macros and functions that nlif will need Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 15/32] doc: Eliminate doxygen warnings from linux_list.h Duncan Roe
` (17 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Produce web and man pages for list_for_each_entry() and other macros.
Mostly a straight conversion of the kerneldoc but also document
struct list_head and macro INIT_LIST_HEAD.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/Makefile.am | 1 +
doxygen/build_man.sh | 7 ++-
doxygen/doxygen.cfg.in | 5 ++-
include/libnetfilter_queue/linux_list.h | 60 +++++++++++++++++--------
4 files changed, 52 insertions(+), 21 deletions(-)
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index 68be963..6135f25 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -8,6 +8,7 @@ doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
$(top_srcdir)/src/extra/ipv6.c\
$(top_srcdir)/src/extra/tcp.c\
$(top_srcdir)/src/extra/udp.c\
+ $(top_srcdir)/include/libnetfilter_queue/linux_list.h\
$(top_srcdir)/src/extra/icmp.c
doxyfile.stamp: $(doc_srcs) Makefile build_man.sh
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index 7eab8fa..643ad42 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -84,7 +84,12 @@ post_process(){
make_man7(){
popd >/dev/null
- target=$(grep -Ew INPUT doxygen.cfg | rev | cut -f1 -d' ' | rev)/$2
+
+ # This grep command works for multiple directories on the INPUT line,
+ # as long as the directory containing the source with the main page
+ # comes first.
+ target=/$(grep -Ew INPUT doxygen.cfg | cut -f2- -d/ | cut -f1 -d' ')/$2
+
mypath=$(dirname $0)
# Build up temporary source in temp.c
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index fcfc045..e69dcd7 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -5,8 +5,9 @@ ABBREVIATE_BRIEF =
FULL_PATH_NAMES = NO
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
-INPUT = @abs_top_srcdir@/src
-FILE_PATTERNS = *.c
+INPUT = @abs_top_srcdir@/src \
+ @abs_top_srcdir@/include/libnetfilter_queue
+FILE_PATTERNS = *.c linux_list.h
RECURSIVE = YES
EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
tcp_word_hdr \
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index eaa9c07..88ea386 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -12,17 +12,23 @@
* This file only contains what we use.
*/
+/**
+ * \defgroup List Simple doubly linked list implementation
+ * @{
+ */
+
+
/**
* container_of - cast a member of a structure out to the containing structure
*
- * @ptr: the pointer to the member.
- * @type: the type of the container struct this is embedded in.
- * @member: the name of the member within the struct.
+ * \param ptr: the pointer to the member.
+ * \param type: the type of the container struct this is embedded in.
+ * \param member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
- typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+ typeof( ((type *)0)->member ) *__mptr = (ptr); \
+ (type *)( (char *)__mptr - offsetof(type,member) );})
#define prefetch(x) ((void)0)
@@ -44,10 +50,24 @@
* using the generic single-entry routines.
*/
+/**
+ * \struct list_head
+ * Link to adjacent members of the circular list
+ * \note Each member of a list must start with this structure
+ * (containing structures OK)
+ * \var list_head::next
+ * pointer to the next list member
+ * \var list_head::prev
+ * pointer to the previous list member
+ */
struct list_head {
struct list_head *next, *prev;
};
+/**
+ * INIT_LIST_HEAD - Initialise first member of a new list
+ * \param ptr the &struct list_head pointer.
+ */
#define INIT_LIST_HEAD(ptr) do { \
(ptr)->next = (ptr); (ptr)->prev = (ptr); \
} while (0)
@@ -70,8 +90,8 @@ static inline void __list_add(struct list_head *new,
/**
* list_add - add a new entry
- * @new: new entry to be added
- * @head: list head to add it after
+ * \param new: new entry to be added
+ * \param head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
@@ -96,7 +116,7 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
/**
* list_del - deletes entry from list.
- * @entry: the element to delete from the list.
+ * \param entry: the element to delete from the list.
* Note: list_empty on entry does not return true after this, the entry is
* in an undefined state.
*/
@@ -117,18 +137,18 @@ static inline int list_empty(const struct list_head *head)
}
/**
* list_entry - get the struct for this entry
- * @ptr: the &struct list_head pointer.
- * @type: the type of the struct this is embedded in.
- * @member: the name of the list_struct within the struct.
+ * \param ptr: the &struct list_head pointer.
+ * \param type: the type of the struct this is embedded in.
+ * \param member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each_entry - iterate over list of given type
- * @pos: the type * to use as a loop counter.
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
+ * \param pos: the type * to use as a loop counter.
+ * \param head: the head for your list.
+ * \param member: the name of the list_struct within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
@@ -139,10 +159,10 @@ static inline int list_empty(const struct list_head *head)
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @pos: the type * to use as a loop counter.
- * @n: another type * to use as temporary storage
- * @head: the head for your list.
- * @member: the name of the list_struct within the struct.
+ * \param pos: the type * to use as a loop counter.
+ * \param n: another type * to use as temporary storage
+ * \param head: the head for your list.
+ * \param member: the name of the list_struct within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
@@ -150,4 +170,8 @@ static inline int list_empty(const struct list_head *head)
&pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
+/**
+ * @}
+ */
+
#endif
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 15/32] doc: Eliminate doxygen warnings from linux_list.h
2024-02-14 10:47 ` Pablo Neira Ayuso
` (15 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 14/32] doc: Add linux_list.h to the doxygen system Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 16/32] doc: Eliminate doxygen warnings from iftable.c Duncan Roe
` (16 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
The warnings concerned prefetch(), LIST_POISON1 & LIST_POISON2.
Remove all 3 macros since they do nothing useful in userspace programs.
Also take a few doxygen comment improvements from 6.6 Linux source.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/linux_list.h | 44 ++++++++++++-------------
1 file changed, 21 insertions(+), 23 deletions(-)
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index 88ea386..500481d 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -10,10 +10,20 @@
* This is a cut-down copy of libnfnetlink/include/linux_list.h which is itself
* an old snapshot of linux/include/linux/list.h.
* This file only contains what we use.
+ *
+ * 2024-01-27 12:45:41 +1100 duncan_roe@optusnet.com.au
+ * LIST_POISONx doesn't really work for user space - just use NULL
+ *
+ * 2024-01-27 18:16:51 +1100 duncan_roe@optusnet.com.au
+ * I can't see how the prefetch() calls do any good so remove them
+ * and #define of prefetch
+ *
+ * 2024-01-27 18:53:46 +1100 duncan_roe@optusnet.com.au
+ * Take a few doxygen comment improvements from 6.6 Linux source
*/
/**
- * \defgroup List Simple doubly linked list implementation
+ * \defgroup List Circular doubly linked list implementation
* @{
*/
@@ -30,18 +40,8 @@
typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
-#define prefetch(x) ((void)0)
-
/*
- * These are non-NULL pointers that will result in page faults
- * under normal circumstances, used to verify that nobody uses
- * non-initialized list entries.
- */
-#define LIST_POISON1 ((void *) 0x00100100)
-#define LIST_POISON2 ((void *) 0x00200200)
-
-/*
- * Simple doubly linked list implementation.
+ * Circular doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
@@ -123,8 +123,8 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
- entry->next = LIST_POISON1;
- entry->prev = LIST_POISON2;
+ entry->next = NULL;
+ entry->prev = NULL;
}
/**
@@ -139,30 +139,28 @@ static inline int list_empty(const struct list_head *head)
* list_entry - get the struct for this entry
* \param ptr: the &struct list_head pointer.
* \param type: the type of the struct this is embedded in.
- * \param member: the name of the list_struct within the struct.
+ * \param member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) \
container_of(ptr, type, member)
/**
* list_for_each_entry - iterate over list of given type
- * \param pos: the type * to use as a loop counter.
+ * \param pos: the type * to use as a loop cursor.
* \param head: the head for your list.
- * \param member: the name of the list_struct within the struct.
+ * \param member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
- for (pos = list_entry((head)->next, typeof(*pos), member), \
- prefetch(pos->member.next); \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
&pos->member != (head); \
- pos = list_entry(pos->member.next, typeof(*pos), member), \
- prefetch(pos->member.next))
+ pos = list_entry(pos->member.next, typeof(*pos), member)) \
/**
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * \param pos: the type * to use as a loop counter.
+ * \param pos: the type * to use as a loop cursor.
* \param n: another type * to use as temporary storage
* \param head: the head for your list.
- * \param member: the name of the list_struct within the struct.
+ * \param member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 16/32] doc: Eliminate doxygen warnings from iftable.c
2024-02-14 10:47 ` Pablo Neira Ayuso
` (16 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 15/32] doc: Eliminate doxygen warnings from linux_list.h Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 17/32] whitespace: remove trailing spaces " Duncan Roe
` (15 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Introduce some new doxygen content. Not yet converted to use libmnl.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/Makefile.am | 1 +
doxygen/doxygen.cfg.in | 2 ++
src/iftable.c | 53 +++++++++++++++++++++++++-----------------
3 files changed, 35 insertions(+), 21 deletions(-)
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index 6135f25..aae1ccc 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -2,6 +2,7 @@ if HAVE_DOXYGEN
doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
$(top_srcdir)/src/nlmsg.c\
+ $(top_srcdir)/src/iftable.c\
$(top_srcdir)/src/extra/checksum.c\
$(top_srcdir)/src/extra/ipv4.c\
$(top_srcdir)/src/extra/pktbuff.c\
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index e69dcd7..c795df1 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -17,6 +17,8 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfnl_handle \
nfnl_subsys_handle \
mnl_socket \
+ ifindex_node \
+ nlif_handle \
nfnl_callback2 \
tcp_flag_word
EXAMPLE_PATTERNS =
diff --git a/src/iftable.c b/src/iftable.c
index aab59b3..22c3952 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -2,6 +2,7 @@
*
* (C) 2004 by Astaro AG, written by Harald Welte <hwelte@astaro.com>
* (C) 2008 by Pablo Neira Ayuso <pablo@netfilter.org>
+ * (C) 2024 by Duncan Roe <duncan_roe@optusnet.com.au>
*
* This software is Free Software and licensed under GNU GPLv2+.
*/
@@ -25,11 +26,14 @@
#include "linux_list.h"
/**
- * \defgroup iftable Functions in iftable.c [DEPRECATED]
- * This documentation is provided for the benefit of maintainers of legacy code.
+ * \defgroup iftable Functions to manage a table of network interfaces
+ * These functions maintain a database of the name and flags of each
+ * network interface.
*
- * New applications should use
- * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/).
+ * mnl API programs may instead use
+ * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/)
+ * calls directly to maintain an
+ * interface table with more (or less!) data points, e.g. MTU.
* @{
*/
@@ -52,8 +56,8 @@ struct nlif_handle {
};
/* iftable_add - Add/Update an entry to/in the interface table
- * @n: netlink message header of a RTM_NEWLINK message
- * @arg: not used
+ * \param n: netlink message header of a RTM_NEWLINK message
+ * \param arg: not used
*
* This function adds/updates an entry in the intrface table.
* Returns -1 on error, 1 on success.
@@ -114,8 +118,8 @@ static int iftable_add(struct nlmsghdr *n, void *arg)
}
/* iftable_del - Delete an entry from the interface table
- * @n: netlink message header of a RTM_DELLINK nlmsg
- * @arg: not used
+ * \param n: netlink message header of a RTM_DELLINK nlmsg
+ * \param arg: not used
*
* Delete an entry from the interface table.
* Returns -1 on error, 0 if no matching entry was found or 1 on success.
@@ -148,9 +152,10 @@ static int iftable_del(struct nlmsghdr *n, void *arg)
return 0;
}
-/** Get the name for an ifindex
+/**
+ * nlif_index2name - get the name for an ifindex
*
- * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param h pointer to nlif_handle created by nlif_open()
* \param index ifindex to be resolved
* \param name interface name, pass a buffer of IFNAMSIZ size
* \return -1 on error, 1 on success
@@ -182,9 +187,10 @@ int nlif_index2name(struct nlif_handle *h,
return -1;
}
-/** Get the flags for an ifindex
+/**
+ * nlif_get_ifflags - get the flags for an ifindex
*
- * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param h pointer to nlif_handle created by nlif_open()
* \param index ifindex to be resolved
* \param flags pointer to variable used to store the interface flags
* \return -1 on error, 1 on success
@@ -215,7 +221,8 @@ int nlif_get_ifflags(const struct nlif_handle *h,
return -1;
}
-/** Initialize interface table
+/**
+ * nlif_open - initialize interface table
*
* Initialize rtnl interface and interface table
* Call this before any nlif_* function
@@ -262,10 +269,10 @@ err:
return NULL;
}
-/** Destructor of interface table
+/**
+ * nlif_close - free all resources associated with the interface table
*
- * \param nlif_handle A pointer to a ::nlif_handle created
- * via nlif_open()
+ * \param h pointer to nlif_handle created by nlif_open()
*/
void nlif_close(struct nlif_handle *h)
{
@@ -289,9 +296,12 @@ void nlif_close(struct nlif_handle *h)
h = NULL; /* bugtrap */
}
-/** Receive message from netlink and update interface table
+/**
+ * nlif_catch - receive message from netlink and update interface table
+ *
+ * FIXME - elaborate a bit
*
- * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param h pointer to nlif_handle created by nlif_open()
* \return 0 if OK
*/
int nlif_catch(struct nlif_handle *h)
@@ -316,7 +326,7 @@ static int nlif_catch_multi(struct nlif_handle *h)
/**
* nlif_query - request a dump of interfaces available in the system
- * @h: pointer to a valid nlif_handler
+ * \param h: pointer to a valid nlif_handler
*/
int nlif_query(struct nlif_handle *h)
{
@@ -328,9 +338,10 @@ int nlif_query(struct nlif_handle *h)
return nlif_catch_multi(h);
}
-/** Returns socket descriptor for the netlink socket
+/**
+ * nlif_fd - get file descriptor for the netlink socket
*
- * \param nlif_handle A pointer to a ::nlif_handle created
+ * \param h pointer to nlif_handle created by nlif_open()
* \return The fd or -1 if there's an error
*/
int nlif_fd(struct nlif_handle *h)
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 17/32] whitespace: remove trailing spaces from iftable.c
2024-02-14 10:47 ` Pablo Neira Ayuso
` (17 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 16/32] doc: Eliminate doxygen warnings from iftable.c Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 18/32] include: Use libmnl.h instead of libnfnetlink.h Duncan Roe
` (14 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Done in a separate commit to ease review of real changes.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/iftable.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/src/iftable.c b/src/iftable.c
index 22c3952..307acc1 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -121,7 +121,7 @@ static int iftable_add(struct nlmsghdr *n, void *arg)
* \param n: netlink message header of a RTM_DELLINK nlmsg
* \param arg: not used
*
- * Delete an entry from the interface table.
+ * Delete an entry from the interface table.
* Returns -1 on error, 0 if no matching entry was found or 1 on success.
*/
static int iftable_del(struct nlmsghdr *n, void *arg)
@@ -158,9 +158,9 @@ static int iftable_del(struct nlmsghdr *n, void *arg)
* \param h pointer to nlif_handle created by nlif_open()
* \param index ifindex to be resolved
* \param name interface name, pass a buffer of IFNAMSIZ size
- * \return -1 on error, 1 on success
+ * \return -1 on error, 1 on success
*/
-int nlif_index2name(struct nlif_handle *h,
+int nlif_index2name(struct nlif_handle *h,
unsigned int index,
char *name)
{
@@ -193,7 +193,7 @@ int nlif_index2name(struct nlif_handle *h,
* \param h pointer to nlif_handle created by nlif_open()
* \param index ifindex to be resolved
* \param flags pointer to variable used to store the interface flags
- * \return -1 on error, 1 on success
+ * \return -1 on error, 1 on success
*/
int nlif_get_ifflags(const struct nlif_handle *h,
unsigned int index,
@@ -324,7 +324,7 @@ static int nlif_catch_multi(struct nlif_handle *h)
return -1;
}
-/**
+/**
* nlif_query - request a dump of interfaces available in the system
* \param h: pointer to a valid nlif_handler
*/
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 18/32] include: Use libmnl.h instead of libnfnetlink.h
2024-02-14 10:47 ` Pablo Neira Ayuso
` (18 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 17/32] whitespace: remove trailing spaces " Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 19/32] src: Convert all nlif_* functions to use libmnl Duncan Roe
` (13 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Add nlif_* prototypes and 64-bit converters to libnetfilter_queue.h.
Fix a couple of libnfnetlink.h references still in libnetfilter_queue.c.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
.../libnetfilter_queue/libnetfilter_queue.h | 36 ++++++++++++++++++-
src/libnetfilter_queue.c | 4 +--
2 files changed, 37 insertions(+), 3 deletions(-)
diff --git a/include/libnetfilter_queue/libnetfilter_queue.h b/include/libnetfilter_queue/libnetfilter_queue.h
index 9bd9c43..84a8a7e 100644
--- a/include/libnetfilter_queue/libnetfilter_queue.h
+++ b/include/libnetfilter_queue/libnetfilter_queue.h
@@ -14,7 +14,7 @@
#define __LIBCTNETLINK_H
#include <sys/time.h>
-#include <libnfnetlink/libnfnetlink.h>
+#include <libmnl/libmnl.h>
#include <libnetfilter_queue/linux_list.h>
#include <libnetfilter_queue/linux_nfnetlink_queue.h>
@@ -26,6 +26,7 @@ extern "C" {
struct nfq_handle;
struct nfq_q_handle;
struct nfq_data;
+struct nlif_handle;
extern int nfq_errno;
@@ -156,8 +157,41 @@ int nfq_nlmsg_parse(const struct nlmsghdr *nlh, struct nlattr **attr);
struct nlmsghdr *nfq_nlmsg_put(char *buf, int type, uint32_t queue_num);
struct nlmsghdr *nfq_nlmsg_put2(char *buf, int type, uint32_t queue_num, uint16_t flags);
+/*
+ * Network Interface Table API
+ */
+
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+
+struct nlif_handle *nlif_open(void);
+void nlif_close(struct nlif_handle *orig);
+int nlif_fd(struct nlif_handle *nlif_handle);
+int nlif_query(struct nlif_handle *nlif_handle);
+int nlif_catch(struct nlif_handle *nlif_handle);
+int nlif_index2name(struct nlif_handle *nlif_handle, unsigned int if_index, char *name);
+int nlif_get_ifflags(const struct nlif_handle *h, unsigned int index, unsigned int *flags);
+
#ifdef __cplusplus
} /* extern "C" */
#endif
+/*
+ * __be46 stuff - should be in libmnl.h maybe?
+ */
+
+#include <byteswap.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+# ifndef __be64_to_cpu
+# define __be64_to_cpu(x) (x)
+# endif
+# else
+# if __BYTE_ORDER == __LITTLE_ENDIAN
+# ifndef __be64_to_cpu
+# define __be64_to_cpu(x) __bswap_64(x)
+# endif
+# endif
+#endif
+
#endif /* __LIBNFQNETLINK_H */
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 2f50b47..3c3f951 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -151,7 +151,7 @@ struct nfnl_subsys_handle {
uint32_t subscriptions;
uint8_t subsys_id;
uint8_t cb_count;
- struct nfnl_callback *cb; /* array of callbacks */
+ struct nfnl_callback2 *cb; /* Not an exact copy: array of callbacks */
};
struct nfnl_handle {
@@ -479,7 +479,7 @@ struct nfq_handle *nfq_open(void)
h->nfnlh->fd = h->nl->fd;
h->nfnlh->local = h->nl->addr;
h->nfnlh->peer.nl_family = AF_NETLINK;
- h->nfnlh->rcv_buffer_size = NFNL_BUFFSIZE;
+ h->nfnlh->rcv_buffer_size = MNL_SOCKET_BUFFER_SIZE;
if (!fill_nfnl_subsys_handle(h))
goto err_close;
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 19/32] src: Convert all nlif_* functions to use libmnl
2024-02-14 10:47 ` Pablo Neira Ayuso
` (19 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 18/32] include: Use libmnl.h instead of libnfnetlink.h Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 20/32] src: Delete rtnl.c Duncan Roe
` (12 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
In iftable.c, replace calls to functions in rtnetlink.c with inline code
(converted to use libmnl instead of libnfnetlink).
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/Makefile.am | 1 +
src/iftable.c | 304 ++++++++++++++++++++++--------------------------
2 files changed, 138 insertions(+), 167 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 079853e..a6813e8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -30,6 +30,7 @@ libnetfilter_queue_la_LDFLAGS = -Wc,-nostartfiles \
-version-info $(LIBVERSION)
libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \
nlmsg.c \
+ iftable.c \
extra/checksum.c \
extra/icmp.c \
extra/ipv6.c \
diff --git a/src/iftable.c b/src/iftable.c
index 307acc1..76a6cad 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -11,19 +11,27 @@
#include <unistd.h>
#include <stdlib.h>
+#include <time.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
-#include <assert.h>
#include <linux/netdevice.h>
-#include <libnfnetlink/libnfnetlink.h>
-#include "rtnl.h"
-#include "linux_list.h"
+#include <linux/rtnetlink.h>
+#include <linux/netfilter/nfnetlink_queue.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
+
+#include "internal.h"
+
+#define NUM_NLIF_BITS 4
+#define NUM_NLIF_ENTRIES (1 << NUM_NLIF_BITS)
+#define NLIF_ENTRY_MASK (NUM_NLIF_ENTRIES -1)
+
+static int data_cb(const struct nlmsghdr *nlh, void *data);
/**
* \defgroup iftable Functions to manage a table of network interfaces
@@ -42,116 +50,16 @@ struct ifindex_node {
uint32_t index;
uint32_t type;
- uint32_t alen;
uint32_t flags;
- char addr[8];
- char name[16];
+ char name[IFNAMSIZ];
};
struct nlif_handle {
- struct list_head ifindex_hash[16];
- struct rtnl_handle *rtnl_handle;
- struct rtnl_handler ifadd_handler;
- struct rtnl_handler ifdel_handler;
+ struct list_head ifindex_hash[NUM_NLIF_ENTRIES];
+ struct mnl_socket *nl;
+ unsigned int portid;
};
-/* iftable_add - Add/Update an entry to/in the interface table
- * \param n: netlink message header of a RTM_NEWLINK message
- * \param arg: not used
- *
- * This function adds/updates an entry in the intrface table.
- * Returns -1 on error, 1 on success.
- */
-static int iftable_add(struct nlmsghdr *n, void *arg)
-{
- unsigned int hash, found = 0;
- struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
- struct ifindex_node *this;
- struct rtattr *cb[IFLA_MAX+1];
- struct nlif_handle *h = arg;
-
- if (n->nlmsg_type != RTM_NEWLINK)
- return -1;
-
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
- return -1;
-
- rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
-
- if (!cb[IFLA_IFNAME])
- return -1;
-
- hash = ifi_msg->ifi_index & 0xF;
- list_for_each_entry(this, &h->ifindex_hash[hash], head) {
- if (this->index == ifi_msg->ifi_index) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- this = malloc(sizeof(*this));
- if (!this)
- return -1;
-
- this->index = ifi_msg->ifi_index;
- }
-
- this->type = ifi_msg->ifi_type;
- this->flags = ifi_msg->ifi_flags;
- if (cb[IFLA_ADDRESS]) {
- unsigned int alen;
- this->alen = alen = RTA_PAYLOAD(cb[IFLA_ADDRESS]);
- if (alen > sizeof(this->addr))
- alen = sizeof(this->addr);
- memcpy(this->addr, RTA_DATA(cb[IFLA_ADDRESS]), alen);
- } else {
- this->alen = 0;
- memset(this->addr, 0, sizeof(this->addr));
- }
- strcpy(this->name, RTA_DATA(cb[IFLA_IFNAME]));
-
- if (!found)
- list_add(&this->head, &h->ifindex_hash[hash]);
-
- return 1;
-}
-
-/* iftable_del - Delete an entry from the interface table
- * \param n: netlink message header of a RTM_DELLINK nlmsg
- * \param arg: not used
- *
- * Delete an entry from the interface table.
- * Returns -1 on error, 0 if no matching entry was found or 1 on success.
- */
-static int iftable_del(struct nlmsghdr *n, void *arg)
-{
- struct ifinfomsg *ifi_msg = NLMSG_DATA(n);
- struct rtattr *cb[IFLA_MAX+1];
- struct nlif_handle *h = arg;
- struct ifindex_node *this, *tmp;
- unsigned int hash;
-
- if (n->nlmsg_type != RTM_DELLINK)
- return -1;
-
- if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi_msg)))
- return -1;
-
- rtnl_parse_rtattr(cb, IFLA_MAX, IFLA_RTA(ifi_msg), IFLA_PAYLOAD(n));
-
- hash = ifi_msg->ifi_index & 0xF;
- list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash], head) {
- if (this->index == ifi_msg->ifi_index) {
- list_del(&this->head);
- free(this);
- return 1;
- }
- }
-
- return 0;
-}
-
/**
* nlif_index2name - get the name for an ifindex
*
@@ -160,6 +68,7 @@ static int iftable_del(struct nlmsghdr *n, void *arg)
* \param name interface name, pass a buffer of IFNAMSIZ size
* \return -1 on error, 1 on success
*/
+EXPORT_SYMBOL
int nlif_index2name(struct nlif_handle *h,
unsigned int index,
char *name)
@@ -167,9 +76,6 @@ int nlif_index2name(struct nlif_handle *h,
unsigned int hash;
struct ifindex_node *this;
- assert(h != NULL);
- assert(name != NULL);
-
if (index == 0) {
strcpy(name, "*");
return 1;
@@ -195,6 +101,7 @@ int nlif_index2name(struct nlif_handle *h,
* \param flags pointer to variable used to store the interface flags
* \return -1 on error, 1 on success
*/
+EXPORT_SYMBOL
int nlif_get_ifflags(const struct nlif_handle *h,
unsigned int index,
unsigned int *flags)
@@ -202,9 +109,6 @@ int nlif_get_ifflags(const struct nlif_handle *h,
unsigned int hash;
struct ifindex_node *this;
- assert(h != NULL);
- assert(flags != NULL);
-
if (index == 0) {
errno = ENOENT;
return -1;
@@ -224,11 +128,12 @@ int nlif_get_ifflags(const struct nlif_handle *h,
/**
* nlif_open - initialize interface table
*
- * Initialize rtnl interface and interface table
+ * Open a netlink socket and initialize interface table
* Call this before any nlif_* function
*
- * \return file descriptor to netlink socket
+ * \return NULL on error, else valid pointer to an nlif_handle structure
*/
+EXPORT_SYMBOL
struct nlif_handle *nlif_open(void)
{
int i;
@@ -238,32 +143,22 @@ struct nlif_handle *nlif_open(void)
if (h == NULL)
goto err;
- for (i=0; i<16; i++)
+ for (i=0; i < NUM_NLIF_ENTRIES; i++)
INIT_LIST_HEAD(&h->ifindex_hash[i]);
- h->ifadd_handler.nlmsg_type = RTM_NEWLINK;
- h->ifadd_handler.handlefn = iftable_add;
- h->ifadd_handler.arg = h;
- h->ifdel_handler.nlmsg_type = RTM_DELLINK;
- h->ifdel_handler.handlefn = iftable_del;
- h->ifdel_handler.arg = h;
+ h->nl = mnl_socket_open(NETLINK_ROUTE);
+ if (!h->nl)
+ goto err_free;
- h->rtnl_handle = rtnl_open();
- if (h->rtnl_handle == NULL)
- goto err;
-
- if (rtnl_handler_register(h->rtnl_handle, &h->ifadd_handler) < 0)
+ if (mnl_socket_bind(h->nl, RTMGRP_LINK, MNL_SOCKET_AUTOPID) < 0)
goto err_close;
-
- if (rtnl_handler_register(h->rtnl_handle, &h->ifdel_handler) < 0)
- goto err_unregister;
+ h->portid = mnl_socket_get_portid(h->nl);
return h;
-err_unregister:
- rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
err_close:
- rtnl_close(h->rtnl_handle);
+ mnl_socket_close(h->nl);
+err_free:
free(h);
err:
return NULL;
@@ -274,18 +169,15 @@ err:
*
* \param h pointer to nlif_handle created by nlif_open()
*/
+EXPORT_SYMBOL
void nlif_close(struct nlif_handle *h)
{
int i;
struct ifindex_node *this, *tmp;
- assert(h != NULL);
+ mnl_socket_close(h->nl);
- rtnl_handler_unregister(h->rtnl_handle, &h->ifadd_handler);
- rtnl_handler_unregister(h->rtnl_handle, &h->ifdel_handler);
- rtnl_close(h->rtnl_handle);
-
- for (i=0; i<16; i++) {
+ for (i=0; i < NUM_NLIF_ENTRIES; i++) {
list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
list_del(&this->head);
free(this);
@@ -304,56 +196,134 @@ void nlif_close(struct nlif_handle *h)
* \param h pointer to nlif_handle created by nlif_open()
* \return 0 if OK
*/
+EXPORT_SYMBOL
int nlif_catch(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return rtnl_receive(h->rtnl_handle);
-
- return -1;
-}
-
-static int nlif_catch_multi(struct nlif_handle *h)
-{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return rtnl_receive_multi(h->rtnl_handle);
+ /*
+ * Use MNL_SOCKET_BUFFER_SIZE instead of MNL_SOCKET_DUMP_SIZE
+ * to keep memory footprint same as it was.
+ */
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ if (!h->nl) /* The old library had this test */
+ return -1;
- return -1;
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof buf);
+ if (ret == -1)
+ return -1;
+ return mnl_cb_run(buf, ret, 0, h->portid, data_cb, h) == -1 ? -1 : 0;
}
/**
* nlif_query - request a dump of interfaces available in the system
* \param h: pointer to a valid nlif_handler
+ * \return -1 on err with errno set, else >=0
*/
+EXPORT_SYMBOL
int nlif_query(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (rtnl_dump_type(h->rtnl_handle, RTM_GETLINK) < 0)
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t seq;
+ int ret;
+ struct rtgenmsg *rt;
+
+ nlh = mnl_nlmsg_put_header(buf);
+ nlh->nlmsg_type = RTM_GETLINK;
+ nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+ nlh->nlmsg_seq = seq = time(NULL);
+ rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
+ rt->rtgen_family = AF_PACKET;
+ if (mnl_socket_sendto(h->nl, nlh, nlh->nlmsg_len) < 0)
return -1;
-
- return nlif_catch_multi(h);
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
+ while (ret > 0) {
+ ret = mnl_cb_run(buf, ret, seq, h->portid, data_cb, h);
+ if (ret <= MNL_CB_STOP)
+ break;
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
+ }
+ return ret;
}
/**
* nlif_fd - get file descriptor for the netlink socket
*
* \param h pointer to nlif_handle created by nlif_open()
- * \return The fd or -1 if there's an error
+ * \return socket fd or -1 on error
*/
+EXPORT_SYMBOL
int nlif_fd(struct nlif_handle *h)
{
- assert(h != NULL);
-
- if (h->rtnl_handle)
- return h->rtnl_handle->rtnl_fd;
-
- return -1;
+ return h->nl? mnl_socket_get_fd(h->nl) : -1;
}
/**
* @}
*/
+
+/*
+ * data_cb - callback for rtnetlink messages
+ * caller will put nlif_handle in data
+ */
+
+static int data_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct ifinfomsg *ifi_msg = mnl_nlmsg_get_payload(nlh);
+ struct nlif_handle *h = data;
+ struct nlattr *attr;
+ uint32_t hash;
+ struct ifindex_node *this, *tmp;
+
+ if (nlh->nlmsg_type != RTM_NEWLINK && nlh->nlmsg_type != RTM_DELLINK) {
+ errno = EPROTO;
+ return MNL_CB_ERROR;
+ }
+ hash = ifi_msg->ifi_index & NLIF_ENTRY_MASK;
+
+ /* RTM_DELLINK is simple, do it first for less indenting */
+ if (nlh->nlmsg_type == RTM_DELLINK) {
+ /*
+ * The original code used list_for_each_entry_safe when deleting
+ * and list_for_each_entry when adding.
+ * The code is only ever going to delete one entry
+ * so what does the safe variant achieve?
+ * In a multi-threaded app,
+ * I'd suggest a pthread rwlock on all nlif accesses.
+ */
+ list_for_each_entry_safe(this, tmp, &h->ifindex_hash[hash],
+ head) {
+ if (this->index == ifi_msg->ifi_index) {
+ list_del(&this->head);
+ free(this);
+ }
+ }
+ return MNL_CB_OK;
+ }
+
+ list_for_each_entry(this, &h->ifindex_hash[hash], head) {
+ if (this->index == ifi_msg->ifi_index)
+ goto found;
+ }
+ this = calloc(1, sizeof(*this));
+ if (!this)
+ return MNL_CB_ERROR;
+ this->index = ifi_msg->ifi_index;
+ this->type = ifi_msg->ifi_type;
+ this->flags = ifi_msg->ifi_flags;
+ list_add(&this->head, &h->ifindex_hash[hash]);
+found:
+ mnl_attr_for_each(attr, nlh, sizeof(*ifi_msg)) {
+ /* All we want is the interface name */
+ if (mnl_attr_get_type(attr) == IFLA_IFNAME) {
+ if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0) {
+ perror("mnl_attr_validate");
+ return MNL_CB_ERROR;
+ }
+ strcpy(this->name, mnl_attr_get_str(attr));
+ break;
+ }
+ }
+ return MNL_CB_OK;
+}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 20/32] src: Delete rtnl.c
2024-02-14 10:47 ` Pablo Neira Ayuso
` (20 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 19/32] src: Convert all nlif_* functions to use libmnl Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 21/32] build: Remove libnfnetlink from the build Duncan Roe
` (11 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
rtnl.c was copied from libnfnetlink for reference: it has now served its
purpose.
Without rtnl.c, doxygen again runs warning-free.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/rtnl.c | 283 -----------------------------------------------------
1 file changed, 283 deletions(-)
delete mode 100644 src/rtnl.c
diff --git a/src/rtnl.c b/src/rtnl.c
deleted file mode 100644
index dff3bef..0000000
--- a/src/rtnl.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/* rtnl - rtnetlink utility functions
- *
- * (C) 2004 by Astaro AG, written by Harald Welte <hwelte@astaro.com>
- *
- * Adapted to nfnetlink by Eric Leblond <eric@inl.fr>
- *
- * This software is free software and licensed under GNU GPLv2+.
- *
- */
-
-/* rtnetlink - routing table netlink interface */
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/uio.h>
-
-#include <netinet/in.h>
-
-#include <linux/types.h>
-#include <sys/socket.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include "rtnl.h"
-
-#define rtnl_log(x, ...)
-
-static inline struct rtnl_handler *
-find_handler(struct rtnl_handle *rtnl_handle, uint16_t type)
-{
- struct rtnl_handler *h;
- for (h = rtnl_handle->handlers; h; h = h->next) {
- if (h->nlmsg_type == type)
- return h;
- }
- return NULL;
-}
-
-static int call_handler(struct rtnl_handle *rtnl_handle,
- uint16_t type,
- struct nlmsghdr *hdr)
-{
- struct rtnl_handler *h = find_handler(rtnl_handle, type);
-
- if (!h) {
- rtnl_log(LOG_DEBUG, "no registered handler for type %u", type);
- return 0;
- }
-
- return (h->handlefn)(hdr, h->arg);
-}
-
-/**
- * \defgroup rtnetlink Functions in rtnl.c [DEPRECATED]
- * This documentation is provided for the benefit of maintainers of legacy code.
- *
- * New applications should use
- * [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/).
- * @{
- */
-
-/**
- * rtnl_handler_register - register handler for given nlmsg type
- * \param: rtnl_handle: Handler ftom rtnl_open()
- * \param: hdlr: callback handler structure
- */
-int rtnl_handler_register(struct rtnl_handle *rtnl_handle,
- struct rtnl_handler *hdlr)
-{
- rtnl_log(LOG_DEBUG, "registering handler for type %u",
- hdlr->nlmsg_type);
- hdlr->next = rtnl_handle->handlers;
- rtnl_handle->handlers = hdlr;
- return 1;
-}
-
-/**
- * rtnl_handler_unregister - unregister handler for given nlmst type
- * \param: hdlr: callback handler structure
- * \param: hdlr: handler structure
- */
-int rtnl_handler_unregister(struct rtnl_handle *rtnl_handle,
- struct rtnl_handler *hdlr)
-{
- struct rtnl_handler *h, *prev = NULL;
-
- rtnl_log(LOG_DEBUG, "unregistering handler for type %u",
- hdlr->nlmsg_type);
-
- for (h = rtnl_handle->handlers; h; h = h->next) {
- if (h == hdlr) {
- if (prev)
- prev->next = h->next;
- else
- rtnl_handle->handlers = h->next;
- return 1;
- }
- prev = h;
- }
- return 0;
-}
-
-int rtnl_parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
-{
- memset(tb, 0, sizeof(struct rtattr *) * max);
-
- while (RTA_OK(rta, len)) {
- if (rta->rta_type <= max)
- tb[rta->rta_type] = rta;
- rta = RTA_NEXT(rta,len);
- }
- if (len)
- return -1;
- return 0;
-}
-
-/* rtnl_dump_type - ask rtnetlink to dump a specific table
- * \param: type: type of table to be dumped
- */
-int rtnl_dump_type(struct rtnl_handle *rtnl_handle, unsigned int type)
-{
- struct {
- struct nlmsghdr nlh;
- struct rtgenmsg g;
- } req;
- struct sockaddr_nl nladdr;
-
- memset(&nladdr, 0, sizeof(nladdr));
- memset(&req, 0, sizeof(req));
- nladdr.nl_family = AF_NETLINK;
-
- req.nlh.nlmsg_len = sizeof(req);
- req.nlh.nlmsg_type = type;
- req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
- req.nlh.nlmsg_pid = 0;
- req.nlh.nlmsg_seq = rtnl_handle->rtnl_dump = ++(rtnl_handle->rtnl_seq);
- req.g.rtgen_family = AF_INET;
-
- return sendto(rtnl_handle->rtnl_fd, &req, sizeof(req), 0,
- (struct sockaddr*)&nladdr, sizeof(nladdr));
-}
-
-/* rtnl_receive - receive netlink packets from rtnetlink socket */
-int rtnl_receive(struct rtnl_handle *rtnl_handle)
-{
- int status;
- char buf[8192];
- struct sockaddr_nl nladdr;
- struct iovec iov = { buf, sizeof(buf) };
- struct nlmsghdr *h;
-
- struct msghdr msg = {
- .msg_name = &nladdr,
- .msg_namelen = sizeof(nladdr),
- .msg_iov = &iov,
- .msg_iovlen = 1,
- };
-
- status = recvmsg(rtnl_handle->rtnl_fd, &msg, 0);
- if (status < 0) {
- if (errno == EINTR)
- return 0;
- rtnl_log(LOG_NOTICE, "OVERRUN on rtnl socket");
- return -1;
- }
- if (status == 0) {
- rtnl_log(LOG_ERROR, "EOF on rtnl socket");
- return -1;
- }
- if (msg.msg_namelen != sizeof(nladdr)) {
- rtnl_log(LOG_ERROR, "invalid address size");
- return -1;
- }
-
- h = (struct nlmsghdr *) buf;
- while (NLMSG_OK(h, status)) {
-#if 0
- if (h->nlmsg_pid != rtnl_local.nl_pid ||
- h->nlmsg_seq != rtnl_dump) {
- goto skip;
- }
-#endif
-
- if (h->nlmsg_type == NLMSG_DONE) {
- rtnl_log(LOG_NOTICE, "NLMSG_DONE");
- return 0;
- }
- if (h->nlmsg_type == NLMSG_ERROR) {
- struct nlmsgerr *err = NLMSG_DATA(h);
- if (h->nlmsg_len>=NLMSG_LENGTH(sizeof(struct nlmsgerr)))
- errno = -err->error;
- rtnl_log(LOG_ERROR, "NLMSG_ERROR, errnp=%d",
- errno);
- return -1;
- }
-
- if (call_handler(rtnl_handle, h->nlmsg_type, h) == 0)
- rtnl_log(LOG_NOTICE, "unhandled nlmsg_type %u",
- h->nlmsg_type);
- h = NLMSG_NEXT(h, status);
- }
- return 1;
-}
-
-int rtnl_receive_multi(struct rtnl_handle *rtnl_handle)
-{
- while (1) {
- if (rtnl_receive(rtnl_handle) <= 0)
- break;
- }
- return 1;
-}
-
-/* rtnl_open - constructor of rtnetlink module */
-struct rtnl_handle *rtnl_open(void)
-{
- socklen_t addrlen;
- struct rtnl_handle *h;
-
- h = calloc(1, sizeof(struct rtnl_handle));
- if (!h)
- return NULL;
-
- addrlen = sizeof(h->rtnl_local);
-
- h->rtnl_local.nl_pid = getpid();
- h->rtnl_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (h->rtnl_fd < 0) {
- rtnl_log(LOG_ERROR, "unable to create rtnetlink socket");
- goto err;
- }
-
- memset(&h->rtnl_local, 0, sizeof(h->rtnl_local));
- h->rtnl_local.nl_family = AF_NETLINK;
- h->rtnl_local.nl_groups = RTMGRP_LINK;
- if (bind(h->rtnl_fd, (struct sockaddr *) &h->rtnl_local, addrlen) < 0) {
- rtnl_log(LOG_ERROR, "unable to bind rtnetlink socket");
- goto err_close;
- }
-
- if (getsockname(h->rtnl_fd,
- (struct sockaddr *) &h->rtnl_local,
- &addrlen) < 0) {
- rtnl_log(LOG_ERROR, "cannot gescockname(rtnl_socket)");
- goto err_close;
- }
-
- if (addrlen != sizeof(h->rtnl_local)) {
- rtnl_log(LOG_ERROR, "invalid address size %u", addr_len);
- goto err_close;
- }
-
- if (h->rtnl_local.nl_family != AF_NETLINK) {
- rtnl_log(LOG_ERROR, "invalid AF %u", h->rtnl_local.nl_family);
- goto err_close;
- }
-
- h->rtnl_seq = time(NULL);
-
- return h;
-
-err_close:
- close(h->rtnl_fd);
-err:
- free(h);
- return NULL;
-}
-
-/* rtnl_close - destructor of rtnetlink module */
-void rtnl_close(struct rtnl_handle *rtnl_handle)
-{
- close(rtnl_handle->rtnl_fd);
- free(rtnl_handle);
- return;
-}
-
-/**
- * @}
- */
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 21/32] build: Remove libnfnetlink from the build
2024-02-14 10:47 ` Pablo Neira Ayuso
` (21 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 20/32] src: Delete rtnl.c Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 22/32] include: Remove the last remaining use of a libnfnetlink header Duncan Roe
` (10 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
libnfnetlink was a "private library" - always loaded whether user apps
used it or not. Remove it now it is no longer needed.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
Make_global.am | 2 +-
configure.ac | 1 -
libnetfilter_queue.pc.in | 2 --
src/Makefile.am | 2 +-
4 files changed, 2 insertions(+), 5 deletions(-)
diff --git a/Make_global.am b/Make_global.am
index 91da5da..4d8a58e 100644
--- a/Make_global.am
+++ b/Make_global.am
@@ -1,2 +1,2 @@
-AM_CPPFLAGS = -I${top_srcdir}/include ${LIBNFNETLINK_CFLAGS} ${LIBMNL_CFLAGS}
+AM_CPPFLAGS = -I${top_srcdir}/include ${LIBMNL_CFLAGS}
AM_CFLAGS = -Wall ${GCC_FVISIBILITY_HIDDEN}
diff --git a/configure.ac b/configure.ac
index 7359fba..ba7b15f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,7 +42,6 @@ case "$host" in
esac
dnl Dependencies
-PKG_CHECK_MODULES([LIBNFNETLINK], [libnfnetlink >= 0.0.41])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
AS_IF([test "$enable_man_pages" = no -a "$enable_html_doc" = no],
diff --git a/libnetfilter_queue.pc.in b/libnetfilter_queue.pc.in
index 9c6c2c4..1927a8a 100644
--- a/libnetfilter_queue.pc.in
+++ b/libnetfilter_queue.pc.in
@@ -9,8 +9,6 @@ Name: libnetfilter_queue
Description: netfilter userspace packet queueing library
URL: http://netfilter.org/projects/libnetfilter_queue/
Version: @VERSION@
-Requires: libnfnetlink
Conflicts:
Libs: -L${libdir} -lnetfilter_queue
-Libs.private: @LIBNFNETLINK_LIBS@
Cflags: -I${includedir}
diff --git a/src/Makefile.am b/src/Makefile.am
index a6813e8..e5e1d66 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,4 +39,4 @@ libnetfilter_queue_la_SOURCES = libnetfilter_queue.c \
extra/pktbuff.c \
extra/udp.c
-libnetfilter_queue_la_LIBADD = ${LIBNFNETLINK_LIBS} ${LIBMNL_LIBS}
+libnetfilter_queue_la_LIBADD = ${LIBMNL_LIBS}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 22/32] include: Remove the last remaining use of a libnfnetlink header
2024-02-14 10:47 ` Pablo Neira Ayuso
` (22 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 21/32] build: Remove libnfnetlink from the build Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 23/32] doc: Get doxygen to document useful static inline functions Duncan Roe
` (9 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Update (deprecated) include/libnetfilter_queue/linux_nfnetlink_queue.h
to use /usr/include/linux/nfnetlink.h
instead of libnfnetlink/linux_nfnetlink.h
As an aside, everything compiles fine with this line removed
(i.e library, utils and examples all compile),
so maybe we can do without it.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/linux_nfnetlink_queue.h | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/include/libnetfilter_queue/linux_nfnetlink_queue.h b/include/libnetfilter_queue/linux_nfnetlink_queue.h
index 6844270..82d8ece 100644
--- a/include/libnetfilter_queue/linux_nfnetlink_queue.h
+++ b/include/libnetfilter_queue/linux_nfnetlink_queue.h
@@ -8,7 +8,8 @@
#endif
#include <linux/types.h>
-#include <libnfnetlink/linux_nfnetlink.h>
+/* Use the real header since libnfnetlink is going away. */
+#include <linux/nfnetlink.h>
enum nfqnl_msg_types {
NFQNL_MSG_PACKET, /* packet from kernel to userspace */
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 23/32] doc: Get doxygen to document useful static inline functions
2024-02-14 10:47 ` Pablo Neira Ayuso
` (23 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 22/32] include: Remove the last remaining use of a libnfnetlink header Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 24/32] doc: SYNOPSIS of linux_list.h nominates libnetfilter_queue/libnetfilter_queue.h Duncan Roe
` (8 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
include/libnetfilter_queue/linux_list.h contains static inline list_add and
list_del which mnl programs may wish to use. Make a temporary copy of
linux_list.h with 'static' removed and get doxygen to process that.
Also add some detailed description and a SYNOPSIS line to linux_list.h.
Some problems remain with the generated man page.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/Makefile.am | 3 +++
doxygen/doxygen.cfg.in | 3 +--
include/libnetfilter_queue/linux_list.h | 14 ++++++++++++++
3 files changed, 18 insertions(+), 2 deletions(-)
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index aae1ccc..1784afa 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -14,7 +14,10 @@ doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
doxyfile.stamp: $(doc_srcs) Makefile build_man.sh
rm -rf html man
+ sed '/^static inline void [^_]/s/static //' \
+ $(top_srcdir)/include/libnetfilter_queue/linux_list.h > linux_list.h
doxygen doxygen.cfg >/dev/null
+ rm linux_list.h
if BUILD_MAN
$(abs_top_srcdir)/doxygen/build_man.sh libnetfilter_queue libnetfilter_queue.c
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index c795df1..601d4ab 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -5,8 +5,7 @@ ABBREVIATE_BRIEF =
FULL_PATH_NAMES = NO
TAB_SIZE = 8
OPTIMIZE_OUTPUT_FOR_C = YES
-INPUT = @abs_top_srcdir@/src \
- @abs_top_srcdir@/include/libnetfilter_queue
+INPUT = @abs_top_srcdir@/src .
FILE_PATTERNS = *.c linux_list.h
RECURSIVE = YES
EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index 500481d..6e67b9a 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -24,6 +24,20 @@
/**
* \defgroup List Circular doubly linked list implementation
+ *
+ * Unlike file units (which are re-used), network interface indicies
+ * increase monotonically as they are brought up and down.
+ *
+ * To keep memory usage predictable as indices increase,
+ * the nlif_* functions keep their data in a circular list
+ * (in fact a number of lists, to minimise search times).
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libnetfilter_queue/linux_list.h>
+\endmanonly
* @{
*/
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 24/32] doc: SYNOPSIS of linux_list.h nominates libnetfilter_queue/libnetfilter_queue.h
2024-02-14 10:47 ` Pablo Neira Ayuso
` (24 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 23/32] doc: Get doxygen to document useful static inline functions Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 25/32] doc: Move nlif usage description from libnetfilter_queue.c to iftable.c Duncan Roe
` (7 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
This patch enables user apps to compile w/out needing an extra #include
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/linux_list.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index 6e67b9a..76d24ea 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -36,7 +36,7 @@
.SH SYNOPSIS
.nf
\fB
-#include <libnetfilter_queue/linux_list.h>
+#include <libnetfilter_queue/libnetfilter_queue.h>
\endmanonly
* @{
*/
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 25/32] doc: Move nlif usage description from libnetfilter_queue.c to iftable.c
2024-02-14 10:47 ` Pablo Neira Ayuso
` (25 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 24/32] doc: SYNOPSIS of linux_list.h nominates libnetfilter_queue/libnetfilter_queue.h Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 26/32] build: Shave some time off build Duncan Roe
` (6 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Also in iftable.c:
- Expand usage description to cover nlif_catch.
- Add SYNOPSIS.
- Fix some doc typos.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/iftable.c | 57 ++++++++++++++++++++++++++++++++++++----
src/libnetfilter_queue.c | 38 +++------------------------
2 files changed, 56 insertions(+), 39 deletions(-)
diff --git a/src/iftable.c b/src/iftable.c
index 76a6cad..1a53893 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -42,6 +42,55 @@ static int data_cb(const struct nlmsghdr *nlh, void *data);
* [libmnl](https://netfilter.org/projects/libmnl/doxygen/html/)
* calls directly to maintain an
* interface table with more (or less!) data points, e.g. MTU.
+ *
+ * Programs access an nlif database through an opaque __struct nlif_handle__
+ * interface resolving handle. Call nlif_open() to get a handle:
+ * \verbatim
+ h = nlif_open();
+ if (h == NULL) {
+ perror("nlif_open");
+ exit(EXIT_FAILURE);
+ }
+\endverbatim
+ * Once the handler is open, you need to fetch the interface table at a
+ * whole via a call to nlif_query.
+ * \verbatim
+ nlif_query(h);
+\endverbatim
+ * libnetfilter_queue is able to update the interface mapping
+ * when a new interface appears.
+ * To do so, you need to call nlif_catch() on the handler after each
+ * interface related event. The simplest way to get and treat event is to run
+ * a **select()** or **poll()** against the nlif and netilter_queue
+ * file descriptors.
+ * E.g. use nlif_fd() to get the nlif file descriptor, then give this fd to
+ * **poll()** as in this code snippet (error-checking removed):
+ * \verbatim
+ if_fd = nlif_fd(h);
+ qfd = mnl_socket_get_fd(nl); // For mnl API or ...
+ qfd = nfq_fd(qh); // For nfnl API
+ . . .
+ fds[0].fd = ifd;
+ fds[0].events = POLLIN;
+ fds[1].fd = qfd;
+ fds[1].events = POLLIN;
+ for(;;)
+ {
+ poll((struct pollfd *)&fds, 2, -1);
+ if (fds[0].revents & POLLIN)
+ nlif_catch(h);
+\endverbatim
+ * Don't forget to close the handler when you don't need the feature anymore:
+ * \verbatim
+ nlif_close(h);
+\endverbatim
+ *
+ * \manonly
+.SH SYNOPSIS
+.nf
+\fB
+#include <libnetfilter_queue/libnetfilter_queue.h>
+\endmanonly
* @{
*/
@@ -128,8 +177,8 @@ int nlif_get_ifflags(const struct nlif_handle *h,
/**
* nlif_open - initialize interface table
*
- * Open a netlink socket and initialize interface table
- * Call this before any nlif_* function
+ * Open a netlink socket and initialise interface table.
+ * Call this before any other nlif_* function
*
* \return NULL on error, else valid pointer to an nlif_handle structure
*/
@@ -191,8 +240,6 @@ void nlif_close(struct nlif_handle *h)
/**
* nlif_catch - receive message from netlink and update interface table
*
- * FIXME - elaborate a bit
- *
* \param h pointer to nlif_handle created by nlif_open()
* \return 0 if OK
*/
@@ -218,7 +265,7 @@ int nlif_catch(struct nlif_handle *h)
/**
* nlif_query - request a dump of interfaces available in the system
* \param h: pointer to a valid nlif_handler
- * \return -1 on err with errno set, else >=0
+ * \return -1 on error with errno set, else >=0
*/
EXPORT_SYMBOL
int nlif_query(struct nlif_handle *h)
diff --git a/src/libnetfilter_queue.c b/src/libnetfilter_queue.c
index 3c3f951..1be2333 100644
--- a/src/libnetfilter_queue.c
+++ b/src/libnetfilter_queue.c
@@ -1284,34 +1284,7 @@ uint32_t nfq_get_physoutdev(struct nfq_data *nfad)
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
* \return -1 in case of error, >0 if it succeed.
- *
- * To use a nlif_handle, You need first to call nlif_open() and to open
- * an handler. Don't forget to store the result as it will be used
- * during all your program life:
- * \verbatim
- h = nlif_open();
- if (h == NULL) {
- perror("nlif_open");
- exit(EXIT_FAILURE);
- }
-\endverbatim
- * Once the handler is open, you need to fetch the interface table at a
- * whole via a call to nlif_query.
- * \verbatim
- nlif_query(h);
-\endverbatim
- * libnfnetlink is able to update the interface mapping when a new interface
- * appears. To do so, you need to call nlif_catch() on the handler after each
- * interface related event. The simplest way to get and treat event is to run
- * a select() or poll() against the nlif file descriptor. To get this file
- * descriptor, you need to use nlif_fd:
- * \verbatim
- if_fd = nlif_fd(h);
-\endverbatim
- * Don't forget to close the handler when you don't need the feature anymore:
- * \verbatim
- nlif_close(h);
-\endverbatim
+ * \sa __nlif_open__(3)
*
*/
EXPORT_SYMBOL
@@ -1330,9 +1303,8 @@ int nfq_get_indev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
@@ -1350,9 +1322,8 @@ int nfq_get_physindev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
@@ -1370,9 +1341,8 @@ int nfq_get_outdev_name(struct nlif_handle *nlif_handle,
* \param name pointer to the buffer to receive the interface name;
* not more than \c IFNAMSIZ bytes will be copied to it.
*
- * See nfq_get_indev_name() documentation for nlif_handle usage.
- *
* \return -1 in case of error, > 0 if it succeed.
+ * \sa __nlif_open__(3)
*/
EXPORT_SYMBOL
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 26/32] build: Shave some time off build
2024-02-14 10:47 ` Pablo Neira Ayuso
` (26 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 25/32] doc: Move nlif usage description from libnetfilter_queue.c to iftable.c Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 27/32] doc: Resolve most issues with man page generated from linux_list.h Duncan Roe
` (5 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Modify function mygrep in build_man.sh to use pipes rather than the
temporary files. Saves ~20% elapsed time in a make with no compiles on my
system although real & user times increase by about 10%.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/build_man.sh | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index 643ad42..0590009 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -304,15 +304,12 @@ delete_lines(){
}
mygrep(){
- set +e
- grep -En "$1" $2 2>/dev/null >$fileH
- [ $? -ne 0 ] && linnum=0 ||\
- { head -n1 $fileH >$fileG; linnum=$(cat $fileG | cut -f1 -d:); }
- set -e
+ linnum=$(grep -En "$1" $2 2>/dev/null | head -n1 | tee $fileG | cut -f1 -d:)
+ [ $linnum ] || linnum=0
}
make_temp_files(){
- temps="A B C G H"
+ temps="A B C G"
for i in $temps
do declare -g file$i=$(mktemp)
done
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 27/32] doc: Resolve most issues with man page generated from linux_list.h
2024-02-14 10:47 ` Pablo Neira Ayuso
` (27 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 26/32] build: Shave some time off build Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 28/32] build: Get real & user times back to what they were Duncan Roe
` (4 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
build_man.sh has extra logic to extract documented macros into the "Name"
line.
doxygen.cfg.in excludes the list_head structure.
doxygen 1.10.0 has a bug which appends ".PP" to macro "Value:" headings.
This is fixed in the latest snapshot and should be in the next release.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/build_man.sh | 10 ++++++++++
doxygen/doxygen.cfg.in | 1 +
2 files changed, 11 insertions(+)
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index 0590009..b3d1989 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -261,6 +261,16 @@ fix_name_line(){
[ -z "$all_funcs" ] && all_funcs=$func ||\
all_funcs="$all_funcs, $func"
done
+
+ # macros (if any) come after functions
+ while :
+ do mygrep '^\.SS "#' $fileC
+ [ $linnum -ne 0 ] || break
+ tail -n+$(($linnum + 1)) $fileC >$fileB
+ cp $fileB $fileC
+ func=$(cat $fileG | cut -f3 -d' ' | cut -f1 -d\()
+ [ -z "$all_funcs" ] && all_funcs=$func || all_funcs="$all_funcs, $func"
+ done
# For now, assume name is at line 5
head -n4 $target >$fileA
desc=$(head -n5 $target | tail -n1 | cut -f3- -d" ")
diff --git a/doxygen/doxygen.cfg.in b/doxygen/doxygen.cfg.in
index 601d4ab..ad83581 100644
--- a/doxygen/doxygen.cfg.in
+++ b/doxygen/doxygen.cfg.in
@@ -17,6 +17,7 @@ EXCLUDE_SYMBOLS = EXPORT_SYMBOL \
nfnl_subsys_handle \
mnl_socket \
ifindex_node \
+ list_head \
nlif_handle \
nfnl_callback2 \
tcp_flag_word
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 28/32] build: Get real & user times back to what they were
2024-02-14 10:47 ` Pablo Neira Ayuso
` (28 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 27/32] doc: Resolve most issues with man page generated from linux_list.h Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 29/32] doc: Cater for doxygen variants w.r.t. #define stmts Duncan Roe
` (3 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
In build_man.sh, mygrep becomes mygrep2 and
all functions except fix_name_line use a new simpler mygrep.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/build_man.sh | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index b3d1989..5c1a019 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -251,7 +251,7 @@ fix_name_line(){
head -n$linnum $target >$fileC
while :
- do mygrep ^\\.RI $fileC
+ do mygrep2 ^\\.RI $fileC
[ $linnum -ne 0 ] || break
# Discard this entry
tail -n+$(($linnum + 1)) $fileC >$fileB
@@ -264,7 +264,7 @@ fix_name_line(){
# macros (if any) come after functions
while :
- do mygrep '^\.SS "#' $fileC
+ do mygrep2 '^\.SS "#' $fileC
[ $linnum -ne 0 ] || break
tail -n+$(($linnum + 1)) $fileC >$fileB
cp $fileB $fileC
@@ -314,6 +314,13 @@ delete_lines(){
}
mygrep(){
+ linnum=$(grep -En "$1" $2 2>/dev/null | head -n1 | cut -f1 -d:)
+ [ $linnum ] || linnum=0
+}
+
+# mygrep2 copies found line to $fileG. Only fix_name_line() needs this.
+# Using mygrep everywhere else gives a measurable CPU saving.
+mygrep2(){
linnum=$(grep -En "$1" $2 2>/dev/null | head -n1 | tee $fileG | cut -f1 -d:)
[ $linnum ] || linnum=0
}
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 29/32] doc: Cater for doxygen variants w.r.t. #define stmts
2024-02-14 10:47 ` Pablo Neira Ayuso
` (29 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 28/32] build: Get real & user times back to what they were Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 30/32] doc: Fix list_empty() doxygen comments Duncan Roe
` (2 subsequent siblings)
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
More changes to doxygen/build_man.sh.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/build_man.sh | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/doxygen/build_man.sh b/doxygen/build_man.sh
index 5c1a019..d3bd748 100755
--- a/doxygen/build_man.sh
+++ b/doxygen/build_man.sh
@@ -7,6 +7,7 @@
# Args: none or 2 being man7 page name & relative path of source with \mainpage
declare -A renamed_page
+no_macroRI=maybe
main(){
set -e
@@ -250,10 +251,18 @@ fix_name_line(){
mygrep "^\\.SH \"Function Documentation" $target
head -n$linnum $target >$fileC
+ # Different versions of doxygen present macros and functions differently.
+ # Some versions have .RI lines for macros then functions.
+ # Some versions have .SS lines for macros instead of .RI.
+ # All versions (so far) have .SS lines for macros after all .RI lines.
+ # Look for #define in .RI lines and look for .SS lines if none found
+ # to cater for either scenario.
+
while :
do mygrep2 ^\\.RI $fileC
[ $linnum -ne 0 ] || break
# Discard this entry
+ ! grep -E -q '#define' $fileG || no_macroRI=
tail -n+$(($linnum + 1)) $fileC >$fileB
cp $fileB $fileC
@@ -262,9 +271,9 @@ fix_name_line(){
all_funcs="$all_funcs, $func"
done
- # macros (if any) come after functions
+ [ -z "$no_macroRI" ] ||
while :
- do mygrep2 '^\.SS "#' $fileC
+ do mygrep2 '^\.SS "#define' $fileC
[ $linnum -ne 0 ] || break
tail -n+$(($linnum + 1)) $fileC >$fileB
cp $fileB $fileC
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 30/32] doc: Fix list_empty() doxygen comments
2024-02-14 10:47 ` Pablo Neira Ayuso
` (30 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 29/32] doc: Cater for doxygen variants w.r.t. #define stmts Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 31/32] src: Use a cast in place of convoluted construct Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 32/32] whitespace: Fix more checkpatch errors & warnings Duncan Roe
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Need blank line between list_empty and list_entry.
Translate kerneldoc comments to doxygen.
Not all static inline functions are void any more.
Use \note instead of Note:.
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
doxygen/Makefile.am | 2 +-
include/libnetfilter_queue/linux_list.h | 7 +++++--
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/doxygen/Makefile.am b/doxygen/Makefile.am
index 1784afa..4934e8e 100644
--- a/doxygen/Makefile.am
+++ b/doxygen/Makefile.am
@@ -14,7 +14,7 @@ doc_srcs = $(top_srcdir)/src/libnetfilter_queue.c\
doxyfile.stamp: $(doc_srcs) Makefile build_man.sh
rm -rf html man
- sed '/^static inline void [^_]/s/static //' \
+ sed '/^static inline [^ ]* [^_]/s/static //' \
$(top_srcdir)/include/libnetfilter_queue/linux_list.h > linux_list.h
doxygen doxygen.cfg >/dev/null
rm linux_list.h
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index 76d24ea..f687d20 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -131,7 +131,8 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
/**
* list_del - deletes entry from list.
* \param entry: the element to delete from the list.
- * Note: list_empty on entry does not return true after this, the entry is
+ * \note
+ * list_empty() on **entry** does not return true after this, **entry** is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
@@ -143,12 +144,14 @@ static inline void list_del(struct list_head *entry)
/**
* list_empty - tests whether a list is empty
- * @head: the list to test.
+ * \param head: the list to test.
+ * \return 1 if list is empty, 0 otherwise
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}
+
/**
* list_entry - get the struct for this entry
* \param ptr: the &struct list_head pointer.
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 31/32] src: Use a cast in place of convoluted construct
2024-02-14 10:47 ` Pablo Neira Ayuso
` (31 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 30/32] doc: Fix list_empty() doxygen comments Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
2024-03-15 7:33 ` [PATCH libnetfilter_queue 32/32] whitespace: Fix more checkpatch errors & warnings Duncan Roe
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
I.e. when calling list_del() and list_add().
We have a list of struct ifindex_node but the fns want struct list_head
which is at the head of struct ifindex_node.
Also audit counter loops to count downwards (c/w 0 is faster).
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
src/iftable.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/iftable.c b/src/iftable.c
index 1a53893..7eada24 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -192,7 +192,7 @@ struct nlif_handle *nlif_open(void)
if (h == NULL)
goto err;
- for (i=0; i < NUM_NLIF_ENTRIES; i++)
+ for (i = NUM_NLIF_ENTRIES - 1; i>= 0; i--)
INIT_LIST_HEAD(&h->ifindex_hash[i]);
h->nl = mnl_socket_open(NETLINK_ROUTE);
@@ -226,9 +226,9 @@ void nlif_close(struct nlif_handle *h)
mnl_socket_close(h->nl);
- for (i=0; i < NUM_NLIF_ENTRIES; i++) {
+ for (i = NUM_NLIF_ENTRIES - 1; i>= 0; i--) {
list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
- list_del(&this->head);
+ list_del((struct list_head *)this);
free(this);
}
}
@@ -359,7 +359,7 @@ static int data_cb(const struct nlmsghdr *nlh, void *data)
this->index = ifi_msg->ifi_index;
this->type = ifi_msg->ifi_type;
this->flags = ifi_msg->ifi_flags;
- list_add(&this->head, &h->ifindex_hash[hash]);
+ list_add((struct list_head *)this, &h->ifindex_hash[hash]);
found:
mnl_attr_for_each(attr, nlh, sizeof(*ifi_msg)) {
/* All we want is the interface name */
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread* [PATCH libnetfilter_queue 32/32] whitespace: Fix more checkpatch errors & warnings
2024-02-14 10:47 ` Pablo Neira Ayuso
` (32 preceding siblings ...)
2024-03-15 7:33 ` [PATCH libnetfilter_queue 31/32] src: Use a cast in place of convoluted construct Duncan Roe
@ 2024-03-15 7:33 ` Duncan Roe
33 siblings, 0 replies; 39+ messages in thread
From: Duncan Roe @ 2024-03-15 7:33 UTC (permalink / raw)
To: pablo; +Cc: netfilter-devel
Fix errors & warnings in the copies of linux_list.h & iftable.c.
One possible false +ve:
typeof(((type *)0)->member) *__mptr = (ptr);
gets "need consistent spacing around '*' (ctx:WxV)"
Signed-off-by: Duncan Roe <duncan_roe@optusnet.com.au>
---
include/libnetfilter_queue/linux_list.h | 10 +++++-----
src/iftable.c | 10 +++++-----
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/include/libnetfilter_queue/linux_list.h b/include/libnetfilter_queue/linux_list.h
index f687d20..738d834 100644
--- a/include/libnetfilter_queue/linux_list.h
+++ b/include/libnetfilter_queue/linux_list.h
@@ -51,8 +51,8 @@
*
*/
#define container_of(ptr, type, member) ({ \
- typeof( ((type *)0)->member ) *__mptr = (ptr); \
- (type *)( (char *)__mptr - offsetof(type,member) );})
+ typeof(((type *)0)->member) *__mptr = (ptr); \
+ (type *)((char *)__mptr - offsetof(type, member)); })
/*
* Circular doubly linked list implementation.
@@ -122,7 +122,7 @@ static inline void list_add(struct list_head *new, struct list_head *head)
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
-static inline void __list_del(struct list_head * prev, struct list_head * next)
+static inline void __list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
@@ -169,7 +169,7 @@ static inline int list_empty(const struct list_head *head)
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = list_entry(pos->member.next, typeof(*pos), member)) \
/**
@@ -182,7 +182,7 @@ static inline int list_empty(const struct list_head *head)
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_entry((head)->next, typeof(*pos), member), \
n = list_entry(pos->member.next, typeof(*pos), member); \
- &pos->member != (head); \
+ &pos->member != (head); \
pos = n, n = list_entry(n->member.next, typeof(*n), member))
/**
diff --git a/src/iftable.c b/src/iftable.c
index 7eada24..322b18e 100644
--- a/src/iftable.c
+++ b/src/iftable.c
@@ -29,7 +29,7 @@
#define NUM_NLIF_BITS 4
#define NUM_NLIF_ENTRIES (1 << NUM_NLIF_BITS)
-#define NLIF_ENTRY_MASK (NUM_NLIF_ENTRIES -1)
+#define NLIF_ENTRY_MASK (NUM_NLIF_ENTRIES - 1)
static int data_cb(const struct nlmsghdr *nlh, void *data);
@@ -192,7 +192,7 @@ struct nlif_handle *nlif_open(void)
if (h == NULL)
goto err;
- for (i = NUM_NLIF_ENTRIES - 1; i>= 0; i--)
+ for (i = NUM_NLIF_ENTRIES - 1; i >= 0; i--)
INIT_LIST_HEAD(&h->ifindex_hash[i]);
h->nl = mnl_socket_open(NETLINK_ROUTE);
@@ -226,7 +226,7 @@ void nlif_close(struct nlif_handle *h)
mnl_socket_close(h->nl);
- for (i = NUM_NLIF_ENTRIES - 1; i>= 0; i--) {
+ for (i = NUM_NLIF_ENTRIES - 1; i >= 0; i--) {
list_for_each_entry_safe(this, tmp, &h->ifindex_hash[i], head) {
list_del((struct list_head *)this);
free(this);
@@ -256,7 +256,7 @@ int nlif_catch(struct nlif_handle *h)
if (!h->nl) /* The old library had this test */
return -1;
- ret = mnl_socket_recvfrom(h->nl, buf, sizeof buf);
+ ret = mnl_socket_recvfrom(h->nl, buf, sizeof(buf));
if (ret == -1)
return -1;
return mnl_cb_run(buf, ret, 0, h->portid, data_cb, h) == -1 ? -1 : 0;
@@ -303,7 +303,7 @@ int nlif_query(struct nlif_handle *h)
EXPORT_SYMBOL
int nlif_fd(struct nlif_handle *h)
{
- return h->nl? mnl_socket_get_fd(h->nl) : -1;
+ return h->nl ? mnl_socket_get_fd(h->nl) : -1;
}
/**
--
2.35.8
^ permalink raw reply related [flat|nested] 39+ messages in thread