Conversation
| LL_FOREACH(dodag->parents, elt) { | ||
| new_best = dodag->instance->of->which_parent(new_best, elt); | ||
| } | ||
| LL_SORT(dodag->parents, dodag->instance->of->which_parent); |
There was a problem hiding this comment.
this does not update new_best anymore, I would guess that also changes the behaviour of this function, or not?
There was a problem hiding this comment.
Ah, you're right there, that wasn't supposed to happen. An new_best = dodag->parents after the LL_SORT should be sufficient to restore the old behaviour
There was a problem hiding this comment.
however, I generally like your suggestion/idea of having the parent list sorted right away. But then this should be done on add/del of a parent so there would be no need to this here.
There was a problem hiding this comment.
Yes, but for example with MRHOF as an objective function, the sorting of the parents can vary over time because it depends not only on the advertised rank of a parent, but also on the link quality to the parent.
So sorting the parents on add/del works if the parents have a fixed order, but I don't think it works when the relative sorting of the parents change over time.
There was a problem hiding this comment.
good point, then it should be done when ever the rank of a parent changes - what could be quite often and would introduce lots of overhead, which we don't want on an embedded node.
OK, I see this is not as easy as I first thought 😉
There was a problem hiding this comment.
I would not advise to update this every time the path cost of a parent updates, that could be with every transmitted packet (or other event on which the path cost depends).
Recalculating this based on a timer or an event with some build in hysterisis (only update when the path cost changed by some amount) might be enough to lessen the burden of this.
There was a problem hiding this comment.
yes, or only when required, like in this function.
sys/include/net/gnrc/rpl/structs.h
Outdated
| uint16_t ocp; /**< objective code point */ | ||
| uint16_t (*calc_rank)(gnrc_rpl_parent_t *parent, uint16_t base_rank); /**< calculate the rank */ | ||
| gnrc_rpl_parent_t *(*which_parent)(gnrc_rpl_parent_t *, gnrc_rpl_parent_t *); /**< compare for parents */ | ||
| int (*which_parent)(gnrc_rpl_parent_t *, gnrc_rpl_parent_t *); /**< compare for parents */ |
There was a problem hiding this comment.
instead of changing an existing functions (hence the API) wouldn't suffice to add a separate (helper) function, i.e. int parent_cmp(a, b) - which then could also be used by which_parent btw.
|
@smlng I've fixed your comments. I still want to run some additional tests to check if it behaves as intended. Is the API change/addition this way as you requested? |
| LL_FOREACH(dodag->parents, elt) { | ||
| new_best = dodag->instance->of->which_parent(new_best, elt); | ||
| } | ||
| LL_SORT(dodag->parents, dodag->instance->of->parent_cmp); |
There was a problem hiding this comment.
due to this sort the following is obsolete:
LL_DELETE(dodag->parents, new_best);
LL_PREPEND(dodag->parents, new_best);
below lines 320, 321
There was a problem hiding this comment.
Ah, should have noticed that, will remove.
|
though it seems like |
|
Yes, I noticed earlier that not all functions in that struct are (still) in use. The |
|
looks good, please squash @cgundogan can you have a quick look at this, too? |
yeah, I think the RPL code needs some general cleanup - let's do this all at once later on in a separate PR. |
0fc7ae5 to
a8b41f8
Compare
|
squashed |
a8b41f8 to
ea6d00e
Compare
sys/net/gnrc/routing/rpl/of0.c
Outdated
| { | ||
| if (p1->rank <= p2->rank) { | ||
| return p1; | ||
| if(parent_cmp(p1, p2) == 1) { |
There was a problem hiding this comment.
I would recommend to use if(parent_cmp(p1, p2) > 1) instead of strict equality here, this leaves more freedom on the implementation of parent_cmp. For instance, it might be that parent_cmp returns the actual rank difference. Quoting from the man memcmp:
The memcmp() function returns zero if the two strings are identical, otherwise returns the difference between the first two differing bytes (treated as unsigned char values, so that
\200' is greater than\0', for example). Zero-length strings are always identical. This behavior is not required by C and portable code
should only depend on the sign of the returned value.
the last part is what I'm referring to.
There was a problem hiding this comment.
Can't argue against that :)
|
Remark is fixed. Do you want it squashed again, assuming no further remarks? |
sys/net/gnrc/routing/rpl/of0.c
Outdated
| { | ||
| if (p1->rank <= p2->rank) { | ||
| return p1; | ||
| if (parent_cmp(p1, p2)) { |
There was a problem hiding this comment.
I need to insist on if (parent_cmp(p1, p2) > 0) { because -1 will also eval as true, only 0 is false
|
please squash directly |
|
With this comparison fixed, I can reduce the |
6422181 to
25762eb
Compare
I would be careful with that, because rank is of type |
|
Okay, that makes sense. Thanks for the comments so far. |
|
I'd like to get an opinion on this by @cgundogan or @BytesGalore before merge, they the RPL gurus of RIOT 🤓 |
sys/include/net/gnrc/rpl/structs.h
Outdated
| uint16_t (*calc_rank)(gnrc_rpl_parent_t *parent, uint16_t base_rank); /**< calculate the rank */ | ||
| gnrc_rpl_parent_t *(*which_parent)(gnrc_rpl_parent_t *, gnrc_rpl_parent_t *); /**< compare for parents */ | ||
| gnrc_rpl_parent_t *(*which_parent)(gnrc_rpl_parent_t *, gnrc_rpl_parent_t *); /**< retrieve the better parent */ | ||
| int (*parent_cmp)(gnrc_rpl_parent_t *, gnrc_rpl_parent_t *); /**< compare for parents */ |
There was a problem hiding this comment.
I know it hasn't been done before for the other function pointers in this file, but can you add – somehow – a documentation on how to interpret the return value of this function pointer? Is it possible to document function pointers in structs as if they were normal functinos with @param, @return etc.? Would be awesome.
|
IMO the documentation for this function is as important as the function itself, at least. Separating them is a bit too liberal-minded for me (: |
|
my point was not against documentation, but rather that documenting just the new function will look strange too, while documenting all functions (even the unrelated once) would bloat this PR. |
To the contrary, IMO providing a documentation just for this new function makes the commit diff more consistent on its own. The documentation for other functions can still be applied by a separate commit or PR. Although, I would not object if they also happen to be in this PR (: |
|
okay then @bergzand please add proper doc for |
|
That's fine with me, I should have time tomorrow to do the documentation and maybe even some cleanup. |
6494769 to
047ad11
Compare
|
Documentation added. I couldn't get doxygen to understand unnamed function parameters, so they now have names. |
sys/include/net/gnrc/rpl/structs.h
Outdated
| * @param[in] parent1 First parent to compare. | ||
| * @param[in] parent2 Second parent to compare. | ||
| * | ||
| * @return Zero if the parents are of equal preference, |
There was a problem hiding this comment.
please make each case a separate @return, i.e., for <0, 0, and >0.
sys/include/net/gnrc/rpl/structs.h
Outdated
| * | ||
| * This function is used to determine the parent list order. The parents | ||
| * are ordered from the preferred parent to the least preferred parent. | ||
| * This function should compare two parents based on the criteria of the |
There was a problem hiding this comment.
the last sentence is rather vague (should?), be explicit: Compares two parents based on the rank calculated by the objective function. Btw. this sentence should be the first, followed by the other explaining the (possible) usage.
| * positive result if the second parent is prefered, | ||
| * negative result if the first parent is prefered. | ||
| */ | ||
| int (*parent_cmp)(gnrc_rpl_parent_t *parent1, gnrc_rpl_parent_t *parent2); |
There was a problem hiding this comment.
IMHO parameter names p1 and p2 were fine, too - and match with actual implementation in of0.c below.
There was a problem hiding this comment.
I don't mind changing it back to p1, p2. In my opinion this is a bit more clear and I rather change the implementation in of0 to match this
047ad11 to
6f2904f
Compare
|
@smlng I've resolved most of your comments. I'd rather have the first sentence of the explanation without mentioning rank because an objective function can have different criteria than rank comparison (metric containers). Do you have any preference for parent# vs p# for the |
I don't understand, IIRC RPL uses rank only to choose its parent, hence we compare parents by rank. You are right, that an OF may have different/multiple metrics to choose from which to derive the rank. However, in the end RPL needs a rank which way ever that is calculated. Using OF0 the rank is relative to hop-count while using MRHOF it would be relative to ETX, for instance - still both (hop-count or ETX) are converted to a rank, or not.
just a (non-blocking) personal preference by me, I'm fine with naming as is - your choice 😉 |
6f2904f to
426e978
Compare
|
I looked it up and I have to agree with you. I've changed the sentence to your suggestion. |
|
@cgundogan fine for you, too; ready to merge? |
This PR enhances the RPL code to sort the list of parents instead of only comparing whether a parent is better than the current preferred parent.
The aim of this PR is to make it easier for objective functions to determine the parent set.
If the objective function defines the
which_parentfunction such that the list is sorted based on how good (best rank or whatever the OF defines) the parent list should start automatically with the preferred parent, folowed by the rest of the parent set.Since the parent set is needed for rank calculation, the
calc_rankfunction can then iterate over the parent set, and assume that the first N parents from the parent list is his parent set, where N is the parent set. If it encounters an unacceptable parent within the first N parent, it can assume that the following parents are also unacceptable.The advantage is that the
calc_rankfunction only has to iterate over the parent list and not have to determine which parents are in the parent set.This requires a small API change in the RPL objective function. The
which_parentfunction needs to return an integer in the same way as thestrcmpfunction [-1, 0, 1], based on which parent is better.