Allow latency thresholds for TST009 testing
[samplevnf.git] / VNFs / DPPD-PROX / handle_untag.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_ip.h>
18
19 #include "log.h"
20 #include "tx_pkt.h"
21 #include "task_base.h"
22 #include "task_init.h"
23 #include "mpls.h"
24 #include "defines.h"
25 #include "prefetch.h"
26 #include "qinq.h"
27 #include "prox_assert.h"
28 #include "etypes.h"
29
30 struct task_untag {
31         struct task_base base;
32         uint16_t         etype;
33 };
34
35 static void init_task_untag(struct task_base *tbase, __attribute__((unused)) struct task_args *targ)
36 {
37         struct task_untag *task = (struct task_untag *)tbase;
38         task->etype = targ->etype;
39 }
40
41 static inline uint8_t handle_untag(struct task_untag *task, struct rte_mbuf *mbuf);
42
43 static int handle_untag_bulk(struct task_base *tbase, struct rte_mbuf **mbufs, uint16_t n_pkts)
44 {
45         struct task_untag *task = (struct task_untag *)tbase;
46         uint8_t out[MAX_PKT_BURST];
47         uint16_t j;
48
49         prefetch_first(mbufs, n_pkts);
50
51         for (j = 0; j + PREFETCH_OFFSET < n_pkts; ++j) {
52 #ifdef PROX_PREFETCH_OFFSET
53                 PREFETCH0(mbufs[j + PREFETCH_OFFSET]);
54                 PREFETCH0(rte_pktmbuf_mtod(mbufs[j + PREFETCH_OFFSET - 1], void *));
55 #endif
56                 out[j] = handle_untag(task, mbufs[j]);
57         }
58 #ifdef PROX_PREFETCH_OFFSET
59         PREFETCH0(rte_pktmbuf_mtod(mbufs[n_pkts - 1], void *));
60         for (; j < n_pkts; ++j) {
61                 out[j] = handle_untag(task, mbufs[j]);
62         }
63 #endif
64
65         return task->base.tx_pkt(&task->base, mbufs, n_pkts, out);
66 }
67
68 static inline uint8_t untag_mpls(struct rte_mbuf *mbuf, prox_rte_ether_hdr *peth)
69 {
70         prox_rte_ether_hdr *pneweth = (prox_rte_ether_hdr *)rte_pktmbuf_adj(mbuf, 4);
71         const struct mpls_hdr *mpls = (const struct mpls_hdr *)(peth + 1);
72         const prox_rte_ipv4_hdr *pip = (const prox_rte_ipv4_hdr *)(mpls + 1);
73         PROX_ASSERT(pneweth);
74
75         if (mpls->bos == 0) {
76                 // Double MPLS tag
77                 pneweth = (prox_rte_ether_hdr *)rte_pktmbuf_adj(mbuf, 4);
78                 PROX_ASSERT(pneweth);
79         }
80
81         if ((pip->version_ihl >> 4) == 4) {
82                 pneweth->ether_type = ETYPE_IPv4;
83                 return 0;
84         }
85         else if ((pip->version_ihl >> 4) == 6) {
86                 pneweth->ether_type = ETYPE_IPv6;
87                 return 0;
88         }
89
90         plog_warn("Failed Decoding MPLS Packet - neither IPv4 neither IPv6: version %u\n", pip->version_ihl);
91         return OUT_DISCARD;
92 }
93
94 static uint8_t untag_qinq(struct rte_mbuf *mbuf, struct qinq_hdr *qinq)
95 {
96         if ((qinq->cvlan.eth_proto != ETYPE_VLAN)) {
97                 plog_warn("Unexpected proto in QinQ = %#04x\n", qinq->cvlan.eth_proto);
98                 return OUT_DISCARD;
99         }
100
101         rte_pktmbuf_adj(mbuf, sizeof(struct qinq_hdr) - sizeof(prox_rte_ether_hdr));
102         return 0;
103 }
104
105 static inline uint8_t handle_untag(struct task_untag *task, struct rte_mbuf *mbuf)
106 {
107         prox_rte_ether_hdr *peth = rte_pktmbuf_mtod(mbuf, prox_rte_ether_hdr *);
108         const uint16_t etype = peth->ether_type;
109
110         if (etype != task->etype) {
111                 plog_warn("Failed Removing %04x tag: ether_type = %#06x\n", task->etype, peth->ether_type);
112                 return OUT_DISCARD;
113         }
114
115         switch (etype) {
116         case ETYPE_MPLSU:
117                 /* MPLS Decapsulation */
118                 return untag_mpls(mbuf, peth);
119         case ETYPE_LLDP:
120                 return OUT_DISCARD;
121         case ETYPE_IPv6:
122                 return 0;
123         case ETYPE_IPv4:
124                 return 0;
125         case ETYPE_8021ad:
126         case ETYPE_VLAN:
127                 return untag_qinq(mbuf, (struct qinq_hdr *)peth);
128         default:
129                 plog_warn("Failed untagging header: ether_type = %#06x is not supported\n", peth->ether_type);
130                 return OUT_DISCARD;
131         }
132 }
133
134 static struct task_init task_init_untag = {
135         .mode_str = "untag",
136         .init = init_task_untag,
137         .handle = handle_untag_bulk,
138         .size = sizeof(struct task_untag)
139 };
140
141 __attribute__((constructor)) static void reg_task_untag(void)
142 {
143         reg_task(&task_init_untag);
144 }