fb migration, part 1
[ana-net.git] / src / xt_user.c
blob8adcfd9de3058a78937d25253e749e4ce8bf3074
1 /*
2 * Lightweight Autonomic Network Architecture
4 * LANA NETLINK handler for Functional Block userspace control.
6 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
7 * Swiss federal institute of technology (ETH Zurich)
8 * Subject to the GPL.
9 */
11 #include <linux/kernel.h>
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/socket.h>
15 #include <linux/net.h>
16 #include <linux/skbuff.h>
17 #include <net/netlink.h>
18 #include <net/sock.h>
20 #include "xt_idp.h"
21 #include "xt_user.h"
22 #include "xt_fblock.h"
23 #include "xt_builder.h"
25 static struct sock *userctl_sock = NULL;
27 static int __userctl_rcv(struct sk_buff *skb, struct nlmsghdr *nlh)
29 struct lananlmsg *lmsg;
31 if (security_netlink_recv(skb, CAP_NET_ADMIN))
32 return -EPERM;
33 if (nlh->nlmsg_len < NLMSG_LENGTH(sizeof(struct lananlmsg)))
34 return 0;
36 lmsg = NLMSG_DATA(nlh);
38 switch (lmsg->cmd) {
39 case NETLINK_USERCTL_CMD_ADD: {
40 struct fblock *fb;
41 struct lananlmsg_add *msg =
42 (struct lananlmsg_add *) lmsg->buff;
43 fb = build_fblock_object(msg->type, msg->name);
44 if (!fb)
45 return -ENOMEM;
46 } break;
47 case NETLINK_USERCTL_CMD_SET: {
48 int ret;
49 struct fblock *fb;
50 struct lananlmsg_set *msg =
51 (struct lananlmsg_set *) lmsg->buff;
52 fb = search_fblock_n(msg->name);
53 if (!fb)
54 return -EINVAL;
55 ret = fblock_set_option(fb, msg->option);
56 put_fblock(fb);
57 return ret;
58 } break;
59 case NETLINK_USERCTL_CMD_REPLACE: {
60 int ret;
61 struct fblock *fb1, *fb2;
62 struct lananlmsg_replace *msg =
63 (struct lananlmsg_replace *) lmsg->buff;
64 fb1 = search_fblock_n(msg->name1);
65 if (!fb1)
66 return -EINVAL;
67 fb2 = search_fblock_n(msg->name2);
68 if (!fb2) {
69 put_fblock(fb1);
70 return -EINVAL;
72 if (atomic_read(&fb2->refcnt) > 2) {
73 /* Still in use by others */
74 put_fblock(fb1);
75 printk(KERN_ERR "[lana] %s is still in use by others. "
76 "Drop refs first!\n", fb2->name);
77 put_fblock(fb2);
78 return -EBUSY;
80 unregister_fblock_namespace_no_rcu(fb2);
81 if (!strncmp(fb1->factory->type, fb2->factory->type,
82 sizeof(fb1->factory->type)) && !msg->drop_priv) {
83 ret = fblock_migrate(fb2, fb1);
84 if (ret) {
85 put_fblock(fb1);
86 /* We loose fb2 */
87 printk("[lana] fblock migration failed! "
88 "Destination fblock lost!\n");
89 put_fblock(fb2);
90 put_fblock(fb2);
91 return -EIO;
94 unregister_fblock(fb1);
95 put_fblock(fb1);
96 ret = register_fblock(fb2, fb2->idp);
97 put_fblock(fb2);
98 return ret;
99 } break;
100 case NETLINK_USERCTL_CMD_SUBSCRIBE: {
101 int ret;
102 struct fblock *fb1, *fb2;
103 struct lananlmsg_subscribe *msg =
104 (struct lananlmsg_subscribe *) lmsg->buff;
105 fb1 = search_fblock_n(msg->name1);
106 if (!fb1)
107 return -EINVAL;
108 fb2 = search_fblock_n(msg->name2);
109 if (!fb2) {
110 put_fblock(fb1);
111 return -EINVAL;
114 * fb1 is remote block, fb2 is the one that
115 * wishes to be notified.
117 ret = subscribe_to_remote_fblock(fb2, fb1);
118 put_fblock(fb1);
119 put_fblock(fb2);
120 return ret;
121 } break;
122 case NETLINK_USERCTL_CMD_UNSUBSCRIBE: {
123 struct fblock *fb1, *fb2;
124 struct lananlmsg_unsubscribe *msg =
125 (struct lananlmsg_unsubscribe *) lmsg->buff;
126 fb1 = search_fblock_n(msg->name1);
127 if (!fb1)
128 return -EINVAL;
129 fb2 = search_fblock_n(msg->name2);
130 if (!fb2) {
131 put_fblock(fb1);
132 return -EINVAL;
134 unsubscribe_from_remote_fblock(fb2, fb1);
135 put_fblock(fb1);
136 put_fblock(fb2);
137 } break;
138 case NETLINK_USERCTL_CMD_RM: {
139 struct fblock *fb;
140 struct lananlmsg_rm *msg =
141 (struct lananlmsg_rm *) lmsg->buff;
142 fb = search_fblock_n(msg->name);
143 if (!fb)
144 return -EINVAL;
145 if (atomic_read(&fb->refcnt) > 2) {
146 /* Still in use by others */
147 put_fblock(fb);
148 return -EBUSY;
150 unregister_fblock_namespace(fb);
151 put_fblock(fb);
152 } break;
153 case NETLINK_USERCTL_CMD_BIND: {
154 int ret;
155 struct fblock *fb1, *fb2;
156 struct lananlmsg_bind *msg =
157 (struct lananlmsg_bind *) lmsg->buff;
158 fb1 = search_fblock_n(msg->name1);
159 if (!fb1)
160 return -EINVAL;
161 fb2 = search_fblock_n(msg->name2);
162 if (!fb2) {
163 put_fblock(fb1);
164 return -EINVAL;
166 ret = fblock_bind(fb1, fb2);
167 if (ret) {
168 put_fblock(fb1);
169 put_fblock(fb2);
170 return ret;
172 put_fblock(fb1);
173 put_fblock(fb2);
174 } break;
175 case NETLINK_USERCTL_CMD_UNBIND: {
176 int ret;
177 struct fblock *fb1, *fb2;
178 struct lananlmsg_unbind *msg =
179 (struct lananlmsg_unbind *) lmsg->buff;
180 fb1 = search_fblock_n(msg->name1);
181 if (!fb1)
182 return -EINVAL;
183 fb2 = search_fblock_n(msg->name2);
184 if (!fb2) {
185 put_fblock(fb1);
186 return -EINVAL;
188 ret = fblock_unbind(fb1, fb2);
189 if (ret) {
190 put_fblock(fb1);
191 put_fblock(fb2);
192 return ret;
194 put_fblock(fb1);
195 put_fblock(fb2);
196 } break;
197 default:
198 printk("[lana] Unknown command!\n");
199 break;
202 return 0;
205 static void userctl_rcv(struct sk_buff *skb)
207 netlink_rcv_skb(skb, &__userctl_rcv);
210 int init_userctl_system(void)
212 userctl_sock = netlink_kernel_create(&init_net, NETLINK_USERCTL,
213 USERCTLGRP_MAX, userctl_rcv,
214 NULL, THIS_MODULE);
215 if (!userctl_sock)
216 return -ENOMEM;
217 return 0;
219 EXPORT_SYMBOL_GPL(init_userctl_system);
221 void cleanup_userctl_system(void)
223 netlink_kernel_release(userctl_sock);
225 EXPORT_SYMBOL_GPL(cleanup_userctl_system);