EBPF

**eBPF** فناوری است که می تواند برنامه‌ها را در یک محیط محافظت‌شده مانند هسته سیستم عامل اجرا کند. این جانشینی برای مکانیزم قبلی فیلترینگ در لینوکس با نام فیلتر بسته برکلی (BPF، با "e" در اصل به معنای "بسط یافته")  می‌باشد و همچنین در سایر بخش‌های کرنل لینوکس نیز استفاده می‌شود.

از eBPF برای گسترش ایمن و کارآمد قابلیت‌های هسته در زمان اجرا بدون نیاز به تغییر در کد منبع کرنل یا بارگیری ماژول‌های کرنل استفاده می‌شود. ایمنی توسط یک مکانیزم تأیید کننده در داخل کرنل که تجزیه و تحلیل کد ایستا را انجام می‌دهد تضمین می‌شود، بدین صورت که برنامه‌هایی را که از کار می‌افتند، هنگ می‌کنند یا با کرنل تداخل دارند را رد می‌کند.

این مدل اعتبار سنجی با محیط‌های جعبه شنی (جایی که محیط اجرا محدود است و زمان اجرا دیدی در مورد برنامه ندارد) متفاوت است. نمونه‌هایی از برنامه‌هایی که به‌طور خودکار رد می‌شوند، برنامه‌هایی هستند که تضمین‌های خروج قوی ندارند (به عنوان مثال حلقه‌های for/while بدون شرایط خروج) و برنامه‌هایی که مقادیر نشانگرها را بدون بررسی از حافظه دریافت می‌کنند.

## طراحی

برنامه‌های eBPF را می‌توان با استفاده از زبان‌های سطح بالا مانند C، پایتون، و Rust ایجاد کرد. توسعه دهنده پس از ایجاد ، آن‌ها را به دستورهای معماری ماشین eBPF کامپایل می‌کند. نتیجه یک فایل باینری با دستورهای eBPF است. این فایل توسط یک برنامه دیگر (در اینجا به نام برنامه کنترلی به آن ارجا می‌کنیم) به درون هسته سیستم عامل بارگذاری می‌شود. این برنامه از فراخوانی‌های سیستمی برای این عمل استفاده می‌کند که معمولاً با استفاده از کتابخانه‌هایی مانند libbpf این فرایند تسهیل می‌شود.
 
برنامه در حال بارگذاری ابتدا مورد صحت سنجی تأیید کننده (verifier) قرار می‌گیرد. برنامه‌های بارگذاری‌شده که از تأییدکننده عبور کرده‌اند  یا تفسیر می‌شوند (این روش منسوخ شده است) یا برای عملکرد بهتر درجا در هسته کامپایل می‌شوند. پس از این مرحله برنامه در هسته سیستم عامل بارگذاری شده است. برنامه کنترلی می‌تواند برنامه‌های بارگذاری شده را به انواع رویدادهای سطح پایین سیستمی قلاب کند. مدل اجرا مبتنی بر رویداد است. به این معنا که پس از اتصال برنامه به یک رویداد خاص، به ازای هر رویداد برنامه مورد نظر فراخوانی و دستورهایش اجرا می‌شود.

برای اینکه بتوان برنامه‌ای را به یک رویداد خاص قلاب کرد نیاز است که در هسته این امکان پیاده‌سازی شده باشد. برای مثال در برنامه‌های مرتبط با شبکه این امکان فراهم شده است تا برنامه ساز eBPF بتواند در هنگام دریافت یک بسته (packet) در سطح درایور کارت شبکه اطلاعات بسته را مشاهده کرده و عمل متناسب را اتخاذ کند. برای فراهم کردن این امکان، درایورهای کارت شبکه باید امکان اتصال یک برنامه eBPF و فراخوانی آن در زمان مناسب را پیاده‌سازی کنند. اهمیت این موضوع در این است که قابلیت برنامه‌های eBPF از نحوه پیاده‌سازی قلاب‌ها حاصل می‌شود. به عنوان مثال، به صورت رسمی قلابی در رابط درایو حالت جامد وجود ندارد ولی به صورت تحقیقاتی نشان داده شده است که با پیاده‌سازی مناسب می‌تواند کاربردی باشد. 

موارد استفاده از eBPF شامل شبکه هایی مانند XDP ، ردیابی و زیرسیستم های امنیتی است (که البته به این‌ها محدود نیست). با توجه به کارایی و انعطاف eBPF که فرصت‌های جدیدی را برای حل مشکلات فراهم کرده است، برندان گرگ eBPF را «ابرقدرت لینوکس» نامیده است. لینوس توروالدز چنین می‌گوید: «BPF واقعاً مفید بوده است و قدرت واقعی آن این است که چگونه به افراد اجازه می‌دهد تا کدها را تا زمانی که درخواست نشده‌اند فعال و اجرا نکند». به دلیل موفقیت در لینوکس، زمان اجرای eBPF در سیستم عامل های دیگر مانند ویندوز نیز مورد استفاده قرار گرفته است.

## اصطلاحات و مفاهیم

### MAP
برنامه‌های eBPF امکان تخصیص حافظه را در زمان اجرای برنامه ندارند. در عوض، برای اینکه نیاز برنامه‌های حالتمند (stateful) برطرف شود، این قابلیت وجود دارد تا  در زمان بارگذاری بخشی از حافظه هسته به برنامه اختصاص یابد. این قابلیت از طریق رابط برنامه سازی (API) به نام MAP صورت می‌گیرد. برای این منظور برنامه یک بخش (section) مشخص با برچسب «.map» در فایل باینری ایجاد می‌کند (برای اطلاعات بیشتر ساختار فایل ELF را مطلعه فرمایید). در این بخش اطلاعاتی مانند نوع MAP، اندازه کلید، اندازه مقدار (value) و تعداد عضوهای MAP را مشخص می‌کند . اندازه یک MAP نمی‌تواند از ۴ گیگابایت بیشتر شود. تکه کد زیر نحوه درخواست یک MAP از نوع آرایه را نشان می‌دهد. اندازه کلید از نوع int و اندازه مقدار از نوع ساختار my_value تعیین می‌شود. 


```c
struct my_value {
	int a;
	int b;
};

struct {
	__uint(type, BPF_MAP_TYPE_ARRAY);
	__type(key,  int);
	__type(value, struct my_value);
	__uint(max_entries, 100);
} my_array SEC(".maps");
```


برنامه eBPF می‌تواند با استفاده از تابع کمکی `bpf_map_lookup_elem(map_ptr, key_ptr)` اشاره‌گری به مقدار انتخاب شده توسط کلید ارائه شده دریافت کند. الزامی است که برنامه تهی (Null) نبودن اشاره‌گر دریافتی را قبل از ارجاع به آن بررسی کند (تاییدگر این عمل را الزامی می‌داند).

## صحت سنجی برنامه‌های eBPF

یک برنامه eBPF از طریق یک فراخوانی غیر مستقیم (indirect function call) و بدون تعویض زمینه (context switch) درون هسته سیستم‌عامل اجرا می‌شود. این طراحی سربار پایین‌تری در مقایسه با روش تعویض زمینه برای اجرای برنامه ایجاد می‌کند. اما در نقطه مقابل، پیش‌آمد خطا و اشکال درون برنامه eBPF منجر به توقف هسته می‌شود که درنتیجه آن کارکرد سیستم مختل می‌گردد. به همین منظور در طراحی eBPF صحت سنجی اجرای برنامه اجباری در نظر گرفته شده است و تنها توسط خود هسته انجام می‌شود (این تصمیم توسعه دهندگان لینوکس بوده است. ویندوز این صحت سنجی را در خارج هسته انجام می‌دهد. همچنین محققان راه‌های جایگزین مانند ارائه گواهی صحت سنجی به هسته را بررسی کرده‌اند).

تاییدگر (verifier) موارد گوناگونی را صحت سنجی می‌کند. در ادامه چند مورد مهم ذکر شده اند.

# **درستی ارجاعات به حافظه:** تمام ارجاعات حافظه در یک برنامه eBPF باید به آدرسی از حافظه که در تعلق برنامه است باشد. این مورد باید به صورت ایستا (قبل از اجرای برنامه) اثبات شود. اگر آدرس حافظه به پشته برنامه تعلق دارد، باید حتماً قبل از خواند، مقدار در آن نوشته شده باشد.
# ** خاتمه جریان اجرای برنامه:** اثبات خاتمه برنامه‌های eBPF با بررسی تمام حالات ممکن اجرای برنامه صورت می‌گیرد. برای محدود کردن زمان اجرای صحت سنجی بررسی هر شاخه ممکن از اجرای برنامه به یک میلیون دستور (در سطح ماشین eBPF) محدود شده است. همچنین تعداد پرش‌های ممکن به ۸۱۹۲ عدد محدود شده است.
# **رهاسازی قفل:** در صورتی که برنامه eBPF یک قفل را در یک مسیر اجرای برنامه دراختیار بگیرد حتماً باید آن را قبل از پایان برنامه و یا اجرای تابعی دیگر رها کند.

## تاریخچه
eBPF بر روی بستر فیلتر بسته برکلی (cBPF) ساخته شده است. در پایین ترین سطح، از ده رجیستر ۶۴ بیتی (به جای دو رجیستر طولانی ۳۲ بیتی برای cBPF)، مکانیزم پرش متفاوت، دستورالعمل فراخوانی و کنوانسیون عبور از رجیستر مربوطه، دستورالعمل‌های جدید و رمزگذاری متفاوت استفاده کرده است.

## نام تجاری
نام مستعار eBPF و BPF که اغلب به جای هم استفاده می‌شوند، برای مثال توسط جامعه هسته لینوکس مورد استفاده قرار گرفته است. eBPF و BPF به عنوان یک نام فناوری مانند LLVM شناخته می‌شوند.  eBPF بر بستر فیلتر بسته برکلی تکامل یافته است، اما موارد استفاده آن از BPF پیشی گرفته است.

زنبور عسل آرم رسمی eBPF است. در اولین اجلاس eBPF رأی‌گیری صورت گرفت و شگون‌نما زنبور عسل «eBee» نام گرفت. این لوگو در اصل توسط Vadim Shchekoldin ساخته شده است. شگون‌نماهای غیررسمی دیگری باری eBPF در گذشته وجود داشته است،  که با پذیرش گسترده‌ای مواجه نشده بودند.

## کنترل و راهبری
بنیاد eBPF در آگوست ۲۰۲۱ با هدف گسترش مشارکت های انجام شده بر روی eBPF ایجاد شده است. اعضای مؤسس عبارتند از متا، گوگل، ایزووالنت، مایکروسافت و نتفلیکس. هدف جمع‌آوری، برنامه‌ریزی و صرف بودجه برای حمایت از پروژه های منبع باز، داده باز و/یا استانداردهای باز مرتبط با eBPF  است تا رشد اکوسیستم eBPF را بیشتر کند. از زمان آغاز به کارRed Hat ،Huawei ، Crowdstrike ، Tigera، DaoCloud، Datoms، FutureWei نیز به آن پیوسته‌اند.

## همین‌طور ببینید

* مسیر داده اکسپرس

## منابع

رده:نرم‌افزارهای دارای اجازه‌نامه ام‌آی‌تی
رده:نرم‌افزارهایی که از پروانه جی‌پی‌ال استفاده می‌کنند
رده:نرم‌افزارهای سیستمی آزاد
رده:نرم‌افزارهای آزاد نوشته‌شده با سی