diff mbox series

[RFC,net-next,1/7] selftests: openvswitch: Support explicit tunnel port creation.

Message ID 20240613181333.984810-2-aconole@redhat.com
State Superseded
Headers show
Series selftests: net: Switch pmtu.sh to use the internal ovs script. | expand

Commit Message

Aaron Conole June 13, 2024, 6:13 p.m. UTC
The OVS module can operate in conjunction with various types of
tunnel ports.  These are created as either explicit tunnel vport
types, OR by creating a tunnel interface which acts as an anchor
for the lightweight tunnel support.

This patch adds the ability to add tunnel ports to an OVS
datapath for testing various scenarios with tunnel ports.  With
this addition, the vswitch "plumbing" will at least be able to
push packets around using the tunnel vports.  Future patches
will add support for setting required tunnel metadata for lwts
in the datapath.  The end goal will be to push packets via these
tunnels, and will be used in an upcoming commit for testing the
path MTU.

Signed-off-by: Aaron Conole <aconole@redhat.com>
---
 .../selftests/net/openvswitch/ovs-dpctl.py    | 81 +++++++++++++++++--
 1 file changed, 75 insertions(+), 6 deletions(-)

Comments

Simon Horman June 16, 2024, 4:25 p.m. UTC | #1
On Thu, Jun 13, 2024 at 02:13:27PM -0400, Aaron Conole wrote:
> The OVS module can operate in conjunction with various types of
> tunnel ports.  These are created as either explicit tunnel vport
> types, OR by creating a tunnel interface which acts as an anchor
> for the lightweight tunnel support.
> 
> This patch adds the ability to add tunnel ports to an OVS
> datapath for testing various scenarios with tunnel ports.  With
> this addition, the vswitch "plumbing" will at least be able to
> push packets around using the tunnel vports.  Future patches
> will add support for setting required tunnel metadata for lwts
> in the datapath.  The end goal will be to push packets via these
> tunnels, and will be used in an upcoming commit for testing the
> path MTU.
> 
> Signed-off-by: Aaron Conole <aconole@redhat.com>

...

> @@ -1702,12 +1711,43 @@ class OvsVport(GenericNetlinkSocket):
>          msg["dpifindex"] = dpindex
>          port_type = OvsVport.str_to_type(ptype)
>  
> -        msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
>          msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
>          msg["attrs"].append(
>              ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
>          )
>  
> +        TUNNEL_DEFAULTS = [("geneve", 6081),
> +                           ("vxlan", 4798)]

Hi Aaron,

It is corrected as part of another patch in this series, but
the correct port for vxlan is 4789 (i.e. 89 rather than 98).

With that fixed, feel free to add:

Reviewed-by: Simon Horman <horms@kernel.org>
Tested-by: Simon Horman <horms@kernel.org>

..
Aaron Conole June 17, 2024, 5:03 p.m. UTC | #2
Simon Horman <horms@kernel.org> writes:

> On Thu, Jun 13, 2024 at 02:13:27PM -0400, Aaron Conole wrote:
>> The OVS module can operate in conjunction with various types of
>> tunnel ports.  These are created as either explicit tunnel vport
>> types, OR by creating a tunnel interface which acts as an anchor
>> for the lightweight tunnel support.
>> 
>> This patch adds the ability to add tunnel ports to an OVS
>> datapath for testing various scenarios with tunnel ports.  With
>> this addition, the vswitch "plumbing" will at least be able to
>> push packets around using the tunnel vports.  Future patches
>> will add support for setting required tunnel metadata for lwts
>> in the datapath.  The end goal will be to push packets via these
>> tunnels, and will be used in an upcoming commit for testing the
>> path MTU.
>> 
>> Signed-off-by: Aaron Conole <aconole@redhat.com>
>
> ...
>
>> @@ -1702,12 +1711,43 @@ class OvsVport(GenericNetlinkSocket):
>>          msg["dpifindex"] = dpindex
>>          port_type = OvsVport.str_to_type(ptype)
>>  
>> -        msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
>>          msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
>>          msg["attrs"].append(
>>              ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
>>          )
>>  
>> +        TUNNEL_DEFAULTS = [("geneve", 6081),
>> +                           ("vxlan", 4798)]
>
> Hi Aaron,
>
> It is corrected as part of another patch in this series, but
> the correct port for vxlan is 4789 (i.e. 89 rather than 98).
>
> With that fixed, feel free to add:

Thanks Simon!  Done.

> Reviewed-by: Simon Horman <horms@kernel.org>
> Tested-by: Simon Horman <horms@kernel.org>
>
> ..
diff mbox series

Patch

diff --git a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
index 1dd057afd3fb..56f6bd162d3e 100644
--- a/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
+++ b/tools/testing/selftests/net/openvswitch/ovs-dpctl.py
@@ -10,6 +10,7 @@  import ipaddress
 import logging
 import multiprocessing
 import re
+import socket
 import struct
 import sys
 import time
@@ -29,6 +30,7 @@  try:
     from pyroute2.netlink.exceptions import NetlinkError
     from pyroute2.netlink.generic import GenericNetlinkSocket
     import pyroute2
+    import pyroute2.iproute
 
 except ModuleNotFoundError:
     print("Need to install the python pyroute2 package >= 0.6.")
@@ -1617,7 +1619,7 @@  class OvsVport(GenericNetlinkSocket):
             ("OVS_VPORT_ATTR_PORT_NO", "uint32"),
             ("OVS_VPORT_ATTR_TYPE", "uint32"),
             ("OVS_VPORT_ATTR_NAME", "asciiz"),
-            ("OVS_VPORT_ATTR_OPTIONS", "none"),
+            ("OVS_VPORT_ATTR_OPTIONS", "vportopts"),
             ("OVS_VPORT_ATTR_UPCALL_PID", "array(uint32)"),
             ("OVS_VPORT_ATTR_STATS", "vportstats"),
             ("OVS_VPORT_ATTR_PAD", "none"),
@@ -1625,6 +1627,13 @@  class OvsVport(GenericNetlinkSocket):
             ("OVS_VPORT_ATTR_NETNSID", "uint32"),
         )
 
