Add the corresponding ODP actions and tests in this patch
before implementing SRv6 tunnel in userspace datapath.

Signed-off-by: Nobuhiro MIKI <[email protected]>
---
 include/linux/openvswitch.h  |  1 +
 lib/odp-util.c               | 56 ++++++++++++++++++++++++++++++++++++
 lib/packets.h                | 11 +++++++
 python/ovs/flow/odp.py       |  8 ++++++
 python/ovs/tests/test_odp.py | 16 +++++++++++
 tests/odp.at                 |  1 +
 6 files changed, 93 insertions(+)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index bc8f74991849..e305c331516b 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -254,6 +254,7 @@ enum ovs_vport_type {
        OVS_VPORT_TYPE_IP6GRE = 109,
        OVS_VPORT_TYPE_GTPU = 110,
        OVS_VPORT_TYPE_BAREUDP = 111,  /* Bareudp tunnel. */
+       OVS_VPORT_TYPE_SRV6 = 112,  /* SRv6 tunnel. */
        __OVS_VPORT_TYPE_MAX
 };
 
diff --git a/lib/odp-util.c b/lib/odp-util.c
index dbd4554d0626..75f4d5242183 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -714,6 +714,24 @@ format_odp_tnl_push_header(struct ds *ds, struct 
ovs_action_push_tnl *data)
             ds_put_char(ds, ')');
         }
 
+        ds_put_char(ds, ')');
+    } else if (data->tnl_type == OVS_VPORT_TYPE_SRV6) {
+        const struct srv6_base_hdr *srh;
+        struct in6_addr *segs;
+        int nr_segs;
+        int i;
+
+        srh = (const struct srv6_base_hdr *) l4;
+        segs = ALIGNED_CAST(struct in6_addr *, srh + 1);
+        nr_segs = srh->last_entry + 1;
+
+        ds_put_format(ds, "srv6(");
+        ds_put_format(ds, "segments_left=%d", srh->rt_hdr.segments_left);
+        ds_put_format(ds, ",segs=");
+        for (i = 0; i < nr_segs; i++) {
+            ds_put_format(ds, i > 0 ? "," : "");
+            ipv6_format_addr(&segs[nr_segs - i - 1], ds);
+        }
         ds_put_char(ds, ')');
     } else if (data->tnl_type == OVS_VPORT_TYPE_GRE ||
                data->tnl_type == OVS_VPORT_TYPE_IP6GRE) {
@@ -1534,6 +1552,7 @@ ovs_parse_tnl_push(const char *s, struct 
ovs_action_push_tnl *data)
     uint8_t hwid, dir;
     uint32_t teid;
     uint8_t gtpu_flags, gtpu_msgtype;
+    uint8_t segments_left;
 
     if (!ovs_scan_len(s, &n, "tnl_push(tnl_port(%"SCNi32"),", 
&data->tnl_port)) {
         return -EINVAL;
@@ -1775,6 +1794,43 @@ ovs_parse_tnl_push(const char *s, struct 
ovs_action_push_tnl *data)
         tnl_type = OVS_VPORT_TYPE_GTPU;
         header_len = sizeof *eth + ip_len +
                      sizeof *udp + sizeof *gtph;
+    } else if (ovs_scan_len(s, &n, "srv6(segments_left=%"SCNu8,
+                            &segments_left)) {
+        struct srv6_base_hdr *srh = (struct srv6_base_hdr *) (ip6 + 1);
+        uint8_t n_segs = segments_left + 1;
+        char seg_s[IPV6_SCAN_LEN + 1];
+        struct in6_addr *segs;
+        struct in6_addr seg;
+
+        ip6->ip6_nxt = IPPROTO_ROUTING;
+
+        srh->rt_hdr.type = IPV6_SRCRT_TYPE_4;
+        srh->rt_hdr.segments_left = segments_left;
+        srh->rt_hdr.hdrlen = 2 * n_segs;
+        srh->last_entry = n_segs - 1;
+
+        tnl_type = OVS_VPORT_TYPE_SRV6;
+        header_len = sizeof *eth + ip_len +
+                     sizeof *srh + 8 * srh->rt_hdr.hdrlen;
+
+        /* Parse segment list */
+        if (!ovs_scan_len(s, &n, ",segs="IPV6_SCAN_FMT, seg_s)
+            || inet_pton(AF_INET6, seg_s, &seg) != 1) {
+            return -EINVAL;
+        }
+
+        segs = ALIGNED_CAST(struct in6_addr *, srh + 1);
+        segs += n_segs - 1;
+        memcpy(segs--, &seg, sizeof(struct in6_addr));
+
+        while (ovs_scan_len(s, &n, ","IPV6_SCAN_FMT, seg_s)
+               && inet_pton(AF_INET6, seg_s, &seg) == 1) {
+            memcpy(segs--, &seg, sizeof(struct in_addr));
+        }
+
+        if (!ovs_scan_len(s, &n, "))")) {
+            return -EINVAL;
+        }
     } else {
         return -EINVAL;
     }
diff --git a/lib/packets.h b/lib/packets.h
index abff24db016e..312e849f9f26 100644
--- a/lib/packets.h
+++ b/lib/packets.h
@@ -1527,6 +1527,17 @@ BUILD_ASSERT_DECL(sizeof(struct vxlanhdr) == 8);
 #define VXLAN_F_GPE  0x4000
 #define VXLAN_HF_GPE 0x04000000
 
+/* SRv6 protocol header */
+#define IPV6_SRCRT_TYPE_4 4
+#define SRV6_BASE_HDR_LEN 8
+struct srv6_base_hdr {
+    struct ip6_rt_hdr rt_hdr;
+    uint8_t last_entry;
+    uint8_t flags;
+    ovs_be16 tag;
+};
+BUILD_ASSERT_DECL(sizeof(struct srv6_base_hdr) == SRV6_BASE_HDR_LEN);
+
 /* Input values for PACKET_TYPE macros have to be in host byte order.
  * The _BE postfix indicates result is in network byte order. Otherwise result
  * is in host byte order. */
diff --git a/python/ovs/flow/odp.py b/python/ovs/flow/odp.py
index db63afc8d64d..88aee17fb2a4 100644
--- a/python/ovs/flow/odp.py
+++ b/python/ovs/flow/odp.py
@@ -474,6 +474,14 @@ class ODPFlow(Flow):
                                             }
                                         )
                                     ),
