On 3/15/23 07:07, Nobuhiro MIKI wrote: > This patch adds ODP actions for SRv6 and its tests. > > Signed-off-by: Nobuhiro MIKI <nm...@yahoo-corp.jp> > --- > lib/odp-util.c | 56 +++++++++++++++++++++++++++++++++++ > python/ovs/flow/odp.py | 8 +++++ > python/ovs/tests/test_odp.py | 16 ++++++++++ > tests/odp.at | 1 + > tests/tunnel-push-pop-ipv6.at | 23 ++++++++++++++ > 5 files changed, 104 insertions(+) > > 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));
We will overwrite the header here if segments_left + 1 is less than total number of specified segments. E.g. in the following case: srv6(segments_left=0,segs=2001:cafe::92,2001:cafe::93). One solution for this may be to create an SRV6_MAX_SEGS + 1 sized array and parse values there. Once all the values parsed, copy them into an actual header. If more than SRV6_MAX_SEGS values found, then fail the parsing. What do you think? Also, the sizeof seems incorrect here. It should be in6, not in. It also should be just 'sizeof *segs' to avoid any potential problems of this kind. Would be good to add a test to tests/odp.at for many segments parsing while segments_left is small. And it's probably possible to avoid some code duplication here. E.g. (didn't test): if (strncmp(s, ",segs=", 6)) { return -EINVAL; } s += 6; while (ovs_scan_len(s, &n, IPV6_SCAN_FMT, seg_s) && inet_pton(AF_INET6, seg_s, &seg) == 1) { ... if (s[n] == ',') { s++; } } Best regards, Ilya Maximets. _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev