Commit 5f914b68 authored by Tom Herbert's avatar Tom Herbert Committed by David S. Miller

fou: Support IPv6 in fou

This patch adds receive path support for IPv6 with fou.

- Add address family to fou structure for open sockets. This supports
  AF_INET and AF_INET6. Lookups for fou ports are performed on both the
  port number and family.
- In fou and gue receive adjust tot_len in IPv4 header or payload_len
  based on address family.
- Allow AF_INET6 in FOU_ATTR_AF netlink attribute.
Signed-off-by: default avatarTom Herbert <tom@herbertland.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent dc969b81
...@@ -21,6 +21,7 @@ struct fou { ...@@ -21,6 +21,7 @@ struct fou {
u8 protocol; u8 protocol;
u8 flags; u8 flags;
__be16 port; __be16 port;
u8 family;
u16 type; u16 type;
struct list_head list; struct list_head list;
struct rcu_head rcu; struct rcu_head rcu;
...@@ -47,14 +48,17 @@ static inline struct fou *fou_from_sock(struct sock *sk) ...@@ -47,14 +48,17 @@ static inline struct fou *fou_from_sock(struct sock *sk)
return sk->sk_user_data; return sk->sk_user_data;
} }
static int fou_recv_pull(struct sk_buff *skb, size_t len) static int fou_recv_pull(struct sk_buff *skb, struct fou *fou, size_t len)
{ {
struct iphdr *iph = ip_hdr(skb);
/* Remove 'len' bytes from the packet (UDP header and /* Remove 'len' bytes from the packet (UDP header and
* FOU header if present). * FOU header if present).
*/ */
iph->tot_len = htons(ntohs(iph->tot_len) - len); if (fou->family == AF_INET)
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len);
else
ipv6_hdr(skb)->payload_len =
htons(ntohs(ipv6_hdr(skb)->payload_len) - len);
__skb_pull(skb, len); __skb_pull(skb, len);
skb_postpull_rcsum(skb, udp_hdr(skb), len); skb_postpull_rcsum(skb, udp_hdr(skb), len);
skb_reset_transport_header(skb); skb_reset_transport_header(skb);
...@@ -68,7 +72,7 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb) ...@@ -68,7 +72,7 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb)
if (!fou) if (!fou)
return 1; return 1;
if (fou_recv_pull(skb, sizeof(struct udphdr))) if (fou_recv_pull(skb, fou, sizeof(struct udphdr)))
goto drop; goto drop;
return -fou->protocol; return -fou->protocol;
...@@ -141,7 +145,11 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) ...@@ -141,7 +145,11 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
hdrlen = sizeof(struct guehdr) + optlen; hdrlen = sizeof(struct guehdr) + optlen;
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len); if (fou->family == AF_INET)
ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len);
else
ipv6_hdr(skb)->payload_len =
htons(ntohs(ipv6_hdr(skb)->payload_len) - len);
/* Pull csum through the guehdr now . This can be used if /* Pull csum through the guehdr now . This can be used if
* there is a remote checksum offload. * there is a remote checksum offload.
...@@ -426,7 +434,8 @@ static int fou_add_to_port_list(struct net *net, struct fou *fou) ...@@ -426,7 +434,8 @@ static int fou_add_to_port_list(struct net *net, struct fou *fou)
mutex_lock(&fn->fou_lock); mutex_lock(&fn->fou_lock);
list_for_each_entry(fout, &fn->fou_list, list) { list_for_each_entry(fout, &fn->fou_list, list) {
if (fou->port == fout->port) { if (fou->port == fout->port &&
fou->family == fout->family) {
mutex_unlock(&fn->fou_lock); mutex_unlock(&fn->fou_lock);
return -EALREADY; return -EALREADY;
} }
...@@ -471,8 +480,9 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, ...@@ -471,8 +480,9 @@ static int fou_create(struct net *net, struct fou_cfg *cfg,
sk = sock->sk; sk = sock->sk;
fou->flags = cfg->flags;
fou->port = cfg->udp_config.local_udp_port; fou->port = cfg->udp_config.local_udp_port;
fou->family = cfg->udp_config.family;
fou->flags = cfg->flags;
fou->type = cfg->type; fou->type = cfg->type;
fou->sock = sock; fou->sock = sock;
...@@ -524,12 +534,13 @@ static int fou_destroy(struct net *net, struct fou_cfg *cfg) ...@@ -524,12 +534,13 @@ static int fou_destroy(struct net *net, struct fou_cfg *cfg)
{ {
struct fou_net *fn = net_generic(net, fou_net_id); struct fou_net *fn = net_generic(net, fou_net_id);
__be16 port = cfg->udp_config.local_udp_port; __be16 port = cfg->udp_config.local_udp_port;
u8 family = cfg->udp_config.family;
int err = -EINVAL; int err = -EINVAL;
struct fou *fou; struct fou *fou;
mutex_lock(&fn->fou_lock); mutex_lock(&fn->fou_lock);
list_for_each_entry(fou, &fn->fou_list, list) { list_for_each_entry(fou, &fn->fou_list, list) {
if (fou->port == port) { if (fou->port == port && fou->family == family) {
fou_release(fou); fou_release(fou);
err = 0; err = 0;
break; break;
...@@ -567,8 +578,15 @@ static int parse_nl_config(struct genl_info *info, ...@@ -567,8 +578,15 @@ static int parse_nl_config(struct genl_info *info,
if (info->attrs[FOU_ATTR_AF]) { if (info->attrs[FOU_ATTR_AF]) {
u8 family = nla_get_u8(info->attrs[FOU_ATTR_AF]); u8 family = nla_get_u8(info->attrs[FOU_ATTR_AF]);
if (family != AF_INET) switch (family) {
return -EINVAL; case AF_INET:
break;
case AF_INET6:
cfg->udp_config.ipv6_v6only = 1;
break;
default:
return -EAFNOSUPPORT;
}
cfg->udp_config.family = family; cfg->udp_config.family = family;
} }
...@@ -659,6 +677,7 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info) ...@@ -659,6 +677,7 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info)
struct fou_cfg cfg; struct fou_cfg cfg;
struct fou *fout; struct fou *fout;
__be16 port; __be16 port;
u8 family;
int ret; int ret;
ret = parse_nl_config(info, &cfg); ret = parse_nl_config(info, &cfg);
...@@ -668,6 +687,10 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info) ...@@ -668,6 +687,10 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info)
if (port == 0) if (port == 0)
return -EINVAL; return -EINVAL;
family = cfg.udp_config.family;
if (family != AF_INET && family != AF_INET6)
return -EINVAL;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg) if (!msg)
return -ENOMEM; return -ENOMEM;
...@@ -675,7 +698,7 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info) ...@@ -675,7 +698,7 @@ static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info)
ret = -ESRCH; ret = -ESRCH;
mutex_lock(&fn->fou_lock); mutex_lock(&fn->fou_lock);
list_for_each_entry(fout, &fn->fou_list, list) { list_for_each_entry(fout, &fn->fou_list, list) {
if (port == fout->port) { if (port == fout->port && family == fout->family) {
ret = fou_dump_info(fout, info->snd_portid, ret = fou_dump_info(fout, info->snd_portid,
info->snd_seq, 0, msg, info->snd_seq, 0, msg,
info->genlhdr->cmd); info->genlhdr->cmd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment