aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/net_namespace.c
diff options
context:
space:
mode:
authorNicolas Dichtel <nicolas.dichtel@6wind.com>2018-11-26 09:42:04 -0500
committerDavid S. Miller <davem@davemloft.net>2018-11-27 19:20:20 -0500
commitcff478b9d9ccaee0de0e02700c63addf007b5d3c (patch)
tree46a092a1086d179fa5ef72cbc56901ee68419567 /net/core/net_namespace.c
parenta0732ad14d40ee7562c8c6e04b01af6134c82831 (diff)
netns: add support of NETNSA_TARGET_NSID
Like it was done for link and address, add the ability to perform get/dump in another netns by specifying a target nsid attribute. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Reviewed-by: David Ahern <dsahern@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/net_namespace.c')
-rw-r--r--net/core/net_namespace.c86
1 files changed, 75 insertions, 11 deletions
diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c
index f8a5966b086c..885c54197e31 100644
--- a/net/core/net_namespace.c
+++ b/net/core/net_namespace.c
@@ -669,6 +669,7 @@ static const struct nla_policy rtnl_net_policy[NETNSA_MAX + 1] = {
669 [NETNSA_NSID] = { .type = NLA_S32 }, 669 [NETNSA_NSID] = { .type = NLA_S32 },
670 [NETNSA_PID] = { .type = NLA_U32 }, 670 [NETNSA_PID] = { .type = NLA_U32 },
671 [NETNSA_FD] = { .type = NLA_U32 }, 671 [NETNSA_FD] = { .type = NLA_U32 },
672 [NETNSA_TARGET_NSID] = { .type = NLA_S32 },
672}; 673};
673 674
674static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh, 675static int rtnl_net_newid(struct sk_buff *skb, struct nlmsghdr *nlh,
@@ -780,9 +781,10 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
780 .seq = nlh->nlmsg_seq, 781 .seq = nlh->nlmsg_seq,
781 .cmd = RTM_NEWNSID, 782 .cmd = RTM_NEWNSID,
782 }; 783 };
784 struct net *peer, *target = net;
785 bool put_target = false;
783 struct nlattr *nla; 786 struct nlattr *nla;
784 struct sk_buff *msg; 787 struct sk_buff *msg;
785 struct net *peer;
786 int err; 788 int err;
787 789
788 err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX, 790 err = nlmsg_parse(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
@@ -806,13 +808,27 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
806 return PTR_ERR(peer); 808 return PTR_ERR(peer);
807 } 809 }
808 810
811 if (tb[NETNSA_TARGET_NSID]) {
812 int id = nla_get_s32(tb[NETNSA_TARGET_NSID]);
813
814 target = rtnl_get_net_ns_capable(NETLINK_CB(skb).sk, id);
815 if (IS_ERR(target)) {
816 NL_SET_BAD_ATTR(extack, tb[NETNSA_TARGET_NSID]);
817 NL_SET_ERR_MSG(extack,
818 "Target netns reference is invalid");
819 err = PTR_ERR(target);
820 goto out;
821 }
822 put_target = true;
823 }
824
809 msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL); 825 msg = nlmsg_new(rtnl_net_get_size(), GFP_KERNEL);
810 if (!msg) { 826 if (!msg) {
811 err = -ENOMEM; 827 err = -ENOMEM;
812 goto out; 828 goto out;
813 } 829 }
814 830
815 fillargs.nsid = peernet2id(net, peer); 831 fillargs.nsid = peernet2id(target, peer);
816 err = rtnl_net_fill(msg, &fillargs); 832 err = rtnl_net_fill(msg, &fillargs);
817 if (err < 0) 833 if (err < 0)
818 goto err_out; 834 goto err_out;
@@ -823,15 +839,19 @@ static int rtnl_net_getid(struct sk_buff *skb, struct nlmsghdr *nlh,
823err_out: 839err_out:
824 nlmsg_free(msg); 840 nlmsg_free(msg);
825out: 841out:
842 if (put_target)
843 put_net(target);
826 put_net(peer); 844 put_net(peer);
827 return err; 845 return err;
828} 846}
829 847
830struct rtnl_net_dump_cb { 848struct rtnl_net_dump_cb {
849 struct net *tgt_net;
831 struct sk_buff *skb; 850 struct sk_buff *skb;
832 struct net_fill_args fillargs; 851 struct net_fill_args fillargs;
833 int idx; 852 int idx;
834 int s_idx; 853 int s_idx;
854 bool put_tgt_net;
835}; 855};
836 856
837static int rtnl_net_dumpid_one(int id, void *peer, void *data) 857static int rtnl_net_dumpid_one(int id, void *peer, void *data)
@@ -852,10 +872,50 @@ cont:
852 return 0; 872 return 0;
853} 873}
854 874
875static int rtnl_valid_dump_net_req(const struct nlmsghdr *nlh, struct sock *sk,
876 struct rtnl_net_dump_cb *net_cb,
877 struct netlink_callback *cb)
878{
879 struct netlink_ext_ack *extack = cb->extack;
880 struct nlattr *tb[NETNSA_MAX + 1];
881 int err, i;
882
883 err = nlmsg_parse_strict(nlh, sizeof(struct rtgenmsg), tb, NETNSA_MAX,
884 rtnl_net_policy, extack);
885 if (err < 0)
886 return err;
887
888 for (i = 0; i <= NETNSA_MAX; i++) {
889 if (!tb[i])
890 continue;
891
892 if (i == NETNSA_TARGET_NSID) {
893 struct net *net;
894
895 net = rtnl_get_net_ns_capable(sk, nla_get_s32(tb[i]));
896 if (IS_ERR(net)) {
897 NL_SET_BAD_ATTR(extack, tb[i]);
898 NL_SET_ERR_MSG(extack,
899 "Invalid target network namespace id");
900 return PTR_ERR(net);
901 }
902 net_cb->tgt_net = net;
903 net_cb->put_tgt_net = true;
904 } else {
905 NL_SET_BAD_ATTR(extack, tb[i]);
906 NL_SET_ERR_MSG(extack,
907 "Unsupported attribute in dump request");
908 return -EINVAL;
909 }
910 }
911
912 return 0;
913}
914
855static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb) 915static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
856{ 916{
857 struct net *net = sock_net(skb->sk);
858 struct rtnl_net_dump_cb net_cb = { 917 struct rtnl_net_dump_cb net_cb = {
918 .tgt_net = sock_net(skb->sk),
859 .skb = skb, 919 .skb = skb,
860 .fillargs = { 920 .fillargs = {
861 .portid = NETLINK_CB(cb->skb).portid, 921 .portid = NETLINK_CB(cb->skb).portid,
@@ -866,19 +926,23 @@ static int rtnl_net_dumpid(struct sk_buff *skb, struct netlink_callback *cb)
866 .idx = 0, 926 .idx = 0,
867 .s_idx = cb->args[0], 927 .s_idx = cb->args[0],
868 }; 928 };
929 int err = 0;
869 930
870 if (cb->strict_check && 931 if (cb->strict_check) {
871 nlmsg_attrlen(cb->nlh, sizeof(struct rtgenmsg))) { 932 err = rtnl_valid_dump_net_req(cb->nlh, skb->sk, &net_cb, cb);
872 NL_SET_ERR_MSG(cb->extack, "Unknown data in network namespace id dump request"); 933 if (err < 0)
873 return -EINVAL; 934 goto end;
874 } 935 }
875 936
876 spin_lock_bh(&net->nsid_lock); 937 spin_lock_bh(&net_cb.tgt_net->nsid_lock);
877 idr_for_each(&net->netns_ids, rtnl_net_dumpid_one, &net_cb); 938 idr_for_each(&net_cb.tgt_net->netns_ids, rtnl_net_dumpid_one, &net_cb);
878 spin_unlock_bh(&net->nsid_lock); 939 spin_unlock_bh(&net_cb.tgt_net->nsid_lock);
879 940
880 cb->args[0] = net_cb.idx; 941 cb->args[0] = net_cb.idx;
881 return skb->len; 942end:
943 if (net_cb.put_tgt_net)
944 put_net(net_cb.tgt_net);
945 return err < 0 ? err : skb->len;
882} 946}
883 947
884static void rtnl_net_notifyid(struct net *net, int cmd, int id) 948static void rtnl_net_notifyid(struct net *net, int cmd, int id)