some bugfix. added depth for loop avoidance
[vde.git] / ipn / kvde_switch / kvde_switch_main.c
blob004648673a91c815742c98ee1d3986c9de85ed5f
1 #include <linux/module.h>
2 #include <linux/if_ether.h>
3 #include "../af_ipn.h"
4 #include "../ipn_hash.h"
6 MODULE_LICENSE("GPL");
7 MODULE_AUTHOR("VIEW-OS TEAM");
8 MODULE_DESCRIPTION("VDE SWITCH Kernel Module");
10 static struct kmem_cache *kvde_net_cache;
11 #define IS_BROADCAST(addr) ((addr[0] & 1) == 1)
13 static int ipn_kvde_switch_newport(struct ipn_node *newport) {
14 struct ipn_network *ipnn=newport->ipn;
15 int i;
16 for (i=0;i<ipnn->maxports;i++) {
17 if (ipnn->connport[i] == NULL)
18 return i;
20 return -1;
23 static int ipn_kvde_switch_handlemsg(struct ipn_node *from,
24 struct msgpool_item *msgitem,
25 int depth){
26 struct ipn_network *ipnn=from->ipn;
27 struct ipn_hash *vdeh=(struct ipn_hash *)ipnn->proto_private;
28 int port;
29 struct ethhdr *ehdr=(struct ethhdr *)msgitem->data;
30 if (msgitem->len < sizeof(struct ethhdr))
31 return 0;
32 if (!IS_BROADCAST(ehdr->h_source))
33 ipn_hash_add(vdeh,(u16 *)&ehdr->h_source,0,from->portno);
34 if (IS_BROADCAST(ehdr->h_dest) ||
35 (port = ipn_hash_find(vdeh,(u16 *)&ehdr->h_dest,0)) < 0) {
36 /*printk("SWITCH FROM %d -> BROADCAST\n",from->portno);*/
37 for (port=0; port<ipnn->maxports; port++)
38 if (ipnn->connport[port] && ipnn->connport[port] != from)
39 ipn_proto_sendmsg(ipnn->connport[port],msgitem,depth);
40 } else {
41 /*printk("SWITCH FROM %d -> %d\n",from->portno,port);*/
42 ipn_proto_sendmsg(ipnn->connport[port],msgitem,depth);
44 return 0;
47 static void ipn_kvde_switch_delport(struct ipn_node *oldport) {
48 struct ipn_network *ipnn=oldport->ipn;
49 struct ipn_hash *vdeh=(struct ipn_hash *)ipnn->proto_private;
50 ipn_hash_flush_port(vdeh,oldport->portno);
53 static int ipn_kvde_switch_newnet(struct ipn_network *newnet) {
54 struct ipn_hash *vdeh=kmem_cache_alloc(kvde_net_cache,GFP_KERNEL);
55 if (!vdeh)
56 return -ENOMEM;
57 if (!try_module_get(THIS_MODULE))
58 return -EINVAL;
59 newnet->proto_private=vdeh;
60 ipn_hash_new(vdeh,256,30);
61 return 0;
64 static void ipn_kvde_switch_delnet(struct ipn_network *oldnet) {
65 struct ipn_hash *vdeh=(struct ipn_hash *) oldnet->proto_private;
66 ipn_hash_free(vdeh);
67 kmem_cache_free(kvde_net_cache,vdeh);
68 module_put(THIS_MODULE);
71 static int ipn_kvde_switch_setsockopt(struct ipn_node *port,int optname,
72 char __user *optval, int optlen) {return -EOPNOTSUPP;}
73 static int ipn_kvde_switch_getsockopt(struct ipn_node *port,int optname,
74 char __user *optval, int *optlen) {return -EOPNOTSUPP;}
75 static int ipn_kvde_switch_ioctl(struct ipn_node *port,unsigned int request,
76 unsigned long arg) {return -EOPNOTSUPP;}
78 /* static void ipn_kvde_switch_postnewport(struct ipn_node *newport) {} */
79 /* static void ipn_kvde_switch_predelport(struct ipn_node *oldport) {} */
80 static struct ipn_protocol vde_switch_proto={
81 .ipn_p_newport=ipn_kvde_switch_newport,
82 .ipn_p_handlemsg=ipn_kvde_switch_handlemsg,
83 .ipn_p_delport=ipn_kvde_switch_delport,
84 /*.ipn_p_postnewport=ipn_kvde_switch_postnewport,*/
85 /*.ipn_p_predelport=ipn_kvde_switch_predelport,*/
86 .ipn_p_newnet=ipn_kvde_switch_newnet,
87 .ipn_p_delnet=ipn_kvde_switch_delnet,
88 .ipn_p_setsockopt=ipn_kvde_switch_setsockopt,
89 .ipn_p_getsockopt=ipn_kvde_switch_getsockopt,
90 .ipn_p_ioctl=ipn_kvde_switch_ioctl
94 static int kvde_switch_init(void)
96 int rc=0;
97 kvde_net_cache=kmem_cache_create("kvde_net",sizeof(struct ipn_hash),0,0,NULL,NULL);
98 if (!kvde_net_cache) {
99 rc=-ENOMEM;
100 goto out;
102 rc=ipn_proto_register(IPN_VDESWITCH,&vde_switch_proto);
103 out:
104 return rc;
107 static void kvde_switch_exit(void)
109 ipn_proto_deregister(IPN_VDESWITCH);
110 if(kvde_net_cache)
111 kmem_cache_destroy(kvde_net_cache);
114 module_init(kvde_switch_init);
115 module_exit(kvde_switch_exit);