2 * Lightweight Autonomic Network Architecture
4 * Eth/PHY layer. Redirects all traffic into the LANA stack.
7 * Copyright 2011 Daniel Borkmann <dborkma@tik.ee.ethz.ch>,
8 * Swiss federal institute of technology (ETH Zurich)
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/init.h>
15 #include <linux/notifier.h>
16 #include <linux/if_ether.h>
17 #include <linux/if_arp.h>
19 #include <linux/etherdevice.h>
20 #include <linux/rtnetlink.h>
21 #include <linux/seqlock.h>
24 #include "xt_engine.h"
26 #include "xt_fblock.h"
27 #include "xt_builder.h"
30 #define IFF_VLINK_MAS 0x20000
31 #define IFF_VLINK_DEV 0x40000
32 #define IFF_IS_BRIDGED 0x60000
37 struct net_device
*dev
;
40 static LIST_HEAD(fb_eth_devs
);
41 static DEFINE_SPINLOCK(fb_eth_devs_lock
);
43 struct fb_eth_dev_node
{
44 struct list_head list
;
46 struct net_device
*dev
;
49 static inline int fb_eth_dev_is_bridged(struct net_device
*dev
)
51 return (dev
->priv_flags
& IFF_IS_BRIDGED
) == IFF_IS_BRIDGED
;
54 static inline int fb_ethvlink_real_dev_is_hooked(struct net_device
*dev
)
56 return (dev
->priv_flags
& IFF_VLINK_MAS
) == IFF_VLINK_MAS
;
59 static inline void fb_eth_make_dev_bridged(struct net_device
*dev
)
61 dev
->priv_flags
|= IFF_IS_BRIDGED
;
64 static inline void fb_eth_make_dev_unbridged(struct net_device
*dev
)
66 dev
->priv_flags
&= ~IFF_IS_BRIDGED
;
69 static rx_handler_result_t
fb_eth_handle_frame(struct sk_buff
**pskb
)
72 struct sk_buff
*skb
= *pskb
;
73 struct fb_eth_dev_node
*node
;
74 struct fblock
*fb
= NULL
;
75 struct fb_eth_priv __percpu
*fb_priv_cpu
;
77 if (unlikely(skb
->pkt_type
== PACKET_LOOPBACK
))
78 return RX_HANDLER_PASS
;
79 if (unlikely(!is_valid_ether_addr(eth_hdr(skb
)->h_source
)))
81 skb
= skb_share_check(skb
, GFP_ATOMIC
);
83 return RX_HANDLER_CONSUMED
;
85 list_for_each_entry_rcu(node
, &fb_eth_devs
, list
)
86 if (skb
->dev
== node
->dev
)
93 fb_priv_cpu
= this_cpu_ptr(rcu_dereference(fb
->private_data
));
94 if (fb_priv_cpu
->port
[TYPE_INGRESS
] == IDP_UNKNOWN
)
98 seq
= read_seqbegin(&fb_priv_cpu
->lock
);
99 write_next_idp_to_skb(skb
, fb
->idp
,
100 fb_priv_cpu
->port
[TYPE_INGRESS
]);
101 } while (read_seqretry(&fb_priv_cpu
->lock
, seq
));
103 process_packet(skb
, TYPE_INGRESS
);
105 return RX_HANDLER_CONSUMED
;
108 return RX_HANDLER_CONSUMED
;
111 static int fb_eth_netrx(const struct fblock
* const fb
,
112 struct sk_buff
* const skb
,
113 enum path_type
* const dir
)
115 struct fb_eth_priv __percpu
*fb_priv_cpu
;
116 fb_priv_cpu
= this_cpu_ptr(rcu_dereference(fb
->private_data
));
117 write_next_idp_to_skb(skb
, fb
->idp
, IDP_UNKNOWN
);
118 skb
->dev
= fb_priv_cpu
->dev
;
123 static int fb_eth_event(struct notifier_block
*self
, unsigned long cmd
,
129 struct fb_eth_priv __percpu
*fb_priv
;
132 fb
= rcu_dereference_raw(container_of(self
, struct fblock_notifier
, nb
)->self
);
133 fb_priv
= (struct fb_eth_priv __percpu
*) rcu_dereference_raw(fb
->private_data
);
137 case FBLOCK_BIND_IDP
: {
139 struct fblock_bind_msg
*msg
= args
;
141 for_each_online_cpu(cpu
) {
142 struct fb_eth_priv
*fb_priv_cpu
;
143 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
144 if (fb_priv_cpu
->port
[msg
->dir
] == IDP_UNKNOWN
) {
145 write_seqlock(&fb_priv_cpu
->lock
);
146 fb_priv_cpu
->port
[msg
->dir
] = msg
->idp
;
147 write_sequnlock(&fb_priv_cpu
->lock
);
156 printk(KERN_INFO
"[%s::vlink] port %s bound to IDP%u\n",
157 fb
->name
, path_names
[msg
->dir
], msg
->idp
);
159 case FBLOCK_UNBIND_IDP
: {
161 struct fblock_bind_msg
*msg
= args
;
163 for_each_online_cpu(cpu
) {
164 struct fb_eth_priv
*fb_priv_cpu
;
165 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
166 if (fb_priv_cpu
->port
[msg
->dir
] == msg
->idp
) {
167 write_seqlock(&fb_priv_cpu
->lock
);
168 fb_priv_cpu
->port
[msg
->dir
] = IDP_UNKNOWN
;
169 write_sequnlock(&fb_priv_cpu
->lock
);
178 printk(KERN_INFO
"[%s::vlink] port %s unbound\n",
179 fb
->name
, path_names
[msg
->dir
]);
188 static void cleanup_fb_eth(struct net_device
*dev
)
191 if (fb_eth_dev_is_bridged(dev
)) {
192 netdev_rx_handler_unregister(dev
);
193 fb_eth_make_dev_unbridged(dev
);
198 static int init_fb_eth(struct net_device
*dev
)
202 ret
= netdev_rx_handler_register(dev
, fb_eth_handle_frame
, NULL
);
206 fb_eth_make_dev_bridged(dev
);
211 static struct fblock
*fb_eth_build_fblock(struct net_device
*dev
)
216 struct fb_eth_priv __percpu
*fb_priv
;
218 fb
= alloc_fblock(GFP_ATOMIC
);
222 fb_priv
= alloc_percpu(struct fb_eth_priv
);
227 for_each_online_cpu(cpu
) {
228 struct fb_eth_priv
*fb_priv_cpu
;
229 fb_priv_cpu
= per_cpu_ptr(fb_priv
, cpu
);
230 seqlock_init(&fb_priv_cpu
->lock
);
231 fb_priv_cpu
->port
[0] = IDP_UNKNOWN
;
232 fb_priv_cpu
->port
[1] = IDP_UNKNOWN
;
233 fb_priv_cpu
->dev
= dev
;
237 ret
= init_fblock(fb
, dev
->name
, fb_priv
);
241 fb
->netfb_rx
= fb_eth_netrx
;
242 fb
->event_rx
= fb_eth_event
;
245 ret
= register_fblock_namespace(fb
);
248 ret
= init_fb_eth(dev
);
251 __module_get(THIS_MODULE
);
255 unregister_fblock_namespace_no_rcu(fb
);
257 cleanup_fblock_ctor(fb
);
259 free_percpu(fb_priv
);
266 static void fb_eth_destroy_fblock(struct fblock
*fb
)
268 struct fb_eth_priv __percpu
*fb_priv_cpu
;
271 fb_priv_cpu
= this_cpu_ptr(rcu_dereference(fb
->private_data
));
272 cleanup_fb_eth(fb_priv_cpu
->dev
);
275 unregister_fblock_namespace_no_rcu(fb
);
277 free_percpu(rcu_dereference_raw(fb
->private_data
));
279 module_put(THIS_MODULE
);
282 static struct vlink_subsys fb_eth_sys __read_mostly
= {
284 .owner
= THIS_MODULE
,
285 .type
= VLINKNLGRP_ETHERNET
,
286 .rwsem
= __RWSEM_INITIALIZER(fb_eth_sys
.rwsem
),
289 static int fb_eth_start_hook_dev(struct vlinknlmsg
*vhdr
, struct nlmsghdr
*nlh
)
292 struct net_device
*dev
;
293 struct fb_eth_dev_node
*node
;
295 if (vhdr
->cmd
!= VLINKNLCMD_START_HOOK_DEVICE
)
296 return NETLINK_VLINK_RX_NXT
;
298 dev
= dev_get_by_name(&init_net
, vhdr
->real_name
);
299 if (dev
&& (dev
->priv_flags
& IFF_VLINK_DEV
) == IFF_VLINK_DEV
)
302 return NETLINK_VLINK_RX_EMERG
;
304 if (fb_eth_dev_is_bridged(dev
))
306 if (fb_ethvlink_real_dev_is_hooked(dev
))
309 node
= kmalloc(sizeof(*node
), GFP_KERNEL
);
313 node
->fb
= fb_eth_build_fblock(dev
);
319 spin_lock_irqsave(&fb_eth_devs_lock
, flags
);
320 list_add_rcu(&node
->list
, &fb_eth_devs
);
321 spin_unlock_irqrestore(&fb_eth_devs_lock
, flags
);
323 printk(KERN_INFO
"[lana] hook attached to carrier %s\n",
327 return NETLINK_VLINK_RX_STOP
;
330 return NETLINK_VLINK_RX_EMERG
;
333 static int fb_eth_stop_hook_dev(struct vlinknlmsg
*vhdr
, struct nlmsghdr
*nlh
)
336 struct fblock
*fb
= NULL
;
337 struct net_device
*dev
;
338 struct fb_eth_dev_node
*node
;
340 if (vhdr
->cmd
!= VLINKNLCMD_STOP_HOOK_DEVICE
)
341 return NETLINK_VLINK_RX_NXT
;
343 dev
= dev_get_by_name(&init_net
, vhdr
->real_name
);
345 return NETLINK_VLINK_RX_EMERG
;
346 if (!fb_eth_dev_is_bridged(dev
))
348 if ((dev
->flags
& IFF_RUNNING
) == IFF_RUNNING
)
351 spin_lock_irqsave(&fb_eth_devs_lock
, flags
);
352 list_for_each_entry_rcu(node
, &fb_eth_devs
, list
) {
353 if (dev
== node
->dev
) {
358 spin_unlock_irqrestore(&fb_eth_devs_lock
, flags
);
362 if (atomic_read(&fb
->refcnt
) > 2) {
363 printk(KERN_INFO
"Cannot remove vlink dev! Still in use by "
368 spin_lock_irqsave(&fb_eth_devs_lock
, flags
);
369 list_del_rcu(&node
->list
);
370 spin_unlock_irqrestore(&fb_eth_devs_lock
, flags
);
372 fb_eth_destroy_fblock(fb
);
376 printk(KERN_INFO
"[lana] hook detached from carrier %s\n",
380 return NETLINK_VLINK_RX_STOP
;
383 return NETLINK_VLINK_RX_EMERG
;
386 static struct vlink_callback fb_eth_start_hook_dev_cb
=
387 VLINK_CALLBACK_INIT(fb_eth_start_hook_dev
, NETLINK_VLINK_PRIO_HIGH
);
388 static struct vlink_callback fb_eth_stop_hook_dev_cb
=
389 VLINK_CALLBACK_INIT(fb_eth_stop_hook_dev
, NETLINK_VLINK_PRIO_HIGH
);
391 static int __init
init_fb_eth_module(void)
394 ret
= vlink_subsys_register(&fb_eth_sys
);
398 vlink_add_callback(&fb_eth_sys
, &fb_eth_start_hook_dev_cb
);
399 vlink_add_callback(&fb_eth_sys
, &fb_eth_stop_hook_dev_cb
);
401 printk(KERN_INFO
"[lana] Ethernet vlink layer loaded!\n");
405 static void __exit
cleanup_fb_eth_module(void)
407 vlink_subsys_unregister_batch(&fb_eth_sys
);
408 printk(KERN_INFO
"[lana] Ethernet vlink layer removed!\n");
411 module_init(init_fb_eth_module
);
412 module_exit(cleanup_fb_eth_module
);
414 MODULE_LICENSE("GPL");
415 MODULE_AUTHOR("Daniel Borkmann <dborkma@tik.ee.ethz.ch>");
416 MODULE_DESCRIPTION("Ethernet virtual link layer driver");