P4C
The P4 Compiler
 
Loading...
Searching...
No Matches
ebpfPipeline.h
1/*
2Copyright 2022-present Orange
3Copyright 2022-present Open Networking Foundation
4
5Licensed under the Apache License, Version 2.0 (the "License");
6you may not use this file except in compliance with the License.
7You may obtain a copy of the License at
8
9 http://www.apache.org/licenses/LICENSE-2.0
10
11Unless required by applicable law or agreed to in writing, software
12distributed under the License is distributed on an "AS IS" BASIS,
13WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14See the License for the specific language governing permissions and
15limitations under the License.
16*/
17#ifndef BACKENDS_EBPF_PSA_EBPFPIPELINE_H_
18#define BACKENDS_EBPF_PSA_EBPFPIPELINE_H_
19
20#include "backends/ebpf/ebpfProgram.h"
21#include "backends/ebpf/target.h"
22#include "ebpfPsaControl.h"
23#include "ebpfPsaDeparser.h"
24
25namespace EBPF {
26
27/*
28 * EBPFPipeline represents a single eBPF program in the TC/XDP hook.
29 */
30class EBPFPipeline : public EBPFProgram {
31 public:
32 // a custom name of eBPF program
33 cstring name;
34 // eBPF section name, which should a concatenation of `classifier/` + a custom name.
35 cstring sectionName;
36 // Variable name storing pointer to eBPF packet descriptor (e.g., __sk_buff).
37 cstring contextVar;
38 // Variable name storing current timestamp retrieved from bpf_ktime_get_ns().
39 cstring timestampVar;
40 // Variable storing ingress interface index.
41 cstring ifindexVar;
42 // Variable storing skb->priority value (TC only).
43 cstring priorityVar;
44 // Variables storing global metadata (packet_path & instance).
45 cstring packetPathVar, pktInstanceVar;
46 // A name of an internal variable storing global metadata.
47 cstring compilerGlobalMetadata;
48 // A variable name storing "1" value. Used to access BPF array map index.
49 cstring oneKey;
50 // A unique mark used to differentiate packets processed by P4/eBPF from others.
51 unsigned packetMark;
52 // A variable to store ifindex after mapping (e.g. due to recirculation)
53 cstring inputPortVar;
54
55 EBPFControlPSA *control;
56 EBPFDeparserPSA *deparser;
57
58 EBPFPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
59 P4::TypeMap *typeMap)
60 : EBPFProgram(options, nullptr, refMap, typeMap, nullptr),
61 name(name),
62 packetMark(0x99),
63 control(nullptr),
64 deparser(nullptr) {
65 sectionName = "classifier/" + name;
66 functionName = name.replace("-", "_") + "_func";
67 errorEnum = "ParserError_t";
68 packetStartVar = cstring("pkt");
69 headerStartVar = cstring("hdr_start");
70 contextVar = cstring("skb");
71 lengthVar = cstring("pkt_len");
72 endLabel = cstring("deparser");
73 timestampVar = cstring("tstamp");
74 ifindexVar = cstring("skb->ifindex");
75 compilerGlobalMetadata = cstring("compiler_meta__");
76 packetPathVar = compilerGlobalMetadata + cstring("->packet_path");
77 pktInstanceVar = compilerGlobalMetadata + cstring("->instance");
78 priorityVar = cstring("skb->priority");
79 oneKey = EBPFModel::reserved("one");
80 inputPortVar = cstring("ebpf_input_port");
81 progTarget = new KernelSamplesTarget(options.emitTraceMessages);
82 }
83
84 /* Check if pipeline does any processing.
85 * Return false if not. */
86 bool isEmpty() const;
87
88 virtual cstring dropReturnCode() {
89 if (sectionName.startsWith("xdp")) {
90 return "XDP_DROP";
91 }
92
93 // TC is the default hookpoint
94 return "TC_ACT_SHOT";
95 }
96 virtual cstring forwardReturnCode() {
97 if (sectionName.startsWith("xdp")) {
98 return "XDP_PASS";
99 }
100
101 // TC is the default hookpoint
102 return "TC_ACT_OK";
103 }
104
105 virtual void emit(CodeBuilder *builder) = 0;
106 virtual void emitTrafficManager(CodeBuilder *builder) = 0;
107 virtual void emitPSAControlInputMetadata(CodeBuilder *builder) = 0;
108 virtual void emitPSAControlOutputMetadata(CodeBuilder *builder) = 0;
109
110 /* Generates a pointer to struct Headers_t and puts it on the BPF program's stack. */
111 void emitLocalHeaderInstancesAsPointers(CodeBuilder *builder);
112 /* Generates a pointer to struct hdr_md. The pointer is used to access data from per-CPU map. */
113 void emitCPUMAPHeadersInitializers(CodeBuilder *builder);
114 /* Generates an instance of struct Headers_t,
115 * allocated in the per-CPU map. */
116 void emitHeaderInstances(CodeBuilder *builder) override;
117 /* Generates a set of helper variables that are used during packet processing. */
118 void emitLocalVariables(CodeBuilder *builder) override;
119
120 /* Generates and instance of user metadata for a pipeline,
121 * allocated in the per-CPU map. */
122 void emitUserMetadataInstance(CodeBuilder *builder);
123
124 virtual void emitCPUMAPInitializers(CodeBuilder *builder);
125 virtual void emitCPUMAPLookup(CodeBuilder *builder);
126 /* Generates a pointer to skb->cb and maps it to
127 * psa_global_metadata to access global metadata shared between pipelines. */
128 virtual void emitGlobalMetadataInitializer(CodeBuilder *builder);
129 virtual void emitPacketLength(CodeBuilder *builder);
130 virtual void emitTimestamp(CodeBuilder *builder);
131 void emitInputPortMapping(CodeBuilder *builder);
132
133 void emitHeadersFromCPUMAP(CodeBuilder *builder);
134 void emitMetadataFromCPUMAP(CodeBuilder *builder);
135
136 bool hasAnyMeter() const {
137 auto directMeter = std::find_if(control->tables.begin(), control->tables.end(),
138 [](std::pair<const cstring, EBPFTable *> elem) {
139 return !elem.second->to<EBPFTablePSA>()->meters.empty();
140 });
141 bool anyDirectMeter = directMeter != control->tables.end();
142 return anyDirectMeter || (!control->meters.empty());
143 }
144 /*
145 * Returns whether the compiler should generate
146 * timestamp retrieved by bpf_ktime_get_ns().
147 *
148 * This allows to avoid overhead introduced by bpf_ktime_get_ns(),
149 * if the timestamp field is not used within a pipeline.
150 */
151 bool shouldEmitTimestamp() const { return hasAnyMeter() || control->timestampIsUsed; }
152
153 DECLARE_TYPEINFO(EBPFPipeline, EBPFProgram);
154};
155
156/*
157 * EBPFIngressPipeline represents a hook-independent EBPF-based ingress pipeline.
158 * It includes common definitions for TC and XDP.
159 */
161 public:
162 unsigned int maxResubmitDepth;
163 // actUnspecCode stores the "undefined action" value.
164 // It's returned from eBPF program is PSA-eBPF doesn't make any forwarding/drop decision.
165 int actUnspecCode;
166
167 EBPFIngressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
168 P4::TypeMap *typeMap)
169 : EBPFPipeline(name, options, refMap, typeMap) {
170 // FIXME: hardcoded
171 maxResubmitDepth = 4;
172 // actUnspecCode should not collide with TC/XDP return codes,
173 // but it's safe to use the same value as TC_ACT_UNSPEC.
174 actUnspecCode = -1;
175 }
176
177 void emitSharedMetadataInitializer(CodeBuilder *builder);
178
179 void emit(CodeBuilder *builder) override;
180 void emitPSAControlInputMetadata(CodeBuilder *builder) override;
181 void emitPSAControlOutputMetadata(CodeBuilder *builder) override;
182
183 DECLARE_TYPEINFO(EBPFIngressPipeline, EBPFPipeline);
184};
185
186/*
187 * EBPFEgressPipeline represents a hook-independent EBPF-based egress pipeline.
188 * It includes common definitions for TC and XDP.
189 */
191 public:
192 EBPFEgressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
193 P4::TypeMap *typeMap)
194 : EBPFPipeline(name, options, refMap, typeMap) {}
195
196 void emit(CodeBuilder *builder) override;
197 void emitPSAControlInputMetadata(CodeBuilder *builder) override;
198 void emitPSAControlOutputMetadata(CodeBuilder *builder) override;
199 void emitCPUMAPLookup(CodeBuilder *builder) override;
200
201 virtual void emitCheckPacketMarkMetadata(CodeBuilder *builder) = 0;
202
203 DECLARE_TYPEINFO(EBPFEgressPipeline, EBPFPipeline);
204};
205
207 public:
208 TCIngressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
209 P4::TypeMap *typeMap)
210 : EBPFIngressPipeline(name, options, refMap, typeMap) {}
211
212 void emitGlobalMetadataInitializer(CodeBuilder *builder) override;
213 void emitTrafficManager(CodeBuilder *builder) override;
214
215 private:
216 void emitTCWorkaroundUsingMeta(CodeBuilder *builder);
217 void emitTCWorkaroundUsingHead(CodeBuilder *builder);
218 void emitTCWorkaroundUsingCPUMAP(CodeBuilder *builder);
219
220 DECLARE_TYPEINFO(TCIngressPipeline, EBPFIngressPipeline);
221};
222
224 public:
225 TCEgressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
226 P4::TypeMap *typeMap)
227 : EBPFEgressPipeline(name, options, refMap, typeMap) {}
228
229 void emitTrafficManager(CodeBuilder *builder) override;
230 void emitCheckPacketMarkMetadata(CodeBuilder *builder) override;
231
232 DECLARE_TYPEINFO(TCEgressPipeline, EBPFEgressPipeline);
233};
234
236 public:
237 XDPIngressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
238 P4::TypeMap *typeMap)
239 : EBPFIngressPipeline(name, options, refMap, typeMap) {
240 sectionName = "xdp_ingress/" + name;
241 ifindexVar = cstring("skb->ingress_ifindex");
242 packetPathVar = cstring(compilerGlobalMetadata + "->packet_path");
243 progTarget = new XdpTarget(options.emitTraceMessages);
244 }
245
246 void emitGlobalMetadataInitializer(CodeBuilder *builder) override;
247 void emitTrafficManager(CodeBuilder *builder) override;
248
249 DECLARE_TYPEINFO(XDPIngressPipeline, EBPFIngressPipeline);
250};
251
253 public:
254 XDPEgressPipeline(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
255 P4::TypeMap *typeMap)
256 : EBPFEgressPipeline(name, options, refMap, typeMap) {
257 sectionName = "xdp_devmap/" + name;
258 ifindexVar = cstring("skb->egress_ifindex");
259 // we do not support packet path, instance & priority in the XDP egress.
260 packetPathVar = cstring("0");
261 pktInstanceVar = cstring("0");
262 priorityVar = cstring("0");
263 progTarget = new XdpTarget(options.emitTraceMessages);
264 }
265
266 void emitGlobalMetadataInitializer(CodeBuilder *builder) override;
267 void emitTrafficManager(CodeBuilder *builder) override;
268 void emitCheckPacketMarkMetadata(CodeBuilder *builder) override;
269
270 DECLARE_TYPEINFO(XDPEgressPipeline, EBPFEgressPipeline);
271};
272
274 public:
275 TCTrafficManagerForXDP(cstring name, const EbpfOptions &options, P4::ReferenceMap *refMap,
276 P4::TypeMap *typeMap)
277 : TCIngressPipeline(name, options, refMap, typeMap) {}
278
279 void emitGlobalMetadataInitializer(CodeBuilder *builder) override;
280 void emit(CodeBuilder *builder) override;
281
282 private:
283 void emitReadXDP2TCMetadataFromHead(CodeBuilder *builder);
284 void emitReadXDP2TCMetadataFromCPUMAP(CodeBuilder *builder);
285
286 DECLARE_TYPEINFO(TCTrafficManagerForXDP, TCIngressPipeline);
287};
288
289} // namespace EBPF
290
291#endif /* BACKENDS_EBPF_PSA_EBPFPIPELINE_H_ */
Definition codeGen.h:33
Definition ebpfPsaControl.h:58
Definition ebpfPsaDeparser.h:39
Definition ebpfPipeline.h:190
Definition ebpfPipeline.h:160
Definition ebpfPipeline.h:30
Definition ebpfProgram.h:39
Definition target.h:126
Definition ebpfPipeline.h:223
Definition ebpfPipeline.h:206
Definition ebpfPipeline.h:273
Definition ebpfPipeline.h:252
Definition ebpfPipeline.h:235
Definition target.h:200
Definition ebpfOptions.h:26
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeMap.h:42
Definition cstring.h:72