Commit 7389074c authored by David S. Miller's avatar David S. Miller

Merge branch 'ioam-fixes'

Justin Iurman says:

====================
Correct the IOAM behavior for undefined trace type bits

(@Jakub @David: there will be a conflict for #2 when merging net->net-next, due
to commit [1]. The conflict is only 5-10 lines for #2 (#1 should be fine) inside
the file tools/testing/selftests/net/ioam6.sh, so quite short though possibly
ugly. Sorry for that, I didn't expect to post this one... Had I known, I'd have
made the opposite.)

Modify both the input and output behaviors regarding the trace type when one of
the undefined bits is set. The goal is to keep the interoperability when new
fields (aka new bits inside the range 12-21) will be defined.

The draft [2] says the following:
---------------------------------------------------------------
"Bit 12-21  Undefined.  These values are available for future
       assignment in the IOAM Trace-Type Registry (Section 8.2).
       Every future node data field corresponding to one of
       these bits MUST be 4-octets long.  An IOAM encapsulating
       node MUST set the value of each undefined bit to 0.  If
       an IOAM transit node receives a packet with one or more
       of these bits set to 1, it MUST either:

       1.  Add corresponding node data filled with the reserved
           value 0xFFFFFFFF, after the node data fields for the
           IOAM-Trace-Type bits defined above, such that the
           total node data added by this node in units of
           4-octets is equal to NodeLen, or

       2.  Not add any node data fields to the packet, even for
           the IOAM-Trace-Type bits defined above."
---------------------------------------------------------------

The output behavior has been modified to respect the fact that "an IOAM encap
node MUST set the value of each undefined bit to 0" (i.e., undefined bits can't
be set anymore).

As for the input behavior, current implementation is based on the second choice
(i.e., "not add any data fields to the packet [...]"). With this solution, any
interoperability is lost (i.e., if a new bit is defined, then an "old" kernel
implementation wouldn't fill IOAM data when such new bit is set inside the trace
type).