+                                    "srv6": nested_kv_decoder(
+                                        KVDecoders(
+                                            {
+                                                "segments_left": decode_int,
+                                                "segs": decode_default,
+                                            }
+                                        )
+                                    ),
                                 }
                             )
                         ),
diff --git a/python/ovs/tests/test_odp.py b/python/ovs/tests/test_odp.py
index f8017ca8a169..ce02d3b61998 100644
--- a/python/ovs/tests/test_odp.py
+++ b/python/ovs/tests/test_odp.py
@@ -452,6 +452,22 @@ def test_odp_fields(input_string, expected):
                 ),
             ],
         ),
+        (
+            
"actions:tnl_push(header(srv6(segments_left=0,segs=2001:cafe::92)))",  # noqa: 
E501
+            [
+                KeyValue(
+                    "tnl_push",
+                    {
+                        "header": {
+                            "srv6": {
+                                "segments_left": 0,
+                                "segs": "2001:cafe::92",
+                            }
+                        }
+                    },
+                ),
+            ],
+        ),
         (
             "actions:clone(1),clone(clone(push_vlan(vid=12,pcp=0),2),1)",
             [
diff --git a/tests/odp.at b/tests/odp.at
index 26cda2967239..dccb781a4e73 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -342,6 +342,7 @@ 
tnl_push(tnl_port(6),header(size=70,type=4,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:1
 
tnl_push(tnl_port(6),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0x0),geneve(oam,vni=0x1c7)),out_port(1))
 
tnl_push(tnl_port(6),header(size=78,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0x0),geneve(crit,vni=0x1c7,options({class=0xffff,type=0x80,len=4,0xa}))),out_port(1))
 
tnl_push(tnl_port(6),header(size=70,type=5,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=17,tclass=0x0,hlimit=64),udp(src=0,dst=6081,csum=0xffff),geneve(vni=0x1c7)),out_port(1))
+tnl_push(tnl_port(6),header(size=78,type=112,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=43,tclass=0x0,hlimit=64),srv6(segments_left=0,segs=2001:cafe::92)),out_port(1))
 ct
 ct(commit)
 ct(commit,zone=5)
-- 
2.31.1

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to