diff options
author | WANG Cong <xiyou.wangcong@gmail.com> | 2015-04-10 15:00:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-04-12 21:25:13 -0400 |
commit | 7a6c8c34e5b71ac50e39588e20b39494a9e1d8e5 (patch) | |
tree | 3593ce71a5a16427c35823a073072292a0d2a704 | |
parent | 02d793c5bbebf2c750da03df4c950fc4e8e8a5a7 (diff) |
fou: implement FOU_CMD_GET
Cc: Tom Herbert <tom@herbertland.com>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/uapi/linux/fou.h | 1 | ||||
-rw-r--r-- | net/ipv4/fou.c | 109 |
2 files changed, 110 insertions, 0 deletions
diff --git a/include/uapi/linux/fou.h b/include/uapi/linux/fou.h index c303588bb767..d2947c52dc67 100644 --- a/include/uapi/linux/fou.h +++ b/include/uapi/linux/fou.h | |||
@@ -25,6 +25,7 @@ enum { | |||
25 | FOU_CMD_UNSPEC, | 25 | FOU_CMD_UNSPEC, |
26 | FOU_CMD_ADD, | 26 | FOU_CMD_ADD, |
27 | FOU_CMD_DEL, | 27 | FOU_CMD_DEL, |
28 | FOU_CMD_GET, | ||
28 | 29 | ||
29 | __FOU_CMD_MAX, | 30 | __FOU_CMD_MAX, |
30 | }; | 31 | }; |
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index c244b1a65787..263710259774 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -21,6 +21,7 @@ struct fou { | |||
21 | u8 protocol; | 21 | u8 protocol; |
22 | u8 flags; | 22 | u8 flags; |
23 | __be16 port; | 23 | __be16 port; |
24 | u16 type; | ||
24 | struct udp_offload udp_offloads; | 25 | struct udp_offload udp_offloads; |
25 | struct list_head list; | 26 | struct list_head list; |
26 | }; | 27 | }; |
@@ -487,6 +488,8 @@ static int fou_create(struct net *net, struct fou_cfg *cfg, | |||
487 | goto error; | 488 | goto error; |
488 | } | 489 | } |
489 | 490 | ||
491 | fou->type = cfg->type; | ||
492 | |||
490 | udp_sk(sk)->encap_type = 1; | 493 | udp_sk(sk)->encap_type = 1; |
491 | udp_encap_enable(); | 494 | udp_encap_enable(); |
492 | 495 | ||
@@ -617,6 +620,106 @@ static int fou_nl_cmd_rm_port(struct sk_buff *skb, struct genl_info *info) | |||
617 | return fou_destroy(net, &cfg); | 620 | return fou_destroy(net, &cfg); |
618 | } | 621 | } |
619 | 622 | ||
623 | static int fou_fill_info(struct fou *fou, struct sk_buff *msg) | ||
624 | { | ||
625 | if (nla_put_u8(msg, FOU_ATTR_AF, fou->sock->sk->sk_family) || | ||
626 | nla_put_be16(msg, FOU_ATTR_PORT, fou->port) || | ||
627 | nla_put_u8(msg, FOU_ATTR_IPPROTO, fou->protocol) || | ||
628 | nla_put_u8(msg, FOU_ATTR_TYPE, fou->type)) | ||
629 | return -1; | ||
630 | |||
631 | if (fou->flags & FOU_F_REMCSUM_NOPARTIAL) | ||
632 | if (nla_put_flag(msg, FOU_ATTR_REMCSUM_NOPARTIAL)) | ||
633 | return -1; | ||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static int fou_dump_info(struct fou *fou, u32 portid, u32 seq, | ||
638 | u32 flags, struct sk_buff *skb, u8 cmd) | ||
639 | { | ||
640 | void *hdr; | ||
641 | |||
642 | hdr = genlmsg_put(skb, portid, seq, &fou_nl_family, flags, cmd); | ||
643 | if (!hdr) | ||
644 | return -ENOMEM; | ||
645 | |||
646 | if (fou_fill_info(fou, skb) < 0) | ||
647 | goto nla_put_failure; | ||
648 | |||
649 | genlmsg_end(skb, hdr); | ||
650 | return 0; | ||
651 | |||
652 | nla_put_failure: | ||
653 | genlmsg_cancel(skb, hdr); | ||
654 | return -EMSGSIZE; | ||
655 | } | ||
656 | |||
657 | static int fou_nl_cmd_get_port(struct sk_buff *skb, struct genl_info *info) | ||
658 | { | ||
659 | struct net *net = genl_info_net(info); | ||
660 | struct fou_net *fn = net_generic(net, fou_net_id); | ||
661 | struct sk_buff *msg; | ||
662 | struct fou_cfg cfg; | ||
663 | struct fou *fout; | ||
664 | __be16 port; | ||
665 | int ret; | ||
666 | |||
667 | ret = parse_nl_config(info, &cfg); | ||
668 | if (ret) | ||
669 | return ret; | ||
670 | port = cfg.udp_config.local_udp_port; | ||
671 | if (port == 0) | ||
672 | return -EINVAL; | ||
673 | |||
674 | msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); | ||
675 | if (!msg) | ||
676 | return -ENOMEM; | ||
677 | |||
678 | ret = -ESRCH; | ||
679 | mutex_lock(&fn->fou_lock); | ||
680 | list_for_each_entry(fout, &fn->fou_list, list) { | ||
681 | if (port == fout->port) { | ||
682 | ret = fou_dump_info(fout, info->snd_portid, | ||
683 | info->snd_seq, 0, msg, | ||
684 | info->genlhdr->cmd); | ||
685 | break; | ||
686 | } | ||
687 | } | ||
688 | mutex_unlock(&fn->fou_lock); | ||
689 | if (ret < 0) | ||
690 | goto out_free; | ||
691 | |||
692 | return genlmsg_reply(msg, info); | ||
693 | |||
694 | out_free: | ||
695 | nlmsg_free(msg); | ||
696 | return ret; | ||
697 | } | ||
698 | |||
699 | static int fou_nl_dump(struct sk_buff *skb, struct netlink_callback *cb) | ||
700 | { | ||
701 | struct net *net = sock_net(skb->sk); | ||
702 | struct fou_net *fn = net_generic(net, fou_net_id); | ||
703 | struct fou *fout; | ||
704 | int idx = 0, ret; | ||
705 | |||
706 | mutex_lock(&fn->fou_lock); | ||
707 | list_for_each_entry(fout, &fn->fou_list, list) { | ||
708 | if (idx++ < cb->args[0]) | ||
709 | continue; | ||
710 | ret = fou_dump_info(fout, NETLINK_CB(cb->skb).portid, | ||
711 | cb->nlh->nlmsg_seq, NLM_F_MULTI, | ||
712 | skb, FOU_CMD_GET); | ||
713 | if (ret) | ||
714 | goto done; | ||
715 | } | ||
716 | mutex_unlock(&fn->fou_lock); | ||
717 | |||
718 | done: | ||
719 | cb->args[0] = idx; | ||
720 | return skb->len; | ||
721 | } | ||
722 | |||
620 | static const struct genl_ops fou_nl_ops[] = { | 723 | static const struct genl_ops fou_nl_ops[] = { |
621 | { | 724 | { |
622 | .cmd = FOU_CMD_ADD, | 725 | .cmd = FOU_CMD_ADD, |
@@ -630,6 +733,12 @@ static const struct genl_ops fou_nl_ops[] = { | |||
630 | .policy = fou_nl_policy, | 733 | .policy = fou_nl_policy, |
631 | .flags = GENL_ADMIN_PERM, | 734 | .flags = GENL_ADMIN_PERM, |
632 | }, | 735 | }, |
736 | { | ||
737 | .cmd = FOU_CMD_GET, | ||
738 | .doit = fou_nl_cmd_get_port, | ||
739 | .dumpit = fou_nl_dump, | ||
740 | .policy = fou_nl_policy, | ||
741 | }, | ||
633 | }; | 742 | }; |
634 | 743 | ||
635 | size_t fou_encap_hlen(struct ip_tunnel_encap *e) | 744 | size_t fou_encap_hlen(struct ip_tunnel_encap *e) |