summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuhiro MIKI <nmiki@yahoo-corp.jp>2023-03-29 14:51:18 +0900
committerIlya Maximets <i.maximets@ovn.org>2023-03-29 22:16:04 +0200
commit7381fd440a88ae92ca3bbc6b2ee34c5d5861a061 (patch)
tree14b653a9c07c42dea92340c4d3e4c78e1c417710
parent03fc1ad78521544c7269355ec72fec8c2373b96d (diff)
downloadopenvswitch-7381fd440a88ae92ca3bbc6b2ee34c5d5861a061.tar.gz
odp: Add SRv6 tunnel actions.
This patch adds ODP actions for SRv6 and its tests. Signed-off-by: Nobuhiro MIKI <nmiki@yahoo-corp.jp> Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
-rw-r--r--lib/odp-util.c70
-rw-r--r--python/ovs/flow/odp.py8
-rw-r--r--python/ovs/tests/test_odp.py16
-rw-r--r--tests/odp.at12
-rw-r--r--tests/tunnel-push-pop-ipv6.at23
5 files changed, 127 insertions, 2 deletions
diff --git a/lib/odp-util.c b/lib/odp-util.c
index dbd4554d0..2ec889c41 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -715,6 +715,24 @@ format_odp_tnl_push_header(struct ds *ds, struct ovs_action_push_tnl *data)
}
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_format(ds, "))");
} else if (data->tnl_type == OVS_VPORT_TYPE_GRE ||
data->tnl_type == OVS_VPORT_TYPE_IP6GRE) {
const struct gre_base_hdr *greh;
@@ -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,57 @@ 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);
+ char seg_s[IPV6_SCAN_LEN + 1];
+ struct in6_addr *segs;
+ struct in6_addr seg;
+ uint8_t n_segs = 0;
+
+ if (segments_left + 1 > SRV6_MAX_SEGS) {
+ return -EINVAL;
+ }
+
+ ip6->ip6_nxt = IPPROTO_ROUTING;
+
+ srh->rt_hdr.hdrlen = 2 * (segments_left + 1);
+ srh->rt_hdr.segments_left = segments_left;
+ srh->rt_hdr.type = IPV6_SRCRT_TYPE_4;
+ srh->last_entry = segments_left;
+
+ 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(")) {
+ return -EINVAL;
+ }
+
+ segs = ALIGNED_CAST(struct in6_addr *, srh + 1);
+ segs += segments_left;
+
+ while (ovs_scan_len(s, &n, IPV6_SCAN_FMT, seg_s)
+ && inet_pton(AF_INET6, seg_s, &seg) == 1) {
+ if (n_segs == segments_left + 1) {
+ return -EINVAL;
+ }
+
+ memcpy(segs--, &seg, sizeof *segs);
+ n_segs++;
+
+ if (s[n] == ',') {
+ n++;
+ }
+ }
+
+ if (!ovs_scan_len(s, &n, ")))")) {
+ return -EINVAL;
+ }
+
+ if (n_segs != segments_left + 1) {
+ return -EINVAL;
+ }
} else {
return -EINVAL;
}
diff --git a/python/ovs/flow/odp.py b/python/ovs/flow/odp.py
index db63afc8d..88aee17fb 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 f8017ca8a..a50d3185c 100644
--- a/python/ovs/tests/test_odp.py
+++ b/python/ovs/tests/test_odp.py
@@ -453,6 +453,22 @@ def test_odp_fields(input_string, expected):
],
),
(
+ "actions:tnl_push(header(srv6(segments_left=1,segs(2001:cafe::90,2001:cafe::91))))", # noqa: E501
+ [
+ KeyValue(
+ "tnl_push",
+ {
+ "header": {
+ "srv6": {
+ "segments_left": 1,
+ "segs": "2001:cafe::90,2001:cafe::91",
+ }
+ }
+ },
+ ),
+ ],
+ ),
+ (
"actions:clone(1),clone(clone(push_vlan(vid=12,pcp=0),2),1)",
[
KeyValue("clone", [{"output": {"port": 1}}]),
diff --git a/tests/odp.at b/tests/odp.at
index 26cda2967..ba20604e4 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -342,6 +342,8 @@ 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::90))),out_port(1))
+tnl_push(tnl_port(6),header(size=110,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=2,segs(2001:cafe::90,2001:cafe::91,2001:cafe::92))),out_port(1))
ct
ct(commit)
ct(commit,zone=5)
@@ -400,8 +402,14 @@ AT_CLEANUP
AT_SETUP([OVS datapath actions parsing and formatting - invalid forms])
dnl This caused a hang in older versions.
-AT_CHECK([echo 'encap_nsh@:{@' | ovstest test-odp parse-actions
-], [0], [dnl
+AT_DATA([actions.txt], [dnl
+encap_nsh@:{@
+tnl_push(tnl_port(6),header(size=94,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=2,segs(2001:cafe::90,2001:cafe::91))),out_port(1))
+tnl_push(tnl_port(6),header(size=126,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=2,segs(2001:cafe::90,2001:cafe::91,2001:cafe::92,2001:cafe::93))),out_port(1))
+])
+AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [dnl
+odp_actions_from_string: error
+odp_actions_from_string: error
odp_actions_from_string: error
])
AT_CLEANUP
diff --git a/tests/tunnel-push-pop-ipv6.at b/tests/tunnel-push-pop-ipv6.at
index 2cf306c67..e300fe3a0 100644
--- a/tests/tunnel-push-pop-ipv6.at
+++ b/tests/tunnel-push-pop-ipv6.at
@@ -202,6 +202,8 @@ AT_CHECK([ovs-vsctl add-port int-br t2 -- set Interface t2 type=vxlan \
options:remote_ip=flow options:key=123 ofport_request=5\
-- add-port int-br t5 -- set Interface t5 type=gre \
options:remote_ip=2001:cafe::92 options:key=455 options:packet_type=legacy_l3 ofport_request=6\
+ -- add-port int-br t6 -- set Interface t6 type=srv6 \
+ options:remote_ip=2001:cafe::92 ofport_request=7\
], [0])
AT_CHECK([ovs-appctl dpif/show], [0], [dnl
@@ -216,12 +218,15 @@ dummy@ovs-dummy: hit:0 missed:0
t3 4/4789: (vxlan: csum=true, out_key=flow, remote_ip=2001:cafe::93)
t4 5/6081: (geneve: key=123, remote_ip=flow)
t5 6/3: (gre: key=455, packet_type=legacy_l3, remote_ip=2001:cafe::92)
+ t6 7/6: (srv6: remote_ip=2001:cafe::92)
])
AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
Listening ports:
genev_sys_6081 (6081) ref_cnt=1
gre_sys (3) ref_cnt=2
+srv6_sys (6) ref_cnt=1
+srv6_sys (6) ref_cnt=1
vxlan_sys_4789 (4789) ref_cnt=2
])
@@ -363,6 +368,8 @@ AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
Listening ports:
genev_sys_6081 (6081) ref_cnt=1
gre_sys (3) ref_cnt=2
+srv6_sys (6) ref_cnt=1
+srv6_sys (6) ref_cnt=1
vxlan_sys_4789 (4789) ref_cnt=2
])
@@ -384,6 +391,12 @@ AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_pop(6081)
])
+dnl Check SRv6 tunnel pop
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(1),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:00),eth_type(0x86dd),ipv6(src=2001:cafe::92,dst=2001:cafe::88,label=0,proto=4,tclass=0x0,hlimit=64)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: tnl_pop(6)
+])
+
dnl Check VXLAN tunnel push
AT_CHECK([ovs-ofctl add-flow int-br action=2])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
@@ -405,6 +418,13 @@ AT_CHECK([tail -1 stdout], [0],
[Datapath actions: tnl_push(tnl_port(3),header(size=62,type=109,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=47,tclass=0x0,hlimit=64),gre((flags=0x2000,proto=0x6558),key=0x1c8)),out_port(100)),1
])
+dnl Check SRv6 tunnel push
+AT_CHECK([ovs-ofctl add-flow int-br action=7])
+AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
+AT_CHECK([tail -1 stdout], [0],
+ [Datapath actions: pop_eth,tnl_push(tnl_port(6),header(size=78,type=112,eth(dst=f8:bc:12:44:34:b6,src=aa:55:aa:55:00:00,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(100)),1
+])
+
dnl Check Geneve tunnel push
AT_CHECK([ovs-ofctl add-flow int-br "actions=set_field:2001:cafe::92->tun_ipv6_dst,5"])
AT_CHECK([ovs-appctl ofproto/trace ovs-dummy 'in_port(2),eth(src=f8:bc:12:44:34:b6,dst=aa:55:aa:55:00:01),eth_type(0x0800),ipv4(src=1.1.3.88,dst=1.1.3.112,proto=47,tos=0,ttl=64,frag=no)'], [0], [stdout])
@@ -510,6 +530,8 @@ AT_CHECK([ovs-appctl tnl/ports/show |sort], [0], [dnl
Listening ports:
genev_sys_6081 (6081) ref_cnt=1
gre_sys (3) ref_cnt=1
+srv6_sys (6) ref_cnt=1
+srv6_sys (6) ref_cnt=1
vxlan_sys_4789 (4789) ref_cnt=1
vxlan_sys_4790 (4790) ref_cnt=1
])
@@ -518,6 +540,7 @@ AT_CHECK([ovs-vsctl del-port int-br t1 \
-- del-port int-br t2 \
-- del-port int-br t4 \
-- del-port int-br t5 \
+ -- del-port int-br t6 \
], [0])
dnl Check tunnel lookup entries after deleting all remaining tunnel ports