Commit 19415dbf authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'tipc-introduce-128-bit-auto-configurable-node-id'



Jon Maloy says:

====================
tipc: introduce 128-bit auto-configurable node id

We introduce a 128-bit free-format node identity as an alternative to
the legacy <Zone.Cluster.Node> structured 32-bit node address.

We also make configuration of this identity optional; if a bearer is
enabled without a pre-configured node id it will be set automatically
based on the used interface's MAC or IP address.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 59461949 52dfae5c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -169,6 +169,8 @@ enum {
	TIPC_NLA_NET_UNSPEC,
	TIPC_NLA_NET_ID,		/* u32 */
	TIPC_NLA_NET_ADDR,		/* u32 */
	TIPC_NLA_NET_NODEID,		/* u64 */
	TIPC_NLA_NET_NODEID_W1,		/* u64 */

	__TIPC_NLA_NET_MAX,
	TIPC_NLA_NET_MAX = __TIPC_NLA_NET_MAX - 1
+68 −60
Original line number Diff line number Diff line
/*
 * net/tipc/addr.c: TIPC address utility routines
 *
 * Copyright (c) 2000-2006, Ericsson AB
 * Copyright (c) 2000-2006, 2018, Ericsson AB
 * Copyright (c) 2004-2005, 2010-2011, Wind River Systems
 * All rights reserved.
 *
@@ -34,82 +34,90 @@
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/kernel.h>
#include "addr.h"
#include "core.h"

/**
 * in_own_cluster - test for cluster inclusion; <0.0.0> always matches
 */
int in_own_cluster(struct net *net, u32 addr)
bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr)
{
	return in_own_cluster_exact(net, addr) || !addr;
	if (!domain || (domain == addr))
		return true;
	if (!legacy_format)
		return false;
	if (domain == tipc_cluster_mask(addr)) /* domain <Z.C.0> */
		return true;
	if (domain == (addr & TIPC_ZONE_CLUSTER_MASK)) /* domain <Z.C.0> */
		return true;
	if (domain == (addr & TIPC_ZONE_MASK)) /* domain <Z.0.0> */
		return true;
	return false;
}

int in_own_cluster_exact(struct net *net, u32 addr)
void tipc_set_node_id(struct net *net, u8 *id)
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_net *tn = tipc_net(net);
	u32 *tmp = (u32 *)id;

	return !((addr ^ tn->own_addr) >> 12);
	memcpy(tn->node_id, id, NODE_ID_LEN);
	tipc_nodeid2string(tn->node_id_string, id);
	tn->trial_addr = tmp[0] ^ tmp[1] ^ tmp[2] ^ tmp[3];
	pr_info("Own node identity %s, cluster identity %u\n",
		tipc_own_id_string(net), tn->net_id);
}

/**
 * in_own_node - test for node inclusion; <0.0.0> always matches
 */
int in_own_node(struct net *net, u32 addr)
void tipc_set_node_addr(struct net *net, u32 addr)
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_net *tn = tipc_net(net);
	u8 node_id[NODE_ID_LEN] = {0,};

	return (addr == tn->own_addr) || !addr;
	tn->node_addr = addr;
	if (!tipc_own_id(net)) {
		sprintf(node_id, "%x", addr);
		tipc_set_node_id(net, node_id);
	}
	tn->trial_addr = addr;
	pr_info("32-bit node address hash set to %x\n", addr);
}

/**
 * tipc_addr_domain_valid - validates a network domain address
 *
 * Accepts <Z.C.N>, <Z.C.0>, <Z.0.0>, and <0.0.0>,
 * where Z, C, and N are non-zero.
 *
 * Returns 1 if domain address is valid, otherwise 0
 */
