eBPF è una tecnologia di programmazione basata sugli eventi che consente agli sviluppatori di scrivere programmi efficienti, sicuri e non intrusivi che vengono eseguiti direttamente nello spazio kernel del sistema operativo (OS) Linux, "estendendo" di fatto il kernel del sistema operativo.
Il kernel di un sistema operativo è un'entità estremamente, e intenzionalmente, stabile. Supporta l'intero sistema operativo e quindi, già per come è stato progettato, può essere complicato e laborioso modificarlo. Le soluzioni eBPF affrontano questa sfida di estensibilità permettendo agli sviluppatori di eseguire programmi sandboxed in contesti privilegiati, come un kernel OS.
Lo stack del sistema operativo può essere suddiviso in tre livelli logici: il livello hardware, il livello kernel e il livello utente. Il livello del kernel è il cuore di un sistema operativo. Si colloca tra il livello fisico (che ospita tutto l'hardware, la memoria e i componenti di storage di un sistema operativo) e il livello utente (che ospita i browser web e le applicazione di un sistema operativo).
Le app e i browser nello spazio utente devono comunicare con i componenti del livello fisico per completare i rispettivi compiti, tuttavia ogni componente del livello fisico ha protocolli di comunicazione e requisiti di compatibilità specifici. È qui che entra in scena il livello del kernel (o spazio del kernel). Interpreta le chiamate di sistema e consente alle applicazioni di comunicare efficacemente con i componenti fisici della rete.
Gli strumenti eBPF aiutano gli sviluppatori ad espandere più facilmente le caratteristiche del software esistente durante il runtime, senza modificare il codice sorgente del kernel, caricare moduli del kernel (pezzi di codice caricabili che possono estendere le funzioni del kernel) o altrimenti interrompere lo spazio del kernel.
Le tecnologie eBPF rappresentano un'evoluzione del Berkeley Packet Filter (BPF) originale, che forniva un modo semplice per selezionare e analizzare i pacchetti di rete in un programma dello spazio utente. Tuttavia, oltre al filtraggio dei pacchetti, i programmi BPF mancavano della flessibilità necessaria per gestire compiti più complessi all'interno del kernel.
Riconoscendo la necessità di una tecnologia più versatile, la community di Linux ha sviluppato la tecnologia eBPF, basata sulle funzionalità backend di BPF ma con una programmabilità interna estesa al kernel. Le funzionalità avanzate dei programmi eBPF (e il loro approccio sandbox), permettono agli sviluppatori di implementare processi di filtraggio dei pacchetti migliorati, così come di migliorare l'osservabilità e il monitoraggio nello spazio kernel, condurre analisi delle prestazioni di alto livello e far rispettare le politiche di di sicurezza a livello di kernel nei data center on-premise e negli ambienti cloud-native.
I componenti principali di un programma eBPF sono:
I programmi eBPF vengono inizialmente scritti in un sottoinsieme C limitato e poi compilati in bytecode eBPF utilizzando strumenti come LLVM, che funge da architettura back-end dell'eBPF per i linguaggi di programmazione front-end (ad esempio Clang). Il bytecode è essenzialmente un insieme ristretto di istruzioni che aderiscono all'architettura del set di istruzioni eBPF e prevengono gli errori di runtime.
La tecnologia del kernel Linux può convertire il bytecode eBPF in azioni eseguibili, tuttavia i compilatori just-in-time (JIT) offrono prestazioni superiori. I compilatori JIT possono convertire il bytecode in codice macchina nativo per piattaforme hardware specifiche, secondo le necessità.
I loader dello spazio utente sono programmi nello spazio utente che caricano il bytecode eBPF nel kernel, collegandolo agli hook appropriati e gestendo tutte le mappe eBPF associate. Esempi di loader dello spazio utente includono strumenti come BPF Compiler Collection (BCC) e bpftrace.
Le mappe eBPF sono strutture di dati con coppie chiave-valore e accesso in lettura e scrittura che offrono uno spazio di storage condiviso e facilitano l'interazione tra i programmi eBPF kernel e le applicazioni dello spazio utente. Create e gestite tramite chiamate di sistema, le mappe eBPF possono anche essere utilizzate per mantenere lo stato tra diverse iterazioni dei programmi eBPF.
Il verifier, un componente critico dei sistemi eBPF, controlla il bytecode prima che venga caricato nel kernel per assicurarsi che il programma non contenga operazioni dannose, come cicli infiniti, istruzioni illegali o accesso alla memoria fuori dai limiti. Aiuta anche a garantire che tutti i percorsi dati del programma terminino correttamente.
Gli hook sono punti del codice del kernel in cui i programmi eBPF possono essere collegati. Quando il kernel raggiunge un hook, esegue il programma eBPF allegato.
Diversi tipi di hook come tracepoint, kprobe, uprobe e code di ricezione dei pacchetti di rete forniscono ai programmi eBPF un ampio accesso ai dati e consentono loro di completare varie operazioni. I tracepoint, ad esempio, consentono ai programmi di ispezionare e raccogliere dati sul kernel o su altri processi, mentre gli hook di controllo del traffico possono essere utilizzati per ispezionare e modificare i pacchetti di rete. Inoltre, kprobe e uprobe facilitano il tracciamento dinamico a livello di kernel e di utente.
Gli XDP sono percorsi dati ad alte prestazioni che accelerano l'elaborazione dei pacchetti a livello di driver e facilitano il trasferimento tra i livelli di comunicazione. Consentono ai sistemi eBPF di prendere decisioni di routing dei dati prima ancora che i pacchetti di dati raggiungano il kernel.
L'integrazione degli XDP con il kernel Linux (a metà degli anni 2010) ha infine permesso agli sviluppatori di distribuire funzioni di bilanciamento del carico basate su eBPF, capaci di gestire il traffico dati anche nei data center più trafficati.
Poiché gli eBPF non sono in grado di generare funzioni arbitrarie e devono mantenere la compatibilità con ogni possibile versione del kernel, talvolta i set di istruzioni eBPF di base non sono abbastanza dettagliati per eseguire operazioni avanzate. Le funzioni di supporto colmano questa lacuna.
Le funzioni helper (insiemi di funzioni kernel predefinite basate su API che gli eBPF possono chiamare all'interno del sistema) consentono ai programmi eBPF di completare operazioni più complesse (come ottenere l'ora e la data attuali o generare numeri casuali) che non sono supportate direttamente dal set di istruzioni.
In genere, gli eBPF funzionano come virtual machine (VM) all'interno del kernel Linux, lavorando su un'architettura di istruzioni di basso livello ed eseguendo il bytecode eBPF. Tuttavia, il complesso processo di esecuzione di un programma eBPF tende a seguire alcuni passaggi principali.
Gli sviluppatori prima scrivono il programma eBPF, quindi compilano il bytecode. Lo scopo del programma determinerà il tipo di codice appropriato. Ad esempio, se un team vuole monitorare l'uso della CPU, scriverà codice che include funzioni per catturare le metriche di utilizzo.
Dopo che il compilatore eBPF converte il codice C di alto livello in un bytecode di livello inferiore, un loader dello spazio utente genera una chiamata di sistema BPF per caricare il programma nel kernel. Il loader è anche responsabile della risoluzione degli errori e dell'impostazione di tutte le mappe eBPF necessarie al programma.
Con il bytecode del programma e le mappe a disposizione, l'eBPF eseguirà un processo di verifica per confermare che il programma è sicuro da eseguire nel kernel. Se viene ritenuto non sicuro, la chiamata di sistema per caricare il programma fallirà e il programma di caricamento riceverà un messaggio di errore. Se il programma supera la verifica, può essere eseguito.
Utilizzando un interprete o un compilatore JIT, l'eBPF convertirà il bytecode in codice macchina fruibile. Tuttavia, poiché eBPF è una tecnologia guidata dagli eventi, viene eseguita in risposta a specifici hook point o eventi all'interno del kernel (chiamate di sistema, eventi di rete, avvio di processi, inattività della CPU, per esempio). Quando si verifica un evento, l'eBPF esegue il corrispondente programma bytecode, permettendo agli sviluppatori di ispezionare e manipolare vari componenti del sistema.
Quando il programma eBPF è in esecuzione, gli sviluppatori possono interagire con esso dallo spazio utente utilizzando le mappe eBPF. Ad esempio, l'applicazione potrebbe controllare periodicamente una mappa per raccogliere dati dal programma eBPF, oppure potrebbe aggiornare una mappa per modificare il comportamento del programma.
L'unloading del programma è il passaggio finale della maggior parte dei processi di esecuzione eBPF. Quando l'eBPF ha fatto il suo lavoro, il loader può utilizzare di nuovo il sistema BPF per scaricarlo dal kernel. A quel punto l'eBPF smette di funzionare e libera le risorse associate. Il processo di unloading potrebbe includere anche l'iterazione su qualsiasi mappa eBPF di cui il team non ha più bisogno per liberare singoli elementi utili, e poi l'eliminazione della mappa stessa (utilizzando la syscall "delete").
Il Berkeley Packet Filter (BPF) è stato originariamente sviluppato come meccanismo per il filtraggio dei pacchetti in sistemi basati su Unix, permettendo al codice a livello utente di definire filtri in grado di catturare e processare efficacemente i pacchetti di rete all'interno del kernel. Pertanto, questo approccio minimizzava la potenza di calcolo necessaria per trasferire dati non necessari allo spazio utente e poteva semplificare e ottimizzare le reti informatiche.
BPF utilizza un agente kernel per elaborare i pacchetti al punto di ingresso dello stack di rete. Dopo lo sviluppo di un programma BPF, viene caricato nello spazio del kernel da un agente BPF del kernel, che ne verifica l'accuratezza prima di collegarlo al socket pertinente. Di conseguenza, nello spazio utente, solo i pacchetti che corrispondono al filtro del programma BPF possono ricevere dati da un dato socket. Questa caratteristiche di protezione limita l'accesso di un programma alle aree di memoria consentite e previene potenziali crash del kernel.
La tecnologia eBPF è emersa per la prima volta nel 2014 e ha rappresentato al tempo un'evoluzione significativa del concetto originale di BPF. Oltre ai casi d'uso della rete originali, le applicazioni eBPF si ampliarono fino a includere chiamate di sistema e altre funzioni, motivo per cui gli sviluppatori spesso chiamavano questa tecnologia "fully extended Berkeley Packet Filter".
Uno degli ambiti chiave in cui la tecnologia eBPF eccelle è il monitoraggio delle prestazioni di rete. Consente ai team IT di effettuare analisi e risoluzione dei problemi in tempo reale, fornendo insight granulari sul comportamento della rete, sulle metriche delle prestazioni e sui colli di bottiglia. L'eBPF svolge un ruolo chiave nella sicurezza della rete, nel monitoraggio e filtraggio delle chiamate e delle attività di rete, nell'applicazione delle politiche di sicurezza della rete e nel rilevamento delle anomalie di sistema.
L'eBPF offre inoltre agli sviluppatori uno strumento prezioso per tracciare e profilare sia applicazioni nel kernel che nello spazio utente, ed eseguire azioni personalizzate e trasformazioni dei dati mentre i dati attraversano il kernel, migliorandone ulteriormente la versatilità e l'utilità. Grazie a queste ampie funzionalità (che vanno ben oltre il filtraggio dei pacchetti), eBPF è ora riconosciuto come un termine autonomo, piuttosto che come acronimo di extended Berkeley Packet Filter.
I progressi della tecnologia eBPF hanno spinto gli sviluppatori software ad espanderne le applicazioni a tutti i sistemi operativi, in modo che anche le piattaforme non basate su Linux possano utilizzare le sofisticate funzionalità di tracciamento, rete e monitoraggio di eBPF.1
Infatti, l'eBPF Foundation, un'estensione della Linux Foundation i cui membri comprendono Google, Meta, Netflix, Microsoft, Intel e Isovalent, tra gli altri, hanno investito molto nell'espansione della compatibilità del sistema operativo per i programmi eBPF, nella speranza di ampliare l'utilità della programmazione eBPF.2
Sebbene BPF abbia gettato le basi per un filtraggio efficiente dei pacchetti, eBPF ne ha innegabilmente ampliato la portata. Gli eBPF moderni forniscono uno strumento completo per l'osservabilità ottimizzata, le prestazioni e la sicurezza nei sistemi Linux. La sua capacità di eseguire programmi dinamici e definiti dall'utente all'interno del kernel crea nuove possibilità per il monitoraggio e la gestione dei sistemi, rendendo l'eBPF uno strumento indispensabile sia per gli sviluppatori software che per i programmatori informatici.
Le tecnologie eBPF sono già diventate una pietra miliare dei moderni sistemi Linux, poiché consentono di avere un controllo preciso sul kernel Linux e permettono alle aziende di creare programmi più innovativi all'interno dell'ecosistema Linux.
L'eBPF ha facilitato i progressi in:
eBPF consente agli sviluppatori di installare caratteristiche di elaborazione dei pacchetti più rapide e personalizzate, processi di bilanciamento del carico, script di profilazione applicazione e pratiche di monitoraggio della rete. Le piattaforme open source, come Cilium, implementano eBPF per fornire una rete sicura, scalabile e osservabile per cluster e workload Kubernetes, oltre ad altri microservizi containerizzati.
eBPF aiuta inoltre i team IT a imporre regole semplici e complesse nelle prime fasi del percorso degli eventi per un routing del traffico più efficace, così come per filtrare i contenuti e prevenire le perdite. Utilizzando la logica di inoltro dei pacchetti a livello di kernel, gli eBPF possono ridurre al minimo la latenza, semplificare i processi di routing e rendere più rapida la risposta complessiva della rete.
Via via che le app vengono suddivise in microservizi, l'osservabilità nello spazio utente può diventare una sfida. Gli eBPF forniscono agli strumenti di monitoraggio un punto di vista kernel-space, in modo che l'osservabilità rimanga intatta end-to-end.
Gli eBPF consentono agli sviluppatori di dotare il kernel e le applicazioni dello spazio utente degli strumenti necessari per raccogliere dati e metriche dettagliate sulle prestazioni, senza influire in modo significativo sulle prestazioni del sistema. Queste funzionalità aiutano le organizzazioni a rimanere all'avanguardia, consentendo il monitoraggio e l'osservabilità in tempo reale per ogni componente della rete (e le sue dipendenze).
Gli eBPF possono monitorare le chiamate di sistema, il traffico di rete e il comportamento del sistema sia a livello di kernel che di socket, per rilevare e rispondere alle potenziali minacce alla sicurezza in tempo reale. Falco (uno strumento di sicurezza runtime cloud-native), ad esempio, utilizza eBPF per implementare audit di sicurezza in runtime e di risposta agli incidenti, migliorando la sicurezza complessiva del sistema.
Molti strumenti eBPF possono tracciare le chiamate di sistema, monitorare l'uso della CPU e tracciare l'uso delle risorse (I/O disco, per esempio). Queste funzionalità possono aiutare gli sviluppatori a individuare più facilmente i colli di bottiglia nelle prestazioni del sistema, implementare protocolli di debug e individuare opportunità di ottimizzazione.
Gli eBPF possono installare e applicare politiche di sicurezza a livello di kernel (ad esempio filtri del traffico di rete, firewall e restrizioni comportamentali) e controlli di sicurezza per impedire a malintenzionati e utenti non autorizzati di accedere alla rete.
In un'architettura a microservizi, la visibilità dei workload di produzione all'interno del container è fondamentale. Tuttavia, gli strumenti di osservabilità tradizionali possono faticare a tenere il passo con i microservizi containerizzati.
I container sono effimeri per progettazione; vengono creati quando necessario e poi distrutti non appena hanno svolto il loro scopo. Ogni container agisce come un host individuale e, in un ambiente di produzione, l'enorme quantità di metriche che creano può facilmente sovraccaricare gli strumenti standard di monitoraggio di app, rete e infrastruttura. Le macchine virtuali possono comportarsi in modo simile, ma la natura a cicli rapidi dei container può complicare l'acquisizione della telemetria.
Inoltre, i container vengono spesso implementati in gran numero negli ambienti cloud, rendendo la visibilità ancora più difficile.
eBPF, che funziona a livello di kernel di un host o container, consente agli sviluppatori di raccogliere telemetria da entità dati di breve durata. Aiuta a integrare la visibilità a livello di rete, applicazioni e infrastrutture in un servizio unificato basato su eBPF. Con eBPF, gli sviluppatori possono acquisire dati sui processi, sull'utilizzo della memoria, sull'attività di rete e sull'accesso ai file a livello di container, anche se i container non sono implementati nel cloud.
Analogamente, negli ambienti containerizzati basati su Kubernetes, eBPF utilizza un'unica interfaccia e un unico set di strumenti per raccogliere dati da cluster eterogenei, così che i team IT non debbano implementare singoli agenti dello spazio utente per completare attività di raccolta dei dati in tutta la rete. Gli strumenti eBPF possono funzionare su nodi del piano di controllo (ad esempio per il monitoraggio dei server API) e monitorare i nodi worker per generare insight, correlando punti dati e insight da entrambi i tipi di nodi, per una perfezionata osservabilità del cluster.
Red Hat OpenShift on IBM Cloud è una OpenShift Container Platform (OCP) completamente gestita.
Virtualizzazione dello storage sicura, affidabile ed efficiente per ambienti VMware con IBM Spectrum Virtualize.
Trova la soluzione di infrastruttura cloud adatta alle esigenze della tua azienda e scala le risorse on-demand.
1 Foundation Proposes Advancing eBPF Adoption Across Multiple OSes, DevOps.com, 21 agosto 2021.
2 Latest eBPF Advances Are Harbingers of Major Changes to IT, DevOps.com, 13 settembre 2023.