diff options
Diffstat (limited to 'net/tipc/link.c')
| -rw-r--r-- | net/tipc/link.c | 299 | 
1 files changed, 156 insertions, 143 deletions
| diff --git a/net/tipc/link.c b/net/tipc/link.c index ac1832a66f8a..b4b9b30167a3 100644 --- a/net/tipc/link.c +++ b/net/tipc/link.c @@ -484,7 +484,7 @@ static void link_release_outqueue(struct tipc_link *l_ptr)  	while (buf) {  		next = buf->next; -		buf_discard(buf); +		kfree_skb(buf);  		buf = next;  	}  	l_ptr->first_out = NULL; @@ -503,7 +503,7 @@ void tipc_link_reset_fragments(struct tipc_link *l_ptr)  	while (buf) {  		next = buf->next; -		buf_discard(buf); +		kfree_skb(buf);  		buf = next;  	}  	l_ptr->defragm_buf = NULL; @@ -522,20 +522,20 @@ void tipc_link_stop(struct tipc_link *l_ptr)  	buf = l_ptr->oldest_deferred_in;  	while (buf) {  		next = buf->next; -		buf_discard(buf); +		kfree_skb(buf);  		buf = next;  	}  	buf = l_ptr->first_out;  	while (buf) {  		next = buf->next; -		buf_discard(buf); +		kfree_skb(buf);  		buf = next;  	}  	tipc_link_reset_fragments(l_ptr); -	buf_discard(l_ptr->proto_msg_queue); +	kfree_skb(l_ptr->proto_msg_queue);  	l_ptr->proto_msg_queue = NULL;  } @@ -571,12 +571,12 @@ void tipc_link_reset(struct tipc_link *l_ptr)  	/* Clean up all queues: */  	link_release_outqueue(l_ptr); -	buf_discard(l_ptr->proto_msg_queue); +	kfree_skb(l_ptr->proto_msg_queue);  	l_ptr->proto_msg_queue = NULL;  	buf = l_ptr->oldest_deferred_in;  	while (buf) {  		struct sk_buff *next = buf->next; -		buf_discard(buf); +		kfree_skb(buf);  		buf = next;  	}  	if (!list_empty(&l_ptr->waiting_ports)) @@ -810,7 +810,7 @@ static int link_bundle_buf(struct tipc_link *l_ptr,  	skb_copy_to_linear_data_offset(bundler, to_pos, buf->data, size);  	msg_set_size(bundler_msg, to_pos + size);  	msg_set_msgcnt(bundler_msg, msg_msgcnt(bundler_msg) + 1); -	buf_discard(buf); +	kfree_skb(buf);  	l_ptr->stats.sent_bundled++;  	return 1;  } @@ -871,17 +871,15 @@ int tipc_link_send_buf(struct tipc_link *l_ptr, struct sk_buff *buf)  	u32 queue_limit = l_ptr->queue_limit[imp];  	u32 max_packet = l_ptr->max_pkt; -	msg_set_prevnode(msg, tipc_own_addr);	/* If routed message */ -  	/* Match msg importance against queue limits: */  	if (unlikely(queue_size >= queue_limit)) {  		if (imp <= TIPC_CRITICAL_IMPORTANCE) {  			link_schedule_port(l_ptr, msg_origport(msg), size); -			buf_discard(buf); +			kfree_skb(buf);  			return -ELINKCONG;  		} -		buf_discard(buf); +		kfree_skb(buf);  		if (imp > CONN_MANAGER) {  			warn("Resetting link <%s>, send queue full", l_ptr->name);  			tipc_link_reset(l_ptr); @@ -968,10 +966,10 @@ int tipc_link_send(struct sk_buff *buf, u32 dest, u32 selector)  		if (l_ptr)  			res = tipc_link_send_buf(l_ptr, buf);  		else -			buf_discard(buf); +			kfree_skb(buf);  		tipc_node_unlock(n_ptr);  	} else { -		buf_discard(buf); +		kfree_skb(buf);  	}  	read_unlock_bh(&tipc_net_lock);  	return res; @@ -1018,7 +1016,7 @@ void tipc_link_send_names(struct list_head *message_list, u32 dest)  	list_for_each_safe(buf, temp_buf, ((struct sk_buff *)message_list)) {  		list_del((struct list_head *)buf); -		buf_discard(buf); +		kfree_skb(buf);  	}  } @@ -1262,7 +1260,7 @@ again:  error:  				for (; buf_chain; buf_chain = buf) {  					buf = buf_chain->next; -					buf_discard(buf_chain); +					kfree_skb(buf_chain);  				}  				return -EFAULT;  			} @@ -1316,7 +1314,7 @@ error:  			tipc_node_unlock(node);  			for (; buf_chain; buf_chain = buf) {  				buf = buf_chain->next; -				buf_discard(buf_chain); +				kfree_skb(buf_chain);  			}  			goto again;  		} @@ -1324,7 +1322,7 @@ error:  reject:  		for (; buf_chain; buf_chain = buf) {  			buf = buf_chain->next; -			buf_discard(buf_chain); +			kfree_skb(buf_chain);  		}  		return tipc_port_reject_sections(sender, hdr, msg_sect, num_sect,  						 total_len, TIPC_ERR_NO_NODE); @@ -1390,7 +1388,7 @@ u32 tipc_link_push_packet(struct tipc_link *l_ptr)  		msg_set_bcast_ack(buf_msg(buf), l_ptr->owner->bclink.last_in);  		if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) {  			l_ptr->unacked_window = 0; -			buf_discard(buf); +			kfree_skb(buf);  			l_ptr->proto_msg_queue = NULL;  			return 0;  		} else { @@ -1501,13 +1499,13 @@ static void link_retransmit_failure(struct tipc_link *l_ptr,  		tipc_node_lock(n_ptr);  		tipc_addr_string_fill(addr_string, n_ptr->addr); -		info("Multicast link info for %s\n", addr_string); +		info("Broadcast link info for %s\n", addr_string); +		info("Supportable: %d,  ", n_ptr->bclink.supportable);  		info("Supported: %d,  ", n_ptr->bclink.supported);  		info("Acked: %u\n", n_ptr->bclink.acked);  		info("Last in: %u,  ", n_ptr->bclink.last_in); -		info("Gap after: %u,  ", n_ptr->bclink.gap_after); -		info("Gap to: %u\n", n_ptr->bclink.gap_to); -		info("Nack sync: %u\n\n", n_ptr->bclink.nack_sync); +		info("Oos state: %u,  ", n_ptr->bclink.oos_state); +		info("Last sent: %u\n", n_ptr->bclink.last_sent);  		tipc_k_signal((Handler)link_reset_all, (unsigned long)n_ptr->addr); @@ -1679,7 +1677,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)  		/* Ensure message data is a single contiguous unit */ -		if (unlikely(buf_linearize(buf))) +		if (unlikely(skb_linearize(buf)))  			goto cont;  		/* Handle arrival of a non-unicast link message */ @@ -1736,7 +1734,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)  		/* Release acked messages */ -		if (tipc_node_is_up(n_ptr) && n_ptr->bclink.supported) +		if (n_ptr->bclink.supported)  			tipc_bclink_acknowledge(n_ptr, msg_bcast_ack(msg));  		crs = l_ptr->first_out; @@ -1744,7 +1742,7 @@ void tipc_recv_msg(struct sk_buff *head, struct tipc_bearer *b_ptr)  		       less_eq(buf_seqno(crs), ackd)) {  			struct sk_buff *next = crs->next; -			buf_discard(crs); +			kfree_skb(crs);  			crs = next;  			released++;  		} @@ -1773,52 +1771,56 @@ protocol_check:  				if (unlikely(l_ptr->oldest_deferred_in))  					head = link_insert_deferred_queue(l_ptr,  									  head); -				if (likely(msg_is_dest(msg, tipc_own_addr))) {  deliver: -					if (likely(msg_isdata(msg))) { -						tipc_node_unlock(n_ptr); -						tipc_port_recv_msg(buf); -						continue; +				if (likely(msg_isdata(msg))) { +					tipc_node_unlock(n_ptr); +					tipc_port_recv_msg(buf); +					continue; +				} +				switch (msg_user(msg)) { +					int ret; +				case MSG_BUNDLER: +					l_ptr->stats.recv_bundles++; +					l_ptr->stats.recv_bundled += +						msg_msgcnt(msg); +					tipc_node_unlock(n_ptr); +					tipc_link_recv_bundle(buf); +					continue; +				case NAME_DISTRIBUTOR: +					tipc_node_unlock(n_ptr); +					tipc_named_recv(buf); +					continue; +				case CONN_MANAGER: +					tipc_node_unlock(n_ptr); +					tipc_port_recv_proto_msg(buf); +					continue; +				case MSG_FRAGMENTER: +					l_ptr->stats.recv_fragments++; +					ret = tipc_link_recv_fragment( +						&l_ptr->defragm_buf, +						&buf, &msg); +					if (ret == 1) { +						l_ptr->stats.recv_fragmented++; +						goto deliver;  					} -					switch (msg_user(msg)) { -					case MSG_BUNDLER: -						l_ptr->stats.recv_bundles++; -						l_ptr->stats.recv_bundled += -							msg_msgcnt(msg); -						tipc_node_unlock(n_ptr); -						tipc_link_recv_bundle(buf); -						continue; -					case NAME_DISTRIBUTOR: -						tipc_node_unlock(n_ptr); -						tipc_named_recv(buf); -						continue; -					case CONN_MANAGER: -						tipc_node_unlock(n_ptr); -						tipc_port_recv_proto_msg(buf); -						continue; -					case MSG_FRAGMENTER: -						l_ptr->stats.recv_fragments++; -						if (tipc_link_recv_fragment(&l_ptr->defragm_buf, -									    &buf, &msg)) { -							l_ptr->stats.recv_fragmented++; +					if (ret == -1) +						l_ptr->next_in_no--; +					break; +				case CHANGEOVER_PROTOCOL: +					type = msg_type(msg); +					if (link_recv_changeover_msg(&l_ptr, +								     &buf)) { +						msg = buf_msg(buf); +						seq_no = msg_seqno(msg); +						if (type == ORIGINAL_MSG)  							goto deliver; -						} -						break; -					case CHANGEOVER_PROTOCOL: -						type = msg_type(msg); -						if (link_recv_changeover_msg(&l_ptr, &buf)) { -							msg = buf_msg(buf); -							seq_no = msg_seqno(msg); -							if (type == ORIGINAL_MSG) -								goto deliver; -							goto protocol_check; -						} -						break; -					default: -						buf_discard(buf); -						buf = NULL; -						break; +						goto protocol_check;  					} +					break; +				default: +					kfree_skb(buf); +					buf = NULL; +					break;  				}  				tipc_node_unlock(n_ptr);  				tipc_net_route_msg(buf); @@ -1847,23 +1849,22 @@ deliver:  		}  		tipc_node_unlock(n_ptr);  cont: -		buf_discard(buf); +		kfree_skb(buf);  	}  	read_unlock_bh(&tipc_net_lock);  }  /* - * link_defer_buf(): Sort a received out-of-sequence packet - *                   into the deferred reception queue. - * Returns the increase of the queue length,i.e. 0 or 1 + * tipc_link_defer_pkt - Add out-of-sequence message to deferred reception queue + * + * Returns increase in queue length (i.e. 0 or 1)   */ -u32 tipc_link_defer_pkt(struct sk_buff **head, -			struct sk_buff **tail, +u32 tipc_link_defer_pkt(struct sk_buff **head, struct sk_buff **tail,  			struct sk_buff *buf)  { -	struct sk_buff *prev = NULL; -	struct sk_buff *crs = *head; +	struct sk_buff *queue_buf; +	struct sk_buff **prev;  	u32 seq_no = buf_seqno(buf);  	buf->next = NULL; @@ -1881,31 +1882,30 @@ u32 tipc_link_defer_pkt(struct sk_buff **head,  		return 1;  	} -	/* Scan through queue and sort it in */ -	do { -		struct tipc_msg *msg = buf_msg(crs); +	/* Locate insertion point in queue, then insert; discard if duplicate */ +	prev = head; +	queue_buf = *head; +	for (;;) { +		u32 curr_seqno = buf_seqno(queue_buf); -		if (less(seq_no, msg_seqno(msg))) { -			buf->next = crs; -			if (prev) -				prev->next = buf; -			else -				*head = buf; -			return 1; +		if (seq_no == curr_seqno) { +			kfree_skb(buf); +			return 0;  		} -		if (seq_no == msg_seqno(msg)) + +		if (less(seq_no, curr_seqno))  			break; -		prev = crs; -		crs = crs->next; -	} while (crs); -	/* Message is a duplicate of an existing message */ +		prev = &queue_buf->next; +		queue_buf = queue_buf->next; +	} -	buf_discard(buf); -	return 0; +	buf->next = queue_buf; +	*prev = buf; +	return 1;  } -/** +/*   * link_handle_out_of_seq_msg - handle arrival of out-of-sequence packet   */ @@ -1930,7 +1930,7 @@ static void link_handle_out_of_seq_msg(struct tipc_link *l_ptr,  	if (less(seq_no, mod(l_ptr->next_in_no))) {  		l_ptr->stats.duplicates++; -		buf_discard(buf); +		kfree_skb(buf);  		return;  	} @@ -1956,6 +1956,13 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,  	u32 msg_size = sizeof(l_ptr->proto_msg);  	int r_flag; +	/* Discard any previous message that was deferred due to congestion */ + +	if (l_ptr->proto_msg_queue) { +		kfree_skb(l_ptr->proto_msg_queue); +		l_ptr->proto_msg_queue = NULL; +	} +  	if (link_blocked(l_ptr))  		return; @@ -1964,9 +1971,11 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,  	if ((l_ptr->owner->block_setup) && (msg_typ != RESET_MSG))  		return; +	/* Create protocol message with "out-of-sequence" sequence number */ +  	msg_set_type(msg, msg_typ);  	msg_set_net_plane(msg, l_ptr->b_ptr->net_plane); -	msg_set_bcast_ack(msg, mod(l_ptr->owner->bclink.last_in)); +	msg_set_bcast_ack(msg, l_ptr->owner->bclink.last_in);  	msg_set_last_bcast(msg, tipc_bclink_get_last_sent());  	if (msg_typ == STATE_MSG) { @@ -2020,44 +2029,36 @@ void tipc_link_send_proto_msg(struct tipc_link *l_ptr, u32 msg_typ,  	r_flag = (l_ptr->owner->working_links > tipc_link_is_up(l_ptr));  	msg_set_redundant_link(msg, r_flag);  	msg_set_linkprio(msg, l_ptr->priority); - -	/* Ensure sequence number will not fit : */ +	msg_set_size(msg, msg_size);  	msg_set_seqno(msg, mod(l_ptr->next_out_no + (0xffff/2))); -	/* Congestion? */ - -	if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { -		if (!l_ptr->proto_msg_queue) { -			l_ptr->proto_msg_queue = -				tipc_buf_acquire(sizeof(l_ptr->proto_msg)); -		} -		buf = l_ptr->proto_msg_queue; -		if (!buf) -			return; -		skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); -		return; -	} - -	/* Message can be sent */ -  	buf = tipc_buf_acquire(msg_size);  	if (!buf)  		return;  	skb_copy_to_linear_data(buf, msg, sizeof(l_ptr->proto_msg)); -	msg_set_size(buf_msg(buf), msg_size); -	if (tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { -		l_ptr->unacked_window = 0; -		buf_discard(buf); +	/* Defer message if bearer is already congested */ + +	if (tipc_bearer_congested(l_ptr->b_ptr, l_ptr)) { +		l_ptr->proto_msg_queue = buf;  		return;  	} -	/* New congestion */ -	tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); -	l_ptr->proto_msg_queue = buf; -	l_ptr->stats.bearer_congs++; +	/* Defer message if attempting to send results in bearer congestion */ + +	if (!tipc_bearer_send(l_ptr->b_ptr, buf, &l_ptr->media_addr)) { +		tipc_bearer_schedule(l_ptr->b_ptr, l_ptr); +		l_ptr->proto_msg_queue = buf; +		l_ptr->stats.bearer_congs++; +		return; +	} + +	/* Discard message if it was sent successfully */ + +	l_ptr->unacked_window = 0; +	kfree_skb(buf);  }  /* @@ -2105,6 +2106,8 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)  			l_ptr->owner->block_setup = WAIT_NODE_DOWN;  		} +		link_state_event(l_ptr, RESET_MSG); +  		/* fall thru' */  	case ACTIVATE_MSG:  		/* Update link settings according other endpoint's values */ @@ -2127,16 +2130,22 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)  		} else {  			l_ptr->max_pkt = l_ptr->max_pkt_target;  		} -		l_ptr->owner->bclink.supported = (max_pkt_info != 0); +		l_ptr->owner->bclink.supportable = (max_pkt_info != 0); -		link_state_event(l_ptr, msg_type(msg)); +		/* Synchronize broadcast link info, if not done previously */ + +		if (!tipc_node_is_up(l_ptr->owner)) { +			l_ptr->owner->bclink.last_sent = +				l_ptr->owner->bclink.last_in = +				msg_last_bcast(msg); +			l_ptr->owner->bclink.oos_state = 0; +		}  		l_ptr->peer_session = msg_session(msg);  		l_ptr->peer_bearer_id = msg_bearer_id(msg); -		/* Synchronize broadcast sequence numbers */ -		if (!tipc_node_redundant_links(l_ptr->owner)) -			l_ptr->owner->bclink.last_in = mod(msg_last_bcast(msg)); +		if (msg_type(msg) == ACTIVATE_MSG) +			link_state_event(l_ptr, ACTIVATE_MSG);  		break;  	case STATE_MSG: @@ -2177,7 +2186,9 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)  		/* Protocol message before retransmits, reduce loss risk */ -		tipc_bclink_check_gap(l_ptr->owner, msg_last_bcast(msg)); +		if (l_ptr->owner->bclink.supported) +			tipc_bclink_update_link_state(l_ptr->owner, +						      msg_last_bcast(msg));  		if (rec_gap || (msg_probe(msg))) {  			tipc_link_send_proto_msg(l_ptr, STATE_MSG, @@ -2191,7 +2202,7 @@ static void link_recv_proto_msg(struct tipc_link *l_ptr, struct sk_buff *buf)  		break;  	}  exit: -	buf_discard(buf); +	kfree_skb(buf);  } @@ -2389,7 +2400,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr,  			warn("Link changeover error, duplicate msg dropped\n");  			goto exit;  		} -		buf_discard(tunnel_buf); +		kfree_skb(tunnel_buf);  		return 1;  	} @@ -2421,7 +2432,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr,  	} else {  		*buf = buf_extract(tunnel_buf, INT_H_SIZE);  		if (*buf != NULL) { -			buf_discard(tunnel_buf); +			kfree_skb(tunnel_buf);  			return 1;  		} else {  			warn("Link changeover error, original msg dropped\n"); @@ -2429,7 +2440,7 @@ static int link_recv_changeover_msg(struct tipc_link **l_ptr,  	}  exit:  	*buf = NULL; -	buf_discard(tunnel_buf); +	kfree_skb(tunnel_buf);  	return 0;  } @@ -2451,7 +2462,7 @@ void tipc_link_recv_bundle(struct sk_buff *buf)  		pos += align(msg_size(buf_msg(obuf)));  		tipc_net_route_msg(obuf);  	} -	buf_discard(buf); +	kfree_skb(buf);  }  /* @@ -2500,11 +2511,11 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)  		}  		fragm = tipc_buf_acquire(fragm_sz + INT_H_SIZE);  		if (fragm == NULL) { -			buf_discard(buf); +			kfree_skb(buf);  			while (buf_chain) {  				buf = buf_chain;  				buf_chain = buf_chain->next; -				buf_discard(buf); +				kfree_skb(buf);  			}  			return -ENOMEM;  		} @@ -2521,7 +2532,7 @@ static int link_send_long_buf(struct tipc_link *l_ptr, struct sk_buff *buf)  		crs += fragm_sz;  		msg_set_type(&fragm_hdr, FRAGMENT);  	} -	buf_discard(buf); +	kfree_skb(buf);  	/* Append chain of fragments to send queue & send them */ @@ -2608,7 +2619,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,  		if (msg_type(imsg) == TIPC_MCAST_MSG)  			max = TIPC_MAX_USER_MSG_SIZE + MCAST_H_SIZE;  		if (msg_size(imsg) > max) { -			buf_discard(fbuf); +			kfree_skb(fbuf);  			return 0;  		}  		pbuf = tipc_buf_acquire(msg_size(imsg)); @@ -2623,9 +2634,11 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,  			set_fragm_size(pbuf, fragm_sz);  			set_expected_frags(pbuf, exp_fragm_cnt - 1);  		} else { -			warn("Link unable to reassemble fragmented message\n"); +			dbg("Link unable to reassemble fragmented message\n"); +			kfree_skb(fbuf); +			return -1;  		} -		buf_discard(fbuf); +		kfree_skb(fbuf);  		return 0;  	} else if (pbuf && (msg_type(fragm) != FIRST_FRAGMENT)) {  		u32 dsz = msg_data_sz(fragm); @@ -2634,7 +2647,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,  		u32 exp_frags = get_expected_frags(pbuf) - 1;  		skb_copy_to_linear_data_offset(pbuf, crs,  					       msg_data(fragm), dsz); -		buf_discard(fbuf); +		kfree_skb(fbuf);  		/* Is message complete? */ @@ -2651,7 +2664,7 @@ int tipc_link_recv_fragment(struct sk_buff **pending, struct sk_buff **fb,  		set_expected_frags(pbuf, exp_frags);  		return 0;  	} -	buf_discard(fbuf); +	kfree_skb(fbuf);  	return 0;  } @@ -2682,7 +2695,7 @@ static void link_check_defragm_bufs(struct tipc_link *l_ptr)  				prev->next = buf->next;  			else  				l_ptr->defragm_buf = buf->next; -			buf_discard(buf); +			kfree_skb(buf);  		}  		buf = next;  	} @@ -3057,7 +3070,7 @@ struct sk_buff *tipc_link_cmd_show_stats(const void *req_tlv_area, int req_tlv_s  	str_len = tipc_link_stats((char *)TLV_DATA(req_tlv_area),  				  (char *)TLV_DATA(rep_tlv), MAX_LINK_STATS_INFO);  	if (!str_len) { -		buf_discard(buf); +		kfree_skb(buf);  		return tipc_cfg_reply_error_string("link not found");  	} | 