int tipc_addr_domain_valid(u32 addr)
char *tipc_nodeid2string(char *str, u8 *id)
{
	u32 n = tipc_node(addr);
	u32 c = tipc_cluster(addr);
	u32 z = tipc_zone(addr);
	int i;
	u8 c;

	if (n && (!z || !c))
		return 0;
	if (c && !z)
		return 0;
	return 1;
	/* Already a string ? */
	for (i = 0; i < NODE_ID_LEN; i++) {
		c = id[i];
		if (c >= '0' && c <= '9')
			continue;
		if (c >= 'A' && c <= 'Z')
			continue;
		if (c >= 'a' && c <= 'z')
			continue;
		if (c == '.')
			continue;
		if (c == ':')
			continue;
		if (c == '_')
			continue;
		if (c == '-')
			continue;
		if (c == '@')
			continue;
		if (c != 0)
			break;
	}

/**
 * tipc_addr_node_valid - validates a proposed network address for this node
 *
 * Accepts <Z.C.N>, where Z, C, and N are non-zero.
 *
 * Returns 1 if address can be used, otherwise 0
 */
int tipc_addr_node_valid(u32 addr)
{
	return tipc_addr_domain_valid(addr) && tipc_node(addr);
	if (i == NODE_ID_LEN) {
		memcpy(str, id, NODE_ID_LEN);
		str[NODE_ID_LEN] = 0;
		return str;
	}

int tipc_in_scope(u32 domain, u32 addr)
{
	if (!domain || (domain == addr))
		return 1;
	if (domain == tipc_cluster_mask(addr)) /* domain <Z.C.0> */
		return 1;
	if (domain == tipc_zone_mask(addr)) /* domain <Z.0.0> */
		return 1;
	return 0;
}
	/* Translate to hex string */
	for (i = 0; i < NODE_ID_LEN; i++)
		sprintf(&str[2 * i], "%02x", id[i]);

char *tipc_addr_string_fill(char *string, u32 addr)
{
	snprintf(string, 16, "<%u.%u.%u>",
		 tipc_zone(addr), tipc_cluster(addr), tipc_node(addr));
	return string;
	/* Strip off trailing zeroes */
	for (i = NODE_ID_STR_LEN - 2; str[i] == '0'; i--)
		str[i] = 0;

	return str;
}
+22 −15
Original line number Diff line number Diff line
/*
 * net/tipc/addr.h: Include file for TIPC address utility routines
 *
 * Copyright (c) 2000-2006, Ericsson AB
 * Copyright (c) 2000-2006, 2018, Ericsson AB
 * Copyright (c) 2004-2005, Wind River Systems
 * All rights reserved.
 *
@@ -45,14 +45,21 @@

static inline u32 tipc_own_addr(struct net *net)
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	return tipc_net(net)->node_addr;
}

static inline u8 *tipc_own_id(struct net *net)
{
	struct tipc_net *tn = tipc_net(net);

	return tn->own_addr;
	if (!strlen(tn->node_id_string))
		return NULL;
	return tn->node_id;
}

static inline u32 tipc_zone_mask(u32 addr)
static inline char *tipc_own_id_string(struct net *net)
{
	return addr & TIPC_ZONE_MASK;
	return tipc_net(net)->node_id_string;
}

static inline u32 tipc_cluster_mask(u32 addr)
@@ -70,15 +77,15 @@ static inline int tipc_scope2node(struct net *net, int sc)
	return sc != TIPC_NODE_SCOPE ? 0 : tipc_own_addr(net);
}

u32 tipc_own_addr(struct net *net);
int in_own_cluster(struct net *net, u32 addr);
int in_own_cluster_exact(struct net *net, u32 addr);
int in_own_node(struct net *net, u32 addr);
u32 addr_domain(struct net *net, u32 sc);
int tipc_addr_domain_valid(u32);
int tipc_addr_node_valid(u32 addr);
int tipc_in_scope(u32 domain, u32 addr);
int tipc_addr_scope(u32 domain);
char *tipc_addr_string_fill(char *string, u32 addr);
static inline int in_own_node(struct net *net, u32 addr)
{
	return addr == tipc_own_addr(net) || !addr;
}

bool tipc_in_scope(bool legacy_format, u32 domain, u32 addr);
void tipc_set_node_id(struct net *net, u8 *id);
void tipc_set_node_addr(struct net *net, u32 addr);
char *tipc_nodeid2string(char *str, u8 *id);
u32 tipc_node_id2hash(u8 *id128);

#endif
+71 −81
Original line number Diff line number Diff line
@@ -210,7 +210,7 @@ void tipc_bearer_add_dest(struct net *net, u32 bearer_id, u32 dest)
	rcu_read_lock();
	b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
	if (b)
		tipc_disc_add_dest(b->link_req);
		tipc_disc_add_dest(b->disc);
	rcu_read_unlock();
}

@@ -222,7 +222,7 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
	rcu_read_lock();
	b = rcu_dereference_rtnl(tn->bearer_list[bearer_id]);
	if (b)
		tipc_disc_remove_dest(b->link_req);
		tipc_disc_remove_dest(b->disc);
	rcu_read_unlock();
}

@@ -230,88 +230,67 @@ void tipc_bearer_remove_dest(struct net *net, u32 bearer_id, u32 dest)
 * tipc_enable_bearer - enable bearer with the given name
 */
static int tipc_enable_bearer(struct net *net, const char *name,
			      u32 disc_domain, u32 priority,
			      u32 disc_domain, u32 prio,
			      struct nlattr *attr[])
{
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	struct tipc_net *tn = tipc_net(net);
	struct tipc_bearer_names b_names;
	int with_this_prio = 1;
	struct tipc_bearer *b;
	struct tipc_media *m;
	struct tipc_bearer_names b_names;
	struct sk_buff *skb;
	char addr_string[16];
	u32 bearer_id;
	u32 with_this_prio;
	u32 i;
	int bearer_id = 0;
	int res = -EINVAL;
	char *errstr = "";

	if (!tn->own_addr) {
		pr_warn("Bearer <%s> rejected, not supported in standalone mode\n",
			name);
		return -ENOPROTOOPT;
	}
	if (!bearer_name_validate(name, &b_names)) {
		pr_warn("Bearer <%s> rejected, illegal name\n", name);
		return -EINVAL;
	}
	if (tipc_addr_domain_valid(disc_domain) &&
	    (disc_domain != tn->own_addr)) {
		if (tipc_in_scope(disc_domain, tn->own_addr)) {
			disc_domain = tn->own_addr & TIPC_ZONE_CLUSTER_MASK;
			res = 0;   /* accept any node in own cluster */
		} else if (in_own_cluster_exact(net, disc_domain))
			res = 0;   /* accept specified node in own cluster */
	}
	if (res) {
		pr_warn("Bearer <%s> rejected, illegal discovery domain\n",
			name);
		return -EINVAL;
		errstr = "illegal name";
		goto rejected;
	}
	if ((priority > TIPC_MAX_LINK_PRI) &&
	    (priority != TIPC_MEDIA_LINK_PRI)) {
		pr_warn("Bearer <%s> rejected, illegal priority\n", name);
		return -EINVAL;

	if (prio > TIPC_MAX_LINK_PRI && prio != TIPC_MEDIA_LINK_PRI) {
		errstr = "illegal priority";
		goto rejected;
	}

	m = tipc_media_find(b_names.media_name);
	if (!m) {
		pr_warn("Bearer <%s> rejected, media <%s> not registered\n",
			name, b_names.media_name);
		return -EINVAL;
		errstr = "media not registered";
		goto rejected;
	}

	if (priority == TIPC_MEDIA_LINK_PRI)
		priority = m->priority;
	if (prio == TIPC_MEDIA_LINK_PRI)
		prio = m->priority;

restart:
	bearer_id = MAX_BEARERS;
	with_this_prio = 1;
	for (i = MAX_BEARERS; i-- != 0; ) {
		b = rtnl_dereference(tn->bearer_list[i]);
		if (!b) {
			bearer_id = i;
			continue;
		}
	/* Check new bearer vs existing ones and find free bearer id if any */
	while (bearer_id < MAX_BEARERS) {
		b = rtnl_dereference(tn->bearer_list[bearer_id]);
		if (!b)
			break;
		if (!strcmp(name, b->name)) {
			pr_warn("Bearer <%s> rejected, already enabled\n",
				name);
			return -EINVAL;
		}
		if ((b->priority == priority) &&
		    (++with_this_prio > 2)) {
			if (priority-- == 0) {
				pr_warn("Bearer <%s> rejected, duplicate priority\n",
					name);
				return -EINVAL;
			}
			pr_warn("Bearer <%s> priority adjustment required %u->%u\n",
				name, priority + 1, priority);
			goto restart;
			errstr = "already enabled";
			goto rejected;
		}
		bearer_id++;
		if (b->priority != prio)
			continue;
		if (++with_this_prio <= 2)
			continue;
		pr_warn("Bearer <%s>: already 2 bearers with priority %u\n",
			name, prio);
		if (prio == TIPC_MIN_LINK_PRI) {
			errstr = "cannot adjust to lower";
			goto rejected;
		}
		pr_warn("Bearer <%s>: trying with adjusted priority\n", name);
		prio--;
		bearer_id = 0;
		with_this_prio = 1;
	}

	if (bearer_id >= MAX_BEARERS) {
		pr_warn("Bearer <%s> rejected, bearer limit reached (%u)\n",
			name, MAX_BEARERS);
		return -EINVAL;
		errstr = "max 3 bearers permitted";
		goto rejected;
	}

	b = kzalloc(sizeof(*b), GFP_ATOMIC);
@@ -322,10 +301,9 @@ restart:
	b->media = m;
	res = m->enable_media(net, b, attr);
	if (res) {
		pr_warn("Bearer <%s> rejected, enable failure (%d)\n",
			name, -res);
		kfree(b);
		return -EINVAL;
		errstr = "failed to enable media";
		goto rejected;
	}

	b->identity = bearer_id;
@@ -333,15 +311,15 @@ restart:
	b->window = m->window;
	b->domain = disc_domain;
	b->net_plane = bearer_id + 'A';
	b->priority = priority;
	b->priority = prio;
	test_and_set_bit_lock(0, &b->up);

	res = tipc_disc_create(net, b, &b->bcast_addr, &skb);
	if (res) {
		bearer_disable(net, b);
		pr_warn("Bearer <%s> rejected, discovery object creation failed\n",
			name);
		return -EINVAL;
		kfree(b);
		errstr = "failed to create discoverer";
		goto rejected;
	}

	rcu_assign_pointer(tn->bearer_list[bearer_id], b);
@@ -353,9 +331,11 @@ restart:
		return -ENOMEM;
	}

	pr_info("Enabled bearer <%s>, discovery domain %s, priority %u\n",
		name,
		tipc_addr_string_fill(addr_string, disc_domain), priority);
	pr_info("Enabled bearer <%s>, priority %u\n", name, prio);

	return res;
rejected:
	pr_warn("Enabling of bearer <%s> rejected, %s\n", name, errstr);
	return res;
}

@@ -385,8 +365,8 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b)
	tipc_node_delete_links(net, bearer_id);
	b->media->disable_media(b);
	RCU_INIT_POINTER(b->media_ptr, NULL);
	if (b->link_req)
		tipc_disc_delete(b->link_req);
	if (b->disc)
		tipc_disc_delete(b->disc);
	RCU_INIT_POINTER(tn->bearer_list[bearer_id], NULL);
	kfree_rcu(b, rcu);
	tipc_mon_delete(net, bearer_id);
@@ -395,11 +375,13 @@ static void bearer_disable(struct net *net, struct tipc_bearer *b)
int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
			 struct nlattr *attr[])
{
	char *dev_name = strchr((const char *)b->name, ':') + 1;
	int hwaddr_len = b->media->hwaddr_len;
	u8 node_id[NODE_ID_LEN] = {0,};
	struct net_device *dev;
	char *driver_name = strchr((const char *)b->name, ':') + 1;

	/* Find device with specified name */
	dev = dev_get_by_name(net, driver_name);
	dev = dev_get_by_name(net, dev_name);
	if (!dev)
		return -ENODEV;
	if (tipc_mtu_bad(dev, 0)) {
@@ -407,6 +389,16 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
		return -EINVAL;
	}

	/* Autoconfigure own node identity if needed */
	if (!tipc_own_id(net) && hwaddr_len <= NODE_ID_LEN) {
		memcpy(node_id, dev->dev_addr, hwaddr_len);
		tipc_net_init(net, node_id, 0);
	}
	if (!tipc_own_id(net)) {
		pr_warn("Failed to obtain node identity\n");
		return -EINVAL;
	}

	/* Associate TIPC bearer with L2 bearer */
	rcu_assign_pointer(b->media_ptr, dev);
	b->pt.dev = dev;
@@ -414,7 +406,7 @@ int tipc_enable_l2_media(struct net *net, struct tipc_bearer *b,
	b->pt.func = tipc_l2_rcv_msg;
	dev_add_pack(&b->pt);
	memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
	memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
	memcpy(b->bcast_addr.value, dev->broadcast, hwaddr_len);
	b->bcast_addr.media_id = b->media->type_id;
	b->bcast_addr.broadcast = TIPC_BROADCAST_SUPPORT;
	b->mtu = dev->mtu;
@@ -861,12 +853,10 @@ int __tipc_nl_bearer_enable(struct sk_buff *skb, struct genl_info *info)
	char *bearer;
	struct nlattr *attrs[TIPC_NLA_BEARER_MAX + 1];
	struct net *net = sock_net(skb->sk);
	struct tipc_net *tn = net_generic(net, tipc_net_id);
	u32 domain;
	u32 domain = 0;
	u32 prio;

	prio = TIPC_MEDIA_LINK_PRI;
	domain = tn->own_addr & TIPC_ZONE_CLUSTER_MASK;

	if (!info->attrs[TIPC_NLA_BEARER])
		return -EINVAL;
+1 −1
Original line number Diff line number Diff line
@@ -159,7 +159,7 @@ struct tipc_bearer {
	u32 tolerance;
	u32 domain;
	u32 identity;
	struct tipc_link_req *link_req;
	struct tipc_discoverer *disc;
	char net_plane;
	unsigned long up;
};
Loading