Merge "VNF_Catalogue Codebase"
[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
33 struct task_qinq_encap6 {
34         struct task_base                    base;
35         uint16_t                            qinq_tag;
36         uint8_t                             tx_portid;
37         uint8_t                             runtime_flags;
38         struct rte_table_hash               *cpe_table;
39 };
40
41 static void init_task_qinq_encap6(struct task_base *tbase, struct task_args *targ)
42 {
43         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
44
45         task->qinq_tag = targ->qinq_tag;
46         task->cpe_table = targ->cpe_table;
47         task->runtime_flags = targ->runtime_flags;
48 }
49
50 /* Encapsulate IPv6 packet in QinQ where the QinQ is derived from the IPv6 address */
51 static inline uint8_t handle_qinq_encap6(struct rte_mbuf *mbuf, struct task_qinq_encap6 *task)
52 {
53         struct qinq_hdr *pqinq = (struct qinq_hdr *)rte_pktmbuf_prepend(mbuf, 2 * sizeof(struct vlan_hdr));
54
55         PROX_ASSERT(pqinq);
56         struct ipv6_hdr *pip6 = (struct ipv6_hdr *)(pqinq + 1);
57
58         if (pip6->hop_limits) {
59                 pip6->hop_limits--;
60         }
61         else {
62                 plog_info("TTL = 0 => Dropping\n");
63                 return OUT_DISCARD;
64         }
65
66         // TODO: optimize to use bulk as intended with the rte_table_library
67         uint64_t pkts_mask = RTE_LEN2MASK(1, uint64_t);
68         uint64_t lookup_hit_mask;
69         struct cpe_data* entries[64]; // TODO: use bulk size
70         rte_table_hash_ext_dosig_ops.f_lookup(task->cpe_table, &mbuf, pkts_mask, &lookup_hit_mask, (void**)entries);
71
72         if (lookup_hit_mask == 0x1) {
73                 /* will also overwrite part of the destination addr */
74                 (*(uint64_t *)pqinq) = entries[0]->mac_port_8bytes;
75                 pqinq->svlan.eth_proto = task->qinq_tag;
76                 pqinq->cvlan.eth_proto = ETYPE_VLAN;
77                 pqinq->svlan.vlan_tci = entries[0]->qinq_svlan;
78                 pqinq->cvlan.vlan_tci = entries[0]->qinq_cvlan;
79                 pqinq->ether_type = ETYPE_IPv6;
80
81                 /* classification can only be done from this point */
82                 if (task->runtime_flags & TASK_CLASSIFY) {
83                         rte_sched_port_pkt_write(mbuf, 0, entries[0]->user, 0, 0, 0);
84                 }
85                 return 0;
86         }
87         else {
88                 plogx_err("Unknown IP " IPv6_BYTES_FMT "\n", IPv6_BYTES(pip6->dst_addr));
89                 return OUT_DISCARD;
90         }
91 }
92
93 void init_cpe6_table(struct task_args *targ)
94 {
95         char name[64];
96         sprintf(name, "core_%u_CPEv6Table", targ->lconf->id);
97
98         uint8_t table_part = targ->nb_slave_threads;
99         if (!rte_is_power_of_2(table_part)) {
100                 table_part = rte_align32pow2(table_part) >> 1;
101         }
102
103         uint32_t n_entries = MAX_GRE / table_part;
104         struct rte_table_hash_ext_params table_hash_params = {
105                 .key_size = sizeof(struct ipv6_addr),
106                 .n_keys = n_entries,
107                 .n_buckets = n_entries >> 2,
108                 .n_buckets_ext = n_entries >> 3,
109                 .f_hash = hash_crc32,
110                 .seed = 0,
111                 .signature_offset = HASH_METADATA_OFFSET(0),
112                 .key_offset = HASH_METADATA_OFFSET(0),
113         };
114
115         size_t entry_size = sizeof(struct cpe_data);
116         if (!rte_is_power_of_2(entry_size)) {
117                 entry_size = rte_align32pow2(entry_size);
118         }
119
120         struct rte_table_hash* phash = rte_table_hash_ext_dosig_ops.
121                 f_create(&table_hash_params, rte_lcore_to_socket_id(targ->lconf->id), entry_size);
122         PROX_PANIC(phash == NULL, "Unable to allocate memory for IPv6 hash table on core %u\n", targ->lconf->id);
123
124         for (uint8_t task_id = 0; task_id < targ->lconf->n_tasks_all; ++task_id) {
125                 enum task_mode smode = targ->lconf->targs[task_id].mode;
126                 if (smode == QINQ_DECAP6 || smode == QINQ_ENCAP6) {
127                         targ->lconf->targs[task_id].cpe_table = phash;
128                 }
129         }
130 }
131
132 static void early_init(struct task_args *targ)
133 {
134         if (!targ->cpe_table) {
135                 init_cpe6_table(targ);
136         }
137 }
138
139 static int handle_qinq_encap6_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
140 {
141         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
142         uint8_t out[MAX_PKT_BURST];
143         uint16_t j;
144
145         prefetch_first(mbufs, n_pkts);
146
147         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
148 #ifdef PROX_PREFETCH_OFFSET
149                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
150                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
151 #endif
152                 out[j] = handle_qinq_encap6(mbufs[j], task);
153         }
154 #ifdef PROX_PREFETCH_OFFSET
155         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
156         for (; j < n_pkts; ++j) {
157                 out[j] = handle_qinq_encap6(mbufs[j], task);
158         }
159 #endif
160
161         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
162 }
163
164 static int handle_qinq_encap6_untag_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
165 {
166         struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
167         uint8_t out[MAX_PKT_BURST];
168         uint16_t j;
169
170         prefetch_first(mbufs, n_pkts);
171
172         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
173 #ifdef PROX_PREFETCH_OFFSET
174                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
175                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
176 #endif
177                 if (likely(mpls_untag(mbufs[j]))) {
178                         out[j] = handle_qinq_encap6(mbufs[j], task);
179                 }
180                 else {
181                         out[j] = OUT_DISCARD;
182                 }
183         }
184 #ifdef PROX_PREFETCH_OFFSET
185         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
186         for (; j < n_pkts; ++j) {
187                 if (likely(mpls_untag(mbufs[j]))) {
188                         out[j] = handle_qinq_encap6(mbufs[j], task);
189                 }
190                 else {
191                         out[j] = OUT_DISCARD;
192                 }
193         }
194 #endif
195
196         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
197 }
198
199 static struct task_init task_init_qinq_encap6 = {
200         .mode = QINQ_ENCAP6,
201         .mode_str = "qinqencapv6",
202         .init = init_task_qinq_encap6,
203         .early_init = early_init,
204         .handle = handle_qinq_encap6_bulk,
205         .flag_features = TASK_FEATURE_CLASSIFY,
206         .size = sizeof(struct task_qinq_encap6)
207 };
208
209 static struct task_init task_init_qinq_encap6_untag = {
210         .mode = QINQ_ENCAP6,
211         .mode_str = "qinqencapv6",
212         .sub_mode_str = "unmpls",
213         .early_init = early_init,
214         .init = init_task_qinq_encap6,
215         .handle = handle_qinq_encap6_untag_bulk,
216         .flag_features = TASK_FEATURE_CLASSIFY,
217         .size = sizeof(struct task_qinq_encap6)
218 };
219
220 __attribute__((constructor)) static void reg_task_qinq_encap6(void)
221 {
222         reg_task(&task_init_qinq_encap6);
223         reg_task(&task_init_qinq_encap6_untag);
224 }