Fix problem with identifying SNAP frames when extracting flows.
[sliver-openvswitch.git] / datapath / datapath_t.c
1 #include "datapath_t.h"
2 #include <linux/skbuff.h>
3 #include <linux/in.h>
4 #include <linux/ip.h>
5 #include <linux/if_ether.h>
6 #include <linux/udp.h>
7 #include <linux/rcupdate.h>
8
9 #include "datapath.h"
10
11 static struct sk_buff *
12 gen_sk_buff(struct datapath *dp, uint32_t packet_size)
13 {
14         int in_port;
15         struct sk_buff *skb;
16         struct ethhdr *eh;
17         struct iphdr *ih;
18         struct udphdr *uh;
19
20         for (in_port = 0; in_port < OFPP_MAX; in_port++) {
21                 if (dp->ports[in_port] != NULL)
22                         break;
23         }
24
25         if (in_port == OFPP_MAX) {
26                 printk("benchmark: no in_port to send packets as\n");
27                 return NULL;
28         }
29
30         skb = alloc_skb(packet_size, GFP_ATOMIC);
31         if (!skb) {
32                 printk("benchmark: cannot allocate skb for benchmark\n");
33                 return NULL;
34         }
35
36         skb_put(skb, packet_size);
37         skb_set_mac_header(skb, 0);
38         eh = eth_hdr(skb);
39         memcpy(eh->h_dest, "\x12\x34\x56\x78\x9a\xbc", ETH_ALEN);
40         memcpy(eh->h_source, "\xab\xcd\xef\x12\x34\x56", ETH_ALEN);
41         eh->h_proto = htons(ETH_P_IP);
42         skb_set_network_header(skb, sizeof(*eh));
43         ih = ip_hdr(skb);
44         ih->ihl = 5;
45         ih->version = IPVERSION;
46         ih->tos = 0;
47         ih->tot_len = htons(packet_size - sizeof(*eh));
48         ih->id = htons(12345);
49         ih->frag_off = 0;
50         ih->ttl = IPDEFTTL;
51         ih->protocol = IPPROTO_UDP;
52         ih->check = 0; /* want this to be right?! */
53         ih->saddr = 0x12345678;
54         ih->daddr = 0x1234abcd;
55         skb_set_transport_header(skb, sizeof(*eh) + sizeof(*ih));
56         uh = udp_hdr(skb);
57         uh->source = htons(1234);
58         uh->dest = htons(5678);
59         uh->len = htons(packet_size - sizeof(*eh) - sizeof(*ih));
60         uh->check = 0;
61         if (dp_set_origin(dp, in_port, skb)) {
62                 printk("benchmark: could not set origin\n");
63                 kfree_skb(skb);
64                 return NULL;
65         }
66
67         return skb;
68 }
69
70 int
71 dp_genl_benchmark_nl(struct sk_buff *skb, struct genl_info *info)
72 {
73         struct datapath *dp;
74         uint32_t num_packets = 0;
75         int i, err = 0;
76         struct sk_buff *skb2;
77
78         if (!info->attrs[DP_GENL_A_DP_IDX] || !info->attrs[DP_GENL_A_NPACKETS]
79                         || !info->attrs[DP_GENL_A_PSIZE])
80                 return -EINVAL;
81
82         num_packets = nla_get_u32((info->attrs[DP_GENL_A_NPACKETS]));
83
84         rcu_read_lock();
85         dp = dp_get(nla_get_u32((info->attrs[DP_GENL_A_DP_IDX])));
86         if (!dp)
87                 err = -ENOENT;
88         else {
89                 if (num_packets == 0)
90                         goto benchmark_unlock;
91
92                 skb2 = gen_sk_buff(dp, nla_get_u32((info->attrs[DP_GENL_A_PSIZE])));
93                 if (skb2 == NULL) {
94                         err = -ENOMEM;
95                         goto benchmark_unlock;
96                 }
97
98                 for (i = 0; i < num_packets; i++) {
99                         struct sk_buff *copy = skb_get(skb2);
100                         if (copy == NULL) {
101                                 printk("benchmark: skb_get failed\n");
102                                 err = -ENOMEM;
103                                 break;
104                         }
105                         if ((err = dp_output_control(dp, copy, -1,
106                                                 0, OFPR_ACTION)))
107                         {
108                                 printk("benchmark: output control ret %d on iter %d\n", err, i);
109                                 break;
110                         }
111                 }
112                 kfree_skb(skb2);
113         }
114
115 benchmark_unlock:
116         rcu_read_unlock();
117         return err;
118 }