Any further thoughts on these issues, Maxim? I'm keen to get this patch merged already!
> > > I raised question about coding style question on today’s arch call > > > discussion. And agreement was: > > > > > > 1. variables are on top. (actually we discussed that but looks like > > > forget to document.) Some exceptions acceptable if you link to 3-rd > > > party code which you can not modify. Like netmap. > > > > My interpretation was the variable declarations at the top of the > > function is the default. If you want/need to deviate from the default, > > you need to document why. One such reason is this reassembly example > > where an inner block with local variables is simpler (as in less > > complexity) than calling a separate function. The reason is that the > > code has multiple outputs which is complicated to handle in C. Inner > > blocks with local variable declarations is not some obscure C language > > feature and solves the problem nicely. > > I'm glad to hear that there was some discussion around these issues. I do > think that I have sufficient reason to place variable declarations within > the body of functions in a few places here, particularly in long functions > like "main" and "add_fraglist_to_fraglist". > > Though these form of declarations are mostly within new scopes, there are > currently a couple of places in which the declarations are needed for the > remainder of the function body, and so don't live within new scopes to > prevent unnecessary indentation. Would this be considered to break this > newly formed formatting rule? > > > > 2. Empty braces {} are ok along intend is clear. > > Ok, great! As far as I'm concerned, intent is nearly always clear with these > sorts of constructs though. If variables are declared at the top of the new > scope, then it's clear that these variables need only live for the lifetime > of the scope. What do you consider to be clear intent? > > > > gcc version 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3) > > > odp_ipfragreass-odp_ipfragreass_reassemble.o: In function > > > `atomic_strong_cas_16': > > > /opt/Linaro/odp3.git/example/ipfragreass/odp_ipfragreass_helpers.h:123: > > > undefined reference to `__atomic_compare_exchange_16' > > > /opt/Linaro/odp3.git/example/ipfragreass/odp_ipfragreass_helpers.h:123: > > > undefined reference to `__atomic_compare_exchange_16' > > > /opt/Linaro/odp3.git/example/ipfragreass/odp_ipfragreass_helpers.h:123: > > > undefined reference to `__atomic_compare_exchange_16' > > > > You may need to link with -latomic on certain targets to get 128-bit > > atomics support. > > Also, are you sure you're using v2 of the patch? There was an issue that > could cause errors of this sort in v1, but as __atomic_compare_exchange_n is > actually used internally to ODP as well as in this example, it should no > longer cause a problem if the rest of ODP is able to compile correctly. > > > >>>> +#include <stdio.h> > > >>>> +#include <assert.h> > > >>>> + > > >>>> +#include "odp_ipfragreass_ip.h" > > >>>> +#include "odp_ipfragreass_fragment.h" > > >>>> + > > >>>> +int fragment_ipv4_packet(odp_packet_t orig_packet, odp_packet_t *out, > > >>>> + int *out_len) > > >>>> +{ > > >>>> + uint32_t orig_len = odp_packet_len(orig_packet); > > >>>> + odph_ipv4hdr_t *orig_header = odp_packet_data(orig_packet); > > >>>> + uint32_t header_len = ipv4hdr_ihl(*orig_header); > > >>>> + uint32_t bytes_remaining = orig_len - header_len; > > >>>> + > > >>>> + if (bytes_remaining <= MTU) > > >>>> + return -1; > > >>>> + > > >>>> + /* > > >>>> + * The main fragmentation loop (continue until all bytes from > > >>>> the > > >>>> + * original payload have been assigned to a fragment) > > >>>> + */ > > >>>> + odp_packet_t frag = orig_packet; > > >>> > > >>> 1. why to you need second variable for the same packet handle? > > >> > > >> For readability! You're right that I could call the "orig_packet" > > >> parameter > > >> "frag" and be done with it, but it's really much clearer if rather than > > >> reusing the same variable for two effectively unrelated purposes, I use > > >> the > > >> wonderful ability granted to us by the programming gods to associate > > >> values > > >> with names that describe their purpose. And best of all, for all but the > > >> most > > >> primitive or idiotic of compilers, it's completely free! (And, actually, > > >> probably makes the optimiser's life easier.) > > >> > > > > > > I think it decrease portability. > > ??? > > I would really like to hear the arguments for this opinion. > > > > > I think it decrease portability. It's very hard to argue because > > > different people look from different angle. And what is nice for one > > > looks bad for other.. > > The driving force behind my decision to keep things the way they were written > here is not from the perspective of aesthetics. Far from it, I've tried to > abide to the checkpatch script to the letter. This is about code readability. > Using the name "frag" for the input packet to the function, which is itself > not expected to be a fragment, is misleading and makes the code harder to > understand. I'm not willing to compromise on this point. Especially not for > unsubstantiated claims of increased portability. > > > >>> 2. Variable should be declared at the begining of the scope. > > >> > > >> Is this a hard requirement? I noticed that it wasn't picked up by > > >> checkpatch, > > >> and I can't see it outlined in the kernel's coding style guidelines > > >> either. I > > >> don't think this would cause a total readability disaster here, but I do > > >> think it would make the code at least a little harder to read. Mentally, > > >> for > > >> me, the variable declarations are clearly split between auxiliary data > > >> required for the whole function (declared at the top), and data that is > > >> instrumental in operating the big ol' while loop (declared just before > > >> the > > >> loop). > > >> > > >> Admittedly, the function more or less /is/ the loop here though, and > > >> perhaps > > >> you could argue that this function is too long as per the kernel style > > >> guidelines anyway. I use a similar style in other places in the code, > > >> though, > > >> where I think it's hugely more useful. For instance, in the function > > >> "add_fraglist_to_fraglist". It's a big function, so is helped > > >> significantly > > >> by this. You could definitely argue that it's too long, but it sort of > > >> needs > > >> to be. (In some part, at least, because in my testing the optimiser > > >> failed to > > >> perform tail call optimisation.) > > >> > > > > > > this function also can be split. > > > > Every function can be slit into smaller functions until there is only > > one C statement left in each function. This doesn't make it a good > > idea though. > > In this case, I've tried to split things when it's clearly beneficial to do > so, but have mostly left the cases where it's less clear as single functions > (after all, it's often easier to factor things out than it is to bring them > back to a natural integrated state). In some cases (with the caveat of the > goto, see discussion below), I could split some of these longer functions > into shorter functions with a number of output parameters, but I'm not sure > that's necessarily better. (In fact, in "add_fraglist_to_fraglist" I think it > would often make the code worse, as it may obfuscate some of the core control > code that makes the algorithm tick.) > > > > And goto for hole function is ugly, > > > which you used to save some space to avoid function splitting. > > > > > > things line that "redo:;" > > > > > > it's it nicer to do in kernel style? > > > > > > static incline int __f(...args...) > > > { > > > > > > } > > > > > > void f(..args..) > > > { > > > while (!__f(..args.._)) {}; > > > > > > } > > I don't think using a goto for the whole function with only a few pieces of > state carrying over is /too/ bad, as it effectively mimics tail recursion > (which was originally used in the code before I found that the optimiser > wasn't playing nicely with it). > > Doing it through an iteration construct over a separate inline function isn't > a terrible idea though, and is probably workable (if a little awkward from > the perspective of requiring a "shell" iteration function and an extra out > parameter for the 'real' return value). It does get rid of the goto and > potentially allow some of the code to be factored out of the function though > (see caveat about potentially requiring lots of out parameters), so that's a > plus. I don't feel that strongly about this, so either way is good. > > > > > > >>> 3. For easy reading it's better to have _pkt postfix or prefix to to > > >>> handles. Like pkt_orig or orig_pkt. Like we do in implementation. > > >>> That is optional but it's very easy to see if it's variable or handle. > > >> > > >> Hmm... isn't this what we have types for? I'm not a fan of hungarian > > >> notation, > > >> and while I think this convention is a bit more sensible, it seems > > >> somewhat > > >> unnecessary if variables are properly named. In this context, I think > > >> it's > > >> fairly obvious that a variable named "frag" is a packet of some sort > > >> (whether > > >> it's an ODP handle or a custom struct or whatever -- distinctions which > > >> the > > >> "_pkt" pre/postfix doesn't actually resolve). If there are places in the > > >> code > > >> where you specifically think that adding "pkt" would be helpful, though, > > >> I'd > > >> be more than happy to consider such changes there. > > And all functions should have _func/func_ appended/prepended? > > Just so you know it's a function. > > >> > > > > > > that comment was not strictly say to redo something, it's just my > > > opinion what is better to read. Thinks like: > > > > > > assert(!send_packet(complete_datagram, out)); > > > or > > > assert(!send_packet(complete_datagram, outq)); > > I understand it's just your opinion, but I think it's a solution for a > problem that shouldn't exist in well-written code. (And, at its logical > conclusion, is madness.) > > > > > > >>> 4. Coding style needs to be corrected. > > >> > > >> ??? > > > > > > mostly variables on top. > > (See comments earlier) > > > >>> 5. Do you have linaro email address? Can you plese send patch from it. > > >> > > >> I had some discussions about this yesterday, and it is my understanding > > >> that > > >> I should be able to submit the patch from my ARM email address. Perhaps > > >> this > > >> needs some further dialogue, though? > > >> > > >>> 6. I'm not really convinced about testing of that example. As future > > >>> work I think it might be odp helper. And tools like Snort and Suricate > > >>> can use > > >>> that odp heper for reassembly instead their own implementation. In that > > >>> case we need to proove that algorithm work as expected > > >>> and highlight benefits doing it with ODP. Benefits like faster speed. > > >>> And proving that it works might be processing pcap file with ip > > >>> fragments with your > > >>> program. And as result tcpdump will show no fragmetation on generated > > >>> pcap. Example also should show that code does not reorder or do other > > >>> not needed modifications with packets. > > >> > > >> Yes, perhaps this would integrate nicely into ODP(H) in future. The > > >> checking > > >> performed within the program is fairly decent, and does check the > > >> reassembled > > >> packets against the original copies, but I agree that more extensive > > >> testing > > >> (including performance tuning and measurement) could provide fertile > > >> ground > > >> for future work. > > > > If this example is merged, moving relevant pieces into a helper > > library is easier. We don't need to do all the steps at once. The > > purpose of this example was to show that the current ODP API was > > sufficient to do efficient fragmentation and reassembly (we were > > discussing API additions in this area last year) and to demonstrate a > > lock-free scalable reassembly design (Linux and FreeBSD kernel > > reassembly designs use locks etc. we can do better). > > > > I think one prerequisite for adding a helper function is that you need > > the functionality in more than one place. Is there any ODP > > examples/apps that do their own home grown fragmentation and > > reassembly today? I would think that OFP should be a primary target > > for the lock-free reassembly code. Some of the potential/likely use > > case for OFP will include a lot of fragmented traffic (or so I have > > been told). > > > > >> > > > > > > My point is: > > > > > > original packet -> wrongly fragmented -> original packet > > > vs > > > original packet -> good fragmented -> original packet > > > > > > result is the same, middle is different. > > I don't understand. How do you define wrongly/goodly fragmented? > > I think Maxim is saying that if both the fragmentation /and/ reassembly parts > are broken, then it could end up fudging it such that the result is correct > even though the individual components (the fragmentation and reassembly > logic, on their own) are wrong. It's a fair point, and something that should > be addressed in further testing were this example to be considered a feature > of ODP(H). > > > > > > > > > >>> 7. Will you be able to support this app in next 6 months or later? > > >> > > >> That depends on your definition of "support". Within the next few months, > > >> potentially, but much later than that, probably not. > > >> > > > > > > Review new patches. Answer on some community questions which only you > > > can answer. Something like that.... > > Isn't this what maintainers are for? If you don't understand how the > > code works, you need to ask more questions or demand better > > documentation (preferably as comments in the code IMO). > > I agree with Ola. I'm doing you guys a favour by contributing a helpful > example, and would hope not to be shackled to the project by doing so. That > being said, I appreciate that code contributions are themselves a form of > technical debt, and will probably be able to answer questions for a few > months after the contribution if necessary.