public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
From: Stefano Brivio <sbrivio@redhat.com>
To: David Gibson <david@gibson.dropbear.id.au>
Cc: passt-dev@passt.top
Subject: Re: [PATCH v4 01/16] flow: Common data structures for tracking flow addresses
Date: Mon, 13 May 2024 20:07:00 +0200	[thread overview]
Message-ID: <20240513200700.07fb2518@elisabeth> (raw)
In-Reply-To: <20240503011135.2924437-2-david@gibson.dropbear.id.au>

Minor comments/nits only:

On Fri,  3 May 2024 11:11:20 +1000
David Gibson <david@gibson.dropbear.id.au> wrote:

> Handling of each protocol needs some degree of tracking of the addresses
> and ports at the end of each connection or flow.  Sometimes that's explicit
> (as in the guest visible addresses for TCP connections), sometimes implicit
> (the bound and connected addresses of sockets).
> 
> To allow more general and robust handling, and more consistency across
> protocols we want to uniformly track the address and port at each end of
> the connection.  Furthermore, because we allow port remapping, and we
> sometimes need to apply NAT, the addresses and ports can be different as
> seen by the guest/namespace and as by the host.
> 
> Introduce 'struct flowside' to keep track of common information
> related to one side of each flow.  For now that's the addresses, ports
> and the pif id.  Store two of these in the common fields of a flow to
> track that information for both sides.  For now we just introduce the
> structure itself, helpers to populate it, and logging of the contents
> when starting and ending flows.  Later patches will actually put
> something useful there.
> 
> Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
> ---
>  flow.c     | 28 ++++++++++++++++++--
>  flow.h     | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  passt.h    |  3 +++
>  pif.h      |  1 -
>  tcp_conn.h |  1 -
>  5 files changed, 104 insertions(+), 4 deletions(-)
> 
> diff --git a/flow.c b/flow.c
> index 80dd269..02d6008 100644
> --- a/flow.c
> +++ b/flow.c
> @@ -51,10 +51,11 @@ static_assert(ARRAY_SIZE(flow_proto) == FLOW_NUM_TYPES,
>   *
>   *    ALLOC - A tentatively allocated entry
>   *        Operations:
> + *            - Common flow fields other than type may be accessed
>   *            - flow_alloc_cancel() returns the entry to FREE state
>   *            - FLOW_START() set the entry's type and moves to START state
>   *        Caveats:
> - *            - It's not safe to write fields in the flow entry
> + *            - It's not safe to write flow type specific fields in the entry
>   *            - It's not safe to allocate further entries with flow_alloc()
>   *            - It's not safe to return to the main epoll loop (use FLOW_START()
>   *              to move to START state before doing so)
> @@ -62,6 +63,7 @@ static_assert(ARRAY_SIZE(flow_proto) == FLOW_NUM_TYPES,
>   *
>   *    START - An entry being prepared by flow type specific code
>   *        Operations:
> + *            - Common flow fields other than type may be accessed
>   *            - Flow type specific fields may be accessed
>   *            - flow_*() logging functions
>   *            - flow_alloc_cancel() returns the entry to FREE state
> @@ -168,9 +170,21 @@ void flow_log_(const struct flow_common *f, int pri, const char *fmt, ...)
>  union flow *flow_start(union flow *flow, enum flow_type type,
>  		       unsigned iniside)
>  {
> -	(void)iniside;
> +	char ebuf[INANY_ADDRSTRLEN], fbuf[INANY_ADDRSTRLEN];
> +	const struct flowside *a = &flow->f.side[iniside];

As long as iniside is used as a binary value (I guess it's unsigned
because you have in mind that it could eventually be extended, right?),
I think '!!iniside' would be clearer and perhaps more robust here.

> +	const struct flowside *b = &flow->f.side[!iniside];
> +
>  	flow->f.type = type;
>  	flow_dbg(flow, "START %s", flow_type_str[flow->f.type]);
> +	flow_dbg(flow, "  from side %u (%s): [%s]:%hu -> [%s]:%hu",
> +		 iniside, pif_name(a->pif),
> +		 inany_ntop(&a->eaddr, ebuf, sizeof(ebuf)), a->eport,
> +		 inany_ntop(&a->faddr, fbuf, sizeof(fbuf)), a->fport);
> +	flow_dbg(flow, "    to side %u (%s): [%s]:%hu -> [%s]:%hu",
> +		 !iniside, pif_name(b->pif),
> +		 inany_ntop(&b->faddr, fbuf, sizeof(fbuf)), b->fport,
> +		 inany_ntop(&b->eaddr, ebuf, sizeof(ebuf)), b->eport);
> +
>  	return flow;
>  }
>  
> @@ -180,10 +194,20 @@ union flow *flow_start(union flow *flow, enum flow_type type,
>   */
>  static void flow_end(union flow *flow)
>  {
> +	char ebuf[INANY_ADDRSTRLEN], fbuf[INANY_ADDRSTRLEN];
> +	const struct flowside *a = &flow->f.side[0];
> +	const struct flowside *b = &flow->f.side[1];
> +
>  	if (flow->f.type == FLOW_TYPE_NONE)
>  		return; /* Nothing to do */
>  
>  	flow_dbg(flow, "END %s", flow_type_str[flow->f.type]);
> +	flow_dbg(flow, "  side 0 (%s): [%s]:%hu <-> [%s]:%hu", pif_name(a->pif),
> +		 inany_ntop(&a->faddr, fbuf, sizeof(fbuf)), a->fport,
> +		 inany_ntop(&a->eaddr, ebuf, sizeof(ebuf)), a->eport);
> +	flow_dbg(flow, "  side 1 (%s): [%s]:%hu <-> [%s]:%hu", pif_name(b->pif),
> +		 inany_ntop(&b->faddr, fbuf, sizeof(fbuf)), b->fport,
> +		 inany_ntop(&b->eaddr, ebuf, sizeof(ebuf)), b->eport);
>  	flow->f.type = FLOW_TYPE_NONE;
>  }
>  
> diff --git a/flow.h b/flow.h
> index c943c44..f7fb537 100644
> --- a/flow.h
> +++ b/flow.h
> @@ -35,11 +35,86 @@ extern const uint8_t flow_proto[];
>  #define FLOW_PROTO(f)				\
>  	((f)->type < FLOW_NUM_TYPES ? flow_proto[(f)->type] : 0)
>  
> +/**
> + * struct flowside - Common information for one side of a flow
> + * @eaddr:	Endpoint address (remote address from passt's PoV)
> + * @faddr:	Forwarding address (local address from passt's PoV)
> + * @eport:	Endpoint port
> + * @fport:	Forwarding port
> + * @pif:	pif ID on which this side of the flow exists
> + */
> +struct flowside {
> +	union inany_addr	faddr;
> +	union inany_addr	eaddr;
> +	in_port_t		fport;
> +	in_port_t		eport;
> +	uint8_t			pif;
> +};
> +static_assert(_Alignof(struct flowside) == _Alignof(uint32_t),
> +	      "Unexpected alignment for struct flowside");

I'm too thick to understand the reason behind this assert.

> +
> +/** flowside_from_inany - Initialize flowside from inany addresses

flowside_from_inany(), it's a function.

> + * @fside:	flowside to initialize
> + * @pif:	pif id of this flowside
> + * @faddr:	Forwarding address (inany)
> + * @fport:	Forwarding port
> + * @eaddr:	Endpoint address (inany)
> + * @eport:	Endpoint port
> + */
> +/* cppcheck-suppress unusedFunction */
> +static inline void flowside_from_inany(struct flowside *fside, uint8_t pif,
> +				const union inany_addr *faddr, in_port_t fport,
> +				const union inany_addr *eaddr, in_port_t eport)
> +{
> +	fside->pif = pif;
> +	fside->faddr = *faddr;
> +	fside->eaddr = *eaddr;
> +	fside->fport = fport;
> +	fside->eport = eport;
> +}
> +
> +/** flowside_from_af - Initialize flowside from addresses

flowside_from_af()

> + * @fside:	flowside to initialize
> + * @pif:	pif id of this flowside
> + * @af:		Address family (AF_INET or AF_INET6)
> + * @faddr:	Forwarding address (pointer to in_addr or in6_addr, or NULL)
> + * @fport:	Forwarding port
> + * @eaddr:	Endpoint address (pointer to in_addr or in6_addr, or NULL)
> + * @eport:	Endpoint port
> + *
> + * If NULL is given for either address, the appropriate unspecified/any address

s/any/wildcard/ makes it a bit easier to follow, I guess.

> + * for the address family is substituted.
> + */
> +/* cppcheck-suppress unusedFunction */
> +static inline void flowside_from_af(struct flowside *fside,
> +				    uint8_t pif, sa_family_t af,
> +				    const void *faddr, in_port_t fport,
> +				    const void *eaddr, in_port_t eport)
> +{
> +	const union inany_addr *any = af == AF_INET ? &inany_any4 : &inany_any6;
> +
> +	fside->pif = pif;
> +	if (faddr)
> +		inany_from_af(&fside->faddr, af, faddr);
> +	else
> +		fside->faddr = *any;
> +	if (eaddr)
> +		inany_from_af(&fside->eaddr, af, eaddr);
> +	else
> +		fside->eaddr = *any;
> +	fside->fport = fport;
> +	fside->eport = eport;
> +}
> +
> +#define SIDES			2
> +
>  /**
>   * struct flow_common - Common fields for packet flows
> + * @side[]:	Information for each side of the flow
>   * @type:	Type of packet flow
>   */
>  struct flow_common {
> +	struct flowside	side[SIDES];
>  	uint8_t		type;
>  };
>  
> diff --git a/passt.h b/passt.h
> index bc58d64..3db0b8e 100644
> --- a/passt.h
> +++ b/passt.h
> @@ -17,6 +17,9 @@ union epoll_ref;
>  
>  #include "pif.h"
>  #include "packet.h"
> +#include "siphash.h"
> +#include "ip.h"
> +#include "inany.h"
>  #include "flow.h"
>  #include "icmp.h"
>  #include "fwd.h"
> diff --git a/pif.h b/pif.h
> index bd52936..ca85b34 100644
> --- a/pif.h
> +++ b/pif.h
> @@ -38,7 +38,6 @@ static inline const char *pif_type(enum pif_type pt)
>  		return "?";
>  }
>  
> -/* cppcheck-suppress unusedFunction */
>  static inline const char *pif_name(uint8_t pif)
>  {
>  	return pif_type(pif);
> diff --git a/tcp_conn.h b/tcp_conn.h
> index d280b22..1a07dd5 100644
> --- a/tcp_conn.h
> +++ b/tcp_conn.h
> @@ -106,7 +106,6 @@ struct tcp_tap_conn {
>  	uint32_t	seq_init_from_tap;
>  };
>  
> -#define SIDES			2
>  /**
>   * struct tcp_splice_conn - Descriptor for a spliced TCP connection
>   * @f:			Generic flow information

-- 
Stefano


  reply	other threads:[~2024-05-13 18:14 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-05-03  1:11 [PATCH v4 00/16] RFC: Unified flow table David Gibson
2024-05-03  1:11 ` [PATCH v4 01/16] flow: Common data structures for tracking flow addresses David Gibson
2024-05-13 18:07   ` Stefano Brivio [this message]
2024-05-14  0:11     ` David Gibson
2024-05-03  1:11 ` [PATCH v4 02/16] tcp: Maintain flowside information for "tap" connections David Gibson
2024-05-13 18:07   ` Stefano Brivio
2024-05-14  0:15     ` David Gibson
2024-05-03  1:11 ` [PATCH v4 03/16] tcp_splice: Maintain flowside information for spliced connections David Gibson
2024-05-03  1:11 ` [PATCH v4 04/16] tcp: Obtain guest address from flowside David Gibson
2024-05-13 18:07   ` Stefano Brivio
2024-05-14  0:18     ` David Gibson
2024-05-03  1:11 ` [PATCH v4 05/16] tcp: Simplify endpoint validation using flowside information David Gibson
2024-05-03  1:11 ` [PATCH v4 06/16] tcp, tcp_splice: Construct sockaddrs for connect() from flowside David Gibson
2024-05-03  1:11 ` [PATCH v4 07/16] tcp_splice: Eliminate SPLICE_V6 flag David Gibson
2024-05-03  1:11 ` [PATCH v4 08/16] tcp, flow: Replace TCP specific hash function with general flow hash David Gibson
2024-05-03  1:11 ` [PATCH v4 09/16] flow, tcp: Generalise TCP hash table to general flow hash table David Gibson
2024-05-03  1:11 ` [PATCH v4 10/16] tcp: Re-use flow hash for initial sequence number generation David Gibson
2024-05-03  1:11 ` [PATCH v4 11/16] icmp: Populate flowside information David Gibson
2024-05-03  1:11 ` [PATCH v4 12/16] icmp: Use flowsides as the source of truth wherever possible David Gibson
2024-05-03  1:11 ` [PATCH v4 13/16] icmp: Look up ping flows using flow hash David Gibson
2024-05-03  1:11 ` [PATCH v4 14/16] icmp: Eliminate icmp_id_map David Gibson
2024-05-03  1:11 ` [PATCH v4 15/16] flow, tcp: flow based NAT and port forwarding for TCP David Gibson
2024-05-03  1:11 ` [PATCH v4 16/16] flow, icmp: Use general flow forwarding rules for ICMP David Gibson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240513200700.07fb2518@elisabeth \
    --to=sbrivio@redhat.com \
    --cc=david@gibson.dropbear.id.au \
    --cc=passt-dev@passt.top \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).