summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorR. Parameswaran <parameswaran.r7@gmail.com>2017-04-05 19:50:35 -0400
committerDavid S. Miller <davem@davemloft.net>2017-04-06 16:43:31 -0400
commit113c3075931a334f899008f6c753abe70a3a9323 (patch)
treea0f7e868672699b451a5053824eea0df16ce07cc
parent129858fa0b1ab3072155718b74bf91e440c2d73f (diff)
New kernel function to get IP overhead on a socket.
A new function, kernel_sock_ip_overhead(), is provided to calculate the cumulative overhead imposed by the IP Header and IP options, if any, on a socket's payload. The new function returns an overhead of zero for sockets that do not belong to the IPv4 or IPv6 address families. This is used in the L2TP code path to compute the total outer IP overhead on the L2TP tunnel socket when calculating the default MTU for Ethernet pseudowires. Signed-off-by: R. Parameswaran <rparames@brocade.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/net.h3
-rw-r--r--net/socket.c46
2 files changed, 49 insertions, 0 deletions
diff --git a/include/linux/net.h b/include/linux/net.h
index 0620f5e18c96..a42fab24c8af 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -298,6 +298,9 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
298int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg); 298int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
299int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); 299int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
300 300
301/* Following routine returns the IP overhead imposed by a socket. */
302u32 kernel_sock_ip_overhead(struct sock *sk);
303
301#define MODULE_ALIAS_NETPROTO(proto) \ 304#define MODULE_ALIAS_NETPROTO(proto) \
302 MODULE_ALIAS("net-pf-" __stringify(proto)) 305 MODULE_ALIAS("net-pf-" __stringify(proto))
303 306
diff --git a/net/socket.c b/net/socket.c
index 985ef06792d6..eea997036ada 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -3356,3 +3356,49 @@ int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how)
3356 return sock->ops->shutdown(sock, how); 3356 return sock->ops->shutdown(sock, how);
3357} 3357}
3358EXPORT_SYMBOL(kernel_sock_shutdown); 3358EXPORT_SYMBOL(kernel_sock_shutdown);
3359
3360/* This routine returns the IP overhead imposed by a socket i.e.
3361 * the length of the underlying IP header, depending on whether
3362 * this is an IPv4 or IPv6 socket and the length from IP options turned
3363 * on at the socket.
3364 */
3365u32 kernel_sock_ip_overhead(struct sock *sk)
3366{
3367 struct inet_sock *inet;
3368 struct ip_options_rcu *opt;
3369 u32 overhead = 0;
3370 bool owned_by_user;
3371#if IS_ENABLED(CONFIG_IPV6)
3372 struct ipv6_pinfo *np;
3373 struct ipv6_txoptions *optv6 = NULL;
3374#endif /* IS_ENABLED(CONFIG_IPV6) */
3375
3376 if (!sk)
3377 return overhead;
3378
3379 owned_by_user = sock_owned_by_user(sk);
3380 switch (sk->sk_family) {
3381 case AF_INET:
3382 inet = inet_sk(sk);
3383 overhead += sizeof(struct iphdr);
3384 opt = rcu_dereference_protected(inet->inet_opt,
3385 owned_by_user);
3386 if (opt)
3387 overhead += opt->opt.optlen;
3388 return overhead;
3389#if IS_ENABLED(CONFIG_IPV6)
3390 case AF_INET6:
3391 np = inet6_sk(sk);
3392 overhead += sizeof(struct ipv6hdr);
3393 if (np)
3394 optv6 = rcu_dereference_protected(np->opt,
3395 owned_by_user);
3396 if (optv6)
3397 overhead += (optv6->opt_flen + optv6->opt_nflen);
3398 return overhead;
3399#endif /* IS_ENABLED(CONFIG_IPV6) */
3400 default: /* Returns 0 overhead if the socket is not ipv4 or ipv6 */
3401 return overhead;
3402 }
3403}
3404EXPORT_SYMBOL(kernel_sock_ip_overhead);