From 228bb4e23714d7e133485a2e19841d86ed4c58dd Mon Sep 17 00:00:00 2001 From: Simone Magnani Date: Wed, 13 Nov 2024 09:48:30 +0100 Subject: [PATCH] examples: tcx: use Variable API This commit updates the `example/tcx` program to use the new Variable API rather than traditional bpf maps. The example already depends on `bpf_link`, which requires kernel >= v6.6, therefore the Variable API is already supported and working (since v5.5). Signed-off-by: Simone Magnani --- examples/tcx/bpf_bpfeb.go | 13 +++++-------- examples/tcx/bpf_bpfeb.o | Bin 3224 -> 2408 bytes examples/tcx/bpf_bpfel.go | 13 +++++-------- examples/tcx/bpf_bpfel.o | Bin 3224 -> 2408 bytes examples/tcx/main.go | 14 ++++++-------- examples/tcx/tcx.c | 38 ++++++-------------------------------- 6 files changed, 22 insertions(+), 56 deletions(-) diff --git a/examples/tcx/bpf_bpfeb.go b/examples/tcx/bpf_bpfeb.go index 6e978748d..3883b86a6 100644 --- a/examples/tcx/bpf_bpfeb.go +++ b/examples/tcx/bpf_bpfeb.go @@ -62,14 +62,14 @@ type bpfProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfMapSpecs struct { - EgressPktCount *ebpf.MapSpec `ebpf:"egress_pkt_count"` - IngressPktCount *ebpf.MapSpec `ebpf:"ingress_pkt_count"` } // bpfVariableSpecs contains global variables before they are loaded into the kernel. // // It can be passed ebpf.CollectionSpec.Assign. type bpfVariableSpecs struct { + EgressPktCount *ebpf.VariableSpec `ebpf:"egress_pkt_count"` + IngressPktCount *ebpf.VariableSpec `ebpf:"ingress_pkt_count"` } // bpfObjects contains all objects after they have been loaded into the kernel. @@ -92,21 +92,18 @@ func (o *bpfObjects) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfMaps struct { - EgressPktCount *ebpf.Map `ebpf:"egress_pkt_count"` - IngressPktCount *ebpf.Map `ebpf:"ingress_pkt_count"` } func (m *bpfMaps) Close() error { - return _BpfClose( - m.EgressPktCount, - m.IngressPktCount, - ) + return _BpfClose() } // bpfVariables contains all global variables after they have been loaded into the kernel. // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfVariables struct { + EgressPktCount *ebpf.Variable `ebpf:"egress_pkt_count"` + IngressPktCount *ebpf.Variable `ebpf:"ingress_pkt_count"` } // bpfPrograms contains all programs after they have been loaded into the kernel. diff --git a/examples/tcx/bpf_bpfeb.o b/examples/tcx/bpf_bpfeb.o index 9662849e7dfe9da09926a8d6b3de3d4b6a3ad410..928c8527e75fe36f50169f8bd84422aa83b00e65 100644 GIT binary patch literal 2408 zcmb_dJ8u&~5Z-g_KpxHmQly|bibM{IEFN=4>yW)_cjYi@%yvd+GLo{ zp#7-P0ZxTZDC0tCt2rBodj--M#mL8r1nB?C6ve5 zC!o`+b0d%yQhE(p4ysk*HOgYw^=Z`Fj_1k!cB>|xHU;|0#x$AR+)8*}YsZIB>w6(RgEgx^}tjgl{=BkwBYwp^P>p5fvHy1?U zdb>5(shG`{TT|1?rE$t==aIuId!FD#x^GSOb%eM=8ly?$Q2X%hr)cOl78$bVX`q$y z$`GUeQ<9^ZVzU5P2Q0~jwWh{zg;)Sa4#d9+u|i7R*7%nY>xge^O#A}ZCRevmpT}A~ zia)*7?MKat@ss^B8GGG}@xg;YPsjM+L7?xGA9oQKdS6Nq$DX*)aW-%@HYRi&Z;-?= zX+oSa__$Mz)rDd$;{~$gcs+riByc@}I|+Q4z@Hco4v!3Fh2=XPUs!FYY27WZSpZ#6 zr$?h%&F1qxytX#=YOI5ijNWsUCVJ%jCL)JLui7t_h2UNBD@=jXp)u8)23f3K#-RbO4BFL5u~@%qTwqke|#ye1CnGmrhKf2Z}gpzaN% f(~>#VIQcshzpppM>GAuRMt%tPk2TEW`jh_vYH#v@ literal 3224 zcmcIm&1+p%5TE!c3XKT&z1-ZFg!gja<9?JE z6dDxKjfkkwh0uy1*(ffAy0h-O=pP`6&}G4mxT%Xm{LQ&D_uXETx~LA!nfcAknKS3y zbB23)e&KYb;!sWw-GyE-)1B zL8drQ5mi`~`OdGh;&lo9LgfFQ|CO}fGUv`N9eZ_gL6&?d@%vS~k+CdEK}u8;)YQ9s`~SOA2}odOx@degn)ox4}!`$G|thwF4MHBjAV46-h2WOPh-i2=oN_ zeLe&wEXICze+)hZ{uCQz+mm1}rsQ|t6F;t{^QTP?1=1c};ar}vjPz?!5XWApnRtFX#bQC( z;CXS=TS*%YikmCF2~m5^Yowu1iBIma#P7O37mG?Hfd)*(NtF7D$@7>=Bsyx|p<%lT zgUSr(q?vxnnoi7`Nm~m{E1ib7S?_qQcDtE&yr30qP5@7tam+f3_>G2{u)#JVGR9k> z?=^zNU-#uF$yo`-J7ZnA8Az#bpC zpyny8=dafzeBIWDAB1s0E_NG}B9b0r?Cl^z|FC=u@{ZW}UVaVM`*s+54g55i?;HE< zn}+-b{2kGk5cWPZ{*5T%90ttz527x=lNU4W7@~Ivpq~-!;%W0USQHF-jn}RT{*35* zsI;EpJpZ;}&3`4sj*VA`8d5Z6?ut1ze?b>_rttKAkWp109J z)ULrbD2H(%d)g?J-&maoIkeX>aCAC?S8_GwSphR&@_aD~4S`?=?U zD*T<YvxI*s;X5V#m*SCw zhYpOAn*`m2+$dTe}e-HG*r+pK3!#O%|< O2d>Hd^845I$NmQT-eT(j diff --git a/examples/tcx/bpf_bpfel.go b/examples/tcx/bpf_bpfel.go index d196e43fd..56d03d193 100644 --- a/examples/tcx/bpf_bpfel.go +++ b/examples/tcx/bpf_bpfel.go @@ -62,14 +62,14 @@ type bpfProgramSpecs struct { // // It can be passed ebpf.CollectionSpec.Assign. type bpfMapSpecs struct { - EgressPktCount *ebpf.MapSpec `ebpf:"egress_pkt_count"` - IngressPktCount *ebpf.MapSpec `ebpf:"ingress_pkt_count"` } // bpfVariableSpecs contains global variables before they are loaded into the kernel. // // It can be passed ebpf.CollectionSpec.Assign. type bpfVariableSpecs struct { + EgressPktCount *ebpf.VariableSpec `ebpf:"egress_pkt_count"` + IngressPktCount *ebpf.VariableSpec `ebpf:"ingress_pkt_count"` } // bpfObjects contains all objects after they have been loaded into the kernel. @@ -92,21 +92,18 @@ func (o *bpfObjects) Close() error { // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfMaps struct { - EgressPktCount *ebpf.Map `ebpf:"egress_pkt_count"` - IngressPktCount *ebpf.Map `ebpf:"ingress_pkt_count"` } func (m *bpfMaps) Close() error { - return _BpfClose( - m.EgressPktCount, - m.IngressPktCount, - ) + return _BpfClose() } // bpfVariables contains all global variables after they have been loaded into the kernel. // // It can be passed to loadBpfObjects or ebpf.CollectionSpec.LoadAndAssign. type bpfVariables struct { + EgressPktCount *ebpf.Variable `ebpf:"egress_pkt_count"` + IngressPktCount *ebpf.Variable `ebpf:"ingress_pkt_count"` } // bpfPrograms contains all programs after they have been loaded into the kernel. diff --git a/examples/tcx/bpf_bpfel.o b/examples/tcx/bpf_bpfel.o index 5ff34587e415e4a37e9ec926a4baabd2a4842c72..7acc38c255b7b318c22eb2f30d4d9ace9dc30904 100644 GIT binary patch literal 2408 zcmbtVO-~d-5ba(309g>!0|yUt!K}s%n)pGYheZKJF%sQ_;9*>b;Ug>q*_kyM6Xj&M z=)uJ3O^+V+1V6>ZgFnC@;8EY}shZtwz{FUwsCreey1Hw+*OwF1lf^>8s1(dE(?S|G zrhKI3SFBqxePHf@O#V=@m8bXpM22@H{7&q@^2eLCx_57?I&y1fnoE5ASujJgRvC?{ zo7_MqMQ%gjQ4Iq39Rlc;-0>_?V9W#kWEL-VWpUPb@IOhOBPeBy+lh7Ot&A-NHpifS z&_Urz4>O$M{vPD$j%2u-+{?mceFb`3xFz^>=N!BWjC0y!^dnDUt(?pH8{pud4e{I* z_A)_`tOoPV#YK~>&YP7ug)TLsBndVe>r266GY(A}8h<1WH~o+VZx5lIq>W~ndih%3 zIV^V8dv1CVdKQPlVw8rb$BlfB{gRz^{ z;QrlfCUW<}4YJ>MLOsClS2nl}n}> zCo4;FwBXg(<0bp2H8fo^-+3PJ=aas_xxR@!;Nw-NwRz(w&(^G!ZOBgl&%8jn z{=T-a^jbdc`}QDw`8;`)n5u6;6BTtF%kS1M{9b>nf6`8dulGyCRXF_Zu4q8)t~Bxl zmtc8Ltsjs$pBDSOGx#KVz1ITwoc}5kT+^-pA_dw<>$Sh)w{Y0s6|LXZA08pN^LvB% ze&_!t#0yf#^Yb@L`|G~+|6ZZxW?2sOIgezH+n;Oh*S}lt&z97)KY4Ed>xgwt|6YgL hg66U<^10b6h1Rk)2TLJwbdvE-&IIUxJ_fIf)u9FRI90k8le&4W^!{U37Om(=H6Q- zC^RUd8xg5O7eb4IWTUtc>dw0B!XF@r;IiOG+|)%OKF|Ac=k_K<@Z*qk&w0){?>X=1 z$y}Y8Jzp-B#8FA^Ne?-z$mK&ly{6Tg^ds_?4Gx~XzeDr)pKGTaEQ{RV+1VK>Bzq5T znvMwqKpao}^N@ye%Lw_@%Ktn63u(QnE?$^F_2S&DE%~p+jo(T#Vly1a63K&RskD|W z_}DEe9e}PfD0Jyvp`Ak>q5*yzXAoR{(4H`;dJys{qwk92k&WB9hao3zTotlrbbiZ+ zd-?-&u=5nuKcEmZ19rBTp>uvU@T*|v+yc*o9|7M6FM>e>{rI?X|1?)er;>reTrQ~P zBlx^)eB266sMXK?`w%<~{um6~;YT4!MgKc6(0>fRKcFy#0&6lz%-K8+8_$C4xo12B zJZq{Y6vQ8=Cj#=$)460VO2qfiUAlB`!GG<-8#Dg=!rYAS!%!WijSI$<39?e)YD zS}BT!MT76h>;6*OXh^)i)Em%gt@w>J3M2`{JCy`oFW_V`6Pv&VjKxVO4HA{*Q74h; zgnCO3=|w2aOo7g-iRZNG%#=E*=K|AGyWwxt+kUgvT2I@4*bFzufXCG+Mx8+XT0@QL zV4V;d%af}Ytkyd?-R4>lMsX+}RvU{$!XCoALppBxN65Q0fcVzF0P~KMj)E7# zkAZpL=yPxSOXy#Nc zO~zjXmTyE>t>5L}ve@OnZn4Y1ZL!Ob6uSNo%>OOG-%!Oo%Lk%vXjIX2%{y3|&zLpx z^d`WOT%JYik{rHlV1{{iBWsgi>RgIDFE>Aq; zJQ0(7H`sVmu;2LG`C#aFTAB5AX#D+A%PdCe^74X|{+d3;b-M9G)_xI^ z^>^(7jUe}q3^K7!r+fyy*Z3hjzQ&*&x%$p@4T=qQCN0_fNY58GtN`UB#O$^H>vsJU zI*VDqe(x5$_47B>UiCk*t)yCT7V9(TUiI(T`oG$G{6E1sw|-auENqq8ofgCvIHPSF i*z0J-puYh45@J*U diff --git a/examples/tcx/main.go b/examples/tcx/main.go index e0ac83d94..d31acb153 100644 --- a/examples/tcx/main.go +++ b/examples/tcx/main.go @@ -1,8 +1,7 @@ // This program demonstrates attaching an eBPF program to a network interface -// with Linux TC (Traffic Control). The program counts ingress and egress -// packets using two ARRAY maps. -// The userspace program (Go code in this file) prints the contents -// of the two maps to stdout every second. +// with Linux TCX (Traffic Control with eBPF). The program counts ingress and egress +// packets using two variables. The userspace program (Go code in this file) +// prints the contents of the two variables to stdout every second. // This example depends on tcx bpf_link, available in Linux kernel version 6.6 or newer. package main @@ -78,20 +77,19 @@ func main() { } } -func formatCounters(ingressMap, egressMap *ebpf.Map) (string, error) { +func formatCounters(ingressVar, egressVar *ebpf.Variable) (string, error) { var ( ingressPacketCount uint64 egressPacketCount uint64 - key int32 ) // retrieve value from the ingress map - if err := ingressMap.Lookup(&key, &ingressPacketCount); err != nil { + if err := ingressVar.Get(&ingressPacketCount); err != nil { return "", err } // retrieve value from the egress map - if err := egressMap.Lookup(&key, &egressPacketCount); err != nil { + if err := egressVar.Get(&egressPacketCount); err != nil { return "", err } diff --git a/examples/tcx/tcx.c b/examples/tcx/tcx.c index 61996ba02..248f0c340 100644 --- a/examples/tcx/tcx.c +++ b/examples/tcx/tcx.c @@ -4,43 +4,17 @@ char __license[] SEC("license") = "Dual MIT/GPL"; -/* Define an ARRAY map for storing ingress packet count */ -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); -} ingress_pkt_count SEC(".maps"); - -/* Define an ARRAY map for storing egress packet count */ -struct { - __uint(type, BPF_MAP_TYPE_ARRAY); - __type(key, __u32); - __type(value, __u64); - __uint(max_entries, 1); -} egress_pkt_count SEC(".maps"); - -/* -Upon arrival of each network packet, retrieve and increment -the packet count from the provided map. -Returns TC_ACT_OK, allowing the packet to proceed. -*/ -static __always_inline int update_map_pkt_count(void *map) { - __u32 key = 0; - __u64 *count = bpf_map_lookup_elem(map, &key); - if (count) { - __sync_fetch_and_add(count, 1); - } - - return TC_ACT_OK; -} +__u64 ingress_pkt_count = 0; +__u64 egress_pkt_count = 0; SEC("tc") int ingress_prog_func(struct __sk_buff *skb) { - return update_map_pkt_count(&ingress_pkt_count); + __sync_fetch_and_add(&ingress_pkt_count, 1); + return TC_ACT_OK; } SEC("tc") int egress_prog_func(struct __sk_buff *skb) { - return update_map_pkt_count(&egress_pkt_count); + __sync_fetch_and_add(&egress_pkt_count, 1); + return TC_ACT_OK; }