It is observed that TIPC service binding order will not be kept in the publication event report to user if the service is subscribed after the bindings.
For example, services are bound by application in the following order: Server: bound port A to {18888,66,66} scope 2 Server: bound port A to {18888,33,33} scope 2 Now, if a client subscribes to the service range (e.g. {18888, 0-100}), it will get the 'TIPC_PUBLISHED' events in that binding order only when the subscription is started before the bindings. Otherwise, if started after the bindings, the events will arrive in the opposite order: Client: received event for published {18888,33,33} Client: received event for published {18888,66,66} For the latter case, it is clear that the bindings have existed in the name table already, so when reported, the events' order will follow the order of the rbtree binding nodes (- a node with lesser 'lower'/'upper' range value will be first). This is correct as we provide the tracking on a specific service status (available or not), not the relationship between multiple services. However, some users expect to see the same order of arriving events irrespective of when the subscription is issued. This turns out to be easy to fix. We now add functionality to ensure that publication events always are issued in the same temporal order as the corresponding bindings were performed. Acked-by: Jon Maloy <jon.ma...@ericsson.com> Signed-off-by: Tuong Lien <tuong.t.l...@dektech.com.au> --- net/tipc/name_table.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index 66a65c2cdb23..a98cfba7ed93 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -35,6 +35,7 @@ */ #include <net/sock.h> +#include <linux/list_sort.h> #include "core.h" #include "netlink.h" #include "name_table.h" @@ -54,6 +55,8 @@ * Used by closest_first lookup and multicast lookup algorithm * @all_publ: all publications identical to this one, whatever node and scope * Used by round-robin lookup algorithm + * @list: to form a list of interested service ranges + * @id: the service range's ID in the same tipc service */ struct service_range { u32 lower; @@ -61,11 +64,14 @@ struct service_range { struct rb_node tree_node; struct list_head local_publ; struct list_head all_publ; + struct list_head list; + u16 id; }; /** * struct tipc_service - container for all published instances of a service type * @type: 32 bit 'type' value for service + * @range_cnt: increasing counter for service ranges in this service * @ranges: rb tree containing all service ranges for this service * @service_list: links to adjacent name ranges in hash chain * @subscriptions: list of subscriptions for this service type @@ -74,6 +80,7 @@ struct service_range { */ struct tipc_service { u32 type; + u16 range_cnt; struct rb_root ranges; struct hlist_node service_list; struct list_head subscriptions; @@ -209,6 +216,7 @@ static struct service_range *tipc_service_create_range(struct tipc_service *sc, return NULL; sr->lower = lower; sr->upper = upper; + sr->id = sc->range_cnt++; INIT_LIST_HEAD(&sr->local_publ); INIT_LIST_HEAD(&sr->all_publ); rb_link_node(&sr->tree_node, parent, n); @@ -277,6 +285,17 @@ static struct publication *tipc_service_remove_publ(struct service_range *sr, return NULL; } +static int service_range_cmp(void *priv, struct list_head *a, + struct list_head *b) +{ + struct service_range *sra, *srb; + + sra = container_of(a, struct service_range, list); + srb = container_of(b, struct service_range, list); + + return more(sra->id, srb->id); +} + /** * tipc_service_subscribe - attach a subscription, and optionally * issue the prescribed number of events if there is any service @@ -287,6 +306,7 @@ static void tipc_service_subscribe(struct tipc_service *service, { struct tipc_subscr *sb = &sub->evt.s; struct service_range *sr; + struct list_head sr_list; struct tipc_name_seq ns; struct publication *p; struct rb_node *n; @@ -302,14 +322,19 @@ static void tipc_service_subscribe(struct tipc_service *service, if (tipc_sub_read(sb, filter) & TIPC_SUB_NO_STATUS) return; + INIT_LIST_HEAD(&sr_list); for (n = rb_first(&service->ranges); n; n = rb_next(n)) { sr = container_of(n, struct service_range, tree_node); if (sr->lower > ns.upper) break; if (!tipc_sub_check_overlap(&ns, sr->lower, sr->upper)) continue; - first = true; + list_add(&sr->list, &sr_list); + } + list_sort(NULL, &sr_list, service_range_cmp); + list_for_each_entry(sr, &sr_list, list) { + first = true; list_for_each_entry(p, &sr->all_publ, all_publ) { tipc_sub_report_overlap(sub, sr->lower, sr->upper, TIPC_PUBLISHED, p->port, -- 2.13.7 _______________________________________________ tipc-discussion mailing list tipc-discussion@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/tipc-discussion