2986 lines · 81.9 KB · C
RawDownload
/* * net/tipc/link.c: TIPC link code * * Copyright (c) 1996-2007, 2012-2016, Ericsson AB * Copyright (c) 2004-2007, 2010-2013, Wind River Systems * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * 3. Neither the names of the copyright holders nor the names of its *    contributors may be used to endorse or promote products derived from *    this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "core.h"#include "subscr.h"#include "link.h"#include "bcast.h"#include "socket.h"#include "name_distr.h"#include "discover.h"#include "netlink.h"#include "monitor.h"#include "trace.h"#include "crypto.h" #include <linux/pkt_sched.h> struct tipc_stats {	u32 sent_pkts;	u32 recv_pkts;	u32 sent_states;	u32 recv_states;	u32 sent_probes;	u32 recv_probes;	u32 sent_nacks;	u32 recv_nacks;	u32 sent_acks;	u32 sent_bundled;	u32 sent_bundles;	u32 recv_bundled;	u32 recv_bundles;	u32 retransmitted;	u32 sent_fragmented;	u32 sent_fragments;	u32 recv_fragmented;	u32 recv_fragments;	u32 link_congs;		/* # port sends blocked by congestion */	u32 deferred_recv;	u32 duplicates;	u32 max_queue_sz;	/* send queue size high water mark */	u32 accu_queue_sz;	/* used for send queue size profiling */	u32 queue_sz_counts;	/* used for send queue size profiling */	u32 msg_length_counts;	/* used for message length profiling */	u32 msg_lengths_total;	/* used for message length profiling */	u32 msg_length_profile[7]; /* used for msg. length profiling */}; /** * struct tipc_link - TIPC link data structure * @addr: network address of link's peer node * @name: link name character string * @net: pointer to namespace struct * @peer_session: link session # being used by peer end of link * @peer_bearer_id: bearer id used by link's peer endpoint * @bearer_id: local bearer id used by link * @tolerance: minimum link continuity loss needed to reset link [in ms] * @abort_limit: # of unacknowledged continuity probes needed to reset link * @state: current state of link FSM * @peer_caps: bitmap describing capabilities of peer node * @silent_intv_cnt: # of timer intervals without any reception from peer * @priority: current link priority * @net_plane: current link network plane ('A' through 'H') * @mon_state: cookie with information needed by link monitor * @mtu: current maximum packet size for this link * @advertised_mtu: advertised own mtu when link is being established * @backlogq: queue for messages waiting to be sent * @ackers: # of peers that needs to ack each packet before it can be released * @acked: # last packet acked by a certain peer. Used for broadcast. * @rcv_nxt: next sequence number to expect for inbound messages * @inputq: buffer queue for messages to be delivered upwards * @namedq: buffer queue for name table messages to be delivered upwards * @wakeupq: linked list of wakeup msgs waiting for link congestion to abate * @reasm_buf: head of partially reassembled inbound message fragments * @stats: collects statistics regarding link activity * @session: session to be used by link * @snd_nxt_state: next send seq number * @rcv_nxt_state: next rcv seq number * @in_session: have received ACTIVATE_MSG from peer * @active: link is active * @if_name: associated interface name * @rst_cnt: link reset counter * @drop_point: seq number for failover handling (FIXME) * @failover_reasm_skb: saved failover msg ptr (FIXME) * @failover_deferdq: deferred message queue for failover processing (FIXME) * @transmq: the link's transmit queue * @backlog: link's backlog by priority (importance) * @snd_nxt: next sequence number to be used * @rcv_unacked: # messages read by user, but not yet acked back to peer * @deferdq: deferred receive queue * @window: sliding window size for congestion handling * @min_win: minimal send window to be used by link * @ssthresh: slow start threshold for congestion handling * @max_win: maximal send window to be used by link * @cong_acks: congestion acks for congestion avoidance (FIXME) * @checkpoint: seq number for congestion window size handling * @reasm_tnlmsg: fragmentation/reassembly area for tunnel protocol message * @last_gap: last gap ack blocks for bcast (FIXME) * @last_ga: ptr to gap ack blocks * @bc_rcvlink: the peer specific link used for broadcast reception * @bc_sndlink: the namespace global link used for broadcast sending * @nack_state: bcast nack state * @bc_peer_is_up: peer has acked the bcast init msg */struct tipc_link {	u32 addr;	char name[TIPC_MAX_LINK_NAME];	struct net *net; 	/* Management and link supervision data */	u16 peer_session;	u16 session;	u16 snd_nxt_state;	u16 rcv_nxt_state;	u32 peer_bearer_id;	u32 bearer_id;	u32 tolerance;	u32 abort_limit;	u32 state;	u16 peer_caps;	bool in_session;	bool active;	u32 silent_intv_cnt;	char if_name[TIPC_MAX_IF_NAME];	u32 priority;	char net_plane;	struct tipc_mon_state mon_state;	u16 rst_cnt; 	/* Failover/synch */	u16 drop_point;	struct sk_buff *failover_reasm_skb;	struct sk_buff_head failover_deferdq; 	/* Max packet negotiation */	u16 mtu;	u16 advertised_mtu; 	/* Sending */	struct sk_buff_head transmq;	struct sk_buff_head backlogq;	struct {		u16 len;		u16 limit;		struct sk_buff *target_bskb;	} backlog[5];	u16 snd_nxt; 	/* Reception */	u16 rcv_nxt;	u32 rcv_unacked;	struct sk_buff_head deferdq;	struct sk_buff_head *inputq;	struct sk_buff_head *namedq; 	/* Congestion handling */	struct sk_buff_head wakeupq;	u16 window;	u16 min_win;	u16 ssthresh;	u16 max_win;	u16 cong_acks;	u16 checkpoint; 	/* Fragmentation/reassembly */	struct sk_buff *reasm_buf;	struct sk_buff *reasm_tnlmsg; 	/* Broadcast */	u16 ackers;	u16 acked;	u16 last_gap;	struct tipc_gap_ack_blks *last_ga;	struct tipc_link *bc_rcvlink;	struct tipc_link *bc_sndlink;	u8 nack_state;	bool bc_peer_is_up; 	/* Statistics */	struct tipc_stats stats;}; /* * Error message prefixes */static const char *link_co_err = "Link tunneling error, ";static const char *link_rst_msg = "Resetting link "; /* Send states for broadcast NACKs */enum {	BC_NACK_SND_CONDITIONAL,	BC_NACK_SND_UNCONDITIONAL,	BC_NACK_SND_SUPPRESS,}; #define TIPC_BC_RETR_LIM  (jiffies + msecs_to_jiffies(10))#define TIPC_UC_RETR_TIME (jiffies + msecs_to_jiffies(1)) /* Link FSM states: */enum {	LINK_ESTABLISHED     = 0xe,	LINK_ESTABLISHING    = 0xe  << 4,	LINK_RESET           = 0x1  << 8,	LINK_RESETTING       = 0x2  << 12,	LINK_PEER_RESET      = 0xd  << 16,	LINK_FAILINGOVER     = 0xf  << 20,	LINK_SYNCHING        = 0xc  << 24}; static int tipc_link_proto_rcv(struct tipc_link *l, struct sk_buff *skb,			       struct sk_buff_head *xmitq);static void tipc_link_build_proto_msg(struct tipc_link *l, int mtyp, bool probe,				      bool probe_reply, u16 rcvgap,				      int tolerance, int priority,				      struct sk_buff_head *xmitq);static void link_print(struct tipc_link *l, const char *str);static int tipc_link_build_nack_msg(struct tipc_link *l,				    struct sk_buff_head *xmitq);static void tipc_link_build_bc_init_msg(struct tipc_link *l,					struct sk_buff_head *xmitq);static u8 __tipc_build_gap_ack_blks(struct tipc_gap_ack_blks *ga,				    struct tipc_link *l, u8 start_index);static u16 tipc_build_gap_ack_blks(struct tipc_link *l, struct tipc_msg *hdr);static int tipc_link_advance_transmq(struct tipc_link *l, struct tipc_link *r,				     u16 acked, u16 gap,				     struct tipc_gap_ack_blks *ga,				     struct sk_buff_head *xmitq,				     bool *retransmitted, int *rc);static void tipc_link_update_cwin(struct tipc_link *l, int released,				  bool retransmitted);/* *  Simple non-static link routines (i.e. referenced outside this file) */bool tipc_link_is_up(struct tipc_link *l){	return l->state & (LINK_ESTABLISHED | LINK_SYNCHING);} bool tipc_link_peer_is_down(struct tipc_link *l){	return l->state == LINK_PEER_RESET;} bool tipc_link_is_reset(struct tipc_link *l){	return l->state & (LINK_RESET | LINK_FAILINGOVER | LINK_ESTABLISHING);} bool tipc_link_is_establishing(struct tipc_link *l){	return l->state == LINK_ESTABLISHING;} bool tipc_link_is_synching(struct tipc_link *l){	return l->state == LINK_SYNCHING;} bool tipc_link_is_failingover(struct tipc_link *l){	return l->state == LINK_FAILINGOVER;} bool tipc_link_is_blocked(struct tipc_link *l){	return l->state & (LINK_RESETTING | LINK_PEER_RESET | LINK_FAILINGOVER);} static bool link_is_bc_sndlink(struct tipc_link *l){	return !l->bc_sndlink;} static bool link_is_bc_rcvlink(struct tipc_link *l){	return ((l->bc_rcvlink == l) && !link_is_bc_sndlink(l));} void tipc_link_set_active(struct tipc_link *l, bool active){	l->active = active;} u32 tipc_link_id(struct tipc_link *l){	return l->peer_bearer_id << 16 | l->bearer_id;} int tipc_link_min_win(struct tipc_link *l){	return l->min_win;} int tipc_link_max_win(struct tipc_link *l){	return l->max_win;} int tipc_link_prio(struct tipc_link *l){	return l->priority;} unsigned long tipc_link_tolerance(struct tipc_link *l){	return l->tolerance;} struct sk_buff_head *tipc_link_inputq(struct tipc_link *l){	return l->inputq;} char tipc_link_plane(struct tipc_link *l){	return l->net_plane;} struct net *tipc_link_net(struct tipc_link *l){	return l->net;} void tipc_link_update_caps(struct tipc_link *l, u16 capabilities){	l->peer_caps = capabilities;} void tipc_link_add_bc_peer(struct tipc_link *snd_l,			   struct tipc_link *uc_l,			   struct sk_buff_head *xmitq){	struct tipc_link *rcv_l = uc_l->bc_rcvlink; 	snd_l->ackers++;	rcv_l->acked = snd_l->snd_nxt - 1;	snd_l->state = LINK_ESTABLISHED;	tipc_link_build_bc_init_msg(uc_l, xmitq);} void tipc_link_remove_bc_peer(struct tipc_link *snd_l,			      struct tipc_link *rcv_l,			      struct sk_buff_head *xmitq){	u16 ack = snd_l->snd_nxt - 1; 	snd_l->ackers--;	rcv_l->bc_peer_is_up = true;	rcv_l->state = LINK_ESTABLISHED;	tipc_link_bc_ack_rcv(rcv_l, ack, 0, NULL, xmitq, NULL);	trace_tipc_link_reset(rcv_l, TIPC_DUMP_ALL, "bclink removed!");	tipc_link_reset(rcv_l);	rcv_l->state = LINK_RESET;	if (!snd_l->ackers) {		trace_tipc_link_reset(snd_l, TIPC_DUMP_ALL, "zero ackers!");		tipc_link_reset(snd_l);		snd_l->state = LINK_RESET;		__skb_queue_purge(xmitq);	}} int tipc_link_bc_peers(struct tipc_link *l){	return l->ackers;} static u16 link_bc_rcv_gap(struct tipc_link *l){	struct sk_buff *skb = skb_peek(&l->deferdq);	u16 gap = 0; 	if (more(l->snd_nxt, l->rcv_nxt))		gap = l->snd_nxt - l->rcv_nxt;	if (skb)		gap = buf_seqno(skb) - l->rcv_nxt;	return gap;} void tipc_link_set_mtu(struct tipc_link *l, int mtu){	l->mtu = mtu;} int tipc_link_mtu(struct tipc_link *l){	return l->mtu;} int tipc_link_mss(struct tipc_link *l){#ifdef CONFIG_TIPC_CRYPTO	return l->mtu - INT_H_SIZE - EMSG_OVERHEAD;#else	return l->mtu - INT_H_SIZE;#endif} u16 tipc_link_rcv_nxt(struct tipc_link *l){	return l->rcv_nxt;} u16 tipc_link_acked(struct tipc_link *l){	return l->acked;} char *tipc_link_name(struct tipc_link *l){	return l->name;} u32 tipc_link_state(struct tipc_link *l){	return l->state;} /** * tipc_link_create - create a new link * @net: pointer to associated network namespace * @if_name: associated interface name * @bearer_id: id (index) of associated bearer * @tolerance: link tolerance to be used by link * @net_plane: network plane (A,B,c..) this link belongs to * @mtu: mtu to be advertised by link * @priority: priority to be used by link * @min_win: minimal send window to be used by link * @max_win: maximal send window to be used by link * @session: session to be used by link * @peer: node id of peer node * @peer_caps: bitmap describing peer node capabilities * @bc_sndlink: the namespace global link used for broadcast sending * @bc_rcvlink: the peer specific link used for broadcast reception * @inputq: queue to put messages ready for delivery * @namedq: queue to put binding table update messages ready for delivery * @link: return value, pointer to put the created link * @self: local unicast link id * @peer_id: 128-bit ID of peer * * Return: true if link was created, otherwise false */bool tipc_link_create(struct net *net, char *if_name, int bearer_id,		      int tolerance, char net_plane, u32 mtu, int priority,		      u32 min_win, u32 max_win, u32 session, u32 self,		      u32 peer, u8 *peer_id, u16 peer_caps,		      struct tipc_link *bc_sndlink,		      struct tipc_link *bc_rcvlink,		      struct sk_buff_head *inputq,		      struct sk_buff_head *namedq,		      struct tipc_link **link){	char peer_str[NODE_ID_STR_LEN] = {0,};	char self_str[NODE_ID_STR_LEN] = {0,};	struct tipc_link *l; 	l = kzalloc_obj(*l, GFP_ATOMIC);	if (!l)		return false;	*link = l;	l->session = session; 	/* Set link name for unicast links only */	if (peer_id) {		if (tipc_nodeid2string(self_str, tipc_own_id(net)) > NODE_ID_LEN)			sprintf(self_str, "%x", self);		if (tipc_nodeid2string(peer_str, peer_id) > NODE_ID_LEN)

Lines 1–500 of 2986.