2 // Copyright (c) 2010-2017 Intel Corporation
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
8 // http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <rte_table_hash.h>
19 #include "handle_qinq_encap6.h"
20 #include "handle_qinq_encap4.h"
21 #include "task_base.h"
25 #include "hash_entry_types.h"
30 #include "hash_utils.h"
32 #include "prox_compat.h"
33 #include "handle_sched.h"
35 struct task_qinq_encap6 {
36 struct task_base base;
39 uint8_t runtime_flags;
40 struct rte_table_hash *cpe_table;
41 struct rte_sched_port *sched_port;
44 static void init_task_qinq_encap6(struct task_base *tbase, struct task_args *targ)
46 struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
48 task->qinq_tag = targ->qinq_tag;
49 task->cpe_table = targ->cpe_table;
50 task->runtime_flags = targ->runtime_flags;
51 if (task->runtime_flags & TASK_CLASSIFY) {
52 int rc = init_port_sched(&task->sched_port, targ);
53 PROX_PANIC(rc, "Did not find any QoS task to transmit to => undefined sched_port parameters\n");
57 /* Encapsulate IPv6 packet in QinQ where the QinQ is derived from the IPv6 address */
58 static inline uint8_t handle_qinq_encap6(struct rte_mbuf *mbuf, struct task_qinq_encap6 *task)
60 struct qinq_hdr *pqinq = (struct qinq_hdr *)rte_pktmbuf_prepend(mbuf, 2 * sizeof(prox_rte_vlan_hdr));
63 prox_rte_ipv6_hdr *pip6 = (prox_rte_ipv6_hdr *)(pqinq + 1);
65 if (pip6->hop_limits) {
69 plog_info("TTL = 0 => Dropping\n");
73 // TODO: optimize to use bulk as intended with the rte_table_library
74 uint64_t pkts_mask = RTE_LEN2MASK(1, uint64_t);
75 uint64_t lookup_hit_mask;
76 struct cpe_data* entries[64]; // TODO: use bulk size
77 prox_rte_table_lookup(task->cpe_table, &mbuf, pkts_mask, &lookup_hit_mask, (void**)entries);
79 if (lookup_hit_mask == 0x1) {
80 /* will also overwrite part of the destination addr */
81 (*(uint64_t *)pqinq) = entries[0]->mac_port_8bytes;
82 pqinq->svlan.eth_proto = task->qinq_tag;
83 pqinq->cvlan.eth_proto = ETYPE_VLAN;
84 pqinq->svlan.vlan_tci = entries[0]->qinq_svlan;
85 pqinq->cvlan.vlan_tci = entries[0]->qinq_cvlan;
86 pqinq->ether_type = ETYPE_IPv6;
88 /* classification can only be done from this point */
89 if (task->runtime_flags & TASK_CLASSIFY) {
90 prox_rte_sched_port_pkt_write(task->sched_port, mbuf, 0, entries[0]->user, 0, 0, 0);
95 plogx_err("Unknown IP " IPv6_BYTES_FMT "\n", IPv6_BYTES(pip6->dst_addr));
100 void init_cpe6_table(struct task_args *targ)
103 sprintf(name, "core_%u_CPEv6Table", targ->lconf->id);
105 uint8_t table_part = targ->nb_slave_threads;
106 if (!rte_is_power_of_2(table_part)) {
107 table_part = rte_align32pow2(table_part) >> 1;
110 uint32_t n_entries = MAX_GRE / table_part;
111 static char hash_name[30];
112 sprintf(hash_name, "cpe6_table_%03d", targ->lconf->id);
113 struct prox_rte_table_params table_hash_params = {
115 .key_size = sizeof(struct ipv6_addr),
117 .n_buckets = n_entries >> 2,
118 .f_hash = (rte_table_hash_op_hash)hash_crc32,
120 .key_offset = HASH_METADATA_OFFSET(0),
124 size_t entry_size = sizeof(struct cpe_data);
125 if (!rte_is_power_of_2(entry_size)) {
126 entry_size = rte_align32pow2(entry_size);
129 struct rte_table_hash* phash = prox_rte_table_create(&table_hash_params, rte_lcore_to_socket_id(targ->lconf->id), entry_size);
130 PROX_PANIC(phash == NULL, "Unable to allocate memory for IPv6 hash table on core %u\n", targ->lconf->id);
132 for (uint8_t task_id = 0; task_id < targ->lconf->n_tasks_all; ++task_id) {
133 enum task_mode smode = targ->lconf->targs[task_id].mode;
134 if (smode == QINQ_DECAP6 || smode == QINQ_ENCAP6) {
135 targ->lconf->targs[task_id].cpe_table = phash;
140 static void early_init(struct task_args *targ)
142 if (!targ->cpe_table) {
143 init_cpe6_table(targ);
147 static int handle_qinq_encap6_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
149 struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
150 uint8_t out[MAX_PKT_BURST];
153 prefetch_first(mbufs, n_pkts);
155 for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
156 #ifdef PROX_PREFETCH_OFFSET
157 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
158 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
160 out[j] = handle_qinq_encap6(mbufs[j], task);
162 #ifdef PROX_PREFETCH_OFFSET
163 PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
164 for (; j < n_pkts; ++j) {
165 out[j] = handle_qinq_encap6(mbufs[j], task);
169 return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
172 static int handle_qinq_encap6_untag_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
174 struct task_qinq_encap6 *task = (struct task_qinq_encap6 *)tbase;
175 uint8_t out[MAX_PKT_BURST];
178 prefetch_first(mbufs, n_pkts);
180 for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
181 #ifdef PROX_PREFETCH_OFFSET
182 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
183 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
185 if (likely(mpls_untag(mbufs[j]))) {
186 out[j] = handle_qinq_encap6(mbufs[j], task);
189 out[j] = OUT_DISCARD;
192 #ifdef PROX_PREFETCH_OFFSET
193 PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
194 for (; j < n_pkts; ++j) {
195 if (likely(mpls_untag(mbufs[j]))) {
196 out[j] = handle_qinq_encap6(mbufs[j], task);
199 out[j] = OUT_DISCARD;
204 return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
207 static struct task_init task_init_qinq_encap6 = {
209 .mode_str = "qinqencapv6",
210 .init = init_task_qinq_encap6,
211 .early_init = early_init,
212 .handle = handle_qinq_encap6_bulk,
213 .flag_features = TASK_FEATURE_CLASSIFY,
214 .size = sizeof(struct task_qinq_encap6)
217 static struct task_init task_init_qinq_encap6_untag = {
219 .mode_str = "qinqencapv6",
220 .sub_mode_str = "unmpls",
221 .early_init = early_init,
222 .init = init_task_qinq_encap6,
223 .handle = handle_qinq_encap6_untag_bulk,
224 .flag_features = TASK_FEATURE_CLASSIFY,
225 .size = sizeof(struct task_qinq_encap6)
228 __attribute__((constructor)) static void reg_task_qinq_encap6(void)
230 reg_task(&task_init_qinq_encap6);
231 reg_task(&task_init_qinq_encap6_untag);