The input behavior is therefore relaxed and these undefined bits are now allowed
to be set. It is only possible thanks to the sentence "every future node data
field corresponding to one of these bits MUST be 4-octets long". Indeed, the
default empty value (the one for 4-octet fields) is inserted whenever an
undefined bit is set.

  [1] cfbe9b00
  [2] https://datatracker.ietf.org/doc/html/draft-ietf-ippm-ioam-data#section-5.4.1
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ef1100ef 7b1700e0
...@@ -770,6 +770,66 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb, ...@@ -770,6 +770,66 @@ static void __ioam6_fill_trace_data(struct sk_buff *skb,
data += sizeof(__be32); data += sizeof(__be32);
} }
/* bit12 undefined: filled with empty value */
if (trace->type.bit12) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit13 undefined: filled with empty value */
if (trace->type.bit13) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit14 undefined: filled with empty value */
if (trace->type.bit14) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit15 undefined: filled with empty value */
if (trace->type.bit15) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit16 undefined: filled with empty value */
if (trace->type.bit16) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit17 undefined: filled with empty value */
if (trace->type.bit17) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit18 undefined: filled with empty value */
if (trace->type.bit18) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit19 undefined: filled with empty value */
if (trace->type.bit19) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit20 undefined: filled with empty value */
if (trace->type.bit20) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* bit21 undefined: filled with empty value */
if (trace->type.bit21) {
*(__be32 *)data = cpu_to_be32(IOAM6_U32_UNAVAILABLE);
data += sizeof(__be32);
}
/* opaque state snapshot */ /* opaque state snapshot */
if (trace->type.bit22) { if (trace->type.bit22) {
if (!sc) { if (!sc) {
...@@ -791,16 +851,10 @@ void ioam6_fill_trace_data(struct sk_buff *skb, ...@@ -791,16 +851,10 @@ void ioam6_fill_trace_data(struct sk_buff *skb,
struct ioam6_schema *sc; struct ioam6_schema *sc;
u8 sclen = 0; u8 sclen = 0;
/* Skip if Overflow flag is set OR /* Skip if Overflow flag is set
* if an unknown type (bit 12-21) is set
*/ */
if (trace->overflow || if (trace->overflow)
trace->type.bit12 | trace->type.bit13 | trace->type.bit14 |
trace->type.bit15 | trace->type.bit16 | trace->type.bit17 |
trace->type.bit18 | trace->type.bit19 | trace->type.bit20 |
trace->type.bit21) {
return; return;
}
/* NodeLen does not include Opaque State Snapshot length. We need to /* NodeLen does not include Opaque State Snapshot length. We need to
* take it into account if the corresponding bit is set (bit 22) and * take it into account if the corresponding bit is set (bit 22) and
......
...@@ -75,7 +75,11 @@ static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace) ...@@ -75,7 +75,11 @@ static bool ioam6_validate_trace_hdr(struct ioam6_trace_hdr *trace)
u32 fields; u32 fields;
if (!trace->type_be32 || !trace->remlen || if (!trace->type_be32 || !trace->remlen ||
trace->remlen > IOAM6_TRACE_DATA_SIZE_MAX / 4) trace->remlen > IOAM6_TRACE_DATA_SIZE_MAX / 4 ||
trace->type.bit12 | trace->type.bit13 | trace->type.bit14 |
trace->type.bit15 | trace->type.bit16 | trace->type.bit17 |
trace->type.bit18 | trace->type.bit19 | trace->type.bit20 |
trace->type.bit21)
return false; return false;
trace->nodelen = 0; trace->nodelen = 0;
......
...@@ -468,10 +468,26 @@ out_bits() ...@@ -468,10 +468,26 @@ out_bits()
for i in {0..22} for i in {0..22}
do do
ip -netns ioam-node-alpha route change db01::/64 encap ioam6 trace \ ip -netns ioam-node-alpha route change db01::/64 encap ioam6 trace \
prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} dev veth0 prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} \
dev veth0 &>/dev/null
run_test "out_bit$i" "${desc/<n>/$i}" ioam-node-alpha ioam-node-beta \
db01::2 db01::1 veth0 ${bit2type[$i]} 123 local cmd_res=$?
local descr="${desc/<n>/$i}"
if [[ $i -ge 12 && $i -le 21 ]]
then
if [ $cmd_res != 0 ]
then
npassed=$((npassed+1))
log_test_passed "$descr"
else
nfailed=$((nfailed+1))
log_test_failed "$descr"
fi
else
run_test "out_bit$i" "$descr" ioam-node-alpha ioam-node-beta \
db01::2 db01::1 veth0 ${bit2type[$i]} 123
fi
done done
bit2size[22]=$tmp bit2size[22]=$tmp
...@@ -544,7 +560,7 @@ in_bits() ...@@ -544,7 +560,7 @@ in_bits()
local tmp=${bit2size[22]} local tmp=${bit2size[22]}
bit2size[22]=$(( $tmp + ${#BETA[9]} + ((4 - (${#BETA[9]} % 4)) % 4) )) bit2size[22]=$(( $tmp + ${#BETA[9]} + ((4 - (${#BETA[9]} % 4)) % 4) ))
for i in {0..22} for i in {0..11} {22..22}
do do
ip -netns ioam-node-alpha route change db01::/64 encap ioam6 trace \ ip -netns ioam-node-alpha route change db01::/64 encap ioam6 trace \
prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} dev veth0 prealloc type ${bit2type[$i]} ns 123 size ${bit2size[$i]} dev veth0
......
...@@ -94,16 +94,6 @@ enum { ...@@ -94,16 +94,6 @@ enum {
TEST_OUT_BIT9, TEST_OUT_BIT9,
TEST_OUT_BIT10, TEST_OUT_BIT10,
TEST_OUT_BIT11, TEST_OUT_BIT11,
TEST_OUT_BIT12,
TEST_OUT_BIT13,
TEST_OUT_BIT14,
TEST_OUT_BIT15,
TEST_OUT_BIT16,
TEST_OUT_BIT17,
TEST_OUT_BIT18,
TEST_OUT_BIT19,
TEST_OUT_BIT20,
TEST_OUT_BIT21,
TEST_OUT_BIT22, TEST_OUT_BIT22,
TEST_OUT_FULL_SUPP_TRACE, TEST_OUT_FULL_SUPP_TRACE,
...@@ -125,16 +115,6 @@ enum { ...@@ -125,16 +115,6 @@ enum {
TEST_IN_BIT9, TEST_IN_BIT9,
TEST_IN_BIT10, TEST_IN_BIT10,
TEST_IN_BIT11, TEST_IN_BIT11,
TEST_IN_BIT12,
TEST_IN_BIT13,
TEST_IN_BIT14,
TEST_IN_BIT15,
TEST_IN_BIT16,
TEST_IN_BIT17,
TEST_IN_BIT18,
TEST_IN_BIT19,
TEST_IN_BIT20,
TEST_IN_BIT21,
TEST_IN_BIT22, TEST_IN_BIT22,
TEST_IN_FULL_SUPP_TRACE, TEST_IN_FULL_SUPP_TRACE,
...@@ -199,30 +179,6 @@ static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h, ...@@ -199,30 +179,6 @@ static int check_ioam_header(int tid, struct ioam6_trace_hdr *ioam6h,
ioam6h->nodelen != 2 || ioam6h->nodelen != 2 ||
ioam6h->remlen; ioam6h->remlen;
case TEST_OUT_BIT12:
case TEST_IN_BIT12:
case TEST_OUT_BIT13:
case TEST_IN_BIT13:
case TEST_OUT_BIT14:
case TEST_IN_BIT14:
case TEST_OUT_BIT15:
case TEST_IN_BIT15:
case TEST_OUT_BIT16:
case TEST_IN_BIT16:
case TEST_OUT_BIT17:
case TEST_IN_BIT17:
case TEST_OUT_BIT18:
case TEST_IN_BIT18:
case TEST_OUT_BIT19:
case TEST_IN_BIT19:
case TEST_OUT_BIT20:
case TEST_IN_BIT20:
case TEST_OUT_BIT21:
case TEST_IN_BIT21:
return ioam6h->overflow ||
ioam6h->nodelen ||
ioam6h->remlen != 1;
case TEST_OUT_BIT22: case TEST_OUT_BIT22:
case TEST_IN_BIT22: case TEST_IN_BIT22:
return ioam6h->overflow || return ioam6h->overflow ||
...@@ -326,6 +282,66 @@ static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h, ...@@ -326,6 +282,66 @@ static int check_ioam6_data(__u8 **p, struct ioam6_trace_hdr *ioam6h,
*p += sizeof(__u32); *p += sizeof(__u32);
} }
if (ioam6h->type.bit12) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit13) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit14) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit15) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit16) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit17) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit18) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit19) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit20) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit21) {
if (__be32_to_cpu(*((__u32 *)*p)) != 0xffffffff)
return 1;
*p += sizeof(__u32);
}
if (ioam6h->type.bit22) { if (ioam6h->type.bit22) {
len = cnf.sc_data ? strlen(cnf.sc_data) : 0; len = cnf.sc_data ? strlen(cnf.sc_data) : 0;
aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0; aligned = cnf.sc_data ? __ALIGN_KERNEL(len, 4) : 0;
...@@ -455,26 +471,6 @@ static int str2id(const char *tname) ...@@ -455,26 +471,6 @@ static int str2id(const char *tname)
return TEST_OUT_BIT10; return TEST_OUT_BIT10;
if (!strcmp("out_bit11", tname)) if (!strcmp("out_bit11", tname))
return TEST_OUT_BIT11; return TEST_OUT_BIT11;
if (!strcmp("out_bit12", tname))
return TEST_OUT_BIT12;
if (!strcmp("out_bit13", tname))
return TEST_OUT_BIT13;
if (!strcmp("out_bit14", tname))
return TEST_OUT_BIT14;
if (!strcmp("out_bit15", tname))
return TEST_OUT_BIT15;
if (!strcmp("out_bit16", tname))
return TEST_OUT_BIT16;
if (!strcmp("out_bit17", tname))
return TEST_OUT_BIT17;
if (!strcmp("out_bit18", tname))
return TEST_OUT_BIT18;
if (!strcmp("out_bit19", tname))
return TEST_OUT_BIT19;
if (!strcmp("out_bit20", tname))
return TEST_OUT_BIT20;
if (!strcmp("out_bit21", tname))
return TEST_OUT_BIT21;
if (!strcmp("out_bit22", tname)) if (!strcmp("out_bit22", tname))
return TEST_OUT_BIT22; return TEST_OUT_BIT22;
if (!strcmp("out_full_supp_trace", tname)) if (!strcmp("out_full_supp_trace", tname))
...@@ -509,26 +505,6 @@ static int str2id(const char *tname) ...@@ -509,26 +505,6 @@ static int str2id(const char *tname)
return TEST_IN_BIT10; return TEST_IN_BIT10;
if (!strcmp("in_bit11", tname)) if (!strcmp("in_bit11", tname))
return TEST_IN_BIT11; return TEST_IN_BIT11;
if (!strcmp("in_bit12", tname))
return TEST_IN_BIT12;
if (!strcmp("in_bit13", tname))
return TEST_IN_BIT13;
if (!strcmp("in_bit14", tname))
return TEST_IN_BIT14;
if (!strcmp("in_bit15", tname))
return TEST_IN_BIT15;
if (!strcmp("in_bit16", tname))
return TEST_IN_BIT16;
if (!strcmp("in_bit17", tname))
return TEST_IN_BIT17;
if (!strcmp("in_bit18", tname))
return TEST_IN_BIT18;
if (!strcmp("in_bit19", tname))
return TEST_IN_BIT19;
if (!strcmp("in_bit20", tname))
return TEST_IN_BIT20;
if (!strcmp("in_bit21", tname))
return TEST_IN_BIT21;
if (!strcmp("in_bit22", tname)) if (!strcmp("in_bit22", tname))
return TEST_IN_BIT22; return TEST_IN_BIT22;
if (!strcmp("in_full_supp_trace", tname)) if (!strcmp("in_full_supp_trace", tname))
...@@ -606,16 +582,6 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = { ...@@ -606,16 +582,6 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
[TEST_OUT_BIT9] = check_ioam_header_and_data, [TEST_OUT_BIT9] = check_ioam_header_and_data,
[TEST_OUT_BIT10] = check_ioam_header_and_data, [TEST_OUT_BIT10] = check_ioam_header_and_data,
[TEST_OUT_BIT11] = check_ioam_header_and_data, [TEST_OUT_BIT11] = check_ioam_header_and_data,
[TEST_OUT_BIT12] = check_ioam_header,
[TEST_OUT_BIT13] = check_ioam_header,
[TEST_OUT_BIT14] = check_ioam_header,
[TEST_OUT_BIT15] = check_ioam_header,
[TEST_OUT_BIT16] = check_ioam_header,
[TEST_OUT_BIT17] = check_ioam_header,
[TEST_OUT_BIT18] = check_ioam_header,
[TEST_OUT_BIT19] = check_ioam_header,
[TEST_OUT_BIT20] = check_ioam_header,
[TEST_OUT_BIT21] = check_ioam_header,
[TEST_OUT_BIT22] = check_ioam_header_and_data, [TEST_OUT_BIT22] = check_ioam_header_and_data,
[TEST_OUT_FULL_SUPP_TRACE] = check_ioam_header_and_data, [TEST_OUT_FULL_SUPP_TRACE] = check_ioam_header_and_data,
[TEST_IN_UNDEF_NS] = check_ioam_header, [TEST_IN_UNDEF_NS] = check_ioam_header,
...@@ -633,16 +599,6 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = { ...@@ -633,16 +599,6 @@ static int (*func[__TEST_MAX])(int, struct ioam6_trace_hdr *, __u32, __u16) = {
[TEST_IN_BIT9] = check_ioam_header_and_data, [TEST_IN_BIT9] = check_ioam_header_and_data,
[TEST_IN_BIT10] = check_ioam_header_and_data, [TEST_IN_BIT10] = check_ioam_header_and_data,
[TEST_IN_BIT11] = check_ioam_header_and_data, [TEST_IN_BIT11] = check_ioam_header_and_data,
[TEST_IN_BIT12] = check_ioam_header,
[TEST_IN_BIT13] = check_ioam_header,
[TEST_IN_BIT14] = check_ioam_header,
[TEST_IN_BIT15] = check_ioam_header,
[TEST_IN_BIT16] = check_ioam_header,
[TEST_IN_BIT17] = check_ioam_header,
[TEST_IN_BIT18] = check_ioam_header,
[TEST_IN_BIT19] = check_ioam_header,
[TEST_IN_BIT20] = check_ioam_header,
[TEST_IN_BIT21] = check_ioam_header,
[TEST_IN_BIT22] = check_ioam_header_and_data, [TEST_IN_BIT22] = check_ioam_header_and_data,
[TEST_IN_FULL_SUPP_TRACE] = check_ioam_header_and_data, [TEST_IN_FULL_SUPP_TRACE] = check_ioam_header_and_data,
[TEST_FWD_FULL_SUPP_TRACE] = check_ioam_header_and_data, [TEST_FWD_FULL_SUPP_TRACE] = check_ioam_header_and_data,
......
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