Add support for DPDK 17.11
[samplevnf.git] / VNFs / DPPD-PROX / handle_qinq_encap6.c
1 /*
2 // Copyright (c) 2010-2017 Intel Corporation
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //     http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 */
16
17 #include <rte_table_hash.h>
18
19 #include "handle_qinq_encap6.h"
20 #include "handle_qinq_encap4.h"
21 #include "task_base.h"
22 #include "qinq.h"
23 #include "defines.h"
24 #include "tx_pkt.h"
25 #include "hash_entry_types.h"
26 #include "prefetch.h"
27 #include "log.h"
28 #include "lconf.h"
29 #include "mpls.h"
30 #include "hash_utils.h"
31 #include "quit.h"
32 #include "prox_compat.h"
33
34 struct task_qinq_encap6 {
35         struct task_base                    base;
36         uint16_t                            qinq_tag;
37         uint8_t                             tx_portid;
38         uint8_t                             runtime_flags;
39         struct rte_table_hash               *cpe_table;
40 };
41
42 static void init_task_qinq_encap6(struct task_base *tbase, struct task_args *targ)
43 {
44         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
45
46         task->qinq_tag = targ->qinq_tag;
47         task->cpe_table = targ->cpe_table;
48         task->runtime_flags = targ->runtime_flags;
49 }
50
51 /* Encapsulate IPv6 packet in QinQ where the QinQ is derived from the IPv6 address */
52 static inline uint8_t handle_qinq_encap6(struct rte_mbuf *mbuf, struct task_qinq_encap6 *task)
53 {
54         struct qinq_hdr *pqinq = (struct qinq_hdr *)rte_pktmbuf_prepend(mbuf, 2 * sizeof(struct vlan_hdr));
55
56         PROX_ASSERT(pqinq);
57         struct ipv6_hdr *pip6 = (struct ipv6_hdr *)(pqinq + 1);
58
59         if (pip6->hop_limits) {
60                 pip6->hop_limits--;
61         }
62         else {
63                 plog_info("TTL = 0 => Dropping\n");
64                 return OUT_DISCARD;
65         }
66
67         // TODO: optimize to use bulk as intended with the rte_table_library
68         uint64_t pkts_mask = RTE_LEN2MASK(1, uint64_t);
69         uint64_t lookup_hit_mask;
70         struct cpe_data* entries[64]; // TODO: use bulk size
71         prox_rte_table_lookup(task->cpe_table, &mbuf, pkts_mask, &lookup_hit_mask, (void**)entries);
72
73         if (lookup_hit_mask == 0x1) {
74                 /* will also overwrite part of the destination addr */
75                 (*(uint64_t *)pqinq) = entries[0]->mac_port_8bytes;
76                 pqinq->svlan.eth_proto = task->qinq_tag;
77                 pqinq->cvlan.eth_proto = ETYPE_VLAN;
78                 pqinq->svlan.vlan_tci = entries[0]->qinq_svlan;
79                 pqinq->cvlan.vlan_tci = entries[0]->qinq_cvlan;
80                 pqinq->ether_type = ETYPE_IPv6;
81
82                 /* classification can only be done from this point */
83                 if (task->runtime_flags & TASK_CLASSIFY) {
84                         rte_sched_port_pkt_write(mbuf, 0, entries[0]->user, 0, 0, 0);
85                 }
86                 return 0;
87         }
88         else {
89                 plogx_err("Unknown IP " IPv6_BYTES_FMT "\n", IPv6_BYTES(pip6->dst_addr));
90                 return OUT_DISCARD;
91         }
92 }
93
94 void init_cpe6_table(struct task_args *targ)
95 {
96         char name[64];
97         sprintf(name, "core_%u_CPEv6Table", targ->lconf->id);
98
99         uint8_t table_part = targ->nb_slave_threads;
100         if (!rte_is_power_of_2(table_part)) {
101                 table_part = rte_align32pow2(table_part) >> 1;
102         }
103
104         uint32_t n_entries = MAX_GRE / table_part;
105         static char hash_name[30];
106         sprintf(hash_name, "cpe6_table_%03d", targ->lconf->id);
107         struct prox_rte_table_params table_hash_params = {
108                 .name = hash_name,
109                 .key_size = sizeof(struct ipv6_addr),
110                 .n_keys = n_entries,
111                 .n_buckets = n_entries >> 2,
112                 .f_hash = (rte_table_hash_op_hash)hash_crc32,
113                 .seed = 0,
114                 .key_offset = HASH_METADATA_OFFSET(0),
115                 .key_mask = NULL
116         };
117
118         size_t entry_size = sizeof(struct cpe_data);
119         if (!rte_is_power_of_2(entry_size)) {
120                 entry_size = rte_align32pow2(entry_size);
121         }
122
123         struct rte_table_hash* phash = prox_rte_table_create(&table_hash_params, rte_lcore_to_socket_id(targ->lconf->id), entry_size);
124         PROX_PANIC(phash == NULL, "Unable to allocate memory for IPv6 hash table on core %u\n", targ->lconf->id);
125
126         for (uint8_t task_id = 0; task_id < targ->lconf->n_tasks_all; ++task_id) {
127                 enum task_mode smode = targ->lconf->targs[task_id].mode;
128                 if (smode == QINQ_DECAP6 || smode == QINQ_ENCAP6) {
129                         targ->lconf->targs[task_id].cpe_table = phash;
130                 }
131         }
132 }
133
134 static void early_init(struct task_args *targ)
135 {
136         if (!targ->cpe_table) {
137                 init_cpe6_table(targ);
138         }
139 }
140
141 static int handle_qinq_encap6_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
142 {
143         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
144         uint8_t out[MAX_PKT_BURST];
145         uint16_t j;
146
147         prefetch_first(mbufs, n_pkts);
148
149         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
150 #ifdef PROX_PREFETCH_OFFSET
151                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
152                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
153 #endif
154                 out[j] = handle_qinq_encap6(mbufs[j], task);
155         }
156 #ifdef PROX_PREFETCH_OFFSET
157         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
158         for (; j < n_pkts; ++j) {
159                 out[j] = handle_qinq_encap6(mbufs[j], task);
160         }
161 #endif
162
163         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
164 }
165
166 static int handle_qinq_encap6_untag_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
167 {
168         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
169         uint8_t out[MAX_PKT_BURST];
170         uint16_t j;
171
172         prefetch_first(mbufs, n_pkts);
173
174         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
175 #ifdef PROX_PREFETCH_OFFSET
176                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
177                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
178 #endif
179                 if (likely(mpls_untag(mbufs[j]))) {
180                         out[j] = handle_qinq_encap6(mbufs[j], task);
181                 }
182                 else {
183                         out[j] = OUT_DISCARD;
184                 }
185         }
186 #ifdef PROX_PREFETCH_OFFSET
187         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
188         for (; j < n_pkts; ++j) {
189                 if (likely(mpls_untag(mbufs[j]))) {
190                         out[j] = handle_qinq_encap6(mbufs[j], task);
191                 }
192                 else {
193                         out[j] = OUT_DISCARD;
194                 }
195         }
196 #endif
197
198         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
199 }
200
201 static struct task_init task_init_qinq_encap6 = {
202         .mode = QINQ_ENCAP6,
203         .mode_str = "qinqencapv6",
204         .init = init_task_qinq_encap6,
205         .early_init = early_init,
206         .handle = handle_qinq_encap6_bulk,
207         .flag_features = TASK_FEATURE_CLASSIFY,
208         .size = sizeof(struct task_qinq_encap6)
209 };
210
211 static struct task_init task_init_qinq_encap6_untag = {
212         .mode = QINQ_ENCAP6,
213         .mode_str = "qinqencapv6",
214         .sub_mode_str = "unmpls",
215         .early_init = early_init,
216         .init = init_task_qinq_encap6,
217         .handle = handle_qinq_encap6_untag_bulk,
218         .flag_features = TASK_FEATURE_CLASSIFY,
219         .size = sizeof(struct task_qinq_encap6)
220 };
221
222 __attribute__((constructor)) static void reg_task_qinq_encap6(void)
223 {
224         reg_task(&task_init_qinq_encap6);
225         reg_task(&task_init_qinq_encap6_untag);
226 }