mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-29 04:41:21 -04:00
Merge branch 'ip-ingress-skb-reason'
Menglong Dong says: ==================== net: ip: add skb drop reasons to ip ingress In the series "net: use kfree_skb_reason() for ip/udp packet receive", skb drop reasons are added to the basic ingress path of IPv4. And in the series "net: use kfree_skb_reason() for ip/neighbour", the egress paths of IPv4 and IPv6 are handled. Related links: https://lore.kernel.org/netdev/20220205074739.543606-1-imagedong@tencent.com/ https://lore.kernel.org/netdev/20220226041831.2058437-1-imagedong@tencent.com/ Seems we still have a lot work to do with IP layer, including IPv6 basic ingress path, IPv4/IPv6 forwarding, IPv6 exthdrs, fragment and defrag, etc. In this series, skb drop reasons are added to the basic ingress path of IPv6 protocol and IPv4/IPv6 packet forwarding. Following functions, which are used for IPv6 packet receiving are handled: ip6_pkt_drop() ip6_rcv_core() ip6_protocol_deliver_rcu() And following functions that used for IPv6 TLV parse are handled: ip6_parse_tlv() ipv6_hop_ra() ipv6_hop_ioam() ipv6_hop_jumbo() ipv6_hop_calipso() ipv6_dest_hao() Besides, ip_forward() and ip6_forward(), which are used for IPv4/IPv6 forwarding, are also handled. And following new drop reasons are added: /* host unreachable, corresponding to IPSTATS_MIB_INADDRERRORS */ SKB_DROP_REASON_IP_INADDRERRORS /* network unreachable, corresponding to IPSTATS_MIB_INADDRERRORS */ SKB_DROP_REASON_IP_INNOROUTES /* packet size is too big, corresponding to * IPSTATS_MIB_INTOOBIGERRORS */ SKB_DROP_REASON_PKT_TOO_BIG In order to simply the definition and assignment for 'enum skb_drop_reason', some helper functions are introduced in the 1th patch. I'm not such if this is necessary, but it makes the code simpler. For example, we can replace the code: if (reason == SKB_DROP_REASON_NOT_SPECIFIED) reason = SKB_DROP_REASON_IP_INHDR; with: SKB_DR_OR(reason, IP_INHDR); In the 6th patch, the statistics for skb in ipv6_hop_jum() is removed, as I think it is redundant. There are two call chains for ipv6_hop_jumbo(). The first one is: ipv6_destopt_rcv() -> ip6_parse_tlv() -> ipv6_hop_jumbo() On this call chain, the drop statistics will be done in ipv6_destopt_rcv() with 'IPSTATS_MIB_INHDRERRORS' if ipv6_hop_jumbo() returns false. The second call chain is: ip6_rcv_core() -> ipv6_parse_hopopts() -> ip6_parse_tlv() And the drop statistics will also be done in ip6_rcv_core() with 'IPSTATS_MIB_INHDRERRORS' if ipv6_hop_jumbo() returns false. Therefore, the statistics in ipv6_hop_jumbo() is redundant, which means the drop is counted twice. The statistics in ipv6_hop_jumbo() is almost the same as the outside, except the 'IPSTATS_MIB_INTRUNCATEDPKTS', which seems that we have to ignore it. ====================================================================== Here is a basic test for IPv6 forwarding packet drop that monitored by 'dropwatch' tool: drop at: ip6_forward+0x81a/0xb70 (0xffffffff86c73f8a) origin: software input port ifindex: 7 timestamp: Wed Apr 13 11:51:06 2022 130010176 nsec protocol: 0x86dd length: 94 original length: 94 drop reason: IP_INADDRERRORS The origin cause of this case is that IPv6 doesn't allow to forward the packet with LOCAL-LINK saddr, and results the 'IP_INADDRERRORS' drop reason. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -79,8 +79,9 @@ extern int icmpv6_init(void);
|
||||
extern int icmpv6_err_convert(u8 type, u8 code,
|
||||
int *err);
|
||||
extern void icmpv6_cleanup(void);
|
||||
extern void icmpv6_param_prob(struct sk_buff *skb,
|
||||
u8 code, int pos);
|
||||
extern void icmpv6_param_prob_reason(struct sk_buff *skb,
|
||||
u8 code, int pos,
|
||||
enum skb_drop_reason reason);
|
||||
|
||||
struct flowi6;
|
||||
struct in6_addr;
|
||||
@@ -91,6 +92,12 @@ extern void icmpv6_flow_init(struct sock *sk,
|
||||
const struct in6_addr *daddr,
|
||||
int oif);
|
||||
|
||||
static inline void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
|
||||
{
|
||||
icmpv6_param_prob_reason(skb, code, pos,
|
||||
SKB_DROP_REASON_NOT_SPECIFIED);
|
||||
}
|
||||
|
||||
static inline bool icmpv6_is_err(int type)
|
||||
{
|
||||
switch (type) {
|
||||
|
||||
@@ -447,9 +447,30 @@ enum skb_drop_reason {
|
||||
* 2211, such as a broadcasts
|
||||
* ICMP_TIMESTAMP
|
||||
*/
|
||||
SKB_DROP_REASON_IP_INADDRERRORS, /* host unreachable, corresponding
|
||||
* to IPSTATS_MIB_INADDRERRORS
|
||||
*/
|
||||
SKB_DROP_REASON_IP_INNOROUTES, /* network unreachable, corresponding
|
||||
* to IPSTATS_MIB_INADDRERRORS
|
||||
*/
|
||||
SKB_DROP_REASON_PKT_TOO_BIG, /* packet size is too big (maybe exceed
|
||||
* the MTU)
|
||||
*/
|
||||
SKB_DROP_REASON_MAX,
|
||||
};
|
||||
|
||||
#define SKB_DR_INIT(name, reason) \
|
||||
enum skb_drop_reason name = SKB_DROP_REASON_##reason
|
||||
#define SKB_DR(name) \
|
||||
SKB_DR_INIT(name, NOT_SPECIFIED)
|
||||
#define SKB_DR_SET(name, reason) \
|
||||
(name = SKB_DROP_REASON_##reason)
|
||||
#define SKB_DR_OR(name, reason) \
|
||||
do { \
|
||||
if (name == SKB_DROP_REASON_NOT_SPECIFIED) \
|
||||
SKB_DR_SET(name, reason); \
|
||||
} while (0)
|
||||
|
||||
/* To allow 64K frame to be packed as single skb without frag_list we
|
||||
* require 64K/PAGE_SIZE pages plus 1 additional page to allow for
|
||||
* buffers which do not start on a page boundary.
|
||||
|
||||
@@ -63,6 +63,9 @@
|
||||
EM(SKB_DROP_REASON_TAP_TXFILTER, TAP_TXFILTER) \
|
||||
EM(SKB_DROP_REASON_ICMP_CSUM, ICMP_CSUM) \
|
||||
EM(SKB_DROP_REASON_INVALID_PROTO, INVALID_PROTO) \
|
||||
EM(SKB_DROP_REASON_IP_INADDRERRORS, IP_INADDRERRORS) \
|
||||
EM(SKB_DROP_REASON_IP_INNOROUTES, IP_INNOROUTES) \
|
||||
EM(SKB_DROP_REASON_PKT_TOO_BIG, PKT_TOO_BIG) \
|
||||
EMe(SKB_DROP_REASON_MAX, MAX)
|
||||
|
||||
#undef EM
|
||||
|
||||
@@ -90,6 +90,7 @@ int ip_forward(struct sk_buff *skb)
|
||||
struct rtable *rt; /* Route we use */
|
||||
struct ip_options *opt = &(IPCB(skb)->opt);
|
||||
struct net *net;
|
||||
SKB_DR(reason);
|
||||
|
||||
/* that should never happen */
|
||||
if (skb->pkt_type != PACKET_HOST)
|
||||
@@ -101,8 +102,10 @@ int ip_forward(struct sk_buff *skb)
|
||||
if (skb_warn_if_lro(skb))
|
||||
goto drop;
|
||||
|
||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
|
||||
if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) {
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
|
||||
return NET_RX_SUCCESS;
|
||||
@@ -118,8 +121,10 @@ int ip_forward(struct sk_buff *skb)
|
||||
if (ip_hdr(skb)->ttl <= 1)
|
||||
goto too_many_hops;
|
||||
|
||||
if (!xfrm4_route_forward(skb))
|
||||
if (!xfrm4_route_forward(skb)) {
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
rt = skb_rtable(skb);
|
||||
|
||||
@@ -132,6 +137,7 @@ int ip_forward(struct sk_buff *skb)
|
||||
IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
|
||||
htonl(mtu));
|
||||
SKB_DR_SET(reason, PKT_TOO_BIG);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
@@ -169,7 +175,8 @@ int ip_forward(struct sk_buff *skb)
|
||||
/* Tell the sender its packet died... */
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
|
||||
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
|
||||
SKB_DR_SET(reason, IP_INHDR);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
@@ -945,6 +945,7 @@ static int ip_error(struct sk_buff *skb)
|
||||
struct inet_peer *peer;
|
||||
unsigned long now;
|
||||
struct net *net;
|
||||
SKB_DR(reason);
|
||||
bool send;
|
||||
int code;
|
||||
|
||||
@@ -964,10 +965,12 @@ static int ip_error(struct sk_buff *skb)
|
||||
if (!IN_DEV_FORWARD(in_dev)) {
|
||||
switch (rt->dst.error) {
|
||||
case EHOSTUNREACH:
|
||||
SKB_DR_SET(reason, IP_INADDRERRORS);
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_INADDRERRORS);
|
||||
break;
|
||||
|
||||
case ENETUNREACH:
|
||||
SKB_DR_SET(reason, IP_INNOROUTES);
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES);
|
||||
break;
|
||||
}
|
||||
@@ -983,6 +986,7 @@ static int ip_error(struct sk_buff *skb)
|
||||
break;
|
||||
case ENETUNREACH:
|
||||
code = ICMP_NET_UNREACH;
|
||||
SKB_DR_SET(reason, IP_INNOROUTES);
|
||||
__IP_INC_STATS(net, IPSTATS_MIB_INNOROUTES);
|
||||
break;
|
||||
case EACCES:
|
||||
@@ -1009,7 +1013,7 @@ static int ip_error(struct sk_buff *skb)
|
||||
if (send)
|
||||
icmp_send(skb, ICMP_DEST_UNREACH, code, 0);
|
||||
|
||||
out: kfree_skb(skb);
|
||||
out: kfree_skb_reason(skb, reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -90,12 +90,13 @@ static bool ip6_tlvopt_unknown(struct sk_buff *skb, int optoff,
|
||||
break;
|
||||
fallthrough;
|
||||
case 2: /* send ICMP PARM PROB regardless and drop packet */
|
||||
icmpv6_param_prob(skb, ICMPV6_UNK_OPTION, optoff);
|
||||
icmpv6_param_prob_reason(skb, ICMPV6_UNK_OPTION, optoff,
|
||||
SKB_DROP_REASON_UNHANDLED_PROTO);
|
||||
return false;
|
||||
}
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_UNHANDLED_PROTO);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -218,7 +219,7 @@ static bool ip6_parse_tlv(bool hopbyhop,
|
||||
if (len == 0)
|
||||
return true;
|
||||
bad:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -232,6 +233,7 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
|
||||
struct ipv6_destopt_hao *hao;
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
||||
SKB_DR(reason);
|
||||
int ret;
|
||||
|
||||
if (opt->dsthao) {
|
||||
@@ -246,19 +248,23 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
|
||||
if (hao->length != 16) {
|
||||
net_dbg_ratelimited("hao invalid option length = %d\n",
|
||||
hao->length);
|
||||
SKB_DR_SET(reason, IP_INHDR);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) {
|
||||
net_dbg_ratelimited("hao is not an unicast addr: %pI6\n",
|
||||
&hao->addr);
|
||||
SKB_DR_SET(reason, INVALID_PROTO);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
ret = xfrm6_input_addr(skb, (xfrm_address_t *)&ipv6h->daddr,
|
||||
(xfrm_address_t *)&hao->addr, IPPROTO_DSTOPTS);
|
||||
if (unlikely(ret < 0))
|
||||
if (unlikely(ret < 0)) {
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
if (skb_cloned(skb)) {
|
||||
if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC))
|
||||
@@ -281,7 +287,7 @@ static bool ipv6_dest_hao(struct sk_buff *skb, int optoff)
|
||||
return true;
|
||||
|
||||
discard:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
@@ -931,7 +937,7 @@ static bool ipv6_hop_ra(struct sk_buff *skb, int optoff)
|
||||
}
|
||||
net_dbg_ratelimited("ipv6_hop_ra: wrong RA length %d\n",
|
||||
nh[optoff + 1]);
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -985,7 +991,7 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
|
||||
return true;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -994,31 +1000,30 @@ static bool ipv6_hop_ioam(struct sk_buff *skb, int optoff)
|
||||
static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
|
||||
{
|
||||
const unsigned char *nh = skb_network_header(skb);
|
||||
struct inet6_dev *idev = __in6_dev_get_safely(skb->dev);
|
||||
struct net *net = ipv6_skb_net(skb);
|
||||
SKB_DR(reason);
|
||||
u32 pkt_len;
|
||||
|
||||
if (nh[optoff + 1] != 4 || (optoff & 3) != 2) {
|
||||
net_dbg_ratelimited("ipv6_hop_jumbo: wrong jumbo opt length/alignment %d\n",
|
||||
nh[optoff+1]);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
SKB_DR_SET(reason, IP_INHDR);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
pkt_len = ntohl(*(__be32 *)(nh + optoff + 2));
|
||||
if (pkt_len <= IPV6_MAXPLEN) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff+2);
|
||||
icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, optoff + 2,
|
||||
SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
if (ipv6_hdr(skb)->payload_len) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, optoff);
|
||||
icmpv6_param_prob_reason(skb, ICMPV6_HDR_FIELD, optoff,
|
||||
SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pkt_len > skb->len - sizeof(struct ipv6hdr)) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
SKB_DR_SET(reason, PKT_TOO_SMALL);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
@@ -1029,7 +1034,7 @@ static bool ipv6_hop_jumbo(struct sk_buff *skb, int optoff)
|
||||
return true;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1051,7 +1056,7 @@ static bool ipv6_hop_calipso(struct sk_buff *skb, int optoff)
|
||||
return true;
|
||||
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -629,12 +629,13 @@ void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info,
|
||||
}
|
||||
EXPORT_SYMBOL(icmp6_send);
|
||||
|
||||
/* Slightly more convenient version of icmp6_send.
|
||||
/* Slightly more convenient version of icmp6_send with drop reasons.
|
||||
*/
|
||||
void icmpv6_param_prob(struct sk_buff *skb, u8 code, int pos)
|
||||
void icmpv6_param_prob_reason(struct sk_buff *skb, u8 code, int pos,
|
||||
enum skb_drop_reason reason)
|
||||
{
|
||||
icmp6_send(skb, ICMPV6_PARAMPROB, code, pos, NULL, IP6CB(skb));
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
}
|
||||
|
||||
/* Generate icmpv6 with type/code ICMPV6_DEST_UNREACH/ICMPV6_ADDR_UNREACH
|
||||
|
||||
@@ -145,13 +145,14 @@ static void ip6_list_rcv_finish(struct net *net, struct sock *sk,
|
||||
static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
struct net *net)
|
||||
{
|
||||
enum skb_drop_reason reason;
|
||||
const struct ipv6hdr *hdr;
|
||||
u32 pkt_len;
|
||||
struct inet6_dev *idev;
|
||||
|
||||
if (skb->pkt_type == PACKET_OTHERHOST) {
|
||||
dev_core_stats_rx_otherhost_dropped_inc(skb->dev);
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_OTHERHOST);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -161,9 +162,12 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
|
||||
__IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_IN, skb->len);
|
||||
|
||||
SKB_DR_SET(reason, NOT_SPECIFIED);
|
||||
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
|
||||
!idev || unlikely(idev->cnf.disable_ipv6)) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
if (unlikely(idev->cnf.disable_ipv6))
|
||||
SKB_DR_SET(reason, IPV6DISABLED);
|
||||
goto drop;
|
||||
}
|
||||
|
||||
@@ -187,8 +191,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
|
||||
hdr = ipv6_hdr(skb);
|
||||
|
||||
if (hdr->version != 6)
|
||||
if (hdr->version != 6) {
|
||||
SKB_DR_SET(reason, UNHANDLED_PROTO);
|
||||
goto err;
|
||||
}
|
||||
|
||||
__IP6_ADD_STATS(net, idev,
|
||||
IPSTATS_MIB_NOECTPKTS +
|
||||
@@ -226,8 +232,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
if (!ipv6_addr_is_multicast(&hdr->daddr) &&
|
||||
(skb->pkt_type == PACKET_BROADCAST ||
|
||||
skb->pkt_type == PACKET_MULTICAST) &&
|
||||
idev->cnf.drop_unicast_in_l2_multicast)
|
||||
idev->cnf.drop_unicast_in_l2_multicast) {
|
||||
SKB_DR_SET(reason, UNICAST_IN_L2_MULTICAST);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* RFC4291 2.7
|
||||
* Nodes must not originate a packet to a multicast address whose scope
|
||||
@@ -256,12 +264,11 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
if (pkt_len + sizeof(struct ipv6hdr) > skb->len) {
|
||||
__IP6_INC_STATS(net,
|
||||
idev, IPSTATS_MIB_INTRUNCATEDPKTS);
|
||||
SKB_DR_SET(reason, PKT_TOO_SMALL);
|
||||
goto drop;
|
||||
}
|
||||
if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr))) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
goto drop;
|
||||
}
|
||||
if (pskb_trim_rcsum(skb, pkt_len + sizeof(struct ipv6hdr)))
|
||||
goto err;
|
||||
hdr = ipv6_hdr(skb);
|
||||
}
|
||||
|
||||
@@ -282,9 +289,10 @@ static struct sk_buff *ip6_rcv_core(struct sk_buff *skb, struct net_device *dev,
|
||||
return skb;
|
||||
err:
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
SKB_DR_OR(reason, IP_INHDR);
|
||||
drop:
|
||||
rcu_read_unlock();
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -354,6 +362,7 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
|
||||
const struct inet6_protocol *ipprot;
|
||||
struct inet6_dev *idev;
|
||||
unsigned int nhoff;
|
||||
SKB_DR(reason);
|
||||
bool raw;
|
||||
|
||||
/*
|
||||
@@ -413,12 +422,16 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
|
||||
if (ipv6_addr_is_multicast(&hdr->daddr) &&
|
||||
!ipv6_chk_mcast_addr(dev, &hdr->daddr,
|
||||
&hdr->saddr) &&
|
||||
!ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb)))
|
||||
!ipv6_is_mld(skb, nexthdr, skb_network_header_len(skb))) {
|
||||
SKB_DR_SET(reason, IP_INADDRERRORS);
|
||||
goto discard;
|
||||
}
|
||||
}
|
||||
if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
|
||||
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb))
|
||||
!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
goto discard;
|
||||
}
|
||||
|
||||
ret = INDIRECT_CALL_2(ipprot->handler, tcp_v6_rcv, udpv6_rcv,
|
||||
skb);
|
||||
@@ -444,8 +457,11 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
|
||||
IPSTATS_MIB_INUNKNOWNPROTOS);
|
||||
icmpv6_send(skb, ICMPV6_PARAMPROB,
|
||||
ICMPV6_UNK_NEXTHDR, nhoff);
|
||||
SKB_DR_SET(reason, IP_NOPROTO);
|
||||
} else {
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
}
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
} else {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDELIVERS);
|
||||
consume_skb(skb);
|
||||
@@ -455,7 +471,7 @@ void ip6_protocol_deliver_rcu(struct net *net, struct sk_buff *skb, int nexthdr,
|
||||
|
||||
discard:
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
}
|
||||
|
||||
static int ip6_input_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
|
||||
@@ -469,6 +469,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
struct inet6_skb_parm *opt = IP6CB(skb);
|
||||
struct net *net = dev_net(dst->dev);
|
||||
struct inet6_dev *idev;
|
||||
SKB_DR(reason);
|
||||
u32 mtu;
|
||||
|
||||
idev = __in6_dev_get_safely(dev_get_by_index_rcu(net, IP6CB(skb)->iif));
|
||||
@@ -518,7 +519,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
icmpv6_send(skb, ICMPV6_TIME_EXCEED, ICMPV6_EXC_HOPLIMIT, 0);
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);
|
||||
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_IP_INHDR);
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@@ -537,6 +538,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
|
||||
if (!xfrm6_route_forward(skb)) {
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INDISCARDS);
|
||||
SKB_DR_SET(reason, XFRM_POLICY);
|
||||
goto drop;
|
||||
}
|
||||
dst = skb_dst(skb);
|
||||
@@ -596,7 +598,7 @@ int ip6_forward(struct sk_buff *skb)
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INTOOBIGERRORS);
|
||||
__IP6_INC_STATS(net, ip6_dst_idev(dst),
|
||||
IPSTATS_MIB_FRAGFAILS);
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, SKB_DROP_REASON_PKT_TOO_BIG);
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
@@ -618,8 +620,9 @@ int ip6_forward(struct sk_buff *skb)
|
||||
|
||||
error:
|
||||
__IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
SKB_DR_SET(reason, IP_INADDRERRORS);
|
||||
drop:
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
@@ -4482,6 +4482,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
|
||||
struct dst_entry *dst = skb_dst(skb);
|
||||
struct net *net = dev_net(dst->dev);
|
||||
struct inet6_dev *idev;
|
||||
SKB_DR(reason);
|
||||
int type;
|
||||
|
||||
if (netif_is_l3_master(skb->dev) ||
|
||||
@@ -4494,11 +4495,14 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
|
||||
case IPSTATS_MIB_INNOROUTES:
|
||||
type = ipv6_addr_type(&ipv6_hdr(skb)->daddr);
|
||||
if (type == IPV6_ADDR_ANY) {
|
||||
SKB_DR_SET(reason, IP_INADDRERRORS);
|
||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_INADDRERRORS);
|
||||
break;
|
||||
}
|
||||
SKB_DR_SET(reason, IP_INNOROUTES);
|
||||
fallthrough;
|
||||
case IPSTATS_MIB_OUTNOROUTES:
|
||||
SKB_DR_OR(reason, IP_OUTNOROUTES);
|
||||
IP6_INC_STATS(net, idev, ipstats_mib_noroutes);
|
||||
break;
|
||||
}
|
||||
@@ -4508,7 +4512,7 @@ static int ip6_pkt_drop(struct sk_buff *skb, u8 code, int ipstats_mib_noroutes)
|
||||
skb_dst_drop(skb);
|
||||
|
||||
icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0);
|
||||
kfree_skb(skb);
|
||||
kfree_skb_reason(skb, reason);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user