Commit d6cc76d3 authored by David S. Miller's avatar David S. Miller

Merge branch 'tipc-next'

Jon Maloy says:

====================
tipc: bug fixes and improvements

Intensive and extensive testing has revealed some rather infrequent
problems related to flow control, buffer handling and link
establishment. Commits ##1 to 4 deal with these problems.

The remaining four commits are just code improvments, aiming at
making the code more comprehensible and maintainable. There are
no functional enhancements in this series.

v2: Fixed a typo in commit log #2. Otherwise no changes from v1.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 3fdddd85 9816f061
......@@ -506,18 +506,14 @@ void tipc_bclink_rcv(struct sk_buff *buf)
tipc_node_unlock(node);
tipc_link_bundle_rcv(buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
int ret;
ret = tipc_link_frag_rcv(&node->bclink.reasm_head,
&node->bclink.reasm_tail,
&buf);
if (ret == LINK_REASM_ERROR)
tipc_buf_append(&node->bclink.reasm_buf, &buf);
if (unlikely(!buf && !node->bclink.reasm_buf))
goto unlock;
tipc_bclink_lock();
bclink_accept_pkt(node, seqno);
bcl->stats.recv_fragments++;
if (ret == LINK_REASM_COMPLETE) {
if (buf) {
bcl->stats.recv_fragmented++;
/* Point msg to inner header */
msg = buf_msg(buf);
tipc_bclink_unlock();
goto receive;
......
......@@ -411,28 +411,6 @@ int tipc_disable_bearer(const char *name)
return res;
}
/* tipc_l2_media_addr_set - initialize Ethernet media address structure
*
* Media-dependent "value" field stores MAC address in first 6 bytes
* and zeroes out the remaining bytes.
*/
void tipc_l2_media_addr_set(const struct tipc_bearer *b,
struct tipc_media_addr *a, char *mac)
{
int len = b->media->hwaddr_len;
if (unlikely(sizeof(a->value) < len)) {
WARN_ONCE(1, "Media length invalid\n");
return;
}
memcpy(a->value, mac, len);
memset(a->value + len, 0, sizeof(a->value) - len);
a->media_id = b->media->type_id;
a->broadcast = !memcmp(mac, b->bcast_addr.value, len);
}
int tipc_enable_l2_media(struct tipc_bearer *b)
{
struct net_device *dev;
......@@ -443,21 +421,21 @@ int tipc_enable_l2_media(struct tipc_bearer *b)
if (!dev)
return -ENODEV;
/* Associate TIPC bearer with Ethernet bearer */
/* Associate TIPC bearer with L2 bearer */
rcu_assign_pointer(b->media_ptr, dev);
memset(b->bcast_addr.value, 0, sizeof(b->bcast_addr.value));
memset(&b->bcast_addr, 0, sizeof(b->bcast_addr));
memcpy(b->bcast_addr.value, dev->broadcast, b->media->hwaddr_len);
b->bcast_addr.media_id = b->media->type_id;
b->bcast_addr.broadcast = 1;
b->mtu = dev->mtu;
tipc_l2_media_addr_set(b, &b->addr, (char *)dev->dev_addr);
b->media->raw2addr(b, &b->addr, (char *)dev->dev_addr);
rcu_assign_pointer(dev->tipc_ptr, b);
return 0;
}
/* tipc_disable_l2_media - detach TIPC bearer from an Ethernet interface
/* tipc_disable_l2_media - detach TIPC bearer from an L2 interface
*
* Mark Ethernet bearer as inactive so that incoming buffers are thrown away,
* Mark L2 bearer as inactive so that incoming buffers are thrown away,
* then get worker thread to complete bearer cleanup. (Can't do cleanup
* here because cleanup code needs to sleep and caller holds spinlocks.)
*/
......@@ -473,7 +451,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b)
}
/**
* tipc_l2_send_msg - send a TIPC packet out over an Ethernet interface
* tipc_l2_send_msg - send a TIPC packet out over an L2 interface
* @buf: the packet to be sent
* @b_ptr: the bearer through which the packet is to be sent
* @dest: peer destination address
......@@ -597,7 +575,7 @@ static int tipc_l2_device_event(struct notifier_block *nb, unsigned long evt,
tipc_reset_bearer(b_ptr);
break;
case NETDEV_CHANGEADDR:
tipc_l2_media_addr_set(b_ptr, &b_ptr->addr,
b_ptr->media->raw2addr(b_ptr, &b_ptr->addr,
(char *)dev->dev_addr);
tipc_reset_bearer(b_ptr);
break;
......
......@@ -42,14 +42,12 @@
#define MAX_BEARERS 2
#define MAX_MEDIA 2
/*
* Identifiers associated with TIPC message header media address info
*
* - address info field is 20 bytes long
* - media type identifier located at offset 3
* - remaining bytes vary according to media type
/* Identifiers associated with TIPC message header media address info
* - address info field is 32 bytes long
* - the field's actual content and length is defined per media
* - remaining unused bytes in the field are set to zero
*/
#define TIPC_MEDIA_ADDR_SIZE 20
#define TIPC_MEDIA_ADDR_SIZE 32
#define TIPC_MEDIA_TYPE_OFFSET 3
/*
......@@ -77,9 +75,10 @@ struct tipc_bearer;
* @send_msg: routine which handles buffer transmission
* @enable_media: routine which enables a media
* @disable_media: routine which disables a media
* @addr2str: routine which converts media address to string
* @addr2msg: routine which converts media address to protocol message area
* @msg2addr: routine which converts media address from protocol message area
* @addr2str: convert media address format to string
* @addr2msg: convert from media addr format to discovery msg addr format
* @msg2addr: convert from discovery msg addr format to media addr format
* @raw2addr: convert from raw addr format to media addr format
* @priority: default link (and bearer) priority
* @tolerance: default time (in ms) before declaring link failure
* @window: default window (in packets) before declaring link congestion
......@@ -93,10 +92,16 @@ struct tipc_media {
struct tipc_media_addr *dest);
int (*enable_media)(struct tipc_bearer *b_ptr);
void (*disable_media)(struct tipc_bearer *b_ptr);
int (*addr2str)(struct tipc_media_addr *a, char *str_buf, int str_size);
int (*addr2msg)(struct tipc_media_addr *a, char *msg_area);
int (*msg2addr)(const struct tipc_bearer *b_ptr,
struct tipc_media_addr *a, char *msg_area);
int (*addr2str)(struct tipc_media_addr *addr,
char *strbuf,
int bufsz);
int (*addr2msg)(char *msg, struct tipc_media_addr *addr);
int (*msg2addr)(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg);
int (*raw2addr)(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *raw);
u32 priority;
u32 tolerance;
u32 window;
......@@ -175,8 +180,6 @@ int tipc_media_set_priority(const char *name, u32 new_value);
int tipc_media_set_window(const char *name, u32 new_value);
void tipc_media_addr_printf(char *buf, int len, struct tipc_media_addr *a);
struct sk_buff *tipc_media_get_names(void);
void tipc_l2_media_addr_set(const struct tipc_bearer *b,
struct tipc_media_addr *a, char *mac);
int tipc_enable_l2_media(struct tipc_bearer *b);
void tipc_disable_l2_media(struct tipc_bearer *b);
int tipc_l2_send_msg(struct sk_buff *buf, struct tipc_bearer *b,
......
......@@ -154,10 +154,11 @@ static int __init tipc_init(void)
tipc_max_ports = CONFIG_TIPC_PORTS;
tipc_net_id = 4711;
sysctl_tipc_rmem[0] = CONN_OVERLOAD_LIMIT >> 4 << TIPC_LOW_IMPORTANCE;
sysctl_tipc_rmem[1] = CONN_OVERLOAD_LIMIT >> 4 <<
sysctl_tipc_rmem[0] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
TIPC_LOW_IMPORTANCE;
sysctl_tipc_rmem[1] = TIPC_CONN_OVERLOAD_LIMIT >> 4 <<
TIPC_CRITICAL_IMPORTANCE;
sysctl_tipc_rmem[2] = CONN_OVERLOAD_LIMIT;
sysctl_tipc_rmem[2] = TIPC_CONN_OVERLOAD_LIMIT;
res = tipc_core_start();
if (res)
......
......@@ -57,6 +57,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/rtnetlink.h>
#include <linux/etherdevice.h>
#define TIPC_MOD_VER "2.0.0"
......@@ -187,6 +188,7 @@ static inline void k_term_timer(struct timer_list *timer)
struct tipc_skb_cb {
void *handle;
bool deferred;
struct sk_buff *tail;
};
#define TIPC_SKB_CB(__skb) ((struct tipc_skb_cb *)&((__skb)->cb[0]))
......
/*
* net/tipc/discover.c
*
* Copyright (c) 2003-2006, Ericsson AB
* Copyright (c) 2003-2006, 2014, Ericsson AB
* Copyright (c) 2005-2006, 2010-2011, Wind River Systems
* All rights reserved.
*
......@@ -83,7 +83,7 @@ static void tipc_disc_init_msg(struct sk_buff *buf, u32 type,
msg_set_node_sig(msg, tipc_random);
msg_set_dest_domain(msg, dest_domain);
msg_set_bc_netid(msg, tipc_net_id);
b_ptr->media->addr2msg(&b_ptr->addr, msg_media_addr(msg));
b_ptr->media->addr2msg(msg_media_addr(msg), &b_ptr->addr);
}
/**
......@@ -106,147 +106,150 @@ static void disc_dupl_alert(struct tipc_bearer *b_ptr, u32 node_addr,
}
/**
* tipc_disc_rcv - handle incoming link setup message (request or response)
* tipc_disc_rcv - handle incoming discovery message (request or response)
* @buf: buffer containing message
* @b_ptr: bearer that message arrived on
* @bearer: bearer that message arrived on
*/
void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *b_ptr)
void tipc_disc_rcv(struct sk_buff *buf, struct tipc_bearer *bearer)
{
struct tipc_node *n_ptr;
struct tipc_node *node;
struct tipc_link *link;
struct tipc_media_addr media_addr;
struct tipc_media_addr maddr;
struct sk_buff *rbuf;
struct tipc_msg *msg = buf_msg(buf);
u32 dest = msg_dest_domain(msg);
u32 orig = msg_prevnode(msg);
u32 ddom = msg_dest_domain(msg);
u32 onode = msg_prevnode(msg);
u32 net_id = msg_bc_netid(msg);
u32 type = msg_type(msg);
u32 mtyp = msg_type(msg);
u32 signature = msg_node_sig(msg);
int addr_mismatch;
int link_fully_up;
media_addr.broadcast = 1;
b_ptr->media->msg2addr(b_ptr, &media_addr, msg_media_addr(msg));
bool addr_match = false;
bool sign_match = false;
bool link_up = false;
bool accept_addr = false;
bool accept_sign = false;
bool respond = false;
bearer->media->msg2addr(bearer, &maddr, msg_media_addr(msg));
kfree_skb(buf);
/* Ensure message from node is valid and communication is permitted */
if (net_id != tipc_net_id)
return;
if (media_addr.broadcast)
if (maddr.broadcast)
return;
if (!tipc_addr_domain_valid(dest))
if (!tipc_addr_domain_valid(ddom))
return;
if (!tipc_addr_node_valid(orig))
if (!tipc_addr_node_valid(onode))
return;
if (orig == tipc_own_addr) {
if (memcmp(&media_addr, &b_ptr->addr, sizeof(media_addr)))
disc_dupl_alert(b_ptr, tipc_own_addr, &media_addr);
if (in_own_node(onode)) {
if (memcmp(&maddr, &bearer->addr, sizeof(maddr)))
disc_dupl_alert(bearer, tipc_own_addr, &maddr);
return;
}
if (!tipc_in_scope(dest, tipc_own_addr))
if (!tipc_in_scope(ddom, tipc_own_addr))
return;
if (!tipc_in_scope(b_ptr->domain, orig))
if (!tipc_in_scope(bearer->domain, onode))
return;
/* Locate structure corresponding to requesting node */
n_ptr = tipc_node_find(orig);
if (!n_ptr) {
n_ptr = tipc_node_create(orig);
if (!n_ptr)
return;
}
tipc_node_lock(n_ptr);
/* Locate, or if necessary, create, node: */
node = tipc_node_find(onode);
if (!node)
node = tipc_node_create(onode);
if (!node)
return;
/* Prepare to validate requesting node's signature and media address */
link = n_ptr->links[b_ptr->identity];
addr_mismatch = (link != NULL) &&
memcmp(&link->media_addr, &media_addr, sizeof(media_addr));
tipc_node_lock(node);
link = node->links[bearer->identity];
/*
* Ensure discovery message's signature is correct
*
* If signature is incorrect and there is no working link to the node,
* accept the new signature but invalidate all existing links to the
* node so they won't re-activate without a new discovery message.
*
* If signature is incorrect and the requested link to the node is
* working, accept the new signature. (This is an instance of delayed
* rediscovery, where a link endpoint was able to re-establish contact
* with its peer endpoint on a node that rebooted before receiving a
* discovery message from that node.)
*
* If signature is incorrect and there is a working link to the node
* that is not the requested link, reject the request (must be from
* a duplicate node).
*/
if (signature != n_ptr->signature) {
if (n_ptr->working_links == 0) {
struct tipc_link *curr_link;
int i;
for (i = 0; i < MAX_BEARERS; i++) {
curr_link = n_ptr->links[i];
if (curr_link) {
memset(&curr_link->media_addr, 0,
sizeof(media_addr));
tipc_link_reset(curr_link);
}
}
addr_mismatch = (link != NULL);
} else if (tipc_link_is_up(link) && !addr_mismatch) {
/* delayed rediscovery */
} else {
disc_dupl_alert(b_ptr, orig, &media_addr);
tipc_node_unlock(n_ptr);
return;
}
n_ptr->signature = signature;
/* Prepare to validate requesting node's signature and media address */
sign_match = (signature == node->signature);
addr_match = link && !memcmp(&link->media_addr, &maddr, sizeof(maddr));
link_up = link && tipc_link_is_up(link);
/* These three flags give us eight permutations: */
if (sign_match && addr_match && link_up) {
/* All is fine. Do nothing. */
} else if (sign_match && addr_match && !link_up) {
/* Respond. The link will come up in due time */
respond = true;
} else if (sign_match && !addr_match && link_up) {
/* Peer has changed i/f address without rebooting.
* If so, the link will reset soon, and the next
* discovery will be accepted. So we can ignore it.
* It may also be an cloned or malicious peer having
* chosen the same node address and signature as an
* existing one.
* Ignore requests until the link goes down, if ever.
*/
disc_dupl_alert(bearer, onode, &maddr);
} else if (sign_match && !addr_match && !link_up) {
/* Peer link has changed i/f address without rebooting.
* It may also be a cloned or malicious peer; we can't
* distinguish between the two.
* The signature is correct, so we must accept.
*/
accept_addr = true;
respond = true;
} else if (!sign_match && addr_match && link_up) {
/* Peer node rebooted. Two possibilities:
* - Delayed re-discovery; this link endpoint has already
* reset and re-established contact with the peer, before
* receiving a discovery message from that node.
* (The peer happened to receive one from this node first).
* - The peer came back so fast that our side has not
* discovered it yet. Probing from this side will soon
* reset the link, since there can be no working link
* endpoint at the peer end, and the link will re-establish.
* Accept the signature, since it comes from a known peer.
*/
accept_sign = true;
} else if (!sign_match && addr_match && !link_up) {
/* The peer node has rebooted.
* Accept signature, since it is a known peer.
*/
accept_sign = true;
respond = true;
} else if (!sign_match && !addr_match && link_up) {
/* Peer rebooted with new address, or a new/duplicate peer.
* Ignore until the link goes down, if ever.
*/
disc_dupl_alert(bearer, onode, &maddr);
} else if (!sign_match && !addr_match && !link_up) {
/* Peer rebooted with new address, or it is a new peer.
* Accept signature and address.
*/
accept_sign = true;
accept_addr = true;
respond = true;
}
/*
* Ensure requesting node's media address is correct
*
* If media address doesn't match and the link is working, reject the
* request (must be from a duplicate node).
*
* If media address doesn't match and the link is not working, accept
* the new media address and reset the link to ensure it starts up
* cleanly.
*/
if (addr_mismatch) {
if (tipc_link_is_up(link)) {
disc_dupl_alert(b_ptr, orig, &media_addr);
tipc_node_unlock(n_ptr);
return;
} else {
memcpy(&link->media_addr, &media_addr,
sizeof(media_addr));
tipc_link_reset(link);
}
}
if (accept_sign)
node->signature = signature;
/* Create a link endpoint for this bearer, if necessary */
if (!link) {
link = tipc_link_create(n_ptr, b_ptr, &media_addr);
if (!link) {
tipc_node_unlock(n_ptr);
return;
if (accept_addr) {
if (!link)
link = tipc_link_create(node, bearer, &maddr);
if (link) {
memcpy(&link->media_addr, &maddr, sizeof(maddr));
tipc_link_reset(link);
} else {
respond = false;
}
}
/* Accept discovery message & send response, if necessary */
link_fully_up = link_working_working(link);
if ((type == DSC_REQ_MSG) && !link_fully_up) {
/* Send response, if necessary */
if (respond && (mtyp == DSC_REQ_MSG)) {
rbuf = tipc_buf_acquire(INT_H_SIZE);
if (rbuf) {
tipc_disc_init_msg(rbuf, DSC_RESP_MSG, b_ptr);
tipc_bearer_send(b_ptr->identity, rbuf, &media_addr);
tipc_disc_init_msg(rbuf, DSC_RESP_MSG, bearer);
tipc_bearer_send(bearer->identity, rbuf, &maddr);
kfree_skb(rbuf);
}
}
tipc_node_unlock(n_ptr);
tipc_node_unlock(node);
}
/**
......
/*
* net/tipc/eth_media.c: Ethernet bearer support for TIPC
*
* Copyright (c) 2001-2007, 2013, Ericsson AB
* Copyright (c) 2001-2007, 2013-2014, Ericsson AB
* Copyright (c) 2005-2008, 2011-2013, Wind River Systems
* All rights reserved.
*
......@@ -37,39 +37,52 @@
#include "core.h"
#include "bearer.h"
#define ETH_ADDR_OFFSET 4 /* message header offset of MAC address */
#define ETH_ADDR_OFFSET 4 /* MAC addr position inside address field */
/* convert Ethernet address to string */
static int tipc_eth_addr2str(struct tipc_media_addr *a, char *str_buf,
int str_size)
/* Convert Ethernet address (media address format) to string */
static int tipc_eth_addr2str(struct tipc_media_addr *addr,
char *strbuf, int bufsz)
{
if (str_size < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */
if (bufsz < 18) /* 18 = strlen("aa:bb:cc:dd:ee:ff\0") */
return 1;
sprintf(str_buf, "%pM", a->value);
sprintf(strbuf, "%pM", addr->value);
return 0;
}
/* convert Ethernet address format to message header format */
static int tipc_eth_addr2msg(struct tipc_media_addr *a, char *msg_area)
/* Convert from media address format to discovery message addr format */
static int tipc_eth_addr2msg(char *msg, struct tipc_media_addr *addr)
{
memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE);
msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH;
memcpy(msg_area + ETH_ADDR_OFFSET, a->value, ETH_ALEN);
memset(msg, 0, TIPC_MEDIA_ADDR_SIZE);
msg[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_ETH;
memcpy(msg + ETH_ADDR_OFFSET, addr->value, ETH_ALEN);
return 0;
}
/* convert message header address format to Ethernet format */
static int tipc_eth_msg2addr(const struct tipc_bearer *tb_ptr,
struct tipc_media_addr *a, char *msg_area)
/* Convert raw mac address format to media addr format */
static int tipc_eth_raw2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
if (msg_area[TIPC_MEDIA_TYPE_OFFSET] != TIPC_MEDIA_TYPE_ETH)
return 1;
char bcast_mac[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
tipc_l2_media_addr_set(tb_ptr, a, msg_area + ETH_ADDR_OFFSET);
memset(addr, 0, sizeof(*addr));
ether_addr_copy(addr->value, msg);
addr->media_id = TIPC_MEDIA_TYPE_ETH;
addr->broadcast = !memcmp(addr->value, bcast_mac, ETH_ALEN);
return 0;
}
/* Convert discovery msg addr format to Ethernet media addr format */
static int tipc_eth_msg2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
/* Skip past preamble: */
msg += ETH_ADDR_OFFSET;
return tipc_eth_raw2addr(b, addr, msg);
}
/* Ethernet media registration info */
struct tipc_media eth_media_info = {
.send_msg = tipc_l2_send_msg,
......@@ -78,6 +91,7 @@ struct tipc_media eth_media_info = {
.addr2str = tipc_eth_addr2str,
.addr2msg = tipc_eth_addr2msg,
.msg2addr = tipc_eth_msg2addr,
.raw2addr = tipc_eth_raw2addr,
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.window = TIPC_DEF_LINK_WIN,
......@@ -85,4 +99,3 @@ struct tipc_media eth_media_info = {
.hwaddr_len = ETH_ALEN,
.name = "eth"
};
......@@ -42,7 +42,7 @@
#include "core.h"
#include "bearer.h"
/* convert InfiniBand address to string */
/* convert InfiniBand address (media address format) media address to string */
static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf,
int str_size)
{
......@@ -54,23 +54,35 @@ static int tipc_ib_addr2str(struct tipc_media_addr *a, char *str_buf,
return 0;
}
/* convert InfiniBand address format to message header format */
static int tipc_ib_addr2msg(struct tipc_media_addr *a, char *msg_area)
/* Convert from media address format to discovery message addr format */
static int tipc_ib_addr2msg(char *msg, struct tipc_media_addr *addr)
{
memset(msg_area, 0, TIPC_MEDIA_ADDR_SIZE);
msg_area[TIPC_MEDIA_TYPE_OFFSET] = TIPC_MEDIA_TYPE_IB;
memcpy(msg_area, a->value, INFINIBAND_ALEN);
memset(msg, 0, TIPC_MEDIA_ADDR_SIZE);
memcpy(msg, addr->value, INFINIBAND_ALEN);
return 0;
}
/* convert message header address format to InfiniBand format */
static int tipc_ib_msg2addr(const struct tipc_bearer *tb_ptr,
struct tipc_media_addr *a, char *msg_area)
/* Convert raw InfiniBand address format to media addr format */
static int tipc_ib_raw2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
tipc_l2_media_addr_set(tb_ptr, a, msg_area);
memset(addr, 0, sizeof(*addr));
memcpy(addr->value, msg, INFINIBAND_ALEN);
addr->media_id = TIPC_MEDIA_TYPE_IB;
addr->broadcast = !memcmp(msg, b->bcast_addr.value,
INFINIBAND_ALEN);
return 0;
}
/* Convert discovery msg addr format to InfiniBand media addr format */
static int tipc_ib_msg2addr(struct tipc_bearer *b,
struct tipc_media_addr *addr,
char *msg)
{
return tipc_ib_raw2addr(b, addr, msg);
}
/* InfiniBand media registration info */
struct tipc_media ib_media_info = {
.send_msg = tipc_l2_send_msg,
......@@ -79,6 +91,7 @@ struct tipc_media ib_media_info = {
.addr2str = tipc_ib_addr2str,
.addr2msg = tipc_ib_addr2msg,
.msg2addr = tipc_ib_msg2addr,
.raw2addr = tipc_ib_raw2addr,
.priority = TIPC_DEF_LINK_PRI,
.tolerance = TIPC_DEF_LINK_TOL,
.window = TIPC_DEF_LINK_WIN,
......@@ -86,4 +99,3 @@ struct tipc_media ib_media_info = {
.hwaddr_len = INFINIBAND_ALEN,
.name = "ib"
};
......@@ -37,6 +37,7 @@
#include "core.h"
#include "link.h"
#include "port.h"
#include "socket.h"
#include "name_distr.h"
#include "discover.h"
#include "config.h"
......@@ -398,9 +399,8 @@ static void link_release_outqueue(struct tipc_link *l_ptr)
*/
void tipc_link_reset_fragments(struct tipc_link *l_ptr)
{
kfree_skb(l_ptr->reasm_head);
l_ptr->reasm_head = NULL;
l_ptr->reasm_tail = NULL;
kfree_skb(l_ptr->reasm_buf);
l_ptr->reasm_buf = NULL;
}
/**
......@@ -1573,17 +1573,12 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
}
msg = buf_msg(buf);
} else if (msg_user(msg) == MSG_FRAGMENTER) {
int rc;
l_ptr->stats.recv_fragments++;
rc = tipc_link_frag_rcv(&l_ptr->reasm_head,
&l_ptr->reasm_tail,
&buf);
if (rc == LINK_REASM_COMPLETE) {
if (tipc_buf_append(&l_ptr->reasm_buf, &buf)) {
l_ptr->stats.recv_fragmented++;
msg = buf_msg(buf);
} else {
if (rc == LINK_REASM_ERROR)
if (!l_ptr->reasm_buf)
tipc_link_reset(l_ptr);
tipc_node_unlock(n_ptr);
continue;
......@@ -1596,7 +1591,7 @@ void tipc_rcv(struct sk_buff *head, struct tipc_bearer *b_ptr)
case TIPC_HIGH_IMPORTANCE:
case TIPC_CRITICAL_IMPORTANCE:
tipc_node_unlock(n_ptr);
tipc_port_rcv(buf);
tipc_sk_rcv(buf);
continue;
case MSG_BUNDLER:
l_ptr->stats.recv_bundles++;
......@@ -1831,9 +1826,6 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
if (l_ptr->exp_msg_count)
goto exit;
/* record unnumbered packet arrival (force mismatch on next timeout) */
l_ptr->checkpoint--;
if (l_ptr->net_plane != msg_net_plane(msg))
if (tipc_own_addr > msg_prevnode(msg))
l_ptr->net_plane = msg_net_plane(msg);
......@@ -1909,6 +1901,10 @@ static void tipc_link_proto_rcv(struct tipc_link *l_ptr, struct sk_buff *buf)
tipc_link_reset(l_ptr); /* Enforce change to take effect */
break;
}
/* Record reception; force mismatch at next timeout: */
l_ptr->checkpoint--;
link_state_event(l_ptr, TRAFFIC_MSG_EVT);
l_ptr->stats.recv_states++;
if (link_reset_unknown(l_ptr))
......@@ -2168,9 +2164,7 @@ static struct sk_buff *tipc_link_failover_rcv(struct tipc_link *l_ptr,
}
if (msg_user(msg) == MSG_FRAGMENTER) {
l_ptr->stats.recv_fragments++;
tipc_link_frag_rcv(&l_ptr->reasm_head,
&l_ptr->reasm_tail,
&buf);
tipc_buf_append(&l_ptr->reasm_buf, &buf);
}
}
exit:
......@@ -2308,53 +2302,6 @@ static int tipc_link_frag_xmit(struct tipc_link *l_ptr, struct sk_buff *buf)
return dsz;
}
/* tipc_link_frag_rcv(): Called with node lock on. Returns
* the reassembled buffer if message is complete.
*/
int tipc_link_frag_rcv(struct sk_buff **head, struct sk_buff **tail,
struct sk_buff **fbuf)
{
struct sk_buff *frag = *fbuf;
struct tipc_msg *msg = buf_msg(frag);
u32 fragid = msg_type(msg);
bool headstolen;
int delta;
skb_pull(frag, msg_hdr_sz(msg));
if (fragid == FIRST_FRAGMENT) {
if (*head || skb_unclone(frag, GFP_ATOMIC))
goto out_free;
*head = frag;
skb_frag_list_init(*head);
*fbuf = NULL;
return 0;
} else if (*head &&
skb_try_coalesce(*head, frag, &headstolen, &delta)) {
kfree_skb_partial(frag, headstolen);
} else {
if (!*head)
goto out_free;
if (!skb_has_frag_list(*head))
skb_shinfo(*head)->frag_list = frag;
else
(*tail)->next = frag;
*tail = frag;
(*head)->truesize += frag->truesize;
}
if (fragid == LAST_FRAGMENT) {
*fbuf = *head;
*tail = *head = NULL;
return LINK_REASM_COMPLETE;
}
*fbuf = NULL;
return 0;
out_free:
pr_warn_ratelimited("Link unable to reassemble fragmented message\n");
kfree_skb(*fbuf);
*fbuf = NULL;
return LINK_REASM_ERROR;
}
static void link_set_supervision_props(struct tipc_link *l_ptr, u32 tolerance)
{
if ((tolerance < TIPC_MIN_LINK_TOL) || (tolerance > TIPC_MAX_LINK_TOL))
......
......@@ -40,11 +40,6 @@
#include "msg.h"
#include "node.h"
/* Link reassembly status codes
*/
#define LINK_REASM_ERROR -1
#define LINK_REASM_COMPLETE 1
/* Out-of-range value for link sequence numbers
*/
#define INVALID_LINK_SEQ 0x10000
......@@ -140,8 +135,7 @@ struct tipc_stats {
* @next_out: ptr to first unsent outbound message in queue
* @waiting_ports: linked list of ports waiting for link congestion to abate
* @long_msg_seq_no: next identifier to use for outbound fragmented messages
* @reasm_head: list head of partially reassembled inbound message fragments
* @reasm_tail: last fragment received
* @reasm_buf: head of partially reassembled inbound message fragments
* @stats: collects statistics regarding link activity
*/
struct tipc_link {
......@@ -204,8 +198,7 @@ struct tipc_link {
/* Fragmentation/reassembly */
u32 long_msg_seq_no;
struct sk_buff *reasm_head;
struct sk_buff *reasm_tail;
struct sk_buff *reasm_buf;
/* Statistics */
struct tipc_stats stats;
......@@ -242,9 +235,6 @@ int tipc_link_iovec_xmit_fast(struct tipc_port *sender,
struct iovec const *msg_sect,
unsigned int len, u32 destnode);
void tipc_link_bundle_rcv(struct sk_buff *buf);
int tipc_link_frag_rcv(struct sk_buff **reasm_head,
struct sk_buff **reasm_tail,
struct sk_buff **fbuf);
void tipc_link_proto_xmit(struct tipc_link *l_ptr, u32 msg_typ, int prob,
u32 gap, u32 tolerance, u32 priority, u32 acked_mtu);
void tipc_link_push_queue(struct tipc_link *l_ptr);
......
/*
* net/tipc/msg.c: TIPC message header routines
*
* Copyright (c) 2000-2006, Ericsson AB
* Copyright (c) 2000-2006, 2014, Ericsson AB
* Copyright (c) 2005, 2010-2011, Wind River Systems
* All rights reserved.
*
......@@ -99,3 +99,56 @@ int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
}
return dsz;
}
/* tipc_buf_append(): Append a buffer to the fragment list of another buffer
* Let first buffer become head buffer
* Returns 1 and sets *buf to headbuf if chain is complete, otherwise 0
* Leaves headbuf pointer at NULL if failure
*/
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
{
struct sk_buff *head = *headbuf;
struct sk_buff *frag = *buf;
struct sk_buff *tail;
struct tipc_msg *msg = buf_msg(frag);
u32 fragid = msg_type(msg);
bool headstolen;
int delta;
skb_pull(frag, msg_hdr_sz(msg));
if (fragid == FIRST_FRAGMENT) {
if (head || skb_unclone(frag, GFP_ATOMIC))
goto out_free;
head = *headbuf = frag;
skb_frag_list_init(head);
return 0;
}
if (!head)
goto out_free;
tail = TIPC_SKB_CB(head)->tail;
if (skb_try_coalesce(head, frag, &headstolen, &delta)) {
kfree_skb_partial(frag, headstolen);
} else {
if (!skb_has_frag_list(head))
skb_shinfo(head)->frag_list = frag;
else
tail->next = frag;
head->truesize += frag->truesize;
head->data_len += frag->len;
head->len += frag->len;
TIPC_SKB_CB(head)->tail = frag;
}
if (fragid == LAST_FRAGMENT) {
*buf = head;
TIPC_SKB_CB(head)->tail = NULL;
*headbuf = NULL;
return 1;
}
*buf = NULL;
return 0;
out_free:
pr_warn_ratelimited("Unable to build fragment list\n");
kfree_skb(*buf);
return 0;
}
/*
* net/tipc/msg.h: Include file for TIPC message header routines
*
* Copyright (c) 2000-2007, Ericsson AB
* Copyright (c) 2000-2007, 2014, Ericsson AB
* Copyright (c) 2005-2008, 2010-2011, Wind River Systems
* All rights reserved.
*
......@@ -711,4 +711,7 @@ void tipc_msg_init(struct tipc_msg *m, u32 user, u32 type, u32 hsize,
u32 destnode);
int tipc_msg_build(struct tipc_msg *hdr, struct iovec const *msg_sect,
unsigned int len, int max_size, struct sk_buff **buf);
int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf);
#endif
......@@ -39,6 +39,7 @@
#include "name_distr.h"
#include "subscr.h"
#include "port.h"
#include "socket.h"
#include "node.h"
#include "config.h"
......@@ -141,7 +142,7 @@ void tipc_net_route_msg(struct sk_buff *buf)
if (msg_mcast(msg))
tipc_port_mcast_rcv(buf, NULL);
else if (msg_destport(msg))
tipc_port_rcv(buf);
tipc_sk_rcv(buf);
else
net_route_named_msg(buf);
return;
......
......@@ -286,10 +286,9 @@ static void node_lost_contact(struct tipc_node *n_ptr)
kfree_skb_list(n_ptr->bclink.deferred_head);
n_ptr->bclink.deferred_size = 0;
if (n_ptr->bclink.reasm_head) {
kfree_skb(n_ptr->bclink.reasm_head);
n_ptr->bclink.reasm_head = NULL;
n_ptr->bclink.reasm_tail = NULL;
if (n_ptr->bclink.reasm_buf) {
kfree_skb(n_ptr->bclink.reasm_buf);
n_ptr->bclink.reasm_buf = NULL;
}
tipc_bclink_remove_node(n_ptr->addr);
......
......@@ -69,8 +69,7 @@ enum {
* @deferred_size: number of OOS b'cast messages in deferred queue
* @deferred_head: oldest OOS b'cast message received from node
* @deferred_tail: newest OOS b'cast message received from node
* @reasm_head: broadcast reassembly queue head from node
* @reasm_tail: last broadcast fragment received from node
* @reasm_buf: broadcast reassembly queue head from node
* @recv_permitted: true if node is allowed to receive b'cast messages
*/
struct tipc_node_bclink {
......@@ -81,8 +80,7 @@ struct tipc_node_bclink {
u32 deferred_size;
struct sk_buff *deferred_head;
struct sk_buff *deferred_tail;
struct sk_buff *reasm_head;
struct sk_buff *reasm_tail;
struct sk_buff *reasm_buf;
bool recv_permitted;
};
......
......@@ -165,7 +165,7 @@ void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp)
msg_set_destnode(msg, tipc_own_addr);
if (dp->count == 1) {
msg_set_destport(msg, dp->ports[0]);
tipc_port_rcv(buf);
tipc_sk_rcv(buf);
tipc_port_list_free(dp);
return;
}
......@@ -180,7 +180,7 @@ void tipc_port_mcast_rcv(struct sk_buff *buf, struct tipc_port_list *dp)
if ((index == 0) && (cnt != 0))
item = item->next;
msg_set_destport(buf_msg(b), item->ports[index]);
tipc_port_rcv(b);
tipc_sk_rcv(b);
}
}
exit:
......@@ -343,7 +343,7 @@ int tipc_reject_msg(struct sk_buff *buf, u32 err)
/* send returned message & dispose of rejected message */
src_node = msg_prevnode(msg);
if (in_own_node(src_node))
tipc_port_rcv(rbuf);
tipc_sk_rcv(rbuf);
else
tipc_link_xmit(rbuf, src_node, msg_link_selector(rmsg));
exit:
......@@ -754,37 +754,6 @@ int tipc_port_shutdown(u32 ref)
return tipc_port_disconnect(ref);
}
/**
* tipc_port_rcv - receive message from lower layer and deliver to port user
*/
int tipc_port_rcv(struct sk_buff *buf)
{
struct tipc_port *p_ptr;
struct tipc_msg *msg = buf_msg(buf);
u32 destport = msg_destport(msg);
u32 dsz = msg_data_sz(msg);
u32 err;
/* forward unresolved named message */
if (unlikely(!destport)) {
tipc_net_route_msg(buf);
return dsz;
}
/* validate destination & pass to port, otherwise reject message */
p_ptr = tipc_port_lock(destport);
if (likely(p_ptr)) {
err = tipc_sk_rcv(&tipc_port_to_sock(p_ptr)->sk, buf);
tipc_port_unlock(p_ptr);
if (likely(!err))
return dsz;
} else {
err = TIPC_ERR_NO_PORT;
}
return tipc_reject_msg(buf, err);
}
/*
* tipc_port_iovec_rcv: Concatenate and deliver sectioned
* message for this node.
......@@ -798,7 +767,7 @@ static int tipc_port_iovec_rcv(struct tipc_port *sender,
res = tipc_msg_build(&sender->phdr, msg_sect, len, MAX_MSG_SIZE, &buf);
if (likely(buf))
tipc_port_rcv(buf);
tipc_sk_rcv(buf);
return res;
}
......
......@@ -42,9 +42,10 @@
#include "msg.h"
#include "node_subscr.h"
#define TIPC_FLOW_CONTROL_WIN 512
#define CONN_OVERLOAD_LIMIT ((TIPC_FLOW_CONTROL_WIN * 2 + 1) * \
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
#define TIPC_CONNACK_INTV 256
#define TIPC_FLOWCTRL_WIN (TIPC_CONNACK_INTV * 2)
#define TIPC_CONN_OVERLOAD_LIMIT ((TIPC_FLOWCTRL_WIN * 2 + 1) * \
SKB_TRUESIZE(TIPC_MAX_USER_MSG_SIZE))
/**
* struct tipc_port - TIPC port structure
......@@ -134,7 +135,6 @@ int tipc_port_peer_msg(struct tipc_port *p_ptr, struct tipc_msg *msg);
/*
* TIPC messaging routines
*/
int tipc_port_rcv(struct sk_buff *buf);
int tipc_send(struct tipc_port *port,
struct iovec const *msg_sect,
......@@ -187,7 +187,7 @@ static inline void tipc_port_unlock(struct tipc_port *p_ptr)
static inline int tipc_port_congested(struct tipc_port *p_ptr)
{
return (p_ptr->sent - p_ptr->acked) >= (TIPC_FLOW_CONTROL_WIN * 2);
return ((p_ptr->sent - p_ptr->acked) >= TIPC_FLOWCTRL_WIN);
}
......
/*
* net/tipc/socket.c: TIPC socket API
* net/tipc/socket.c: TIPC socket API
*
* Copyright (c) 2001-2007, 2012-2014, Ericsson AB
* Copyright (c) 2004-2008, 2010-2013, Wind River Systems
......@@ -45,7 +45,7 @@
#define CONN_TIMEOUT_DEFAULT 8000 /* default connect timeout = 8s */
static int backlog_rcv(struct sock *sk, struct sk_buff *skb);
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *skb);
static void tipc_data_ready(struct sock *sk);
static void tipc_write_space(struct sock *sk);
static int tipc_release(struct socket *sock);
......@@ -196,11 +196,12 @@ static int tipc_sk_create(struct net *net, struct socket *sock,
sock->state = state;
sock_init_data(sock, sk);
sk->sk_backlog_rcv = backlog_rcv;
sk->sk_backlog_rcv = tipc_backlog_rcv;
sk->sk_rcvbuf = sysctl_tipc_rmem[1];
sk->sk_data_ready = tipc_data_ready;
sk->sk_write_space = tipc_write_space;
tipc_sk(sk)->conn_timeout = CONN_TIMEOUT_DEFAULT;
tsk->conn_timeout = CONN_TIMEOUT_DEFAULT;
atomic_set(&tsk->dupl_rcvcnt, 0);
tipc_port_unlock(port);
if (sock->state == SS_READY) {
......@@ -1101,7 +1102,7 @@ static int tipc_recvmsg(struct kiocb *iocb, struct socket *sock,
/* Consume received message (optional) */
if (likely(!(flags & MSG_PEEK))) {
if ((sock->state != SS_READY) &&
(++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
(++port->conn_unacked >= TIPC_CONNACK_INTV))
tipc_acknowledge(port->ref, port->conn_unacked);
advance_rx_queue(sk);
}
......@@ -1210,7 +1211,7 @@ static int tipc_recv_stream(struct kiocb *iocb, struct socket *sock,
/* Consume received message (optional) */
if (likely(!(flags & MSG_PEEK))) {
if (unlikely(++port->conn_unacked >= TIPC_FLOW_CONTROL_WIN))
if (unlikely(++port->conn_unacked >= TIPC_CONNACK_INTV))
tipc_acknowledge(port->ref, port->conn_unacked);
advance_rx_queue(sk);
}
......@@ -1416,7 +1417,7 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
}
/**
* backlog_rcv - handle incoming message from backlog queue
* tipc_backlog_rcv - handle incoming message from backlog queue
* @sk: socket
* @buf: message
*
......@@ -1424,47 +1425,73 @@ static u32 filter_rcv(struct sock *sk, struct sk_buff *buf)
*
* Returns 0
*/
static int backlog_rcv(struct sock *sk, struct sk_buff *buf)
static int tipc_backlog_rcv(struct sock *sk, struct sk_buff *buf)
{
u32 res;
struct tipc_sock *tsk = tipc_sk(sk);
res = filter_rcv(sk, buf);
if (res)
if (unlikely(res))
tipc_reject_msg(buf, res);
if (atomic_read(&tsk->dupl_rcvcnt) < TIPC_CONN_OVERLOAD_LIMIT)
atomic_add(buf->truesize, &tsk->dupl_rcvcnt);
return 0;
}
/**
* tipc_sk_rcv - handle incoming message
* @sk: socket receiving message
* @buf: message
*
* Called with port lock already taken.
*
* Returns TIPC error status code (TIPC_OK if message is not to be rejected)
* @buf: buffer containing arriving message
* Consumes buffer
* Returns 0 if success, or errno: -EHOSTUNREACH
*/
u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf)
int tipc_sk_rcv(struct sk_buff *buf)
{
u32 res;
struct tipc_sock *tsk;
struct tipc_port *port;
struct sock *sk;
u32 dport = msg_destport(buf_msg(buf));
int err = TIPC_OK;
uint limit;
/*
* Process message if socket is unlocked; otherwise add to backlog queue
*
* This code is based on sk_receive_skb(), but must be distinct from it
* since a TIPC-specific filter/reject mechanism is utilized
*/
/* Forward unresolved named message */
if (unlikely(!dport)) {
tipc_net_route_msg(buf);
return 0;
}
/* Validate destination */
port = tipc_port_lock(dport);
if (unlikely(!port)) {
err = TIPC_ERR_NO_PORT;
goto exit;
}
tsk = tipc_port_to_sock(port);
sk = &tsk->sk;
/* Queue message */
bh_lock_sock(sk);
if (!sock_owned_by_user(sk)) {
res = filter_rcv(sk, buf);
err = filter_rcv(sk, buf);
} else {
if (sk_add_backlog(sk, buf, rcvbuf_limit(sk, buf)))
res = TIPC_ERR_OVERLOAD;
else
res = TIPC_OK;
if (sk->sk_backlog.len == 0)
atomic_set(&tsk->dupl_rcvcnt, 0);
limit = rcvbuf_limit(sk, buf) + atomic_read(&tsk->dupl_rcvcnt);
if (sk_add_backlog(sk, buf, limit))
err = TIPC_ERR_OVERLOAD;
}
bh_unlock_sock(sk);
tipc_port_unlock(port);
return res;
if (likely(!err))
return 0;
exit:
tipc_reject_msg(buf, err);
return -EHOSTUNREACH;
}
static int tipc_wait_for_connect(struct socket *sock, long *timeo_p)
......
......@@ -44,12 +44,14 @@
* @port: port - interacts with 'sk' and with the rest of the TIPC stack
* @peer_name: the peer of the connection, if any
* @conn_timeout: the time we can wait for an unresponded setup request
* @dupl_rcvcnt: number of bytes counted twice, in both backlog and rcv queue
*/
struct tipc_sock {
struct sock sk;
struct tipc_port port;
unsigned int conn_timeout;
atomic_t dupl_rcvcnt;
};
static inline struct tipc_sock *tipc_sk(const struct sock *sk)
......@@ -67,6 +69,6 @@ static inline void tipc_sock_wakeup(struct tipc_sock *tsk)
tsk->sk.sk_write_space(&tsk->sk);
}
u32 tipc_sk_rcv(struct sock *sk, struct sk_buff *buf);
int tipc_sk_rcv(struct sk_buff *buf);
#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