ipv6: add IPV6_RECVFRAGSIZE cmsg
authorWillem de Bruijn <willemb@google.com>
Wed, 2 Nov 2016 15:02:17 +0000 (11:02 -0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 3 Nov 2016 19:41:11 +0000 (15:41 -0400)
When reading a datagram or raw packet that arrived fragmented, expose
the maximum fragment size if recorded to allow applications to
estimate receive path MTU.

At this point, the field is only recorded when ipv6 connection
tracking is enabled. A follow-up patch will record this field also
in the ipv6 input path.

Tested using the test for IP_RECVFRAGSIZE plus

  ip netns exec to ip addr add dev veth1 fc07::1/64
  ip netns exec from ip addr add dev veth0 fc07::2/64

  ip netns exec to ./recv_cmsg_recvfragsize -6 -u -p 6000 &
  ip netns exec from nc -q 1 -u fc07::1 6000 < payload

Both with and without enabling connection tracking

  ip6tables -A INPUT -m state --state NEW -p udp -j LOG

Signed-off-by: Willem de Bruijn <willemb@google.com>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/linux/ipv6.h
include/uapi/linux/in6.h
net/ipv6/datagram.c
net/ipv6/ipv6_sockglue.c

index ca1ad9ebbc92b7d138eabb50f7401aa9bc318e9b..1afb6e8d35c35300535ccc81cd5ea78bee046329 100644 (file)
@@ -229,8 +229,9 @@ struct ipv6_pinfo {
                                 rxflow:1,
                                rxtclass:1,
                                rxpmtu:1,
-                               rxorigdstaddr:1;
-                               /* 2 bits hole */
+                               rxorigdstaddr:1,
+                               recvfragsize:1;
+                               /* 1 bits hole */
                } bits;
                __u16           all;
        } rxopt;
index b39ea4f2e701d27edb0db76a94560557e3ae408c..46444f8fbee4eed8c4aa223ee5ff3ef1be182765 100644 (file)
@@ -283,6 +283,7 @@ struct in6_flowlabel_req {
 #define IPV6_RECVORIGDSTADDR    IPV6_ORIGDSTADDR
 #define IPV6_TRANSPARENT        75
 #define IPV6_UNICAST_IF         76
+#define IPV6_RECVFRAGSIZE      77
 
 /*
  * Multicast Routing:
index 37874e2f30edf98f31e2a5097761143d507d5b95..620c79a0130a779e834e2d1f12a7d33935b49041 100644 (file)
@@ -715,6 +715,11 @@ void ip6_datagram_recv_specific_ctl(struct sock *sk, struct msghdr *msg,
                        put_cmsg(msg, SOL_IPV6, IPV6_ORIGDSTADDR, sizeof(sin6), &sin6);
                }
        }
+       if (np->rxopt.bits.recvfragsize && opt->frag_max_size) {
+               int val = opt->frag_max_size;
+
+               put_cmsg(msg, SOL_IPV6, IPV6_RECVFRAGSIZE, sizeof(val), &val);
+       }
 }
 
 void ip6_datagram_recv_ctl(struct sock *sk, struct msghdr *msg,
index 636ec56f5f5028277fc69721464ba734621a91e0..6c126780fcf2be5e79870d79cfc3909038bbec7a 100644 (file)
@@ -868,6 +868,10 @@ pref_skip_coa:
                np->autoflowlabel = valbool;
                retv = 0;
                break;
+       case IPV6_RECVFRAGSIZE:
+               np->rxopt.bits.recvfragsize = valbool;
+               retv = 0;
+               break;
        }
 
        release_sock(sk);
@@ -1310,6 +1314,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname,
                val = np->autoflowlabel;
                break;
 
+       case IPV6_RECVFRAGSIZE:
+               val = np->rxopt.bits.recvfragsize;
+               break;
+
        default:
                return -ENOPROTOOPT;
        }