examples/tep_term: implement VXLAN processing
[dpdk.git] / examples / tep_termination / vxlan_setup.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <getopt.h>
35 #include <linux/if_ether.h>
36 #include <linux/if_vlan.h>
37 #include <linux/virtio_net.h>
38 #include <linux/virtio_ring.h>
39 #include <sys/param.h>
40 #include <unistd.h>
41
42 #include <rte_ethdev.h>
43 #include <rte_log.h>
44 #include <rte_string_fns.h>
45 #include <rte_mbuf.h>
46 #include <rte_malloc.h>
47 #include <rte_ip.h>
48 #include <rte_udp.h>
49 #include <rte_tcp.h>
50
51 #include "main.h"
52 #include "rte_virtio_net.h"
53 #include "vxlan.h"
54 #include "vxlan_setup.h"
55
56 #define IPV4_HEADER_LEN 20
57 #define UDP_HEADER_LEN  8
58 #define VXLAN_HEADER_LEN 8
59
60 #define IP_VERSION 0x40
61 #define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
62 #define IP_DEFTTL  64   /* from RFC 1340. */
63 #define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
64
65 #define IP_DN_FRAGMENT_FLAG 0x0040
66
67 /* Used to compare MAC addresses. */
68 #define MAC_ADDR_CMP 0xFFFFFFFFFFFFULL
69
70 /* Configurable number of RX/TX ring descriptors */
71 #define RTE_TEST_RX_DESC_DEFAULT 1024
72 #define RTE_TEST_TX_DESC_DEFAULT 512
73
74 /* VXLAN device */
75 struct vxlan_conf vxdev;
76
77 struct ipv4_hdr app_ip_hdr[VXLAN_N_PORTS];
78 struct ether_hdr app_l2_hdr[VXLAN_N_PORTS];
79
80 /* local VTEP IP address */
81 uint8_t vxlan_multicast_ips[2][4] = { {239, 1, 1, 1 }, {239, 1, 2, 1 } };
82
83 /* Remote VTEP IP address */
84 uint8_t vxlan_overlay_ips[2][4] = { {192, 168, 10, 1}, {192, 168, 30, 1} };
85
86 /* Remote VTEP MAC address */
87 uint8_t peer_mac[6] = {0x00, 0x11, 0x01, 0x00, 0x00, 0x01};
88
89 /* Options for configuring ethernet port */
90 static const struct rte_eth_conf port_conf = {
91         .rxmode = {
92                 .split_hdr_size = 0,
93                 .header_split   = 0, /**< Header Split disabled */
94                 .hw_ip_checksum = 0, /**< IP checksum offload disabled */
95                 .hw_vlan_filter = 0, /**< VLAN filtering disabled */
96                 .jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
97                 .hw_strip_crc   = 0, /**< CRC stripped by hardware */
98         },
99         .txmode = {
100                 .mq_mode = ETH_MQ_TX_NONE,
101         },
102 };
103
104 /**
105  * The one or two device(s) that belongs to the same tenant ID can
106  * be assigned in a VM.
107  */
108 const uint16_t tenant_id_conf[] = {
109         1000, 1000, 1001, 1001, 1002, 1002, 1003, 1003,
110         1004, 1004, 1005, 1005, 1006, 1006, 1007, 1007,
111         1008, 1008, 1009, 1009, 1010, 1010, 1011, 1011,
112         1012, 1012, 1013, 1013, 1014, 1014, 1015, 1015,
113         1016, 1016, 1017, 1017, 1018, 1018, 1019, 1019,
114         1020, 1020, 1021, 1021, 1022, 1022, 1023, 1023,
115         1024, 1024, 1025, 1025, 1026, 1026, 1027, 1027,
116         1028, 1028, 1029, 1029, 1030, 1030, 1031, 1031,
117 };
118
119 /**
120  * Initialises a given port using global settings and with the rx buffers
121  * coming from the mbuf_pool passed as parameter
122  */
123 int
124 vxlan_port_init(uint8_t port, struct rte_mempool *mbuf_pool)
125 {
126         int retval;
127         uint16_t q;
128         struct rte_eth_dev_info dev_info;
129         uint16_t rx_rings, tx_rings = (uint16_t)rte_lcore_count();
130         const uint16_t rx_ring_size = RTE_TEST_RX_DESC_DEFAULT;
131         const uint16_t tx_ring_size = RTE_TEST_TX_DESC_DEFAULT;
132         struct rte_eth_rxconf *rxconf;
133         struct rte_eth_txconf *txconf;
134
135         rte_eth_dev_info_get(port, &dev_info);
136
137         if (dev_info.max_rx_queues > MAX_QUEUES) {
138                 rte_exit(EXIT_FAILURE,
139                         "please define MAX_QUEUES no less than %u in %s\n",
140                         dev_info.max_rx_queues, __FILE__);
141         }
142
143         rxconf = &dev_info.default_rxconf;
144         txconf = &dev_info.default_txconf;
145         txconf->txq_flags = 0;
146
147         if (port >= rte_eth_dev_count())
148                 return -1;
149
150         rx_rings = nb_devices;
151
152         /* Configure ethernet device. */
153         retval = rte_eth_dev_configure(port, rx_rings, tx_rings, &port_conf);
154         if (retval != 0)
155                 return retval;
156
157         /* Setup the queues. */
158         for (q = 0; q < rx_rings; q++) {
159                 retval = rte_eth_rx_queue_setup(port, q, rx_ring_size,
160                                                 rte_eth_dev_socket_id(port),
161                                                 rxconf,
162                                                 mbuf_pool);
163                 if (retval < 0)
164                         return retval;
165         }
166         for (q = 0; q < tx_rings; q++) {
167                 retval = rte_eth_tx_queue_setup(port, q, tx_ring_size,
168                                                 rte_eth_dev_socket_id(port),
169                                                 txconf);
170                 if (retval < 0)
171                         return retval;
172         }
173
174         /* Start the device. */
175         retval  = rte_eth_dev_start(port);
176         if (retval < 0)
177                 return retval;
178
179         rte_eth_macaddr_get(port, &ports_eth_addr[port]);
180         RTE_LOG(INFO, PORT, "Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
181                         " %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
182                         (unsigned)port,
183                         ports_eth_addr[port].addr_bytes[0],
184                         ports_eth_addr[port].addr_bytes[1],
185                         ports_eth_addr[port].addr_bytes[2],
186                         ports_eth_addr[port].addr_bytes[3],
187                         ports_eth_addr[port].addr_bytes[4],
188                         ports_eth_addr[port].addr_bytes[5]);
189         return 0;
190 }
191
192 static int
193 vxlan_rx_process(struct rte_mbuf *pkt)
194 {
195         return  decapsulation(pkt);
196 }
197
198 static void
199 vxlan_tx_process(uint8_t queue_id, struct rte_mbuf *pkt)
200 {
201         encapsulation(pkt, queue_id);
202         return;
203 }
204
205 /*
206  * This function learns the MAC address of the device and set init
207  * L2 header and L3 header info.
208  */
209 int
210 vxlan_link(struct vhost_dev *vdev, struct rte_mbuf *m)
211 {
212         int i;
213         struct ether_hdr *pkt_hdr;
214         struct virtio_net *dev = vdev->dev;
215         uint64_t portid = dev->device_fh;
216         struct ipv4_hdr *ip;
217
218         if (unlikely(portid > VXLAN_N_PORTS)) {
219                 RTE_LOG(INFO, VHOST_DATA,
220                         "(%"PRIu64") WARNING: Not configuring device,"
221                         "as already have %d ports for VXLAN.",
222                         dev->device_fh, VXLAN_N_PORTS);
223                 return -1;
224         }
225
226         /* Learn MAC address of guest device from packet */
227         pkt_hdr = rte_pktmbuf_mtod(m, struct ether_hdr *);
228         if (is_same_ether_addr(&(pkt_hdr->s_addr), &vdev->mac_address)) {
229                 RTE_LOG(INFO, VHOST_DATA,
230                         "(%"PRIu64") WARNING: This device is using an existing"
231                         " MAC address and has not been registered.\n",
232                         dev->device_fh);
233                 return -1;
234         }
235
236         for (i = 0; i < ETHER_ADDR_LEN; i++) {
237                 vdev->mac_address.addr_bytes[i] =
238                         vxdev.port[portid].vport_mac.addr_bytes[i] =
239                         pkt_hdr->s_addr.addr_bytes[i];
240                 vxdev.port[portid].peer_mac.addr_bytes[i] = peer_mac[i];
241         }
242
243         /* Print out inner MAC and VNI info. */
244         RTE_LOG(INFO, VHOST_DATA,
245                 "(%d) MAC_ADDRESS %02x:%02x:%02x:%02x:%02x:%02x and VNI %d registered\n",
246                 vdev->rx_q,
247                 vdev->mac_address.addr_bytes[0],
248                 vdev->mac_address.addr_bytes[1],
249                 vdev->mac_address.addr_bytes[2],
250                 vdev->mac_address.addr_bytes[3],
251                 vdev->mac_address.addr_bytes[4],
252                 vdev->mac_address.addr_bytes[5],
253                 tenant_id_conf[vdev->rx_q]);
254
255         vxdev.port[portid].vport_id = portid;
256
257         for (i = 0; i < 4; i++) {
258                 /* Local VTEP IP */
259                 vxdev.port_ip |= vxlan_multicast_ips[portid][i] << (8 * i);
260                 /* Remote VTEP IP */
261                 vxdev.port[portid].peer_ip |=
262                         vxlan_overlay_ips[portid][i] << (8 * i);
263         }
264
265         vxdev.out_key = tenant_id_conf[vdev->rx_q];
266         ether_addr_copy(&vxdev.port[portid].peer_mac,
267                         &app_l2_hdr[portid].d_addr);
268         ether_addr_copy(&ports_eth_addr[0],
269                         &app_l2_hdr[portid].s_addr);
270         app_l2_hdr[portid].ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
271
272         ip = &app_ip_hdr[portid];
273         ip->version_ihl = IP_VHL_DEF;
274         ip->type_of_service = 0;
275         ip->total_length = 0;
276         ip->packet_id = 0;
277         ip->fragment_offset = IP_DN_FRAGMENT_FLAG;
278         ip->time_to_live = IP_DEFTTL;
279         ip->next_proto_id = IPPROTO_UDP;
280         ip->hdr_checksum = 0;
281         ip->src_addr = vxdev.port_ip;
282         ip->dst_addr = vxdev.port[portid].peer_ip;
283
284         /* Set device as ready for RX. */
285         vdev->ready = DEVICE_RX;
286
287         return 0;
288 }
289
290 /**
291  * Removes cloud filter. Ensures that nothing is adding buffers to the RX
292  * queue before disabling RX on the device.
293  */
294 void
295 vxlan_unlink(struct vhost_dev *vdev)
296 {
297         unsigned i = 0, rx_count;
298         struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
299
300         if (vdev->ready == DEVICE_RX) {
301                 for (i = 0; i < ETHER_ADDR_LEN; i++)
302                         vdev->mac_address.addr_bytes[i] = 0;
303
304                 /* Clear out the receive buffers */
305                 rx_count = rte_eth_rx_burst(ports[0],
306                                 (uint16_t)vdev->rx_q,
307                                 pkts_burst, MAX_PKT_BURST);
308
309                 while (rx_count) {
310                         for (i = 0; i < rx_count; i++)
311                                 rte_pktmbuf_free(pkts_burst[i]);
312
313                         rx_count = rte_eth_rx_burst(ports[0],
314                                         (uint16_t)vdev->rx_q,
315                                         pkts_burst, MAX_PKT_BURST);
316                 }
317                 vdev->ready = DEVICE_MAC_LEARNING;
318         }
319 }
320
321 /* Transmit packets after encapsulating */
322 int
323 vxlan_tx_pkts(uint8_t port_id, uint16_t queue_id,
324                 struct rte_mbuf **tx_pkts, uint16_t nb_pkts) {
325         int ret = 0;
326         uint16_t i;
327
328         for (i = 0; i < nb_pkts; i++)
329                 vxlan_tx_process(queue_id, tx_pkts[i]);
330
331         ret = rte_eth_tx_burst(port_id, queue_id, tx_pkts, nb_pkts);
332
333         return ret;
334 }
335
336 /* Check for decapsulation and pass packets directly to VIRTIO device */
337 int
338 vxlan_rx_pkts(struct virtio_net *dev, struct rte_mbuf **pkts_burst,
339                 uint32_t rx_count)
340 {
341         uint32_t i = 0;
342         uint32_t count = 0;
343         int ret;
344         struct rte_mbuf *pkts_valid[rx_count];
345
346         for (i = 0; i < rx_count; i++) {
347                 ret = vxlan_rx_process(pkts_burst[i]);
348                 if (unlikely(ret < 0))
349                         continue;
350
351                 pkts_valid[count] = pkts_burst[i];
352                         count++;
353         }
354
355         ret = rte_vhost_enqueue_burst(dev, VIRTIO_RXQ, pkts_valid, count);
356         return ret;
357 }