Commit 39a4cd5a authored by Paolo Abeni's avatar Paolo Abeni

Merge branch 'ioam6-fix-write-to-cloned-skb-s'

Justin Iurman says:

====================
ioam6: fix write to cloned skb's

Make sure the IOAM data insertion is not applied on cloned skb's. As a
consequence, ioam selftests needed a refactoring.
====================

Link: https://lore.kernel.org/r/20240219135255.15429-1-justin.iurman@uliege.beSigned-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parents 7d2a894d 187bbb69
...@@ -177,6 +177,8 @@ static bool ip6_parse_tlv(bool hopbyhop, ...@@ -177,6 +177,8 @@ static bool ip6_parse_tlv(bool hopbyhop,
case IPV6_TLV_IOAM: case IPV6_TLV_IOAM:
if (!ipv6_hop_ioam(skb, off)) if (!ipv6_hop_ioam(skb, off))
return false; return false;
nh = skb_network_header(skb);
break; break;
case IPV6_TLV_JUMBO: case IPV6_TLV_JUMBO:
if (!ipv6_hop_jumbo(skb, off)) if (!ipv6_hop_jumbo(skb, off))
...@@ -943,6 +945,14 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff) ...@@ -943,6 +945,14 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
if (!skb_valid_dst(skb)) if (!skb_valid_dst(skb))
ip6_route_input(skb); ip6_route_input(skb);
/* About to mangle packet header */
if (skb_ensure_writable(skb, optoff + 2 + hdr->opt_len))
goto drop;
/* Trace pointer may have changed */
trace = (struct ioam6_trace_hdr *)(skb_network_header(skb)
+ optoff + sizeof(*hdr));
ioam6_fill_trace_data(skb, ns, trace, true); ioam6_fill_trace_data(skb, ns, trace, true);
break; break;
default: default:
......
...@@ -367,14 +367,12 @@ run_test() ...@@ -367,14 +367,12 @@ run_test()
local desc=$2 local desc=$2
local node_src=$3 local node_src=$3
local node_dst=$4 local node_dst=$4
local ip6_src=$5 local ip6_dst=$5
local ip6_dst=$6 local trace_type=$6
local if_dst=$7 local ioam_ns=$7
local trace_type=$8 local type=$8
local ioam_ns=$9
ip netns exec $node_dst ./ioam6_parser $name $trace_type $ioam_ns $type &
ip netns exec $node_dst ./ioam6_parser $if_dst $name $ip6_src $ip6_dst \
$trace_type $ioam_ns &
local spid=$! local spid=$!
sleep 0.1 sleep 0.1
...@@ -489,7 +487,7 @@ out_undef_ns() ...@@ -489,7 +487,7 @@ out_undef_ns()
trace prealloc type 0x800000 ns 0 size 4 dev veth0 trace prealloc type 0x800000 ns 0 size 4 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0x800000 0 db01::1 0x800000 0 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -509,7 +507,7 @@ out_no_room() ...@@ -509,7 +507,7 @@ out_no_room()
trace prealloc type 0xc00000 ns 123 size 4 dev veth0 trace prealloc type 0xc00000 ns 123 size 4 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123 db01::1 0xc00000 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -543,14 +541,14 @@ out_bits() ...@@ -543,14 +541,14 @@ out_bits()
if [ $cmd_res != 0 ] if [ $cmd_res != 0 ]
then then
npassed=$((npassed+1)) npassed=$((npassed+1))
log_test_passed "$descr" log_test_passed "$descr ($1 mode)"
else else
nfailed=$((nfailed+1)) nfailed=$((nfailed+1))
log_test_failed "$descr" log_test_failed "$descr ($1 mode)"
fi fi
else else
run_test "out_bit$i" "$descr ($1 mode)" $ioam_node_alpha \ run_test "out_bit$i" "$descr ($1 mode)" $ioam_node_alpha \
$ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 $ioam_node_beta db01::1 ${bit2type[$i]} 123 $1
fi fi
done done
...@@ -574,7 +572,7 @@ out_full_supp_trace() ...@@ -574,7 +572,7 @@ out_full_supp_trace()
trace prealloc type 0xfff002 ns 123 size 100 dev veth0 trace prealloc type 0xfff002 ns 123 size 100 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xfff002 123 db01::1 0xfff002 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -604,7 +602,7 @@ in_undef_ns() ...@@ -604,7 +602,7 @@ in_undef_ns()
trace prealloc type 0x800000 ns 0 size 4 dev veth0 trace prealloc type 0x800000 ns 0 size 4 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0x800000 0 db01::1 0x800000 0 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -624,7 +622,7 @@ in_no_room() ...@@ -624,7 +622,7 @@ in_no_room()
trace prealloc type 0xc00000 ns 123 size 4 dev veth0 trace prealloc type 0xc00000 ns 123 size 4 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123 db01::1 0xc00000 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -651,7 +649,7 @@ in_bits() ...@@ -651,7 +649,7 @@ in_bits()
dev veth0 dev veth0
run_test "in_bit$i" "${desc/<n>/$i} ($1 mode)" $ioam_node_alpha \ run_test "in_bit$i" "${desc/<n>/$i} ($1 mode)" $ioam_node_alpha \
$ioam_node_beta db01::2 db01::1 veth0 ${bit2type[$i]} 123 $ioam_node_beta db01::1 ${bit2type[$i]} 123 $1
done done
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
...@@ -679,7 +677,7 @@ in_oflag() ...@@ -679,7 +677,7 @@ in_oflag()
trace prealloc type 0xc00000 ns 123 size 4 dev veth0 trace prealloc type 0xc00000 ns 123 size 4 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xc00000 123 db01::1 0xc00000 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
...@@ -703,7 +701,7 @@ in_full_supp_trace() ...@@ -703,7 +701,7 @@ in_full_supp_trace()
trace prealloc type 0xfff002 ns 123 size 80 dev veth0 trace prealloc type 0xfff002 ns 123 size 80 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_beta \
db01::2 db01::1 veth0 0xfff002 123 db01::1 0xfff002 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_beta link set ip6tnl0 down
} }
...@@ -731,7 +729,7 @@ fwd_full_supp_trace() ...@@ -731,7 +729,7 @@ fwd_full_supp_trace()
trace prealloc type 0xfff002 ns 123 size 244 via db01::1 dev veth0 trace prealloc type 0xfff002 ns 123 size 244 via db01::1 dev veth0
run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_gamma \ run_test ${FUNCNAME[0]} "${desc} ($1 mode)" $ioam_node_alpha $ioam_node_gamma \
db01::2 db02::2 veth0 0xfff002 123 db02::2 0xfff002 123 $1
[ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 down [ "$1" = "encap" ] && ip -netns $ioam_node_gamma link set ip6tnl0 down
} }
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
#include <linux/const.h> #include <linux/const.h>
#include <linux/if_ether.h>
#include <linux/ioam6.h> #include <linux/ioam6.h>
#include <linux/ipv6.h> #include <linux/ipv6.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -512,14 +511,6 @@ static int str2id(const char *tname) ...@@ -512,14 +511,6 @@ static int str2id(const char *tname)
return -1; return -1;
} }
static int ipv6_addr_equal(const struct in6_addr *a1, const struct in6_addr *a2)
{
return ((a1->s6_addr32[0] ^ a2->s6_addr32[0]) |
(a1->s6_addr32[1] ^ a2->s6_addr32[1]) |
(a1->s6_addr32[2] ^ a2->s6_addr32[2]) |
(a1->s6_addr32[3] ^ a2->s6_addr32[3])) == 0;
}
static int get_u32(__u32 *val, const char *arg, int base) static int get_u32(__u32 *val, const char *arg, int base)
{ {
unsigned long res; unsigned long res;
...@@ -603,70 +594,80 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = { ...@@ -603,70 +594,80 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int fd, size, hoplen, tid, ret = 1; int fd, size, hoplen, tid, ret = 1, on = 1;
struct in6_addr src, dst;
struct ioam6_hdr *opt; struct ioam6_hdr *opt;
struct ipv6hdr *ip6h; struct cmsghdr *cmsg;
__u8 buffer[400], *p; struct msghdr msg;
__u16 ioam_ns; struct iovec iov;
__u8 buffer[512];
__u32 tr_type; __u32 tr_type;
__u16 ioam_ns;
__u8 *ptr;
if (argc != 7) if (argc != 5)
goto out; goto out;
tid = str2id(argv[2]); tid = str2id(argv[1]);
if (tid < 0 || !func[tid]) if (tid < 0 || !func[tid])
goto out; goto out;
if (inet_pton(AF_INET6, argv[3], &src) != 1 || if (get_u32(&tr_type, argv[2], 16) ||
inet_pton(AF_INET6, argv[4], &dst) != 1) get_u16(&ioam_ns, argv[3], 0))
goto out; goto out;
if (get_u32(&tr_type, argv[5], 16) || fd = socket(PF_INET6, SOCK_RAW,
get_u16(&ioam_ns, argv[6], 0)) !strcmp(argv[4], "encap") ? IPPROTO_IPV6 : IPPROTO_ICMPV6);
if (fd < 0)
goto out; goto out;
fd = socket(AF_PACKET, SOCK_DGRAM, __cpu_to_be16(ETH_P_IPV6)); setsockopt(fd, IPPROTO_IPV6, IPV6_RECVHOPOPTS, &on, sizeof(on));
if (!fd)
goto out;
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iov.iov_len = 1;
argv[1], strlen(argv[1]))) iov.iov_base = malloc(CMSG_SPACE(sizeof(buffer)));
if (!iov.iov_base)
goto close; goto close;
recv: recv:
size = recv(fd, buffer, sizeof(buffer), 0); memset(&msg, 0, sizeof(msg));
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = buffer;
msg.msg_controllen = CMSG_SPACE(sizeof(buffer));
size = recvmsg(fd, &msg, 0);
if (size <= 0) if (size <= 0)
goto close; goto close;
ip6h = (struct ipv6hdr *)buffer; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
cmsg->cmsg_type != IPV6_HOPOPTS ||
cmsg->cmsg_len < sizeof(struct ipv6_hopopt_hdr))
continue;
if (!ipv6_addr_equal(&ip6h->saddr, &src) || ptr = (__u8 *)CMSG_DATA(cmsg);
!ipv6_addr_equal(&ip6h->daddr, &dst))
goto recv;
if (ip6h->nexthdr != IPPROTO_HOPOPTS)
goto close;
p = buffer + sizeof(*ip6h); hoplen = (ptr[1] + 1) << 3;
hoplen = (p[1] + 1) << 3; ptr += sizeof(struct ipv6_hopopt_hdr);
p += sizeof(struct ipv6_hopopt_hdr);
while (hoplen > 0) { while (hoplen > 0) {
opt = (struct ioam6_hdr *)p; opt = (struct ioam6_hdr *)ptr;
if (opt->opt_type == IPV6_TLV_IOAM && if (opt->opt_type == IPV6_TLV_IOAM &&
opt->type == IOAM6_TYPE_PREALLOC) { opt->type == IOAM6_TYPE_PREALLOC) {
p += sizeof(*opt); ptr += sizeof(*opt);
ret = func[tid](tid, (struct ioam6_trace_hdr *)p, ret = func[tid](tid,
(struct ioam6_trace_hdr *)ptr,
tr_type, ioam_ns); tr_type, ioam_ns);
break; goto close;
} }
p += opt->opt_len + 2; ptr += opt->opt_len + 2;
hoplen -= opt->opt_len + 2; hoplen -= opt->opt_len + 2;
} }
}
goto recv;
close: close:
free(iov.iov_base);
close(fd); close(fd);
out: out:
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment