Hi Yi, Some more comments below.
/Jan > -----Original Message----- > From: Yang, Yi [mailto:yi.y.y...@intel.com] > Sent: Tuesday, 29 August, 2017 08:31 > To: Jan Scheurich <jan.scheur...@ericsson.com> > Cc: d...@openvswitch.org; b...@ovn.org > Subject: Re: [PATCH v4 2/3] nsh: add new flow key 'ttl' > > > > > diff --git a/include/openvswitch/flow.h b/include/openvswitch/flow.h > > > index a658a58..cd61fff 100644 > > > --- a/include/openvswitch/flow.h > > > +++ b/include/openvswitch/flow.h > > > @@ -146,7 +146,7 @@ struct flow { > > > struct eth_addr arp_tha; /* ARP/ND target hardware address. */ > > > ovs_be16 tcp_flags; /* TCP flags. With L3 to avoid matching > > > L4. > */ > > > ovs_be16 pad2; /* Pad to 64 bits. */ > > > - struct flow_nsh nsh; /* Network Service Header keys */ > > > + struct ovs_key_nsh nsh; /* Network Service Header keys */ > > > > Why rename this type to struct ovs_key_nsh? > > I have explained it in previous review, new ttl field results in it isn't 64 > bit > aligned, moreover, we musnt't do some unnecessary conversion if we use > struct ovs_key_nsh, netlink also used struct ovs_key_nsh, it is very > reasonable to use struct ovs_key_nsh for this, why don't we use it? Not arguing alignment here. That resulted in merging spi and si into path_hdr and is OK. All structs ovs_key_xxx are defined in datapath/linux/.../openvswitch.h, while all structs flow_xxx are defined in lib/packets.h. You have defined struct ovs_key_nsh in lib/packets.h and refer to it both in struct flow and in the netlink attribute. This violates the standard practices. Even if they are isomorphic, I think we should have independent type definitions and a (trivial) conversion function. > > > > > +static inline void > > > +__nsh_set_xflag(struct nsh_hdr *nsh, uint16_t xflag, uint16_t > > > +xmask) { > > > + nsh->ver_flags_ttl_len > > > + = (nsh->ver_flags_ttl_len & ~htons(xmask)) | htons(xflag); > > > +} > > > > Avoid __* prefix. Better call it nsh_set_base_hdr_masked(). > > We just use __ to mark it as an internal function which will not be used > outside of nsh.h, this is C coding convention. The use of __* prefix is reserved for the C compiler. In OVS we typically use *__ postfix for internal functions. > > > +static inline void nsh_set_flags_and_ttl(struct nsh_hdr *nsh, uint8_t > flags, > > > + uint8_t ttl) { > > > + __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & > > > NSH_FLAGS_MASK) | > > > + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK), > > > + NSH_FLAGS_MASK | NSH_TTL_MASK); } > > > + > > > +static inline void nsh_set_flags_ttl_len(struct nsh_hdr *nsh, uint8_t > flags, > > > + uint8_t ttl, uint8_t len) > > > +{ > > > + len = len >> 2; > > > + __nsh_set_xflag(nsh, ((flags << NSH_FLAGS_SHIFT) & > > > NSH_FLAGS_MASK) | > > > + ((ttl << NSH_TTL_SHIFT) & NSH_TTL_MASK) | > > > + ((len << NSH_LEN_SHIFT) & NSH_LEN_MASK), > > > + NSH_FLAGS_MASK | NSH_TTL_MASK | NSH_LEN_MASK); > > > +} > > > > Do you really need to these hybrid functions? Why not use modular > functions nsh_set_flags(), nsh_set_ttl() and nsh_set_len()? I believe the run- > time overhead is negligible with an optimizing compiler. > > Basically these three functions will be executed together, so one is better. They are set in different combinations. I'd say it is better not have a dedicated setter function for every required combination. Only a significant run-time overhead might tempt one to introduce collapsed functions. > > For symmetry you should also add a function setter function for path_hdr: > > I think put_16aligned_be32(&nsh->path_hdr, path_hdr) is better than > nsh_set_path_hdr, here isn't C++ programming :-) I don't agree. You have nsh_get_path_hdr(), so why are set and get handled differently? The main point of these functions is to shield the user from the nasty alignment details of struct nsh_hdr when accessing the packet headers. > > > > Why did you rename this struct? As part of the struct flow, it was > > more appropriately called struct flow_nsh. > > It isn't name issue, we want to use common struct ovs_key_nsh in multiple > function modules. Please see above. Struct ovs_key_nsh should be defined in datapath/linux/.../openvswitch.h to be used on the netlink interface. struct flow_nsh should be defined here in lib/packets.h and used in struct flow. > > > diff --git a/lib/nx-match.c b/lib/nx-match.c index b782e8c..dc52566 > > > 100644 > > > --- a/lib/nx-match.c > > > +++ b/lib/nx-match.c > > > @@ -1157,13 +1158,22 @@ nx_put_raw(struct ofpbuf *b, enum > > > ofp_version oxm, const struct match *match, > > > /* Network Service Header */ > > > nxm_put_8m(&ctx, MFF_NSH_FLAGS, oxm, flow->nsh.flags, > > > match->wc.masks.nsh.flags); > > > + nxm_put_8m(&ctx, MFF_NSH_TTL, oxm, flow->nsh.ttl, > > > + match->wc.masks.nsh.ttl); > > > nxm_put_8m(&ctx, MFF_NSH_MDTYPE, oxm, flow->nsh.mdtype, > > > match->wc.masks.nsh.mdtype); > > > nxm_put_8m(&ctx, MFF_NSH_NP, oxm, flow->nsh.np, > > > match->wc.masks.nsh.np); > > > - nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, flow->nsh.spi, > > > - match->wc.masks.nsh.spi); > > > - nxm_put_8m(&ctx, MFF_NSH_SI, oxm, flow->nsh.si, match- > > > >wc.masks.nsh.si); > > > + spi_mask = nsh_path_hdr_to_spi(match->wc.masks.nsh.path_hdr); > > > + if (spi_mask == htonl(NSH_SPI_MASK >> NSH_SPI_SHIFT)) { > > > + spi_mask = OVS_BE32_MAX; > > > + } > > > + nxm_put_32m(&ctx, MFF_NSH_SPI, oxm, > > > + nsh_path_hdr_to_spi(flow->nsh.path_hdr), > > > + spi_mask); > > > > I think it is not correct to expand a 24 bit all-ones mask for the SPI > > field to > a full 32-bit all-ones mask. Compare to the MFF_IPV6_LABEL case which is > defined as a 20-bit field in a 4-byte OXM. The codes just puts the mask as > is. > > MFF_IPV6_LABEL is different from this, MPLS_LABEL is same as this one. > But it will return BAD_MASK error if we don't expand it ot OVS_BE32_MAX > because mf_is_mask_valid expects mask is all one, the actual mask is > 0x00FFFFFF. I have tried this many times, please do tell me a better > solution for this if you have a better one. MFF_MPLS_LABEL is not comparable because the label is not maskable. MFF_IPV6_LABEL, in contrast, is a maskable 20 bit field in a 32 bit OXM container. And this is about including the mask in the in the OXM. But I double checked the MFF_IPV6_LABEL code. It indeed sets the internal Mask to OVS_BE32_MAX for an exact match of the IPv6 label field. That's why we can use the generic nxm_put_32_m() function to encode the MFF_IPV6_LABEL OXM into the OpenFlow match. That function internally calls is_all_ones(mask, 4) to check for an exact match. We need to do the same for NSH SPI. So your code was doing the right thing. > > > diff --git a/lib/odp-util.c b/lib/odp-util.c index 4f1499e..ac286ea > > > 100644 > > > --- a/lib/odp-util.c > > > +++ b/lib/odp-util.c > > > @@ -319,17 +320,16 @@ format_nsh_key_mask(struct ds *ds, const > > > struct ovs_key_nsh *key, > > > format_nsh_key(ds, key); > > > } else { > > > bool first = true; > > > - uint32_t spi = (ntohl(key->path_hdr) & NSH_SPI_MASK) >> > > > NSH_SPI_SHIFT; > > > - uint32_t spi_mask = (ntohl(mask->path_hdr) & NSH_SPI_MASK) > >> > > > - NSH_SPI_SHIFT; > > > - if (spi_mask == 0x00ffffff) { > > > + uint32_t spi = nsh_path_hdr_to_spi_uint32(key->path_hdr); > > > + uint32_t spi_mask = nsh_path_hdr_to_spi_uint32(mask- > >path_hdr); > > > + if (spi_mask == (NSH_SPI_MASK >> NSH_SPI_SHIFT)) { > > > spi_mask = UINT32_MAX; > > > } > > > > I understand that you expand the mask here to 32 bits to be able to > > use format_be32_masked helper below, but it is confusing anyhow. > Perhaps it would be clearer to introduce a dedicated formatting function > for SPI. > > But a dedicated formatting function for SPI will have the same code as > format_be32_masked does, so we mustn't duplicate code. OK, see also my conclusion on mask expansion above. > > > @@ -1861,28 +1866,29 @@ parse_odp_encap_nsh_action(const char > *s, > > > struct ofpbuf *actions) > > > continue; > > > } > > > } > > > - else if (encap_nsh.mdtype == NSH_M_TYPE2) { > > > + else if (encap_nsh->mdtype == NSH_M_TYPE2) { > > > struct ofpbuf b; > > > char buf[512]; > > > size_t mdlen; > > > if (ovs_scan_len(s, &n, "md2=0x%511[0-9a-fA-F]", buf)) { > > > - ofpbuf_use_stub(&b, encap_nsh.metadata, > > > - OVS_ENCAP_NSH_MAX_MD_LEN); > > > + ofpbuf_use_stub(&b, encap_nsh->metadata, > > > + NSH_CTX_HDRS_MAX_LEN); > > > ofpbuf_put_hex(&b, buf, &mdlen); > > > > Here it might be necessary to pad the metadata buffer with zeros to 4 > bytes. > > This is parsing the data netlink message put, md2 hex string has been > formated which has followed metadata format, so I don't think this is > necessary, in addition, pad will be helpless because md2 hex string has set > tlv len, we can't change it because of such padding. This code is parsing the datapath action in an ovs-dpctl add-flow command. We cannot rely on that the hex string in the command is 4-byte aligned. If it is not, we must make sure that the buffer for the MD2 TLV is padded with zeros to 4 byte boundary, even though the TLV length field may be a non- integer multiple of 4. > > Actucally lib/ofp-actions.c has handled this, all the data is from lib/ofp- > actions.c, so we mustn't do duplicate and helpless thing here. The code in lib/ofp-actions.c parses the OpenFlow generic encap() action in ovs-ofctl commands. This is completely independent. > > > > > I didn't check the unit test adaptations to the introduction of ttl field. > > I have changed nsh unit tests for ttl and dec_nsh_ttl, they have been > verified by nsh unit tests. > > I'll send out new version after Ben gives me feedbacks. > > > > > BR, Jan _______________________________________________ dev mailing list d...@openvswitch.org https://mail.openvswitch.org/mailman/listinfo/ovs-dev