History

udp: Increment UDP_MIB_IGNOREDMULTI for arriving unmatched multicasts

As NIC multicast filtering isn't perfect, and some platforms are quite content to spew broadcasts, we should not trigger an event for skb:kfree_skb when we do not have a match for such an incoming datagram. We do though want to avoid sweeping the matter under the rug entirely, so increment a suitable statistic. This incorporates feedback from David L. Stevens, Karl Neiss and Eric Dumazet. V3 - use bool per David Miller

Rick Jones committed 12 years ago

Commit 36cbb241 parent f46ad735 files · +20 −6Browse files

Unified · Split

5 files
  1. include/uapi/linux/snmp.h +1 −0
  2. net/ipv4/proc.c +1 −0
  3. net/ipv4/udp.c +9 −3
  4. net/ipv6/proc.c +1 −0
  5. net/ipv6/udp.c +8 −3
include/uapi/linux/snmp.h+1−0
@@ -156,6 +156,7 @@ enum · 155 unmodified lines
156156 UDP_MIB_RCVBUFERRORS, /* RcvbufErrors */
157157 UDP_MIB_SNDBUFERRORS, /* SndbufErrors */
158158 UDP_MIB_CSUMERRORS, /* InCsumErrors */
159+ UDP_MIB_IGNOREDMULTI, /* IgnoredMulti */
159160 __UDP_MIB_MAX
160161 };
161162
net/ipv4/proc.c+1−0
@@ -181,6 +181,7 @@ static const struct snmp_mib snmp4_udp_list[] = { · 180 unmodified lines
181181 SNMP_MIB_ITEM("RcvbufErrors", UDP_MIB_RCVBUFERRORS),
182182 SNMP_MIB_ITEM("SndbufErrors", UDP_MIB_SNDBUFERRORS),
183183 SNMP_MIB_ITEM("InCsumErrors", UDP_MIB_CSUMERRORS),
184+ SNMP_MIB_ITEM("IgnoredMulti", UDP_MIB_IGNOREDMULTI),
184185 SNMP_MIB_SENTINEL
185186 };
186187
net/ipv4/udp.c+9−3
@@ -1647,7 +1647,8 @@ static void udp_sk_rx_dst_set(struct sock *sk, struct dst_entry *dst) · 1646 unmodified lines
16471647 static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
16481648 struct udphdr *uh,
16491649 __be32 saddr, __be32 daddr,
1650− struct udp_table *udptable)
1650+ struct udp_table *udptable,
1651+ int proto)
16511652 {
16521653 struct sock *sk, *stack[256 / sizeof(struct sock *)];
16531654 struct hlist_nulls_node *node;
@@ -1656,6 +1657,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, · 2 unmodified lines
16561657 int dif = skb->dev->ifindex;
16571658 unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
16581659 unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
1660+ bool inner_flushed = false;
16591661
16601662 if (use_hash2) {
16611663 hash2_any = udp4_portaddr_hash(net, htonl(INADDR_ANY), hnum) &
@@ -1674,6 +1676,7 @@ start_lookup: · 12 unmodified lines
16741676 dif, hnum)) {
16751677 if (unlikely(count == ARRAY_SIZE(stack))) {
16761678 flush_stack(stack, count, skb, ~0);
1679+ inner_flushed = true;
16771680 count = 0;
16781681 }
16791682 stack[count++] = sk;
@@ -1695,7 +1698,10 @@ start_lookup: · 15 unmodified lines
16951698 if (count) {
16961699 flush_stack(stack, count, skb, count - 1);
16971700 } else {
1698− kfree_skb(skb);
1701+ if (!inner_flushed)
1702+ UDP_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
1703+ proto == IPPROTO_UDPLITE);
1704+ consume_skb(skb);
16991705 }
17001706 return 0;
17011707 }
@@ -1781,7 +1787,7 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, · 79 unmodified lines
17811787
17821788 if (rt->rt_flags & (RTCF_BROADCAST|RTCF_MULTICAST))
17831789 return __udp4_lib_mcast_deliver(net, skb, uh,
1784− saddr, daddr, udptable);
1790+ saddr, daddr, udptable, proto);
17851791
17861792 sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
17871793 if (sk != NULL) {
net/ipv6/proc.c+1−0
@@ -136,6 +136,7 @@ static const struct snmp_mib snmp6_udp6_list[] = { · 135 unmodified lines
136136 SNMP_MIB_ITEM("Udp6RcvbufErrors", UDP_MIB_RCVBUFERRORS),
137137 SNMP_MIB_ITEM("Udp6SndbufErrors", UDP_MIB_SNDBUFERRORS),
138138 SNMP_MIB_ITEM("Udp6InCsumErrors", UDP_MIB_CSUMERRORS),
139+ SNMP_MIB_ITEM("Udp6IgnoredMulti", UDP_MIB_IGNOREDMULTI),
139140 SNMP_MIB_SENTINEL
140141 };
141142
net/ipv6/udp.c+8−3
@@ -771,7 +771,7 @@ static void udp6_csum_zero_error(struct sk_buff *skb) · 770 unmodified lines
771771 */
772772 static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
773773 const struct in6_addr *saddr, const struct in6_addr *daddr,
774− struct udp_table *udptable)
774+ struct udp_table *udptable, int proto)
775775 {
776776 struct sock *sk, *stack[256 / sizeof(struct sock *)];
777777 const struct udphdr *uh = udp_hdr(skb);
@@ -781,6 +781,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, · 3 unmodified lines
781781 int dif = inet6_iif(skb);
782782 unsigned int count = 0, offset = offsetof(typeof(*sk), sk_nulls_node);
783783 unsigned int hash2 = 0, hash2_any = 0, use_hash2 = (hslot->count > 10);
784+ bool inner_flushed = false;
784785
785786 if (use_hash2) {
786787 hash2_any = udp6_portaddr_hash(net, &in6addr_any, hnum) &
@@ -803,6 +804,7 @@ start_lookup: · 16 unmodified lines
803804 (uh->check || udp_sk(sk)->no_check6_rx)) {
804805 if (unlikely(count == ARRAY_SIZE(stack))) {
805806 flush_stack(stack, count, skb, ~0);
807+ inner_flushed = true;
806808 count = 0;
807809 }
808810 stack[count++] = sk;
@@ -821,7 +823,10 @@ start_lookup: · 12 unmodified lines
821823 if (count) {
822824 flush_stack(stack, count, skb, count - 1);
823825 } else {
824− kfree_skb(skb);
826+ if (!inner_flushed)
827+ UDP_INC_STATS_BH(net, UDP_MIB_IGNOREDMULTI,
828+ proto == IPPROTO_UDPLITE);
829+ consume_skb(skb);
825830 }
826831 return 0;
827832 }
@@ -873,7 +878,7 @@ int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, · 45 unmodified lines
873878 */
874879 if (ipv6_addr_is_multicast(daddr))
875880 return __udp6_lib_mcast_deliver(net, skb,
876− saddr, daddr, udptable);
881+ saddr, daddr, udptable, proto);
877882
878883 /* Unicast */
879884