On 29 Jun 2021, at 18:15, Amber, Kumar wrote:
> Hi Eelco , > > Sorry the formatting seems broken on this email thread. > Replies are inlined . Thanks, looking forward to the v5 (hopefully once I finished this version of the series. I’m currently at patch 10 ;) > From: Eelco Chaudron <echau...@redhat.com> > Sent: Tuesday, June 29, 2021 7:36 PM > To: Amber, Kumar <kumar.am...@intel.com> > Cc: Van Haaren, Harry <harry.van.haa...@intel.com>; d...@openvswitch.org; > i.maxim...@ovn.org; Stokes, Ian <ian.sto...@intel.com>; Flavio Leitner > <f...@sysclose.org> > Subject: Re: [ovs-dev] [v4 02/12] dpif-netdev: Add auto validation function > for miniflow extract > > > Not sure how you replied, but it’s hard to see which comments are mine, and > which are yours. > > On 29 Jun 2021, at 14:27, Amber, Kumar wrote: > > Hi Eelco, > > Thanks Again for reviews , Pls find my replies inline. > > From: Eelco Chaudron <echau...@redhat.com<mailto:echau...@redhat.com>> > Sent: Tuesday, June 29, 2021 5:14 PM > To: Van Haaren, Harry > <harry.van.haa...@intel.com<mailto:harry.van.haa...@intel.com>> ; Amber, > Kumar <kumar.am...@intel.com<mailto:kumar.am...@intel.com>> > Cc: d...@openvswitch.org<mailto:d...@openvswitch.org> ; > i.maxim...@ovn.org<mailto:i.maxim...@ovn.org> ; Stokes, Ian > <ian.sto...@intel.com<mailto:ian.sto...@intel.com>> ; Flavio Leitner > <f...@sysclose.org<mailto:f...@sysclose.org>> > Subject: Re: [ovs-dev] [v4 02/12] dpif-netdev: Add auto validation function > for miniflow extract > > On 17 Jun 2021, at 18:27, Kumar Amber wrote: > > This patch introduced the auto-validation function which > allows users to compare the batch of packets obtained from > different miniflow implementations against the linear > miniflow extract and return a hitmask. > > The autovaidator function can be triggered at runtime using the > following command: > > $ ovs-appctl dpif-netdev/miniflow-parser-set autovalidator > > Signed-off-by: Kumar Amber > <kumar.am...@intel.com<mailto:kumar.am...@intel.com>> > Co-authored-by: Harry van Haaren > <harry.van.haa...@intel.com<mailto:harry.van.haa...@intel.com>> > Signed-off-by: Harry van Haaren > <harry.van.haa...@intel.com<mailto:harry.van.haa...@intel.com>> > --- > lib/dpif-netdev-private-extract.c | 141 ++++++++++++++++++++++++++++++ > lib/dpif-netdev-private-extract.h | 15 ++++ > lib/dpif-netdev.c | 2 +- > 3 files changed, 157 insertions(+), 1 deletion(-) > > diff --git a/lib/dpif-netdev-private-extract.c > b/lib/dpif-netdev-private-extract.c > index fcc56ef26..0741c19f9 100644 > --- a/lib/dpif-netdev-private-extract.c > +++ b/lib/dpif-netdev-private-extract.c > @@ -32,6 +32,11 @@ VLOG_DEFINE_THIS_MODULE(dpif_netdev_extract); > > /* Implementations of available extract options. */ > static struct dpif_miniflow_extract_impl mfex_impls[] = { > + { > + .probe = NULL, > + .extract_func = dpif_miniflow_extract_autovalidator, > + .name = "autovalidator", > + }, > { > .probe = NULL, > .extract_func = NULL, > @@ -84,3 +89,139 @@ dpif_miniflow_extract_info_get(struct > dpif_miniflow_extract_impl **out_ptr) > *out_ptr = mfex_impls; > return ARRAY_SIZE(mfex_impls); > } > + > +uint32_t > +dpif_miniflow_extract_autovalidator(struct dp_packet_batch *packets, > + struct netdev_flow_key *keys, > + uint32_t keys_size, odp_port_t in_port, > + void *pmd_handle) > +{ > + const size_t cnt = dp_packet_batch_size(packets); > + uint16_t good_l2_5_ofs[NETDEV_MAX_BURST]; > + uint16_t good_l3_ofs[NETDEV_MAX_BURST]; > + uint16_t good_l4_ofs[NETDEV_MAX_BURST]; > + uint16_t good_l2_pad_size[NETDEV_MAX_BURST]; > + struct dp_packet *packet; > + struct dp_netdev_pmd_thread *pmd = pmd_handle; > + struct dpif_miniflow_extract_impl *miniflow_funcs; > + > + int32_t mfunc_count = dpif_miniflow_extract_info_get(&miniflow_funcs); > + if (mfunc_count < 0) { > > In theory 0 could not be returned, but just to cover the corner case can we > change this to include zero. > > The code has been adapted as per Flavio comments so will not be a concern. > > + pmd->miniflow_extract_opt = NULL; > > Guess the above needs to be atomic. > > Removed based on Flavio comments. > > + VLOG_ERR("failed to get miniflow extract function implementations\n"); > > Capital F to be in sync with your other error messages? > > Removed based on Flavio comments. > > + return 0; > + } > + ovs_assert(keys_size >= cnt); > > > I don’t think we should assert here. Just return an error like above, so in > production, we get notified, and this implementation gets disabled. > > Actually we do else one would most likely be overwriting the assigned array > space for keys and will hit a Seg fault at some point. > > And hence we would like to know at the compile time if this is the case. > > But this is not a compile time check, it will crash OVS. You could just do > this: > > if (keys_size < cnt) { > pmd->miniflow_extract_opt = NULL; > VLOG_ERR(“Invalid key size supplied etc. etc.\n”); > return 0; > } > > Or you could process up to key_size packets > > Reply: sure I have taken the first approach in v5 as it safe and avoid any > risk of Seg fault in V5. > > + struct netdev_flow_key test_keys[NETDEV_MAX_BURST]; > + > + /* Run scalar miniflow_extract to get default result. */ > + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { > + pkt_metadata_init(&packet->md, in_port); > + miniflow_extract(packet, &keys[i].mf); > + > + /* Store known good metadata to compare with optimized metadata. */ > + good_l2_5_ofs[i] = packet->l2_5_ofs; > + good_l3_ofs[i] = packet->l3_ofs; > + good_l4_ofs[i] = packet->l4_ofs; > + good_l2_pad_size[i] = packet->l2_pad_size; > + } > + > + /* Iterate through each version of miniflow implementations. */ > + for (int j = MFEX_IMPL_START_IDX; j < ARRAY_SIZE(mfex_impls); j++) { > + if (!mfex_impls[j].available) { > + continue; > + } > + > + /* Reset keys and offsets before each implementation. */ > + memset(test_keys, 0, keys_size * sizeof(struct netdev_flow_key)); > + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { > + dp_packet_reset_offsets(packet); > + } > + /* Call optimized miniflow for each batch of packet. */ > + uint32_t hit_mask = mfex_impls[j].extract_func(packets, test_keys, > + keys_size, in_port, pmd_handle); > + > + /* Do a miniflow compare for bits, blocks and offsets for all the > + * classified packets in the hitmask marked by set bits. */ > + while (hit_mask) { > + /* Index for the set bit. */ > + uint32_t i = __builtin_ctz(hit_mask); > + /* Set the index in hitmask to Zero. */ > + hit_mask &= (hit_mask - 1); > + > + uint32_t failed = 0; > + > + /* Check miniflow bits are equal. */ > + if ((keys[i].mf.map.bits[0] != test_keys[i].mf.map.bits[0]) || > + (keys[i].mf.map.bits[1] != test_keys[i].mf.map.bits[1])) { > + VLOG_ERR("Good 0x%llx 0x%llx\tTest 0x%llx 0x%llx\n", > + keys[i].mf.map.bits[0], keys[i].mf.map.bits[1], > + test_keys[i].mf.map.bits[0], > + test_keys[i].mf.map.bits[1]); > + failed = 1; > + } > + > + if (!miniflow_equal(&keys[i].mf, &test_keys[i].mf)) { > + uint32_t block_cnt = miniflow_n_values(&keys[i].mf); > + VLOG_ERR("Autovalidation blocks failed for %s pkt %d", > + mfex_impls[j].name, i); > + VLOG_ERR(" Good hexdump:\n"); > + uint64_t *good_block_ptr = (uint64_t *)&keys[i].buf; > + uint64_t *test_block_ptr = (uint64_t *)&test_keys[i].buf; > + for (uint32_t b = 0; b < block_cnt; b++) { > + VLOG_ERR(" %"PRIx64"\n", good_block_ptr[b]); > + } > + VLOG_ERR(" Test hexdump:\n"); > + for (uint32_t b = 0; b < block_cnt; b++) { > + VLOG_ERR(" %"PRIx64"\n", test_block_ptr[b]); > + } > + failed = 1; > + } > + > + if ((packets->packets[i]->l2_pad_size != good_l2_pad_size[i]) || > + (packets->packets[i]->l2_5_ofs != good_l2_5_ofs[i]) || > + (packets->packets[i]->l3_ofs != good_l3_ofs[i]) || > + (packets->packets[i]->l4_ofs != good_l4_ofs[i])) { > + VLOG_ERR("Autovalidation packet offsets failed for %s pkt %d", > + mfex_impls[j].name, i); > + VLOG_ERR(" Good offsets: l2_pad_size %u, l2_5_ofs : %u" > + " l3_ofs %u, l4_ofs %u\n", > + good_l2_pad_size[i], good_l2_5_ofs[i], > + good_l3_ofs[i], good_l4_ofs[i]); > + VLOG_ERR(" Test offsets: l2_pad_size %u, l2_5_ofs : %u" > + " l3_ofs %u, l4_ofs %u\n", > + packets->packets[i]->l2_pad_size, > + packets->packets[i]->l2_5_ofs, > + packets->packets[i]->l3_ofs, > + packets->packets[i]->l4_ofs); > + failed = 1; > + } > + > + if (failed) { > > Why stop now!? I think we should run all implementations, as others might > need fixing too! > > We had the same model as above by you but with so many debug messages > flooding made it impossible for us to > > Know the root cause and ovs_assert(0); have been removes so will no longer > cause a crash but will simply disable the autovalidator > > I still would opt for getting all in the log. What is worse than getting a > customer to crash (LOG) one failure, and with the provided fix, it will > crash/log the next one :( > And if the logs were not clear enough, maybe they need some rewriting? > > Reply: As pointed out by Flavio in patch 07/12 , I guess we can do the > following here as: > > - Remove the ovs_assert() > > - VLOG_ERR() any mismatches > > - Continue processing rest of burst with MFEX Autovalidator > > On failures, we disable autovalidator *after* the burst, to avoid spamming > output and filling logs. > > + /* Having dumped the debug info, disable autovalidator. */ > + VLOG_ERR("Autovalidation failed in %s pkt %d, disabling.\n", > + mfex_impls[j].name, i); > + /* Halt OVS here on debug builds. */ > + ovs_assert(0); > + pmd->miniflow_extract_opt = NULL; > + break; > + } > + } > + } > + > + /* preserve packet correctness by storing back the good offsets in > + * packets back. */ > + DP_PACKET_BATCH_FOR_EACH (i, packet, packets) { > + packet->l2_5_ofs = good_l2_5_ofs[i]; > + packet->l3_ofs = good_l3_ofs[i]; > + packet->l4_ofs = good_l4_ofs[i]; > + packet->l2_pad_size = good_l2_pad_size[i]; > + } > + > + /* Returning zero implies no packets were hit by autovalidation. This > + * simplifies unit-tests as changing --enable-mfex-default-autovalidator > + * would pass/fail. By always returning zero, autovalidator is a little > + * slower, but we gain consistency in testing. > + */ > + return 0; > +} > diff --git a/lib/dpif-netdev-private-extract.h > b/lib/dpif-netdev-private-extract.h > index b7b0b2be4..455a7b590 100644 > --- a/lib/dpif-netdev-private-extract.h > +++ b/lib/dpif-netdev-private-extract.h > @@ -24,6 +24,11 @@ > /* Max size of dpif_miniflow_extract_impl array. */ > #define MFEX_IMPLS_MAX_SIZE (16) > > +/* Skip the autovalidator study and null when iterating all available > + * miniflow implementations. > + */ > +#define MFEX_IMPL_START_IDX (1) > + > /* Forward declarations. */ > struct dp_packet; > struct miniflow; > @@ -90,5 +95,15 @@ dpif_miniflow_extract_init(void); > int32_t > dpif_miniflow_extract_info_get(struct dpif_miniflow_extract_impl **out_ptr); > > Forgot to comment on this in my previous patch: > > /* Function pointer prototype to be implemented in the optimized miniflow > > * extract code. > * returns the hitmask of the processed packets on success. > * returns zero on failure. > > */ > typedef uint32_t (*miniflow_extract_func)(struct dp_packet_batch *batch, > struct netdev_flow_key *keys, > uint32_t keys_size, > odp_port_t in_port, > void *pmd_handle); > > Maybe we could add some description of what the input parameters mean, are > expected? For example that key_size need to be at least the size of the > batch? If this is the case, do we need it, and can we just assume keys should > be at least batch size long? > > Yes put a comment in there about key size in the description in v5. > > But as per convention whenever we pass an array we should also put the size > of the array and this also complies with various > > Security checkers and also prevents potential exploitations. > > Ack > > +/* Retrieve the hitmask of the batch of pakcets which is obtained by > comparing > + * different miniflow implementations with linear miniflow extract. > + * On error, returns a zero. > + * On success, returns the number of packets in the batch compared. > + */ > +uint32_t > +dpif_miniflow_extract_autovalidator(struct dp_packet_batch *batch, > + struct netdev_flow_key *keys, > + uint32_t keys_size, odp_port_t in_port, > + void *pmd_handle); > > #endif /* DPIF_NETDEV_AVX512_EXTRACT */ > diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c > index 567ebd952..4f4ab2790 100644 > --- a/lib/dpif-netdev.c > +++ b/lib/dpif-netdev.c > @@ -1181,8 +1181,8 @@ dpif_miniflow_extract_impl_set(struct unixctl_conn > *conn, int argc, > struct ds reply = DS_EMPTY_INITIALIZER; > ds_put_format(&reply, "Miniflow implementation set to %s.\n", mfex_name); > const char *reply_str = ds_cstr(&reply); > - unixctl_command_reply(conn, reply_str); > VLOG_INFO("%s", reply_str); > + unixctl_command_reply(conn, reply_str); > ds_destroy(&reply); > } > > -- > 2.25.1 > > _______________________________________________ > dev mailing list > d...@openvswitch.org<mailto:d...@openvswitch.org> > https://mail.openvswitch.org/mailman/listinfo/ovs-dev _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev