On Sep 8, 2014, at 5:06 PM, Ben Pfaff <b...@nicira.com> wrote: > On Fri, Sep 05, 2014 at 04:05:13PM -0700, Jarno Rajahalme wrote: >> When a whole field of a key value is ignored, skip it when formatting >> the key, and allow it to be left out when parsing the key from a >> string. However, when the unmasked bits have non-zero values (as in >> keys received from a datapath), or when the 'verbose' formatting is >> requested those are still formatted, as it may help in debugging. >> >> Now the named key fields can also be given in arbitrary order. >> Duplicate field values are not checked for, so the last one will >> remain in effect. >> >> Signed-off-by: Jarno Rajahalme <jrajaha...@nicira.com> > > This makes the formatting and parsing code less disastery. Thank you. >
(snip) > There's still some nastiness around the difference between an > all-one-bits mask and a null mask. It takes some real care to read > the code to see that it is correct, and I'm sure that it took at least > as much care to write it. Can we do something about that? One way > would be to always supply a mask, one that is all-one-bits if there > would otherwise be no mask. That could be done externally to the > format_*() functions, or it could be internally. > > Here's one approach for the internal version: > > static void > format_eth(struct ds *ds, const char *name, const uint8_t > key[ETH_ADDR_LEN], > const uint8_t (*mask_)[ETH_ADDR_LEN], bool verbose) > { > const uint8_t *mask = mask_ ? *mask_ : eth_addr_broadcast; > if (verbose || !eth_addr_is_zero(key) || !eth_addr_is_zero(mask)) { > if (!eth_mask_is_exact(mask)) { /* Partially masked. */ > ds_put_format(ds, "%s=", name); > eth_format_masked(key, mask, ds); > ds_put_char(ds, ','); > } else { /* Fully masked. */ > ds_put_format(ds, "%s="ETH_ADDR_FMT",", name, > ETH_ADDR_ARGS(key)); > } > } > } > > The external version would be more like: > > const uint8_t big_all_one_bits[] = { [ 0...255 ] = 0xff }; > #define MASK(PTR, FIELD) \ > (OVS_TYPEOF(&PTR->FIELD)) (PTR ? &PTR->FIELD : (const void *) > big_all_one_bits) > > though I see some defects in that already. > How about this variation (I realized that ‘verbose’ covers the case when the key includes non-masked bits): diff --git a/lib/odp-util.c b/lib/odp-util.c index b5c8c2b..ea724da 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -1251,14 +1251,17 @@ static void format_eth(struct ds *ds, const char *name, const uint8_t key[ETH_ADDR_LEN], const uint8_t (*mask)[ETH_ADDR_LEN], bool verbose) { - if (verbose || !eth_addr_is_zero(key) - || !mask || !eth_addr_is_zero(*mask)) { - if (mask && !eth_mask_is_exact(*mask)) { /* Partially masked. */ + bool mask_empty = mask && eth_addr_is_zero(*mask); + + if (verbose || !mask_empty) { + bool mask_full = !mask || eth_mask_is_exact(*mask); + + if (mask_full) { + ds_put_format(ds, "%s="ETH_ADDR_FMT",", name, ETH_ADDR_ARGS(key)); + } else { ds_put_format(ds, "%s=", name); eth_format_masked(key, *mask, ds); ds_put_char(ds, ','); - } else { /* Fully masked. */ - ds_put_format(ds, "%s="ETH_ADDR_FMT",", name, ETH_ADDR_ARGS(key)); } } } (I’ll wait for your response before changing them all…) > In format_ipv6_label(), I personally find that > if (mask && (~*mask & htonl(IPV6_LABEL_MASK))) { /* Partially masked. */ > is easier to understand written as: > if (mask && (*mask & htonl(~IPV6_LABEL_MASK))) { /* Partially masked. */ > or > if (mask && (*mask & ~htonl(IPV6_LABEL_MASK))) { /* Partially masked. */ > Similarly format_tun_flags(). > > In format_u8x(), I personally find that: > if (mask && ~*mask & UINT8_MAX) { /* Partially masked. */ > is easier to understand written as: > if (mask && *mask != UINT8_MAX) { /* Partially masked. */ > Similarly in format_u8u(), format_be16(), format_frag(). > Will do. > format_frag() is kind of funny because masking doesn't really make > sense there; individual bits aren't too meaningful. I guess what > you've done is about as good as we can get. > I learned about that later after I had done that. Since an enum value is not partially maskable we should always print it without a mask (or not at all when the mask is zero). > There may be some common ground with mf_format() and mf_parse() in > lib/meta-flow.c. > I’ll have a look. > On scan_eth(), the 's' parameter is marked OVS_UNUSED, though it is > used. > > I don't recommend marking scan_tcp_flags() inline, because that will > suppress a "function unused" warning if it ever becomes unused. > These are remnants from debugging. I actually used the inline keyword to suppress the “function unused” warning! > scan_tcp_flags() should probably pass NULL as the mask to > parse_flags() if its own 'mask' argument is NULL. > Will check. > In *_bf(), what does "bf" stand for? > “bitfield”, did not want to make the name longer… > > I noticed that a lot of the macros could better protect their > arguments, e.g. in the definition of SCAN_PUT_ATTR, parentheses around > ATTR here: > + if (ATTR == OVS_KEY_ATTR_TUNNEL) { \ > and around DATA here: > + tun_key_to_attr(BUF, (const struct flow_tnl *)(void *)&DATA); \ > + } else { \ > and ATTR and DATA (twice) here: > + nl_msg_put_unspec(BUF, ATTR, &DATA, sizeof DATA); \ > + } > Will fix. > I am not sure whether this is the approach that I would have ended up > with, but whether yes or no, it is a huge improvement in > maintainability. Thank you. > Thanks for the review. I’ll wait for your response on the first point before pushing this. Jarno > Acked-by: Ben Pfaff <b...@nicira.com> _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev