DPDK patches and discussions
 help / color / mirror / Atom feed
From: Luca Vizzarro <Luca.Vizzarro@arm.com>
To: Dean Marx <dmarx@iol.unh.edu>,
	probb@iol.unh.edu, npratte@iol.unh.edu, yoan.picchi@foss.arm.com,
	Honnappa.Nagarahalli@arm.com, paul.szczepanek@arm.com
Cc: dev@dpdk.org
Subject: Re: [PATCH v4] dts: add flow rule dataclass to testpmd shell
Date: Thu, 14 Nov 2024 12:19:13 +0000	[thread overview]
Message-ID: <73a0df5b-feca-4fe8-95b1-d616bb2e8770@arm.com> (raw)
In-Reply-To: <20241010210631.705-1-dmarx@iol.unh.edu>

Hi Dean,

This looks fine for most of it, but some of Juraj's prior comments still 
apply. See comments in line.

On 10/10/2024 22:06, Dean Marx wrote:
> +@dataclass

I'd make this kw_only=True:

   @dataclass(kw_only=True)

this enforces the construction to include field names for the sake of 
readability. Having:

   FlowRule(0, True, "ip", "rss")

is not really as self-descriptive as:

   FlowRule(port_id=0, ingress=True, pattern="ip", actions="rss")

> +class FlowRule:
> +    """Dataclass for setting flow rule parameters."""

We should add the pattern that this is meant to represent in the class 
docstring here above, as suggested by Juraj. Also I'd change the current 
docstring to what the class is actually doing, e.g.:

   Class representation of flow rule parameters.

   This class represents the parameters of any flow rule as per the
   following pattern:

     [group {group_id}] [priority {level}] [ingress] [egress]
     [user_id {user_id}] pattern {item} [/ {item} [...]] / end
     actions {action} [/ {action} [...]] / end

Mind that the pattern above is taking from the testpmd guide[1], I 
excluded the bits that you haven't implemented.

> +
> +    #:
> +    port_id: int

I would leave out the `port_id` here, if we wanted to apply the same 
flow rule to multiple ports, this would complicate things. This should 
belong under the `flow_create` function.

> +    #:
> +    ingress: bool
> +    #:
> +    pattern: str

The rule pattern above also suggests that this...

> +    #:
> +    actions: str

...and this can be `list[str]`, and then joined in __str__:

   "/ ".join(self.actions)

> +
> +    #:
> +    group_id: int | None = None
> +    #:
> +    priority_level: int | None = None
> +    #:
> +    user_id: int | None = None

Perhaps, order the fields in the way they are represented in the flow 
rule. So this should go before actions and patterns.

> +
> +    def __str__(self) -> str:
> +        """Returns the string representation of a flow_func instance.

s/flow_func/FlowRule, or just don't mention it at all as it's implicit:

   Returns the string representation of this instance.

> +
> +        In this case, a properly formatted flow create command that can be sent to testpmd.

I reckon that `flow create` should be created by the flow create command 
function. Let's keep this to just produce the parameters settings...

> +        """
> +        ret = f"flow create {self.port_id} "

...and make this an empty string:

   ret = ""

> +        if self.group_id is not None:
> +            ret += f"group {self.group_id} "
> +        if self.priority_level is not None:
> +            ret += f"priority {self.priority_level} "
> +        ret += "ingress " if self.ingress else "egress "

The pattern above suggests we can have flow rules for both ingress and 
egress. Therefore I'd have a field for egress as well, or we want to get 
fancy, create a FlowRuleDirection enum.Flag, so that we can do:

   FlowRule(direction=FlowRuleDirection.INGRESS|EGRESS, ...)

Or to not overcomplicate we can just rely on mypy's checking:

   class FlowRule:
     ...
     direction: Literal["ingress", "egress", "both"]

   FlowRule(direction="ingress")

> +        if self.user_id is not None:
> +            ret += f"user_id {self.user_id} "
> +        ret += f"pattern {self.pattern} / end "
> +        ret += f"actions {self.actions} / end"
> +        return ret
> +
> +
>   class PacketOffloadFlag(Flag):
>       """Flag representing the Packet Offload Features Flags in DPDK.
>   
> @@ -1717,6 +1755,25 @@ def show_port_stats(self, port_id: int) -> TestPmdPortStats:
>   
>           return TestPmdPortStats.parse(output)
>   
> +    def flow_create(self, flow_rule: FlowRule, verify: bool = True) -> None:

As mentioned, let's put the port_id here.

> +        """Creates a flow rule in the testpmd session.
> +
> +        Args:
> +            flow_rule: FlowRule object used for creating testpmd flow rule.

Reference to the class missing:

   :class:`FlowRule` object

> +            verify: If :data:`True`, the output of the command is scanned
> +            to ensure the flow rule was created successfully.
> +
> +        Raises:
> +            InteractiveCommandExecutionError: If flow rule is invalid.
> +        """
> +        flow_output = self.send_command(str(flow_rule))

And this can be come:

   flow_output = self.send_command(f"flow create {port_id} {flow_rule}")

> +        if verify:
> +            if "created" not in flow_output:
> +                self._logger.debug(f"Failed to create flow rule:\n{flow_output}")
> +                raise InteractiveCommandExecutionError(
> +                    f"Failed to create flow rule:\n{flow_output}"
> +                )
> +
>       @requires_stopped_ports
>       def set_port_mtu(self, port_id: int, mtu: int, verify: bool = True) -> None:
>           """Change the MTU of a port using testpmd.

Finally, I also agree with Juraj's comment to make a structure for 
actions and patterns. But that's overkill for now. We can just deal with 
it if we have to deal with their complexity in the future.

But like also Juraj's said, I'd introduce a flow_delete function with 
flow_create. You should make it so flow_create returns the flow rule ID, 
so that we can manipulate it, and use it with flow_delete.

Last thing, I'd split the FlowRule class and the flow_(create|delete) 
commands in two commits.

I hope my comments are helpful and make sense. Also mind that I don't 
have a thorough knowledge of flows, I've just had a crash course for the 
purpose of this review. So I may not understand everything and could be 
wrong, in which case please correct me.

Best,
Luca

[1] 
https://doc.dpdk.org/guides/testpmd_app_ug/testpmd_funcs.html#flow-syntax

      reply	other threads:[~2024-11-14 12:19 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-07-26 14:22 [PATCH v1] " Dean Marx
2024-08-02 20:49 ` Jeremy Spewock
2024-08-06 16:42 ` [PATCH v2] " Dean Marx
2024-08-13 14:39   ` [PATCH v3] " Dean Marx
2024-08-13 14:41   ` Dean Marx
2024-09-25  8:17     ` Juraj Linkeš
2024-10-10 21:06     ` [PATCH v4] " Dean Marx
2024-11-14 12:19       ` Luca Vizzarro [this message]

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=73a0df5b-feca-4fe8-95b1-d616bb2e8770@arm.com \
    --to=luca.vizzarro@arm.com \
    --cc=Honnappa.Nagarahalli@arm.com \
    --cc=dev@dpdk.org \
    --cc=dmarx@iol.unh.edu \
    --cc=npratte@iol.unh.edu \
    --cc=paul.szczepanek@arm.com \
    --cc=probb@iol.unh.edu \
    --cc=yoan.picchi@foss.arm.com \
    /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.
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 NNTP newsgroup(s).