Status: Draft (2026-10-17), partially measured. Baseline version: cilium/cilium v1.20.1 (commit 7d68cfb394f2). Since a small cluster is running this exact version (agents, operator-generic, and hubble-relay v1.20.1, alongside the cilium-envoy 1.37 family), measurements were performed strictly as read-only on that cluster on 2026-10-17 (running
cilium-dbg·bpftool·hubble observeread commands, reading ConfigMaps and policy counts, and reading relay logs on a single agent pod). Connection results for DNS patterns cite records (PR draft) measured between 2026-10-16 and 17 while preparing contributions. Writing convention: measured data is the baseline; unmeasured items are marked as "Unmeasured", and unverified items are marked as "Unverified".
Table of Contents
- 1. One-Sentence Summary
- 2. Architecture Diagram
- 3. Code Map
- 4. Tracing Core Paths
- 5. Connection to User Contributions
- 6. Measurements
- 7. Where to Start Reading
- 8. Good Places for First Contributions
- 9. Limitations
- References
1. One-Sentence Summary
To summarize Cilium in one sentence: "An office (agent) on each node updates rulebooks (BPF maps), and checkpoints (BPF programs) across the kernel decide on passing, dropping, or address translation by looking solely at the rulebooks." Checkpoints do not call the office. Because going up to user space for every single packet is slow, everything needed for decisions is written into maps in advance. Therefore, the first question to ask when reading Cilium code is always: "Who writes this information to which map, and which hook reads it?"
| Component | Role | Where It Runs |
|---|---|---|
| cilium-agent | Receives Kubernetes state, calculates policies, services, and identities, and writes them to BPF maps. Compiles and loads BPF programs. The DNS proxy and Hubble observer also reside within this process. | Per node (DaemonSet) |
BPF programs (bpf/) |
attached to pod veth devices, host devices, tunnel devices, and socket cgroups to process packets and connect() ) |
Inside the kernel |
| cilium-operator | CRD registration, IPAM (depending on mode), cleaning up remaining identities and CiliumEndpoints, LB-IPAM | One per cluster (leader election) |
| cilium-envoy | Proxy for L7 policies such as HTTP, Ingress, and Gateway. Receives configuration from the agent via xDS. | Per node (separate DaemonSet) |
| Hubble | An observer inside the agent interprets events generated by BPF into flows and stores them in a ring buffer, while relay aggregates flows from all nodes. | Observer inside the agent; relay is one per cluster |
2. Architecture Diagram
- The two boxes above are singular per cluster. The agent watches the API server directly . Since it does not go through the operator, the dataplane of already running nodes remains unaffected even if the operator is temporarily stopped.
- The large box in the middle represents a single node. The six chips inside the agent box are the components we will follow in this post, and the cylinders at the bottom are the BPF maps used by those components.
- The table at the very bottom shows "Hook Location → Attached Program". The filename represents the attachment location.
bpf_lxc.cis on the pod side,bpf_host.cis on the host side,bpf_overlay.cis the tunnel device, andbpf_sock.crepresents socket system calls. The dotted boxes (XDP) are disabled in the small cluster. - The dashed arrow on the left illustrates the path where events emitted by BPF to
cilium_eventsperf maps ascend to the Hubble observer inside the agent (4.4).
3. Code Map
The repository is large, but the starting places are clearly defined.
| Path | Description | Files to Read First |
|---|---|---|
daemon/ |
Agent entrypoint and cell bundling | daemon/cmd/cells.go |
bpf/ |
C programs loaded into the kernel. Entry file bpf_*.c and common headers bpf/lib/ |
bpf/bpf_lxc.c |
pkg/datapath/ |
BPF compilation and loading (loader), device/route/sysctl tuning, map definitions |
pkg/datapath/loader/endpoint.go |
pkg/loadbalancer/ |
Service load balancing control plane redesigned since v1.18 (StateDB tables + reconciler) | pkg/loadbalancer/README.md |
pkg/policy/ |
Policy repository, selector cache, per-endpoint policy calculation | pkg/policy/selectorcache.go |
pkg/fqdn/ |
DNS proxy, name-to-IP cache, matchPattern regex conversion |
pkg/fqdn/matchpattern/matchpattern.go |
pkg/hubble/, hubble-relay/ |
Flow interpretation, ring buffer, gRPC server, and relay | pkg/hubble/observer/local_observer.go |
operator/ |
Operator entrypoint and cells | operator/cmd/root.go |
Both the agent and the operator are assembled using a dependency injection framework called hive . Each feature is a "cell", and cells declare only what they provide and what they require. Agent main is daemon/main.go:11 in
hive.New(cmd.Agent) is a single line, and that Agent is divided into daemon/cmd/cells.go:103
three bundles in Infrastructure·ControlPlane·datapath.Cell . ControlPlane(cells.go:194)
The comment explicitly states the reason for this division. The control plane is "pure business logic," so the goal is to allow integration tests to run without kernel privileges. The actual work of handling BPF was pushed into the pkg/datapath/cells.go:52 module of datapath .
The measured module tree of cilium-dbg status --verbose was also split into controlplane / datapath / infra three parts (Section 6).
4. Following the Core Path
4.1 How the Agent Compiles and Loads BPF
Cilium does not pre-bake BPF objects into the image; it compiles them with clang on the node(the agent image includes clang 19.1.7, as verified). Since kernel features and configurations (such as tunneling, masquerading, and IPv6) differ per node, unused features must be #ifdef completely removed via preprocessor definitions so that the program passes the verifier and does not hit the instruction limit.
- -based datapath.
pkg/datapath/orchestrator/orchestrator.go:167reconcilercallsReinitializewhenever node settings change, andpkg/datapath/loader/base.go:298Reinitializecompilesbpf_overlay.cfor tunnel devices, XDP, and—if socket LB is enabled—bpf_sock.c, attaching them to the (base.go:406) cgroup (pkg/socketlb/socketlb.go:83Enable). - per endpoint (pod).
pkg/datapath/loader/endpoint.go:83ReloadDatapathfirst callscache.go:176fetchOrCompile. This is the core of the design. It creates a hash using the endpoint configuration minus the values that differ per pod (such as endpoint ID, IP, and ifindex),and if an object with the same hash already exists, it reuses it via copy instead of recompiling. The actual compilation is performed bycompile.go:160compile, which runs clang. - Injecting Values and Attaching.
endpoint.go:195reloadEndpointloads the template while overwriting pod-specific values as constants(Constants: endpointConfiguration(...), inserts the policy program into the tail call map first, and then attachescil_from_containerto the ingress of the veth. The sequence is explained in the comments because opening the ingress first allows packets to enter a half-prepared program. The pod-side egress program (cil_to_container) is attached only whenRequireEgressProg()is true.
Measurements show why this matters. Thirteen endpoints on a single node shared a single template hash, and there were only two templates: bpf_lxc.o(approx. 1.0MB) and
bpf_host.o(approx. 1.4MB). Compilation happens once, and subsequent loads only swap constants, removing clang from pod startup latency.
4.2 Replacing kube-proxy: From Service to connect() Backends
kube-proxy translates Services into iptables (or IPVS) rules. Cilium places the same information into BPF hash maps and, whenever possible, changes the socket destination address before packets are even created . In v1.18, this control plane was rewritten to be based on StateDB, and its architecture matches the diagram in
pkg/loadbalancer/README.md .
- Reflection.
pkg/loadbalancer/reflectors/k8s.go:208runServiceEndpointsReflectoraggregates Service and EndpointSlice changes briefly and writes them in a single transaction (to avoid modifying maps thousands of times during massive rollouts). - Writing to Tables.
pkg/loadbalancer/writer/writer.go:326UpsertServiceAndFrontendsand others reconcile references across the three tables: service, frontend, and backend. Even with multiple sources, updates flow exclusively through this Writer. - Matching via Maps.
pkg/loadbalancer/reconciler/bpf_reconciler.go:725Updatewatches the frontend table and writes to the map atupdateFrontend(line 842) . In mapcilium_lb4_services_v2(bpf/lib/lb.h:284, whose key is(주소, 포트, 프로토콜, 슬롯), slot 0 acts as the "head" (backend count and flags), and slots 1..n contain backend IDs. Retries are handled by the reconciler so that data sources do not need to worry about map errors. - Resolving at the Socket.
bpf/bpf_sock.c:467cil_sock4_connectcallsconnect4in the cgroup__sock4_xlate_fwdhook (line 298) , which finds the head usinglb4_lookup_serviceand selects a slot viasock_select_slot() % count + 1to rewrite the socket address to the backend. The application believes it connected to the ClusterIP, but the kernel socket is bound to the backend from the start, eliminating the need for per-packet NAT.
However, there is a catch in the fourth step.
if (is_defined(ENABLE_SOCKET_LB_HOST_ONLY) && !in_hostns)
return -ENXIO;
if (!udp_only && !sock_proto_enabled(protocol))
return -ENOTSUP;
/* In case a direct match fails, we try to look-up surrogate
* service entries via wildcarded lookup for NodePort and
* HostPort services.
*/
svc = lb4_lookup_service(&key, true);
if (!svc)
svc = sock4_wildcard_lookup_full(&key, in_hostns);
if (!svc)
return -ENXIO;
Source: cilium v1.20.1 bpf/bpf_sock.c lines 322–335, GPL-2.0-only OR BSD-2-Clause
socketLB.hostNamespaceOnly When enabled, sockets in the pod namespace simply return here. Who handles service address translation then?
bpf_lxc.c decides this at compile time.
#if !defined(ENABLE_SOCKET_LB_FULL) || \
defined(ENABLE_SOCKET_LB_HOST_ONLY) || \
defined(ENABLE_L7_LB) || \
defined(ENABLE_SCTP) || \
defined(ENABLE_CLUSTER_AWARE_ADDRESSING)
# define ENABLE_PER_PACKET_LB 1
#endif
Source: cilium v1.20.1 bpf/bpf_lxc.c lines 90–96, GPL-2.0-only OR BSD-2-Clause
If there is even a single case where resolution cannot happen entirely at the socket, per-packet LB (__per_packet_lb_svc_xlate_4, line 152)is inserted into the pod veth's tc program. Official documentation explains that this bypass is intended for cases where the original ClusterIP is required (such as Istio sidecars) or for pods where socket LB is ineffective, such as KubeVirt, Kata, or gVisor (kubeproxy-free documentation "Socket LoadBalancer Bypass in Pod Namespace"). The measured small cluster was precisely in this mode (Socket LB Coverage: Hostns-only). Since the TT Lab cluster runs KubeVirt VMs, this choice is justified (KubeVirt Practice VM Series). Consequently, connections from pods to services are resolved within cil_from_container , and the socket reverse-translation map (cilium_lb4_reverse_sk) contained only 13 host namespace sockets. Assuming "kube-proxy replacement = socket LB" across the board is a common misconception.
4.3 How toFQDNs Policies Route Through the DNS Proxy to Allow Specific IPs
BPF only sees IPs and ports. However, users want to write policies using names like *.docker.com . Cilium's answer is It intercepts the DNS response, learns the name-to-IP mapping, and attaches the identity derived from the name to the learned IP.The name does not go down to BPF; BPF simply asks, as it always does, "Is this identity allowed?"
- Selector registration. When the policy has
toFQDNs,pkg/fqdn/namemanager/manager.go:140RegisterFQDNSelectorreceives the selector, and if there is already a matching name in the cache, it immediately exposes the IP. The regular expression for the selector ispkg/policy/api/fqdn.go:115ToRegexcreated via matchpattern by - Query interception. Because of the
rules.dnsin the same policy (port 53),bpf_lxcredirects that pod's DNS packets to the node's DNS proxy.pkg/fqdn/dnsproxy/proxy.go:895ServeDNSusesCheckAllowed(line 763) to inspect the query name. That regex isGeneratePattern(line 1439) built by combining the patterns ofrules.dnswith|. If it does not match, a refusal response is returned (small cluster settings arerefused). - Response → Name cache. If allowed, it is sent upward, and before returning the response to the client upon receiving it is called
NotifyOnDNSMsg. This goes throughpkg/fqdn/messagehandler/message_handler.go:277UpdateOnDNSMsgtonamemanager/manager.go:214UpdateGenerateDNS. - Name matching.
manager.go:422deriveLabelsForNamematches this response name against the regular expressions of all FQDN selectors, and for each matching selector, collects thefqdn:<패턴>labels. - Identity to IP.
manager.go:315updateMetadatauploads those labels to the ipcache for each IP in the response, and ipcache assigns an identity matching the label set. The new identity enterspkg/policy/selectorcache.go:768UpdateIdentitiesinto the selector cache, and an allowance entry is created in the policy map of endpoints using that selector. - Wait and return.
UpdateGenerateDNSreturns a channel that waits until ipcache propagates that change down to the map(WaitForRevision). The handler waits only for (tofqdns-proxy-response-max-delaysmall cluster 100ms) and writes the response to the pod. This order ensures that the policy map is already open as soon as the pod connects upon receiving the response.
It is important to note here that matchpattern is used twice (③ and ⑤ in the figure). The translation rules are short.
func escapeRegexpCharacters(pattern string) string {
// Convert '.' in the match pattern as literal '.' for regex pattern.
pattern = strings.ReplaceAll(pattern, ".", "[.]")
// '**.' in match pattern prefix is a subdomain wildcard specifier which matches one ore more
// entire labels.
pattern = subdomainWildcardSpecifierPrefix.ReplaceAllString(pattern, dnsWildcardREGroup)
// Base case: * becomes .*, but only for DNS valid characters
// `*` wildcard matches all DNS characters within the subdomain boundary(doesn't include '.' literal)
pattern = wildcardSpecifier.ReplaceAllString(pattern, allowedDNSCharsREGroup+"*")
return pattern
}
Source: cilium v1.20.1 pkg/fqdn/matchpattern/matchpattern.go lines 131–144, Apache-2.0
* is changed to [-a-zA-Z0-9_]*(line 17), and
cannot cross dots. Receiving multiple segments is only done by the very first **. (in line 37, ^[*]{2,}\[\.\], in line 23 dnsWildcardREGroup), and the middle
** simply turns into * on the last line. Normalization appending a dot at the end is handled by Sanitize(line 87)
.
Measurement case. This is a record measured in a small cluster while preparing a contribution (2026-10-16~17, PR draft). The policy for the image registry is
toFQDNs: matchPattern: "*.docker.com" and DNS is * accessed each of the three names twice from the opened pod.
| Name | DNS Resolution | Access | Reason |
|---|---|---|---|
hub.docker.com |
Succeeded | Connected (HTTP 200) | One space → *.docker.com matches |
production.cloudflare.docker.com |
Succeeded | Timed out (curl 28) | Two spaces → * cannot cross the dot |
docker.com |
Succeeded | Timed out | *. Must have one space in front |
Since the second line is the CDN name that downloads Docker Hub's image layers, the policy seems correct, but it results in a symptom where only image pulling fails. In the same logs, the result of directly running main's matchpattern in Go(Validate(Sanitize(p))) was also identical to the table(**.docker.com matches the second line), and the result of converting the conversion rules to Python and running them again while writing this post was also the same (table below the figure). Since all DNS queries were resolved, the blockage is at ⑤, not ③. How the same characteristic caused an issue in the practice pod's DNS egress policy is described separately in Blocking Leaks via DNS .
This post only covers which line of code produces that characteristic.
4.4 Hubble: From perf ring buffer to relay
- BPF generates events. When a packet is forwarded, dropped, or evaluated by a policy,
bpf/lib/trace.h:210_send_trace_notifyand others write short records usingcilium_events(bpf/lib/events.h:13,PERF_EVENT_ARRAY). Writing every packet is expensive, so it is reduced usingMONITOR_AGGREGATION. The measured endpoint'sep_config.hwasMONITOR_AGGREGATION 3(summarizing active connection tracking, ConfigMap'smonitor-aggregation: medium). - The agent reads them.
pkg/monitor/agent/agent.go:324handleEventsopens the perf reader, and distributes records to consumers pernotifyPerfEventLocked(line 428) . Hubble is one of those consumers(pkg/hubble/monitor/consumer.go:73). - interpreting into the ring buffer.
pkg/hubble/observer/local_observer.go:116Start's loop turns events intoDecodeflows, passes them through metrics hooks, and puts them into a fixed-size ring viacontainer/ring.go:168Ring.Write. Since the size is a power of 2 minus 1 (default 4095), the index is obtained using a mask instead of division.GetFlows(line 260) only reads this ring. - Relay collects them. relay connects to each agent's Hubble server (:4244, TLS) in advance(
pkg/hubble/relay/pool/manager.go:51). When a request arrives,pkg/hubble/relay/observer/server.go:62GetFlowssends the same request to all peers(observer.go:37), and re-sorts the returned flows chronologically(sortFlows, line 67) before outputting them.
The design philosophy is "Do not store." Flows exist only in the node memory ring, and the relay does not retain them either. The measured node had its ring full at 4095/4095 with 58.5 inflows per second, so the past remembered by a single node is about 70 seconds. To retain data longer, use separate metrics or exporters.
5. Connection to User Contributions
The author has prepared changes to correct the characteristics of 4.3 in the documentation (Section 5 of the original ledger, "Prepared Only"). It has not been published yet. Because Cilium has a policy of not accepting communications (such as PR bodies) largely written by AI, the author must write the main text directly. Therefore, even here, we only write up to "preparation completed."
| Document location (v1.20.1) | Current content | Code basis |
|---|---|---|
Documentation/security/policy/layer7.rst:159 |
L7 DNS's matchPattern description has **. missing |
GeneratePattern also ToUnAnchoredRegexp → same escapeRegexpCharacters |
layer7.rst:166, :227 |
An example matching only one level is called "any subdomains" | * → [-a-zA-Z0-9_]*(line 141) |
layer3.rst:548 |
**. description exists, but "from the beginning only" is missing |
Line 37 regex is ^ fixed to , test's test.**.cilium.io. case |
The basis is the actual measurement table in 4.3 and the Go reproduction result. The draft states that it was confirmed during preparation that three document files and matchpattern.go are identical between v1.20.1 and main.
6. Actual Measurements
2026-10-17, sent read commands only to the agent pod on one control plane node in a small cluster (8 nodes, no kube-proxy DaemonSet). Raw data is stored separately; the values below exclude names and addresses.
| Command | Observed |
|---|---|
cilium-dbg status |
KubeProxyReplacement: True, Routing: Network: Tunnel [vxlan] Host: BPF, Attach Mode: TCX, Device Mode: veth, Masquerading: BPF, Host firewall: Enabled, controllers 90/90, modules 125 OK, cluster health 8/8 |
cilium-dbg status --verbose |
Socket LB: Enabled, Socket LB Coverage: Hostns-only, Backend Selection: Random, XDP Acceleration: Disabled, IPAM allocated 15 out of /24 per node |
cilium-dbg service list |
211 frontends (ClusterIP 171, NodePort 20, LoadBalancer 20) |
cilium-dbg bpf lb list, map list |
cilium_lb4_services_v2 573 slots = head slots 358 + backend slots 215. 127 of the head slots are port 0/ANY wildcard slots (detailed usage unconfirmed). Backend map 163, reverse map 231, socket reverse map 13 |
bpftool net show |
all 13 lxc devices tcx/ingress cil_from_container only, no egress. Physical NIC cil_from/to_netdev, cilium_host·cilium_net cil_to_host·cil_from_host, cilium_vxlan cil_from/to_overlay, XDP empty |
bpftool prog show |
231 Cilium programs (tc 218, cgroup sock_addr 8, cgroup sock 3, socket close tracing 2). On the tc side, roughly 3 entry points + 10 tail calls per endpoint |
bpftool cgroup tree |
in cgroup root cil_sock4_connect·sendmsg4·recvmsg4·getpeername4·post_bind4·sock_release 11 items including |
status directory ls |
2 templates (bpf_lxc.o 1,086,040 bytes, bpf_host.o 1,452,768 bytes). Hashes of template.txt for all 13 endpoints are identical |
hubble observe --last 500 |
500 items worth 10.5 seconds, FORWARDED 489 · DROPPED 11 (all UNSUPPORTED_L3_PROTOCOL). Ring 4095/4095, 58.5 flows/sec |
cilium-dbg fqdn cache list, fqdn names |
This node is empty (FQDN selectors 0) — there were no pods with DNS rules bound to this node |
| Policy count (cluster-wide) | Out of 22 CNPs, rules.dns with 5, toFQDNs with 2 |
| relay logs | to 8 peers :4244, connected via TLS |
There are three things to read.
- Socket LB is only half enabled. This is the
ENABLE_SOCKET_LB_HOST_ONLYpath seen in 4.2. It is also visible in the number of programs. Each endpoint hastail_nodeport_rev_dnat_ipv4·tail_no_service_ipv4similar tc-side LB tail calls attached, and the socket reverse map has only 13 slots. - There is no pod-side egress hook. to the pod Incoming packets are not handed over from the egress of veth, but directly after the host-side program invokes a policy tail call
(
cil_lxc_policy). This is the case where condition 4.1 inRequireEgressProg()is false. This differs from the common diagram depicting "two programs per pod". - No FQDNs were observed on this node. Since only one agent was read, the cache of the node with pods subject to DNS rules is unmeasured.
7. Where to Read From
daemon/cmd/cells.go:103— Browsing the cell list to map what the agent contains. The comments are helpful.pkg/loadbalancer/README.mdandbpf_reconciler.go:842— The shortest place to learn Cilium's new control plane syntax of "table → reconciler → map".bpf/bpf_sock.c:298— The side that reads maps. Let's see how the slot used in #2 is read.pkg/datapath/loader/endpoint.go:195— Template, constant, and tcx attachment order.pkg/fqdn/dnsproxy/proxy.go:895tonamemanager/manager.go:214— Where the userspace proxy and BPF policies meet.bpf/bpf_lxc.c:1780cil_from_container— Read last. There are many tail calls and#ifdef, so you need to understand the first five to avoid getting lost.
8. Good First Issues
These are actual issues encountered while reading the source code (not published, and it has not been verified whether they remain as-is in main).
pkg/loadbalancer/README.md:33Filename without . Although the Kubernetes data source is said to be inreflector.go, that file does not exist in v1.20.1 and the actual implementation isreflectors/k8s.go(the list on line 61 of the same README correctly points to thereflectorsdirectory). This is a good candidate for a one-line documentation fix.bpf/bpf_lxc.c:88Typo in comments. In 「enable per-packet LB is SCTP is enabled」, 「is」 should be 「if」. This is a line where readers pause, as it sits right above the condition cited in 4.2.pkg/fqdn/matchpattern/matchpattern.go:19·:135「one ore more」 in . Two typos. Also, the documentation comment inToAnchoredRegexp(lines 95–99) explains only*and does not mention**.. Since this is the same topic as the documentation change in Section 5, it is good to handle them together.- Explanation of the wildcard header cell. One-third of the measured header cells were port 0/ANY cells, and their usage could not be found except for a single-line
bpf-lb-enable-wildcard-entriesoption comment.bpf lb listThis is a documentation candidate explaining/ANY(whether prior documentation exists has not been verified). - Official guide. If you are a beginner, look at the contributing guide
and start with the
good-first-issuelabel it points to. AI Policy: Cilium does not accept PR bodies and comments heavily generated by AI, so communications must be written yourself.
9. Limitations
- What was not covered: ClusterMesh, BGP control plane, WireGuard/IPsec encryption, Gateway API/Ingress Envoy configuration paths (
pkg/ciliumenvoyconfig), egress gateway, Maglev, XDP acceleration, IPv6, identity allocation details, and operator IPAM allocator (included via build tagipam_provider_*— small clusters do not useipam: kubernetes). - Unmeasured: FQDN cache and selectors on nodes with pods subject to DNS rules, cases where responses are sent earlier by bypassing
tofqdns-proxy-response-max-delay, BPF compilation time (templates were created about 6 weeks prior to agent startup and could not be observed this time), and endpoint recovery upon node restart. - The connection table in 4.3 was not remeasured this time (2026-10-17) but recorded during contribution preparation, due to this measurement's rule of not spawning new pods.
- Envoy only documents xDS relationships. L7 policy paths were unmeasured (
Proxy Statusshowed 「0 redirects active」).
A word from TT. Cilium's checkpoint doesn't pick up the phone. It only looks at the rule sheet it received in advance. So if something is weird, instead of the checkpoint, go find who wrote that sheet. And also, remember that
*is a coward who cannot cross even a single dot.
Note
All materials were accessed on 2026-10-17. The source is the cilium/cilium v1.20.1 tag (commit 7d68cfb394f2).
- Agent Cell: https://github.com/cilium/cilium/blob/v1.20.1/daemon/cmd/cells.go, https://github.com/cilium/cilium/blob/v1.20.1/pkg/datapath/cells.go
- BPF Loading: https://github.com/cilium/cilium/tree/v1.20.1/pkg/datapath/loader, https://github.com/cilium/cilium/blob/v1.20.1/pkg/datapath/orchestrator/orchestrator.go
- BPF Program: https://github.com/cilium/cilium/tree/v1.20.1/bpf (
bpf_lxc.c,bpf_host.c,bpf_overlay.c,bpf_sock.c,bpf_xdp.c,lib/lb.h,lib/trace.h,lib/events.h) - Load Balancing Control Plane: https://github.com/cilium/cilium/tree/v1.20.1/pkg/loadbalancer
- FQDN: https://github.com/cilium/cilium/tree/v1.20.1/pkg/fqdn, https://github.com/cilium/cilium/blob/v1.20.1/pkg/policy/api/fqdn.go, https://github.com/cilium/cilium/blob/v1.20.1/pkg/policy/selectorcache.go
- Hubble: https://github.com/cilium/cilium/tree/v1.20.1/pkg/hubble, https://github.com/cilium/cilium/tree/v1.20.1/pkg/monitor/agent, https://github.com/cilium/cilium/tree/v1.20.1/hubble-relay
- operator: https://github.com/cilium/cilium/blob/v1.20.1/operator/cmd/root.go, https://github.com/cilium/cilium/tree/v1.20.1/operator/pkg/ipam
- kube-proxy replacement documentation (socket LB bypass): https://github.com/cilium/cilium/blob/v1.20.1/Documentation/network/kubernetes/kubeproxy-free.rst
- DNS policy documentation: https://github.com/cilium/cilium/blob/v1.20.1/Documentation/security/policy/layer3.rst, https://github.com/cilium/cilium/blob/v1.20.1/Documentation/security/policy/layer7.rst
- Contributing guide: https://github.com/cilium/cilium/blob/v1.20.1/Documentation/contributing/development/contributing_guide.rst
- Other parts in the same series: Reading MetalLB(Who advertises the address of a LoadBalancer service)
Cited code: bpf/bpf_sock.c·bpf/bpf_lxc.c is GPL-2.0-only OR BSD-2-Clause, pkg/fqdn/matchpattern/matchpattern.go is Apache-2.0 (Copyright Authors of Cilium).