src/dpdk: Rebind DPDK ports to the original driver
[vswitchperf.git] / src / l2fwd / l2fwd.c
1 /*
2 * Copyright 2015 Futurewei Inc.
3 *
4 * l2fwd is free software: you can redistribute it and/or modify
5 * it under the terms of version 2 the GNU General Public License as published
6 * by the Free Software Foundation only
7
8 * l2fwd is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12
13 * You should have received a copy of the GNU General Public License
14 * along with this code.  If not, see
15 * https://www.gnu.org/licenses/gpl-2.0.html
16 *
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
22 */
23
24
25 #include <linux/module.h>
26 #include <linux/kernel.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <linux/init.h>
30 #include <linux/interrupt.h>
31 #include <linux/pci.h>
32 #include <linux/aer.h>
33 #include <linux/netdevice.h>
34 #include <linux/etherdevice.h>
35 #include <linux/if.h>
36 #include <linux/if_ether.h>
37 #include <linux/in.h>
38 #include <linux/rtnetlink.h>
39 #include <linux/prefetch.h>
40 #include <linux/log2.h>
41
42 static char *net1 = "eth1";
43 module_param(net1, charp, 0);
44 MODULE_PARM_DESC(net1, "The first net device name (default is eth1)");
45
46 static char *net2 = "eth2";
47 module_param(net2, charp, 0);
48 MODULE_PARM_DESC(net2, "The second net device name (default is eth2)");
49
50 static bool print = false;
51 module_param(print, bool, 0);
52 MODULE_PARM_DESC(print, "Log forwarding statistics (default is false)");
53
54 static int stats_interval = 10000;
55 module_param(stats_interval, int, 0);
56 MODULE_PARM_DESC(print, "Forwarding statistics packet interval (default is 10000)");
57
58 static bool terminate = false;
59 module_param(terminate, bool, 0);
60 MODULE_PARM_DESC(terminate, "Free skb instead of forwarding");
61
62 static struct net_device *dev1, *dev2;
63 int count;
64
65 static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb)
66 {
67     struct sk_buff *skb = *pskb;
68     struct net_device *dev;
69
70     if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
71         return RX_HANDLER_PASS;
72
73     dev = (struct net_device*) rcu_dereference_rtnl(skb->dev->rx_handler_data);
74     count++;
75     if ( ((count % stats_interval) == 0) && print )
76         printk("l2fwd count %d\n", count);
77
78     if (terminate)
79         {
80             kfree_skb(skb);
81         }
82     else
83         {
84             skb->dev = dev;
85             skb_push(skb, ETH_HLEN);
86             dev_queue_xmit(skb);
87         }
88
89     return RX_HANDLER_CONSUMED;
90 }
91
92 static int __init l2fwd_init_module(void)
93 {
94     int err = -1;
95
96     dev1 = dev_get_by_name(&init_net, net1);
97     if (!dev1)
98         {
99             printk("can't get device %s\n", net1);
100             err = -ENODEV;
101             goto out;
102         }
103
104     dev2 = dev_get_by_name(&init_net, net2);
105     if (!dev2)
106         {
107             printk("can't get device %s\n", net2);
108             err = -ENODEV;
109             goto out_dev1;
110         }
111
112     rtnl_lock();
113     err = netdev_rx_handler_register(dev1, netdev_frame_hook, dev2);
114     if (err)
115         {
116             printk("can't register rx_handler for device %s\n", net1);
117             goto out_dev2;
118         }
119     dev_set_promiscuity(dev1, 1);
120
121     err = netdev_rx_handler_register(dev2, netdev_frame_hook, dev1);
122     if (err)
123         {
124             printk("can't register rx_handler for device %s\n", net2);
125             netdev_rx_handler_unregister(dev1);
126             goto out_dev2;
127         }
128     dev_set_promiscuity(dev2, 1);
129
130     rtnl_unlock();
131     return 0;
132
133 out_dev2:
134     rtnl_unlock();
135     dev_put(dev2);
136     dev2 = NULL;
137 out_dev1:
138     dev_put(dev1);
139     dev1 = NULL;
140 out:
141     return err;
142 }
143
144 static void __exit l2fwd_exit_module(void)
145 {
146     rtnl_lock();
147     if (dev2)
148         {
149             dev_put(dev2);
150             netdev_rx_handler_unregister(dev1);
151         }
152     if (dev1)
153         {
154             dev_put(dev1);
155             netdev_rx_handler_unregister(dev2);
156         }
157     dev_set_promiscuity(dev1, -1);
158     dev_set_promiscuity(dev2, -1);
159     rtnl_unlock();
160 }
161
162 module_init(l2fwd_init_module);
163 module_exit(l2fwd_exit_module);
164
165 MODULE_DESCRIPTION("Huawei L2 Forwarding module");
166 MODULE_LICENSE("GPL");
167 MODULE_VERSION("0.1");