/* tipc_bcbase_xmit - broadcast a packet queue across one or more bearers * * Note that number of reachable destinations, as indicated in the dests[] * array, may transitionally differ from the number of destinations indicated * in each sent buffer. We can sustain this. Excess destination nodes will * drop and never acknowledge the unexpected packets, and missing destinations * will either require retransmission (if they are just about to be added to * the bearer), or be removed from the buffer's 'ackers' counter (if they * just went down) */ static void tipc_bcbase_xmit(struct net *net, struct sk_buff_head *xmitq) { int bearer_id; struct tipc_bc_base *bb = tipc_bc_base(net); struct sk_buff *skb, *_skb; struct sk_buff_head _xmitq; if (skb_queue_empty(xmitq)) return; /* The typical case: at least one bearer has links to all nodes */ bearer_id = bb->primary_bearer; if (bearer_id >= 0) { tipc_bearer_bc_xmit(net, bearer_id, xmitq); return; } /* We have to transmit across all bearers */ skb_queue_head_init(&_xmitq); for (bearer_id = 0; bearer_id < MAX_BEARERS; bearer_id++) { if (!bb->dests[bearer_id]) continue; skb_queue_walk(xmitq, skb) { _skb = pskb_copy_for_clone(skb, GFP_ATOMIC); if (!_skb) break; __skb_queue_tail(&_xmitq, _skb); } tipc_bearer_bc_xmit(net, bearer_id, &_xmitq); }
/** * Directly insert all skbs from @skb_list into @sk TCP write queue regardless * write buffer size. This allows directly forward modified packets without * copying. See do_tcp_sendpages() and tcp_sendmsg() in linux/net/ipv4/tcp.c. * * Can be called in softirq context as well as from kernel thread. * * TODO use MSG_MORE untill we reach end of message. */ int ss_send(struct sock *sk, SsSkbList *skb_list, bool pass_skb) { int r = 0; struct sk_buff *skb, *skb_copy; SsWork sw = { .sk = sk, .action = SS_SEND, }; BUG_ON(!sk); BUG_ON(ss_skb_queue_empty(skb_list)); SS_DBG("%s: cpu=%d sk=%p (cpu=%d) state=%s\n", __func__, smp_processor_id(), sk, sk->sk_incoming_cpu, ss_statename[sk->sk_state]); /* * Remove the skbs from Tempesta lists if we won't use them, * or copy them if they're going to be used by Tempesta during * and after the transmission. */ if (pass_skb) { sw.skb_list = *skb_list; ss_skb_queue_head_init(skb_list); } else { ss_skb_queue_head_init(&sw.skb_list); for (skb = ss_skb_peek(skb_list); skb; skb = ss_skb_next(skb)) { /* tcp_transmit_skb() will clone the skb. */ skb_copy = pskb_copy_for_clone(skb, GFP_ATOMIC); if (!skb_copy) { SS_WARN("Unable to copy an egress SKB.\n"); r = -ENOMEM; goto err; } ss_skb_queue_tail(&sw.skb_list, skb_copy); } } /* * Schedule the socket for TX softirq processing. * Only part of @skb_list could be passed to send queue. */ if (ss_wq_push(&sw)) { SS_WARN("Cannot schedule socket %p for transmission\n", sk); r = -EBUSY; goto err; } return 0; err: if (!pass_skb) while ((skb = ss_skb_dequeue(&sw.skb_list))) kfree_skb(skb); return r; }
/** * tipc_bcbearer_send - send a packet through the broadcast pseudo-bearer * * Send packet over as many bearers as necessary to reach all nodes * that have joined the broadcast link. * * Returns 0 (packet sent successfully) under all circumstances, * since the broadcast link's pseudo-bearer never blocks */ static int tipc_bcbearer_send(struct sk_buff *buf, struct tipc_bearer *unused1, struct tipc_media_addr *unused2) { int bp_index; /* Prepare broadcast link message for reliable transmission, * if first time trying to send it; * preparation is skipped for broadcast link protocol messages * since they are sent in an unreliable manner and don't need it */ if (likely(!msg_non_seq(buf_msg(buf)))) { struct tipc_msg *msg; bcbuf_set_acks(buf, bclink->bcast_nodes.count); msg = buf_msg(buf); msg_set_non_seq(msg, 1); msg_set_mc_netid(msg, tipc_net_id); bcl->stats.sent_info++; if (WARN_ON(!bclink->bcast_nodes.count)) { dump_stack(); return 0; } } /* Send buffer over bearers until all targets reached */ bcbearer->remains = bclink->bcast_nodes; for (bp_index = 0; bp_index < MAX_BEARERS; bp_index++) { struct tipc_bearer *p = bcbearer->bpairs[bp_index].primary; struct tipc_bearer *s = bcbearer->bpairs[bp_index].secondary; struct tipc_bearer *b = p; struct sk_buff *tbuf; if (!p) break; /* No more bearers to try */ if (tipc_bearer_blocked(p)) { if (!s || tipc_bearer_blocked(s)) continue; /* Can't use either bearer */ b = s; } tipc_nmap_diff(&bcbearer->remains, &b->nodes, &bcbearer->remains_new); if (bcbearer->remains_new.count == bcbearer->remains.count) continue; /* Nothing added by bearer pair */ if (bp_index == 0) { /* Use original buffer for first bearer */ tipc_bearer_send(b, buf, &b->bcast_addr); } else { /* Avoid concurrent buffer access */ #ifdef CONFIG_LGP_DATA_TCPIP_MPTCP tbuf = pskb_copy_for_clone(buf, GFP_ATOMIC); #else tbuf = pskb_copy(buf, GFP_ATOMIC); #endif if (!tbuf) break; tipc_bearer_send(b, tbuf, &b->bcast_addr); kfree_skb(tbuf); /* Bearer keeps a clone */ } /* Swap bearers for next packet */ if (s) { bcbearer->bpairs[bp_index].primary = s; bcbearer->bpairs[bp_index].secondary = p; } if (bcbearer->remains_new.count == 0) break; /* All targets reached */ bcbearer->remains = bcbearer->remains_new; } return 0; }