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)
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>
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
))
33 if (nlh
->nlmsg_len
< NLMSG_LENGTH(sizeof(struct lananlmsg
)))
36 lmsg
= NLMSG_DATA(nlh
);
39 case NETLINK_USERCTL_CMD_ADD
: {
41 struct lananlmsg_add
*msg
=
42 (struct lananlmsg_add
*) lmsg
->buff
;
43 fb
= build_fblock_object(msg
->type
, msg
->name
);
47 case NETLINK_USERCTL_CMD_SET
: {
50 struct lananlmsg_set
*msg
=
51 (struct lananlmsg_set
*) lmsg
->buff
;
52 fb
= search_fblock_n(msg
->name
);
55 ret
= fblock_set_option(fb
, msg
->option
);
59 case NETLINK_USERCTL_CMD_REPLACE
: {
61 struct fblock
*fb1
, *fb2
;
62 struct lananlmsg_replace
*msg
=
63 (struct lananlmsg_replace
*) lmsg
->buff
;
64 fb1
= search_fblock_n(msg
->name1
);
67 fb2
= search_fblock_n(msg
->name2
);
72 if (atomic_read(&fb2
->refcnt
) > 2) {
73 /* Still in use by others */
75 printk(KERN_ERR
"[lana] %s is still in use by others. "
76 "Drop refs first!\n", fb2
->name
);
80 unregister_fblock_namespace_no_rcu(fb2
);
81 ret
= fblock_migrate(fb2
, fb1
);
85 printk("[lana] fblock migration failed! "
86 "Destination fblock lost!\n");
91 unregister_fblock(fb1
);
93 ret
= register_fblock(fb2
, fb2
->idp
);
97 /* Now fb2 cannot be used anymore. */
99 strlcpy(fb2
->name
, fb1
->name
,sizeof(fb2
->name
));
100 /* Care about private data transfer ... */
101 if (!strncmp(fb1
->factory
->type
, fb2
->factory
->type
,
102 sizeof(fb1
->factory
->type
)) && !drop_priv
) {
103 /* Free our private_data */
104 rcu_assign_pointer(fb2
->private_data
,
106 /* Now, make sure, we don't free private_data */
108 /* Free fb1 private_data */
110 /* Copy subscribtions */
111 /* Drop fb1, register fb2 as fb1 */
114 case NETLINK_USERCTL_CMD_SUBSCRIBE
: {
116 struct fblock
*fb1
, *fb2
;
117 struct lananlmsg_subscribe
*msg
=
118 (struct lananlmsg_subscribe
*) lmsg
->buff
;
119 fb1
= search_fblock_n(msg
->name1
);
122 fb2
= search_fblock_n(msg
->name2
);
128 * fb1 is remote block, fb2 is the one that
129 * wishes to be notified.
131 ret
= subscribe_to_remote_fblock(fb2
, fb1
);
136 case NETLINK_USERCTL_CMD_UNSUBSCRIBE
: {
137 struct fblock
*fb1
, *fb2
;
138 struct lananlmsg_unsubscribe
*msg
=
139 (struct lananlmsg_unsubscribe
*) lmsg
->buff
;
140 fb1
= search_fblock_n(msg
->name1
);
143 fb2
= search_fblock_n(msg
->name2
);
148 unsubscribe_from_remote_fblock(fb2
, fb1
);
152 case NETLINK_USERCTL_CMD_RM
: {
154 struct lananlmsg_rm
*msg
=
155 (struct lananlmsg_rm
*) lmsg
->buff
;
156 fb
= search_fblock_n(msg
->name
);
159 if (atomic_read(&fb
->refcnt
) > 2) {
160 /* Still in use by others */
164 unregister_fblock_namespace(fb
);
167 case NETLINK_USERCTL_CMD_BIND
: {
169 struct fblock
*fb1
, *fb2
;
170 struct lananlmsg_bind
*msg
=
171 (struct lananlmsg_bind
*) lmsg
->buff
;
172 fb1
= search_fblock_n(msg
->name1
);
175 fb2
= search_fblock_n(msg
->name2
);
180 ret
= fblock_bind(fb1
, fb2
);
189 case NETLINK_USERCTL_CMD_UNBIND
: {
191 struct fblock
*fb1
, *fb2
;
192 struct lananlmsg_unbind
*msg
=
193 (struct lananlmsg_unbind
*) lmsg
->buff
;
194 fb1
= search_fblock_n(msg
->name1
);
197 fb2
= search_fblock_n(msg
->name2
);
202 ret
= fblock_unbind(fb1
, fb2
);
212 printk("[lana] Unknown command!\n");
219 static void userctl_rcv(struct sk_buff
*skb
)
221 netlink_rcv_skb(skb
, &__userctl_rcv
);
224 int init_userctl_system(void)
226 userctl_sock
= netlink_kernel_create(&init_net
, NETLINK_USERCTL
,
227 USERCTLGRP_MAX
, userctl_rcv
,
233 EXPORT_SYMBOL_GPL(init_userctl_system
);
235 void cleanup_userctl_system(void)
237 netlink_kernel_release(userctl_sock
);
239 EXPORT_SYMBOL_GPL(cleanup_userctl_system
);