Hello,

On Thu, 12 Apr 2018, Stephen Suryaputra wrote:

> Thanks for the feedbacks. Please see the detail below:
> 
> On Wed, Apr 11, 2018 at 3:37 PM, Julian Anastasov <j...@ssi.bg> wrote:
> [snip]
> >> -     __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
> >> +     __IP_INC_STATS(net, skb_dst(skb)->dev, IPSTATS_MIB_INHDRERRORS);
> >
> >         May be skb->dev if we want to account it to the
> > input device.
> >
> Yes. I'm about to make change it but see the next one.
> 
> [snip]
> >> diff --git a/net/netfilter/ipvs/ip_vs_xmit.c 
> >> b/net/netfilter/ipvs/ip_vs_xmit.c
> >> index 4527921..32bd3af 100644
> >> --- a/net/netfilter/ipvs/ip_vs_xmit.c
> >> +++ b/net/netfilter/ipvs/ip_vs_xmit.c
> >> @@ -286,7 +286,7 @@ static inline bool decrement_ttl(struct netns_ipvs 
> >> *ipvs,
> >>       {
> >>               if (ip_hdr(skb)->ttl <= 1) {
> >>                       /* Tell the sender its packet died... */
> >> -                     __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
> >> +                     __IP_INC_STATS(net, skb_dst(skb)->dev, 
> >> IPSTATS_MIB_INHDRERRORS);
> >
> >         At this point, skb_dst(skb) can be:
> >
> > - input route at LOCAL_IN => dst->dev is "lo", skb->dev = input_device
> > - output route at LOCAL_OUT => dst->dev is output_device, skb->dev = NULL
> >
> >         We should see this error on LOCAL_IN but better to be
> > safe: use 'skb->dev ? : skb_dst(skb)->dev' instead of just
> > 'skb_dst(skb)->dev'.
> >
> This follows v6 implementation in the same function:
> 
> #ifdef CONFIG_IP_VS_IPV6
>     if (skb_af == AF_INET6) {
>         struct dst_entry *dst = skb_dst(skb);
> 
>         /* check and decrement ttl */
>         if (ipv6_hdr(skb)->hop_limit <= 1) {
>             /* Force OUTPUT device used as source address */

        It looks like IPVS copied it from ip6_forward() but in
IPVS context it has its reason: we want ICMP to exit with
saddr=Virtual_IP. And we are at LOCAL_IN where there is no
output device like in ip6_forward(FORWARD) to use its source
address.

        So, IPVS is special (both input and output path) and needs:

IPv4: skb->dev ? : skb_dst(skb)->dev
IPv6 needs fix for IPVS stats in decrement_ttl:

        idev = skb->dev ? __in6_dev_get(skb->dev) : ip6_dst_idev(dst);
        ...
        __IP6_INC_STATS(net, idev, IPSTATS_MIB_INHDRERRORS);

        Otherwise, stats will go to "lo" if ip6_dst_idev
is used for local input route.

        So, for accounting on input IPv4 path skb->dev should be
used, while for IPv6 some sites may prefer to feed icmpv6_send()
with output dst->dev as device containing the source address (skb->dev).
But this is unrelated to the stats.

>             skb->dev = dst->dev;
>             icmpv6_send(skb, ICMPV6_TIME_EXCEED,
>                     ICMPV6_EXC_HOPLIMIT, 0);
>             __IP6_INC_STATS(net, ip6_dst_idev(dst),
>                     IPSTATS_MIB_INHDRERRORS);
> 
>             return false;
>         }
> 
>         /* don't propagate ttl change to cloned packets */
>         if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
>             return false;
> 
>         ipv6_hdr(skb)->hop_limit--;
>     } else
> #endif
> 
> [snip]
> >
> >         The patch probably has other errors, for example,
> > using rt->dst.dev (lo) when rt->dst.error != 0 in ip_error,
> > may be 'dev' should be used instead...
> 
> Same also here. Examples are ip6_forward and ip6_pkt_drop.
> 
> I think it's better be counted in the input device for them also. Thoughts?

        I think so. ipv6_rcv() works with idev = __in6_dev_get(skb->dev)
but I don't know IPv6 well and whether ip6_dst_idev(skb_dst(skb))
is correct usage for input path. It should be correct for output
path, though.

Regards

--
Julian Anastasov <j...@ssi.bg>

Reply via email to