+        class vportopts(nla):
+            nla_map = (
+                ("OVS_TUNNEL_ATTR_UNSPEC", "none"),
+                ("OVS_TUNNEL_ATTR_DST_PORT", "uint16"),
+                ("OVS_TUNNEL_ATTR_EXTENSION", "none"),
+            )
+
         class vportstats(nla):
             fields = (
                 ("rx_packets", "=Q"),
@@ -1693,7 +1702,7 @@  class OvsVport(GenericNetlinkSocket):
                 raise ne
         return reply
 
-    def attach(self, dpindex, vport_ifname, ptype):
+    def attach(self, dpindex, vport_ifname, ptype, dport, lwt):
         msg = OvsVport.ovs_vport_msg()
 
         msg["cmd"] = OVS_VPORT_CMD_NEW
@@ -1702,12 +1711,43 @@  class OvsVport(GenericNetlinkSocket):
         msg["dpifindex"] = dpindex
         port_type = OvsVport.str_to_type(ptype)
 
-        msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
         msg["attrs"].append(["OVS_VPORT_ATTR_NAME", vport_ifname])
         msg["attrs"].append(
             ["OVS_VPORT_ATTR_UPCALL_PID", [self.upcall_packet.epid]]
         )
 
+        TUNNEL_DEFAULTS = [("geneve", 6081),
+                           ("vxlan", 4798)]
+
+        for tnl in TUNNEL_DEFAULTS:
+            if ptype == tnl[0]:
+                if not dport:
+                    dport = tnl[1]
+
+                if not lwt:
+                    vportopt = OvsVport.ovs_vport_msg.vportopts()
+                    vportopt["attrs"].append(
+                        ["OVS_TUNNEL_ATTR_DST_PORT", socket.htons(dport)]
+                    )
+                    msg["attrs"].append(
+                        ["OVS_VPORT_ATTR_OPTIONS", vportopt]
+                    )
+                else:
+                    port_type = OvsVport.OVS_VPORT_TYPE_NETDEV
+                    ipr = pyroute2.iproute.IPRoute()
+
+                    if tnl[0] == "geneve":
+                        ipr.link("add", ifname=vport_ifname, kind=tnl[0],
+                                 geneve_port=dport,
+                                 geneve_collect_metadata=True,
+                                 geneve_udp_zero_csum6_rx=1)
+                    elif tnl[0] == "vxlan":
+                        ipr.link("add", ifname=vport_ifname, kind=tnl[0],
+                                 vxlan_learning=0, vxlan_collect_metadata=1,
+                                 vxlan_udp_zero_csum6_rx=1, vxlan_port=dport)
+                break
+        msg["attrs"].append(["OVS_VPORT_ATTR_TYPE", port_type])
+
         try:
             reply = self.nlm_request(
                 msg, msg_type=self.prid, msg_flags=NLM_F_REQUEST | NLM_F_ACK
@@ -2053,12 +2093,19 @@  def print_ovsdp_full(dp_lookup_rep, ifindex, ndb=NDB(), vpl=OvsVport()):
     for iface in ndb.interfaces:
         rep = vpl.info(iface.ifname, ifindex)
         if rep is not None:
+            opts = ""
+            vpo = rep.get_attr("OVS_VPORT_ATTR_OPTIONS")
+            if vpo:
+                dpo = vpo.get_attr("OVS_TUNNEL_ATTR_DST_PORT")
+                if dpo:
+                    opts += " tnl-dport:%s" % socket.ntohs(dpo)
             print(
-                "  port %d: %s (%s)"
+                "  port %d: %s (%s%s)"
                 % (
                     rep.get_attr("OVS_VPORT_ATTR_PORT_NO"),
                     rep.get_attr("OVS_VPORT_ATTR_NAME"),
                     OvsVport.type_to_str(rep.get_attr("OVS_VPORT_ATTR_TYPE")),
+                    opts,
                 )
             )
 
@@ -2120,12 +2167,30 @@  def main(argv):
         "--ptype",
         type=str,
         default="netdev",
-        choices=["netdev", "internal"],
+        choices=["netdev", "internal", "geneve", "vxlan"],
         help="Interface type (default netdev)",
     )
+    addifcmd.add_argument(
+        "-p",
+        "--dport",
+        type=int,
+        default=0,
+        help="Destination port (0 for default)"
+    )
+    addifcmd.add_argument(
+        "-l",
+        "--lwt",
+        type=bool,
+        default=True,
+        help="Use LWT infrastructure instead of vport (default true)."
+    )
     delifcmd = subparsers.add_parser("del-if")
     delifcmd.add_argument("dpname", help="Datapath Name")
     delifcmd.add_argument("delif", help="Interface name for adding")
+    delifcmd.add_argument("-d",
+                          "--dellink",
+                          type=bool, default=False,
+                          help="Delete the link as well.")
 
     dumpflcmd = subparsers.add_parser("dump-flows")
     dumpflcmd.add_argument("dumpdp", help="Datapath Name")
@@ -2186,7 +2251,8 @@  def main(argv):
             print("DP '%s' not found." % args.dpname)
             return 1
         dpindex = rep["dpifindex"]
-        rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype)
+        rep = ovsvp.attach(rep["dpifindex"], args.addif, args.ptype,
+                           args.dport, args.lwt)
         msg = "vport '%s'" % args.addif
         if rep and rep["header"]["error"] is None:
             msg += " added."
@@ -2207,6 +2273,9 @@  def main(argv):
             msg += " removed."
         else:
             msg += " failed to remove."
+        if args.dellink:
+            ipr = pyroute2.iproute.IPRoute()
+            ipr.link("del", index=ipr.link_lookup(ifname=args.delif)[0])
     elif hasattr(args, "dumpdp"):
         rep = ovsdp.info(args.dumpdp, 0)
         if rep is None: