aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/udp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/udp.c')
-rw-r--r--net/ipv4/udp.c156
1 files changed, 35 insertions, 121 deletions
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 7d5a8661df76..f57c0e4c2326 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -594,27 +594,6 @@ static inline bool __udp_is_mcast_sock(struct net *net, struct sock *sk,
594 return true; 594 return true;
595} 595}
596 596
597static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk,
598 __be16 loc_port, __be32 loc_addr,
599 __be16 rmt_port, __be32 rmt_addr,
600 int dif)
601{
602 struct hlist_nulls_node *node;
603 struct sock *s = sk;
604 unsigned short hnum = ntohs(loc_port);
605
606 sk_nulls_for_each_from(s, node) {
607 if (__udp_is_mcast_sock(net, s,
608 loc_port, loc_addr,
609 rmt_port, rmt_addr,
610 dif, hnum))
611 goto found;
612 }
613 s = NULL;
614found:
615 return s;
616}
617
618/* 597/*
619 * This routine is called by the ICMP module when it gets some 598 * This routine is called by the ICMP module when it gets some
620 * sort of error condition. If err < 0 then the socket should 599 * sort of error condition. If err < 0 then the socket should
@@ -1588,7 +1567,7 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
1588 goto csum_error; 1567 goto csum_error;
1589 1568
1590 1569
1591 if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { 1570 if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) {
1592 UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS, 1571 UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
1593 is_udplite); 1572 is_udplite);
1594 goto drop; 1573 goto drop;
@@ -1640,6 +1619,8 @@ static void flush_stack(struct sock **stack, unsigned int count,
1640 1619
1641 if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0) 1620 if (skb1 && udp_queue_rcv_skb(sk, skb1) <= 0)
1642 skb1 = NULL; 1621 skb1 = NULL;
1622
1623 sock_put(sk);
1643 } 1624 }
1644 if (unlikely(skb1)) 1625 if (unlikely(skb1))
1645 kfree_skb(skb1); 1626 kfree_skb(skb1);
@@ -1668,41 +1649,50 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
1668 struct udp_table *udptable) 1649 struct udp_table *udptable)
1669{ 1650{
1670 struct sock *sk, *stack[256 / sizeof(struct sock *)]; 1651 struct sock *sk, *stack[256 / sizeof(struct sock *)];
1671 struct udp_hslot *hslot = udp_hashslot(udptable, net, ntohs(uh->dest)); 1652 struct hlist_nulls_node *node;
1672 int dif; 1653 unsigned short hnum = ntohs(uh->dest);
1673 unsigned int i, count = 0; 1654 struct udp_hslot *hslot = udp_hashslot(udptable, net, hnum);
1655 int dif = skb->dev->ifindex;
1656 unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
1657 unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
1658
1659 if (use_hash2) {
1660 hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
1661 udp_table.mask;
1662 hash2 = udp4_portaddr_hash(net, daddr, hnum) & udp_table.mask;
1663start_lookup:
1664 hslot = &udp_table.hash2[hash2];
1665 offset = offsetof(typeof(*sk), __sk_common.skc_portaddr_node);
1666 }
1674 1667
1675 spin_lock(&hslot->lock); 1668 spin_lock(&hslot->lock);
1676 sk = sk_nulls_head(&hslot->head); 1669 sk_nulls_for_each_entry_offset(sk, node, &hslot->head, offset) {
1677 dif = skb->dev->ifindex; 1670 if (__udp_is_mcast_sock(net, sk,
1678 sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); 1671 uh->dest, daddr,
1679 while (sk) { 1672 uh->source, saddr,
1680 stack[count++] = sk; 1673 dif, hnum)) {
1681 sk = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, 1674 if (unlikely(count == ARRAY_SIZE(stack))) {
1682 daddr, uh->source, saddr, dif); 1675 flush_stack(stack, count, skb, ~0);
1683 if (unlikely(count == ARRAY_SIZE(stack))) { 1676 count = 0;
1684 if (!sk) 1677 }
1685 break; 1678 stack[count++] = sk;
1686 flush_stack(stack, count, skb, ~0); 1679 sock_hold(sk);
1687 count = 0;
1688 } 1680 }
1689 } 1681 }
1690 /*
1691 * before releasing chain lock, we must take a reference on sockets
1692 */
1693 for (i = 0; i < count; i++)
1694 sock_hold(stack[i]);
1695 1682
1696 spin_unlock(&hslot->lock); 1683 spin_unlock(&hslot->lock);
1697 1684
1685 /* Also lookup *:port if we are using hash2 and haven't done so yet. */
1686 if (use_hash2 && hash2 != hash2_any) {
1687 hash2 = hash2_any;
1688 goto start_lookup;
1689 }
1690
1698 /* 1691 /*
1699 * do the slow work with no lock held 1692 * do the slow work with no lock held
1700 */ 1693 */
1701 if (count) { 1694 if (count) {
1702 flush_stack(stack, count, skb, count - 1); 1695 flush_stack(stack, count, skb, count - 1);
1703
1704 for (i = 0; i < count; i++)
1705 sock_put(stack[i]);
1706 } else { 1696 } else {
1707 kfree_skb(skb); 1697 kfree_skb(skb);
1708 } 1698 }
@@ -2526,79 +2516,3 @@ void __init udp_init(void)
2526 sysctl_udp_rmem_min = SK_MEM_QUANTUM; 2516 sysctl_udp_rmem_min = SK_MEM_QUANTUM;
2527 sysctl_udp_wmem_min = SK_MEM_QUANTUM; 2517 sysctl_udp_wmem_min = SK_MEM_QUANTUM;
2528} 2518}
2529
2530struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
2531 netdev_features_t features)
2532{
2533 struct sk_buff *segs = ERR_PTR(-EINVAL);
2534 u16 mac_offset = skb->mac_header;
2535 int mac_len = skb->mac_len;
2536 int tnl_hlen = skb_inner_mac_header(skb) - skb_transport_header(skb);
2537 __be16 protocol = skb->protocol;
2538 netdev_features_t enc_features;
2539 int udp_offset, outer_hlen;
2540 unsigned int oldlen;
2541 bool need_csum;
2542
2543 oldlen = (u16)~skb->len;
2544
2545 if (unlikely(!pskb_may_pull(skb, tnl_hlen)))
2546 goto out;
2547
2548 skb->encapsulation = 0;
2549 __skb_pull(skb, tnl_hlen);
2550 skb_reset_mac_header(skb);
2551 skb_set_network_header(skb, skb_inner_network_offset(skb));
2552 skb->mac_len = skb_inner_network_offset(skb);
2553 skb->protocol = htons(ETH_P_TEB);
2554
2555 need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
2556 if (need_csum)
2557 skb->encap_hdr_csum = 1;
2558
2559 /* segment inner packet. */
2560 enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
2561 segs = skb_mac_gso_segment(skb, enc_features);
2562 if (!segs || IS_ERR(segs)) {
2563 skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
2564 mac_len);
2565 goto out;
2566 }
2567
2568 outer_hlen = skb_tnl_header_len(skb);
2569 udp_offset = outer_hlen - tnl_hlen;
2570 skb = segs;
2571 do {
2572 struct udphdr *uh;
2573 int len;
2574
2575 skb_reset_inner_headers(skb);
2576 skb->encapsulation = 1;
2577
2578 skb->mac_len = mac_len;
2579
2580 skb_push(skb, outer_hlen);
2581 skb_reset_mac_header(skb);
2582 skb_set_network_header(skb, mac_len);
2583 skb_set_transport_header(skb, udp_offset);
2584 len = skb->len - udp_offset;
2585 uh = udp_hdr(skb);
2586 uh->len = htons(len);
2587
2588 if (need_csum) {
2589 __be32 delta = htonl(oldlen + len);
2590
2591 uh->check = ~csum_fold((__force __wsum)
2592 ((__force u32)uh->check +
2593 (__force u32)delta));
2594 uh->check = gso_make_checksum(skb, ~uh->check);
2595
2596 if (uh->check == 0)
2597 uh->check = CSUM_MANGLED_0;
2598 }
2599
2600 skb->protocol = protocol;
2601 } while ((skb = skb->next));
2602out:
2603 return segs;
2604}