Commit 8985ecc7 authored by Jon Maloy's avatar Jon Maloy Committed by David S. Miller

tipc: simplify endianness handling in topology subscriber

Because of the requirement for total distribution transparency, users
send subscriptions and receive topology events in their own host format.
It is up to the topology server to determine this format and do the
correct conversions to and from its own host format when needed.

Until now, this has been handled in a rather non-transparent way inside
the topology server and subscriber code, leading to unnecessary
complexity when creating subscriptions and issuing events.

We now improve this situation by adding two new macros, tipc_sub_read()
and tipc_evt_write(). Both those functions calculate the need for
conversion internally before performing their respective operations.
Hence, all handling of such conversions become transparent to the rest
of the code.
Acked-by: default avatarYing Xue <ying.xue@windriver.com>
Signed-off-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 414574a0
...@@ -412,18 +412,22 @@ static struct publication *tipc_nameseq_remove_publ(struct net *net, ...@@ -412,18 +412,22 @@ static struct publication *tipc_nameseq_remove_publ(struct net *net,
* sequence overlapping with the requested sequence * sequence overlapping with the requested sequence
*/ */
static void tipc_nameseq_subscribe(struct name_seq *nseq, static void tipc_nameseq_subscribe(struct name_seq *nseq,
struct tipc_subscription *s, struct tipc_subscription *sub)
bool status)
{ {
struct sub_seq *sseq = nseq->sseqs; struct sub_seq *sseq = nseq->sseqs;
struct tipc_name_seq ns; struct tipc_name_seq ns;
struct tipc_subscr *s = &sub->evt.s;
bool no_status;
tipc_subscrp_convert_seq(&s->evt.s.seq, s->swap, &ns); ns.type = tipc_sub_read(s, seq.type);
ns.lower = tipc_sub_read(s, seq.lower);
ns.upper = tipc_sub_read(s, seq.upper);
no_status = tipc_sub_read(s, filter) & TIPC_SUB_NO_STATUS;
tipc_subscrp_get(s); tipc_subscrp_get(sub);
list_add(&s->nameseq_list, &nseq->subscriptions); list_add(&sub->nameseq_list, &nseq->subscriptions);
if (!status || !sseq) if (no_status || !sseq)
return; return;
while (sseq != &nseq->sseqs[nseq->first_free]) { while (sseq != &nseq->sseqs[nseq->first_free]) {
...@@ -433,7 +437,7 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq, ...@@ -433,7 +437,7 @@ static void tipc_nameseq_subscribe(struct name_seq *nseq,
int must_report = 1; int must_report = 1;
list_for_each_entry(crs, &info->zone_list, zone_list) { list_for_each_entry(crs, &info->zone_list, zone_list) {
tipc_subscrp_report_overlap(s, sseq->lower, tipc_subscrp_report_overlap(sub, sseq->lower,
sseq->upper, sseq->upper,
TIPC_PUBLISHED, TIPC_PUBLISHED,
crs->ref, crs->node, crs->ref, crs->node,
...@@ -808,11 +812,12 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref, ...@@ -808,11 +812,12 @@ int tipc_nametbl_withdraw(struct net *net, u32 type, u32 lower, u32 ref,
/** /**
* tipc_nametbl_subscribe - add a subscription object to the name table * tipc_nametbl_subscribe - add a subscription object to the name table
*/ */
void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status) void tipc_nametbl_subscribe(struct tipc_subscription *sub)
{ {
struct tipc_server *srv = s->server; struct tipc_server *srv = sub->server;
struct tipc_net *tn = tipc_net(srv->net); struct tipc_net *tn = tipc_net(srv->net);
u32 type = tipc_subscrp_convert_seq_type(s->evt.s.seq.type, s->swap); struct tipc_subscr *s = &sub->evt.s;
u32 type = tipc_sub_read(s, seq.type);
int index = hash(type); int index = hash(type);
struct name_seq *seq; struct name_seq *seq;
struct tipc_name_seq ns; struct tipc_name_seq ns;
...@@ -823,10 +828,12 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status) ...@@ -823,10 +828,12 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status)
seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]); seq = tipc_nameseq_create(type, &tn->nametbl->seq_hlist[index]);
if (seq) { if (seq) {
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
tipc_nameseq_subscribe(seq, s, status); tipc_nameseq_subscribe(seq, sub);
spin_unlock_bh(&seq->lock); spin_unlock_bh(&seq->lock);
} else { } else {
tipc_subscrp_convert_seq(&s->evt.s.seq, s->swap, &ns); ns.type = tipc_sub_read(s, seq.type);
ns.lower = tipc_sub_read(s, seq.lower);
ns.upper = tipc_sub_read(s, seq.upper);
pr_warn("Failed to create subscription for {%u,%u,%u}\n", pr_warn("Failed to create subscription for {%u,%u,%u}\n",
ns.type, ns.lower, ns.upper); ns.type, ns.lower, ns.upper);
} }
...@@ -836,19 +843,20 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status) ...@@ -836,19 +843,20 @@ void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status)
/** /**
* tipc_nametbl_unsubscribe - remove a subscription object from name table * tipc_nametbl_unsubscribe - remove a subscription object from name table
*/ */
void tipc_nametbl_unsubscribe(struct tipc_subscription *s) void tipc_nametbl_unsubscribe(struct tipc_subscription *sub)
{ {
struct tipc_server *srv = s->server; struct tipc_server *srv = sub->server;
struct tipc_subscr *s = &sub->evt.s;
struct tipc_net *tn = tipc_net(srv->net); struct tipc_net *tn = tipc_net(srv->net);
struct name_seq *seq; struct name_seq *seq;
u32 type = tipc_subscrp_convert_seq_type(s->evt.s.seq.type, s->swap); u32 type = tipc_sub_read(s, seq.type);
spin_lock_bh(&tn->nametbl_lock); spin_lock_bh(&tn->nametbl_lock);
seq = nametbl_find_seq(srv->net, type); seq = nametbl_find_seq(srv->net, type);
if (seq != NULL) { if (seq != NULL) {
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
list_del_init(&s->nameseq_list); list_del_init(&sub->nameseq_list);
tipc_subscrp_put(s); tipc_subscrp_put(sub);
if (!seq->first_free && list_empty(&seq->subscriptions)) { if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init_rcu(&seq->ns_list); hlist_del_init_rcu(&seq->ns_list);
kfree(seq->sseqs); kfree(seq->sseqs);
......
...@@ -120,7 +120,7 @@ struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type, ...@@ -120,7 +120,7 @@ struct publication *tipc_nametbl_insert_publ(struct net *net, u32 type,
struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type, struct publication *tipc_nametbl_remove_publ(struct net *net, u32 type,
u32 lower, u32 node, u32 ref, u32 lower, u32 node, u32 ref,
u32 key); u32 key);
void tipc_nametbl_subscribe(struct tipc_subscription *s, bool status); void tipc_nametbl_subscribe(struct tipc_subscription *s);
void tipc_nametbl_unsubscribe(struct tipc_subscription *s); void tipc_nametbl_unsubscribe(struct tipc_subscription *s);
int tipc_nametbl_init(struct net *net); int tipc_nametbl_init(struct net *net);
void tipc_nametbl_stop(struct net *net); void tipc_nametbl_stop(struct net *net);
......
...@@ -98,18 +98,6 @@ static bool connected(struct tipc_conn *con) ...@@ -98,18 +98,6 @@ static bool connected(struct tipc_conn *con)
return con && test_bit(CF_CONNECTED, &con->flags); return con && test_bit(CF_CONNECTED, &con->flags);
} }
/**
* htohl - convert value to endianness used by destination
* @in: value to convert
* @swap: non-zero if endianness must be reversed
*
* Returns converted value
*/
static u32 htohl(u32 in, int swap)
{
return swap ? swab32(in) : in;
}
static void tipc_conn_kref_release(struct kref *kref) static void tipc_conn_kref_release(struct kref *kref)
{ {
struct tipc_conn *con = container_of(kref, struct tipc_conn, kref); struct tipc_conn *con = container_of(kref, struct tipc_conn, kref);
...@@ -285,21 +273,12 @@ static int tipc_con_rcv_sub(struct tipc_server *srv, ...@@ -285,21 +273,12 @@ static int tipc_con_rcv_sub(struct tipc_server *srv,
struct tipc_subscr *s) struct tipc_subscr *s)
{ {
struct tipc_subscription *sub; struct tipc_subscription *sub;
bool status;
int swap;
/* Determine subscriber's endianness */
swap = !(s->filter & (TIPC_SUB_PORTS | TIPC_SUB_SERVICE |
TIPC_SUB_CANCEL));
/* Detect & process a subscription cancellation request */ if (tipc_sub_read(s, filter) & TIPC_SUB_CANCEL) {
if (s->filter & htohl(TIPC_SUB_CANCEL, swap)) {
s->filter &= ~htohl(TIPC_SUB_CANCEL, swap);
tipc_con_delete_sub(con, s); tipc_con_delete_sub(con, s);
return 0; return 0;
} }
status = !(s->filter & htohl(TIPC_SUB_NO_STATUS, swap)); sub = tipc_subscrp_subscribe(srv, s, con->conid);
sub = tipc_subscrp_subscribe(srv, s, con->conid, swap, status);
if (!sub) if (!sub)
return -1; return -1;
......
...@@ -38,32 +38,19 @@ ...@@ -38,32 +38,19 @@
#include "name_table.h" #include "name_table.h"
#include "subscr.h" #include "subscr.h"
/**
* htohl - convert value to endianness used by destination
* @in: value to convert
* @swap: non-zero if endianness must be reversed
*
* Returns converted value
*/
static u32 htohl(u32 in, int swap)
{
return swap ? swab32(in) : in;
}
static void tipc_subscrp_send_event(struct tipc_subscription *sub, static void tipc_subscrp_send_event(struct tipc_subscription *sub,
u32 found_lower, u32 found_upper, u32 found_lower, u32 found_upper,
u32 event, u32 port, u32 node) u32 event, u32 port, u32 node)
{ {
struct tipc_event *evt = &sub->evt; struct tipc_event *evt = &sub->evt;
bool swap = sub->swap;
if (sub->inactive) if (sub->inactive)
return; return;
evt->event = htohl(event, swap); tipc_evt_write(evt, event, event);
evt->found_lower = htohl(found_lower, swap); tipc_evt_write(evt, found_lower, found_lower);
evt->found_upper = htohl(found_upper, swap); tipc_evt_write(evt, found_upper, found_upper);
evt->port.ref = htohl(port, swap); tipc_evt_write(evt, port.ref, port);
evt->port.node = htohl(node, swap); tipc_evt_write(evt, port.node, node);
tipc_conn_queue_evt(sub->server, sub->conid, event, evt); tipc_conn_queue_evt(sub->server, sub->conid, event, evt);
} }
...@@ -85,29 +72,22 @@ int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower, ...@@ -85,29 +72,22 @@ int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
return 1; return 1;
} }
u32 tipc_subscrp_convert_seq_type(u32 type, int swap) void tipc_subscrp_report_overlap(struct tipc_subscription *sub,
{ u32 found_lower, u32 found_upper,
return htohl(type, swap); u32 event, u32 port, u32 node,
} u32 scope, int must)
void tipc_subscrp_convert_seq(struct tipc_name_seq *in, int swap,
struct tipc_name_seq *out)
{
out->type = htohl(in->type, swap);
out->lower = htohl(in->lower, swap);
out->upper = htohl(in->upper, swap);
}
void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower,
u32 found_upper, u32 event, u32 port_ref,
u32 node, u32 scope, int must)
{ {
u32 filter = htohl(sub->evt.s.filter, sub->swap);
struct tipc_name_seq seq; struct tipc_name_seq seq;
struct tipc_subscr *s = &sub->evt.s;
u32 filter = tipc_sub_read(s, filter);
seq.type = tipc_sub_read(s, seq.type);
seq.lower = tipc_sub_read(s, seq.lower);
seq.upper = tipc_sub_read(s, seq.upper);
tipc_subscrp_convert_seq(&sub->evt.s.seq, sub->swap, &seq);
if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper)) if (!tipc_subscrp_check_overlap(&seq, found_lower, found_upper))
return; return;
if (!must && !(filter & TIPC_SUB_PORTS)) if (!must && !(filter & TIPC_SUB_PORTS))
return; return;
if (filter & TIPC_SUB_CLUSTER_SCOPE && scope == TIPC_NODE_SCOPE) if (filter & TIPC_SUB_CLUSTER_SCOPE && scope == TIPC_NODE_SCOPE)
...@@ -116,7 +96,7 @@ void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower, ...@@ -116,7 +96,7 @@ void tipc_subscrp_report_overlap(struct tipc_subscription *sub, u32 found_lower,
return; return;
spin_lock(&sub->lock); spin_lock(&sub->lock);
tipc_subscrp_send_event(sub, found_lower, found_upper, tipc_subscrp_send_event(sub, found_lower, found_upper,
event, port_ref, node); event, port, node);
spin_unlock(&sub->lock); spin_unlock(&sub->lock);
} }
...@@ -156,11 +136,11 @@ void tipc_subscrp_get(struct tipc_subscription *subscription) ...@@ -156,11 +136,11 @@ void tipc_subscrp_get(struct tipc_subscription *subscription)
static struct tipc_subscription *tipc_subscrp_create(struct tipc_server *srv, static struct tipc_subscription *tipc_subscrp_create(struct tipc_server *srv,
struct tipc_subscr *s, struct tipc_subscr *s,
int conid, bool swap) int conid)
{ {
struct tipc_net *tn = tipc_net(srv->net); struct tipc_net *tn = tipc_net(srv->net);
struct tipc_subscription *sub; struct tipc_subscription *sub;
u32 filter = htohl(s->filter, swap); u32 filter = tipc_sub_read(s, filter);
/* Refuse subscription if global limit exceeded */ /* Refuse subscription if global limit exceeded */
if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) { if (atomic_read(&tn->subscription_count) >= TIPC_MAX_SUBSCRIPTIONS) {
...@@ -177,39 +157,38 @@ static struct tipc_subscription *tipc_subscrp_create(struct tipc_server *srv, ...@@ -177,39 +157,38 @@ static struct tipc_subscription *tipc_subscrp_create(struct tipc_server *srv,
} }
/* Initialize subscription object */ /* Initialize subscription object */
if (filter & TIPC_SUB_PORTS && filter & TIPC_SUB_SERVICE)
goto err;
if (tipc_sub_read(s, seq.lower) > tipc_sub_read(s, seq.upper))
goto err;
sub->server = srv; sub->server = srv;
sub->conid = conid; sub->conid = conid;
sub->inactive = false; sub->inactive = false;
if (((filter & TIPC_SUB_PORTS) && (filter & TIPC_SUB_SERVICE)) ||
(htohl(s->seq.lower, swap) > htohl(s->seq.upper, swap))) {
pr_warn("Subscription rejected, illegal request\n");
kfree(sub);
return NULL;
}
sub->swap = swap;
memcpy(&sub->evt.s, s, sizeof(*s)); memcpy(&sub->evt.s, s, sizeof(*s));
spin_lock_init(&sub->lock); spin_lock_init(&sub->lock);
atomic_inc(&tn->subscription_count); atomic_inc(&tn->subscription_count);
kref_init(&sub->kref); kref_init(&sub->kref);
return sub; return sub;
err:
pr_warn("Subscription rejected, illegal request\n");
kfree(sub);
return NULL;
} }
struct tipc_subscription *tipc_subscrp_subscribe(struct tipc_server *srv, struct tipc_subscription *tipc_subscrp_subscribe(struct tipc_server *srv,
struct tipc_subscr *s, struct tipc_subscr *s,
int conid, bool swap, int conid)
bool status)
{ {
struct tipc_subscription *sub = NULL; struct tipc_subscription *sub = NULL;
u32 timeout; u32 timeout;
sub = tipc_subscrp_create(srv, s, conid, swap); sub = tipc_subscrp_create(srv, s, conid);
if (!sub) if (!sub)
return NULL; return NULL;
tipc_nametbl_subscribe(sub, status); tipc_nametbl_subscribe(sub);
timer_setup(&sub->timer, tipc_subscrp_timeout, 0); timer_setup(&sub->timer, tipc_subscrp_timeout, 0);
timeout = htohl(sub->evt.s.timeout, swap); timeout = tipc_sub_read(&sub->evt.s, timeout);
if (timeout != TIPC_WAIT_FOREVER) if (timeout != TIPC_WAIT_FOREVER)
mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout)); mod_timer(&sub->timer, jiffies + msecs_to_jiffies(timeout));
return sub; return sub;
......
...@@ -52,7 +52,6 @@ struct tipc_conn; ...@@ -52,7 +52,6 @@ struct tipc_conn;
* @timer: timer governing subscription duration (optional) * @timer: timer governing subscription duration (optional)
* @nameseq_list: adjacent subscriptions in name sequence's subscription list * @nameseq_list: adjacent subscriptions in name sequence's subscription list
* @subscrp_list: adjacent subscriptions in subscriber's subscription list * @subscrp_list: adjacent subscriptions in subscriber's subscription list
* @swap: indicates if subscriber uses opposite endianness in its messages
* @evt: template for events generated by subscription * @evt: template for events generated by subscription
*/ */
struct tipc_subscription { struct tipc_subscription {
...@@ -63,28 +62,47 @@ struct tipc_subscription { ...@@ -63,28 +62,47 @@ struct tipc_subscription {
struct list_head subscrp_list; struct list_head subscrp_list;
struct tipc_event evt; struct tipc_event evt;
int conid; int conid;
bool swap;
bool inactive; bool inactive;
spinlock_t lock; /* serialize up/down and timer events */ spinlock_t lock; /* serialize up/down and timer events */
}; };
struct tipc_subscription *tipc_subscrp_subscribe(struct tipc_server *srv, struct tipc_subscription *tipc_subscrp_subscribe(struct tipc_server *srv,
struct tipc_subscr *s, struct tipc_subscr *s,
int conid, bool swap, int conid);
bool status);
void tipc_sub_delete(struct tipc_subscription *sub); void tipc_sub_delete(struct tipc_subscription *sub);
int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower, int tipc_subscrp_check_overlap(struct tipc_name_seq *seq, u32 found_lower,
u32 found_upper); u32 found_upper);
void tipc_subscrp_report_overlap(struct tipc_subscription *sub, void tipc_subscrp_report_overlap(struct tipc_subscription *sub,
u32 found_lower, u32 found_upper, u32 event, u32 found_lower, u32 found_upper,
u32 port_ref, u32 node, u32 scope, int must); u32 event, u32 port, u32 node,
void tipc_subscrp_convert_seq(struct tipc_name_seq *in, int swap, u32 scope, int must);
struct tipc_name_seq *out);
u32 tipc_subscrp_convert_seq_type(u32 type, int swap);
int tipc_topsrv_start(struct net *net); int tipc_topsrv_start(struct net *net);
void tipc_topsrv_stop(struct net *net); void tipc_topsrv_stop(struct net *net);
void tipc_subscrp_put(struct tipc_subscription *subscription); void tipc_subscrp_put(struct tipc_subscription *subscription);
void tipc_subscrp_get(struct tipc_subscription *subscription); void tipc_subscrp_get(struct tipc_subscription *subscription);
#define TIPC_FILTER_MASK (TIPC_SUB_PORTS | TIPC_SUB_SERVICE | TIPC_SUB_CANCEL)
/* tipc_sub_read - return field_ of struct sub_ in host endian format
*/
#define tipc_sub_read(sub_, field_) \
({ \
struct tipc_subscr *sub__ = sub_; \
u32 val__ = (sub__)->field_; \
int swap_ = !((sub__)->filter & TIPC_FILTER_MASK); \
(swap_ ? swab32(val__) : val__); \
})
/* tipc_evt_write - write val_ to field_ of struct evt_ in user endian format
*/
#define tipc_evt_write(evt_, field_, val_) \
({ \
struct tipc_event *evt__ = evt_; \
u32 val__ = val_; \
int swap_ = !((evt__)->s.filter & (TIPC_FILTER_MASK)); \
(evt__)->field_ = swap_ ? swab32(val__) : val__; \
})
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment