.\" -*- coding: UTF-8 -*- .\" Copyright 2015, Alexei Starovoitov .\" Copyright 2015, Michael Kerrisk .\" Copyright, the authors of the Linux man-pages project .\" .\" SPDX-License-Identifier: Linux-man-pages-copyleft .\" .\"******************************************************************* .\" .\" This file was generated with po4a. Translate the source file. .\" .\"******************************************************************* .TH bpf 2 "10 فبراير 2026" "صفحات دليل لينكس 6.18" .SH الاسم bpf \- تنفيذ أمر على برنامج أو خريطة BPF ممتدة .SH موجز .nf \fB#include \fP .P \fBint bpf(int \fP\fIcmd\fP\fB, union bpf_attr *\fP\fIattr\fP\fB, unsigned int \fP\fIsize\fP\fB);\fP .fi .SH الوصف يُنفذ استدعاء النظام \fBbpf\fP() مجموعة من العمليات المتعلقة بمرشحات حزم بيركلي الممتدة (Berkeley Packet Filters). إن BPF الممتد (أو eBPF) مشابه لـ BPF الأصلي ("التقليدي" أو cBPF) المستخدم لترشيح حزم الشبكة. وبالنسبة لبرامج cBPF و eBPF معًا، تحلل النواة البرامج سكونيًا قبل تحميلها، وذلك لضمان عدم إلحاقها الضرر بالنظام المشغل. .P .\" See 'enum bpf_func_id' in include/uapi/linux/bpf.h .\" يوسع eBPF نظام cBPF بطرق متعددة، بما في ذلك القدرة على استدعاء مجموعة ثابتة من الدوال المساعدة داخل النواة (عبر امتداد شفرة العملية \fBBPF_CALL\fP الذي يوفره eBPF) والوصول إلى هياكل البيانات المشتركة مثل خرائط eBPF. .SS "تصميم/معمارية BPF الممتد" خرائط eBPF هي هيكل بيانات عام لتخزين أنواع مختلفة من البيانات. تُعامل أنواع البيانات عمومًا ككتل ثنائية، لذا يحدد المستخدم حجم المفتاح وحجم القيمة عند وقت إنشاء الخريطة فقط. بمعنى آخر، يمكن أن يكون للمفتاح/القيمة في خريطة معينة هيكل تعسفي. .P يمكن لعملية المستخدم إنشاء خرائط متعددة (تكون فيها أزواج المفتاح/القيمة عبارة عن بايتات بيانات مبهمة) والوصول إليها عبر واصفات الملفات. يمكن لبرامج eBPF المختلفة الوصول إلى الخرائط نفسها بالتوازي. ويعود الأمر لعملية المستخدم وبرنامج eBPF لتقرير ما سيخزن داخل الخرائط. .P .\" Defined by the kernel constant MAX_TAIL_CALL_CNT in include/linux/bpf.h ثمة نوع خاص من الخرائط يسمى مصفوفة البرامج. يخزن هذا النوع من الخرائط واصفات ملفات تشير إلى برامج eBPF أخرى. عند إجراء بحث في الخريطة، يُعاد توجيه تدفق البرنامج في مكانه إلى بداية برنامج eBPF آخر ولا يعود إلى البرنامج المستدعِي. لمستوى التعشيش حد ثابت هو 32، حتى لا يمكن صياغة حلقات لانهائية. في وقت التشغيل، يمكن تعديل واصفات ملفات البرامج المخزنة في الخريطة، وبذلك يمكن تغيير وظائف البرنامج بناءً على متطلبات محددة. يجب أن تكون جميع البرامج المشار إليها في خريطة مصفوفة البرامج قد حُمّلت مسبقًا في النواة عبر \fBbpf\fP(). إذا فشل البحث في الخريطة، يكمل البرنامج الحالي تنفيذه. انظر \fBBPF_MAP_TYPE_PROG_ARRAY\fP أدناه لمزيد من التفاصيل. .P عمومًا، تُحمّل برامج eBPF بواسطة عملية المستخدم وتُفرّغ آليًا عند خروج العملية. في بعض الحالات، مثل \fBtc\-bpf\fP(8)، سيستمر البرنامج حيًا داخل النواة حتى بعد خروج العملية التي حمّلت البرنامج. في هذه الحالة، يحتفظ نظام tc الفرعي بمرجع لبرنامج eBPF بعد أن يُغلق واصف الملف بواسطة برنامج مساحة المستخدم. وبالتالي، فإن بقاء برنامج معين داخل النواة يعتمد على كيفية ربطه بنظام فرعي معين للنواة بعد تحميله عبر \fBbpf\fP(). .P كل برنامج eBPF هو مجموعة من التعليمات الآمن تشغيلها حتى اكتمالها. يحدد مدقق داخل النواة سكونيًا أن برنامج eBPF ينتهي وأنه آمن للتنفيذ. أثناء التحقق، تزيد النواة عدادات المراجع لكل خريطة يستخدمها برنامج eBPF، بحيث لا يمكن إزالة الخرائط المتصلة حتى يُفرّغ البرنامج. .P يمكن ربط برامج eBPF بأحداث مختلفة. قد تكون هذه الأحداث وصول حزم الشبكة، أو أحداث التتبع، أو أحداث التصنيف بواسطة ضوابط طوابير الشبكة (لبرامج eBPF المربوطة بمصنف \fBtc\fP(8))، وأنواع أخرى قد تُضاف مستقبلاً. يقدح الحدث الجديد تنفيذ برنامج eBPF، والذي قد يخزن معلومات عن الحدث في خرائط eBPF. وإلى جانب تخزين البيانات، قد تستدعي برامج eBPF مجموعة ثابتة من الدوال المساعدة داخل النواة. .P يمكن ربط برنامج eBPF نفسه بأحداث متعددة، ويمكن لبرامج eBPF مختلفة الوصول إلى الخريطة ذاتها: .P .in +4n .EX tracing tracing tracing packet packet packet event A event B event C on eth0 on eth1 on eth2 | | | | | \[ha] | | | | v | \-\-> tracing <\-\- tracing socket tc ingress tc egress prog_1 prog_2 prog_3 classifier action | | | | prog_4 prog_5 |\-\-\- \-\-\-\-\-| |\-\-\-\-\-\-| map_3 | | map_1 map_2 \-\-| map_4 |\-\- .EE .in .\" .SS المعطيات تُحدد العملية المطلوب تنفيذها بواسطة استدعاء النظام \fBbpf\fP() عبر المعطى \fIcmd\fP. تأخذ كل عملية معطى مصاحبًا يُوفر عبر \fIattr\fP، وهو مؤشر إلى اتحاد (union) من النوع \fIbpf_attr\fP (انظر أدناه). يجب تصفير الحقول غير المستخدمة والحشوات (padding) قبل الاستدعاء. المعطى \fIsize\fP هو حجم الاتحاد الذي يشير إليه \fIattr\fP. .P القيمة المقدمة في \fIcmd\fP هي واحدة مما يلي: .TP \fBBPF_MAP_CREATE\fP إنشاء خريطة وإرجاع واصف ملف يشير إليها. يُفعّل علم واصف ملف الإغلاق عند التنفيذ (انظر \fBfcntl\fP(2)) آليًا لواصف الملف الجديد. .TP \fBBPF_MAP_LOOKUP_ELEM\fP البحث عن عنصر بواسطة المفتاح في خريطة محددة وإرجاع قيمته. .TP \fBBPF_MAP_UPDATE_ELEM\fP إنشاء عنصر أو تحديثه (زوج مفتاح/قيمة) في خريطة محددة. .TP \fBBPF_MAP_DELETE_ELEM\fP البحث عن عنصر بواسطة المفتاح وحذفه في خريطة محددة. .TP \fBBPF_MAP_GET_NEXT_KEY\fP البحث عن عنصر بواسطة المفتاح في خريطة محددة وإرجاع مفتاح العنصر التالي. .TP \fBBPF_PROG_LOAD\fP التحقق من برنامج eBPF وتحميله، مع إرجاع واصف ملف جديد مرتبط بالبرنامج. يُفعّل علم واصف ملف الإغلاق عند التنفيذ (انظر \fBfcntl\fP(2)) آليًا لواصف الملف الجديد. .IP يتكون اتحاد \fIbpf_attr\fP من هياكل مجهولة مختلفة تُستخدم بواسطة أوامر \fBbpf\fP() المختلفة: .P .in +4n .EX .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 union bpf_attr { struct { /* تُستخدم بواسطة BPF_MAP_CREATE */ __u32 map_type; __u32 key_size; /* حجم المفتاح بالبايت */ __u32 value_size; /* حجم القيمة بالبايت */ __u32 max_entries; /* أقصى عدد من المدخلات في الخريطة */ }; \& struct { /* تُستخدم بواسطة أوامر BPF_MAP_*_ELEM و BPF_MAP_GET_NEXT_KEY */ __u32 map_fd; __aligned_u64 key; union { __aligned_u64 value; __aligned_u64 next_key; }; __u64 flags; }; \& struct { /* تُستخدم بواسطة BPF_PROG_LOAD */ __u32 prog_type; __u32 insn_cnt; __aligned_u64 insns; /* \[aq]const struct bpf_insn *\[aq] */ __aligned_u64 license; /* \[aq]const char *\[aq] */ __u32 log_level; /* مستوى إسهاب المدقق */ __u32 log_size; /* حجم مخزن المستخدم المؤقت */ __aligned_u64 log_buf; /* مخزن \[aq]char *\[aq] المؤقت الذي يوفره المستخدم */ __u32 kern_version; /* يُفحص عندما prog_type=kprobe (منذ لينكس 4.1) */ }; } __attribute__((aligned(8))); .EE .in .\" .SS "خرائط eBPF" الخرائط هي هيكل بيانات عام لتخزين أنواع مختلفة من البيانات. وهي تتيح مشاركة البيانات بين برامج eBPF في النواة، وكذلك بين النواة وتطبيقات مساحة المستخدم. .P لكل نوع خريطة السمات التالية: .IP \[bu] 3 النوع .IP \[bu] أقصى عدد من العناصر .IP \[bu] حجم المفتاح بالبايت .IP \[bu] حجم القيمة بالبايت .P توضح الدوال المغلفة التالية كيفية استخدام أوامر \fBbpf\fP() المختلفة للوصول إلى الخرائط. تستخدم الدوال المعطى \fIcmd\fP لاستدعاء عمليات مختلفة. .TP \fBBPF_MAP_CREATE\fP يُنشئ الأمر \fBBPF_MAP_CREATE\fP خريطة جديدة، ويُرجع واصف ملف جديد يشير إلى الخريطة. .IP .in +4n .EX int bpf_create_map(enum bpf_map_type map_type, unsigned int key_size, unsigned int value_size, unsigned int max_entries) { union bpf_attr attr = { .map_type = map_type, .key_size = key_size, .value_size = value_size, .max_entries = max_entries }; \& return bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); } .EE .in .IP للخريطة الجديدة النوع المحدد بواسطة \fImap_type\fP، والسمات المحددة في \fIkey_size\fP و \fIvalue_size\fP و \fImax_entries\fP. عند النجاح، تُرجع هذه العملية واصف ملف. عند حدوث خطأ، يُرجع \-1 ويُضبط \fIerrno\fP على \fBEINVAL\fP أو \fBEPERM\fP أو \fBENOMEM\fP. .IP ستُستخدم سمتا \fIkey_size\fP و \fIvalue_size\fP بواسطة المدقق أثناء تحميل البرنامج للتحقق من أن البرنامج يستدعي الدوال المساعدة \fBbpf_map_*_elem\fP() مع \fIkey\fP مُهيأ بشكل صحيح وللتحقق من أن البرنامج لا يصل إلى عنصر الخريطة \fIvalue\fP بما يتجاوز \fIvalue_size\fP المحدد. على سبيل المثال، عندما تُنشأ خريطة بـ \fIkey_size\fP قدره 8 ويستدعي برنامج eBPF .IP .in +4n .EX bpf_map_lookup_elem(map_fd, fp \- 4) .EE .in .IP سيُرفض البرنامج، لأن الدالة المساعدة داخل النواة .IP .in +4n .EX bpf_map_lookup_elem(map_fd, void *key) .EE .in .IP تتوقع قراءة 8 بايت من الموقع الذي يشير إليه \fIkey\fP، لكن عنوان البدء \fIfp\ \-\ 4\fP (حيث \fIfp\fP هو قمة المكدس) سيؤدي إلى وصول للمكدس خارج الحدود. .IP وبالمثل، عندما تُنشأ خريطة بـ \fIvalue_size\fP قدره 1 ويحتوي برنامج eBPF على .IP .in +4n .EX value = bpf_map_lookup_elem(...); *(u32 *) value = 1; .EE .in .IP سيُرفض البرنامج، لأنه يصل إلى مؤشر \fIvalue\fP بما يتجاوز حد 1 بايت لـ \fIvalue_size\fP المحدد. .IP حاليًا، القيم التالية مدعومة لـ \fImap_type\fP: .IP .in +4n .EX enum bpf_map_type { BPF_MAP_TYPE_UNSPEC, /* حجز 0 كنوع خريطة غير صالح */ BPF_MAP_TYPE_HASH, BPF_MAP_TYPE_ARRAY, BPF_MAP_TYPE_PROG_ARRAY, BPF_MAP_TYPE_PERF_EVENT_ARRAY, BPF_MAP_TYPE_PERCPU_HASH, BPF_MAP_TYPE_PERCPU_ARRAY, BPF_MAP_TYPE_STACK_TRACE, BPF_MAP_TYPE_CGROUP_ARRAY, BPF_MAP_TYPE_LRU_HASH, BPF_MAP_TYPE_LRU_PERCPU_HASH, BPF_MAP_TYPE_LPM_TRIE, BPF_MAP_TYPE_ARRAY_OF_MAPS, BPF_MAP_TYPE_HASH_OF_MAPS, BPF_MAP_TYPE_DEVMAP, BPF_MAP_TYPE_SOCKMAP, BPF_MAP_TYPE_CPUMAP, BPF_MAP_TYPE_XSKMAP, BPF_MAP_TYPE_SOCKHASH, BPF_MAP_TYPE_CGROUP_STORAGE, BPF_MAP_TYPE_REUSEPORT_SOCKARRAY, BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK, /* انظر /usr/include/linux/bpf.h للقائمة الكاملة. */ }; .EE .in .IP .\" FIXME We need an explanation of why one might choose each of .\" these map implementations يختار \fImap_type\fP أحد تطبيقات الخرائط المتاحة في النواة. بالنسبة لجميع أنواع الخرائط، تصل برامج eBPF إلى الخرائط باستخدام نفس الدوال المساعدة \fBbpf_map_lookup_elem\fP() و \fBbpf_map_update_elem\fP(). ترد مزيد من التفاصيل حول أنواع الخرائط المختلفة أدناه. .TP \fBBPF_MAP_LOOKUP_ELEM\fP يبحث الأمر \fBBPF_MAP_LOOKUP_ELEM\fP عن عنصر بـ \fIkey\fP معين في الخريطة التي يشير إليها واصف الملف \fIfd\fP. .IP .in +4n .EX int bpf_lookup_elem(int fd, const void *key, void *value) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), }; \& return bpf(BPF_MAP_LOOKUP_ELEM, &attr, sizeof(attr)); } .EE .in .IP إذا عُثر على عنصر، تُرجع العملية صفرًا وتخزن قيمة العنصر في \fIvalue\fP، والذي يجب أن يشير إلى مخزن مؤقت بحجم \fIvalue_size\fP بايت. .IP إذا لم يُعثر على أي عنصر، تُرجع العملية \-1 وتُضبط \fIerrno\fP على \fBENOENT\fP. .TP \fBBPF_MAP_UPDATE_ELEM\fP يُنشئ الأمر \fBBPF_MAP_UPDATE_ELEM\fP عنصرًا أو يحدثه بـ \fIkey/value\fP معطيين في الخريطة التي يشير إليها واصف الملف \fIfd\fP. .IP .in +4n .EX int bpf_update_elem(int fd, const void *key, const void *value, uint64_t flags) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .value = ptr_to_u64(value), .flags = flags, }; \& return bpf(BPF_MAP_UPDATE_ELEM, &attr, sizeof(attr)); } .EE .in .IP يجب تحديد المعطى \fIflags\fP كواحد مما يلي: .RS .TP \fBBPF_ANY\fP إنشاء عنصر جديد أو تحديث عنصر موجود. .TP \fBBPF_NOEXIST\fP أنشئ عنصراً جديداً فقط إذا لم يكن موجوداً. .TP \fBBPF_EXIST\fP حدّث عنصراً موجوداً بالفعل. .RE .IP عند النجاح، تُعيد العملية صفراً. عند حدوث خطأ، يُعاد \-1 ويُضبط \fIerrno\fP على \fBEINVAL\fP، أو \fBEPERM\fP، أو \fBENOMEM\fP، أو \fBE2BIG\fP. تشير \fBE2BIG\fP إلى أن عدد العناصر في الخريطة قد وصل إلى حد \fImax_entries\fP المحدد وقت إنشاء الخريطة. تُعاد \fBEEXIST\fP إذا حددت \fIflags\fP القيمة \fBBPF_NOEXIST\fP وكان العنصر ذو المفتاح \fIkey\fP موجوداً بالفعل في الخريطة. وتُعاد \fBENOENT\fP إذا حددت \fIflags\fP القيمة \fBBPF_EXIST\fP وكان العنصر ذو المفتاح \fIkey\fP غير موجود في الخريطة. .TP \fBBPF_MAP_DELETE_ELEM\fP يحذف الأمر \fBBPF_MAP_DELETE_ELEM\fP العنصر الذي مفتاحه \fIkey\fP من الخريطة المشار إليها بواسطة واصف الملف \fIfd\fP. .IP .in +4n .EX int bpf_delete_elem(int fd, const void *key) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), }; \& return bpf(BPF_MAP_DELETE_ELEM, &attr, sizeof(attr)); } .EE .in .IP عند النجاح، يُعاد صفر. إذا لم يُعثر على العنصر، يُعاد \-1 ويُضبط \fIerrno\fP على \fBENOENT\fP. .TP \fBBPF_MAP_GET_NEXT_KEY\fP يبحث الأمر \fBBPF_MAP_GET_NEXT_KEY\fP عن عنصر بواسطة \fIkey\fP في الخريطة المشار إليها بواسطة واصف الملف \fIfd\fP ويضبط مؤشر \fInext_key\fP على مفتاح العنصر التالي. .IP .in +4n .EX int bpf_get_next_key(int fd, const void *key, void *next_key) { union bpf_attr attr = { .map_fd = fd, .key = ptr_to_u64(key), .next_key = ptr_to_u64(next_key), }; \& return bpf(BPF_MAP_GET_NEXT_KEY, &attr, sizeof(attr)); } .EE .in .IP إذا وُجد \fIkey\fP، تُعيد العملية صفراً وتضبط مؤشر \fInext_key\fP على مفتاح العنصر التالي. إذا لم يُعثر على \fIkey\fP، تُعيد العملية صفراً وتضبط مؤشر \fInext_key\fP على مفتاح العنصر الأول. إذا كان \fIkey\fP هو العنصر الأخير، يُعاد \-1 ويُضبط \fIerrno\fP على \fBENOENT\fP. قيم \fIerrno\fP المحتملة الأخرى هي \fBENOMEM\fP و \fBEFAULT\fP و \fBEPERM\fP و \fBEINVAL\fP. يمكن استخدام هذا الأسلوب للتكرار عبر جميع العناصر في الخريطة. .TP \fBclose(map_fd)\fP .\" احذف الخريطة المشار إليها بواسطة واصف الملف \fImap_fd\fP. عندما يخرج برنامج مساحة المستخدم الذي أنشأ الخريطة، ستُحذف جميع الخرائط آلياً (لكن انظر الملاحظات NOTES). .SS "أنواع خرائط eBPF" أنواع الخرائط التالية مدعومة: .TP \fBBPF_MAP_TYPE_HASH\fP .\" commit 0f8e4bd8a1fc8c4185f1630061d0a1f2d197a475 تتميز خرائط جدول التجزئة (Hash\-table) بالخصائص التالية: .RS .IP \[bu] 3 تُنشأ الخرائط وتُدمر بواسطة برامج مساحة المستخدم. يمكن لكل من برامج مساحة المستخدم وبرامج eBPF إجراء عمليات البحث والتحديث والحذف. .IP \[bu] تتولى النواة مسؤولية تخصيص وتحرير أزواج المفتاح/القيمة. .IP \[bu] سيفشل المساعد \fBmap_update_elem\fP() في إدراج عنصر جديد عند الوصول إلى حد \fImax_entries\fP. (يضمن هذا عدم استنفاد برامج eBPF للذاكرة.) .IP \[bu] يستبدل \fBmap_update_elem\fP() العناصر الموجودة بشكل ذري. .RE .IP خُصصت خرائط جدول التجزئة لتكون محسنة لسرعة البحث. .TP \fBBPF_MAP_TYPE_ARRAY\fP .\" commit 28fbcfa08d8ed7c5a50d41a0433aad222835e8e3 تتميز خرائط المصفوفة (Array) بالخصائص التالية: .RS .IP \[bu] 3 خُصصت لتكون محسنة لأسرع بحث ممكن. في المستقبل، قد يتعرف المدقق أو مصرف JIT على عمليات lookup() التي تستخدم مفتاحاً ثابتاً ويحسنها إلى مؤشر ثابت. من الممكن أيضًا تحسين المفتاح غير الثابت إلى حسابات مؤشرات مباشرة، بما أن المؤشرات و \fIvalue_size\fP ثابتة طوال عمر برنامج eBPF. بمعنى آخر، قد يُضمن \fBarray_map_lookup_elem\fP() داخلياً بواسطة المدقق أو مصرف JIT مع الحفاظ على الوصول المتزامن لهذه الخريطة من مساحة المستخدم. .IP \[bu] جميع عناصر المصفوفة مخصصة مسبقاً ومصفرة عند التهيئة. .IP \[bu] المفتاح هو فهرس مصفوفة، ويجب أن يكون أربعة بايتات بالضبط. .IP \[bu] يفشل \fBmap_delete_elem\fP() بالخطأ \fBEINVAL\fP، حيث لا يمكن حذف العناصر. .IP \[bu] يستبدل \fBmap_update_elem\fP() العناصر بطريقة غير ذرية (nonatomic)؛ وللتحديثات الذرية، يجب استخدام خريطة جدول تجزئة بدلاً من ذلك. ومع ذلك، توجد حالة خاصة واحدة يمكن استخدامها أيضًا مع المصفوفات: يمكن استخدام البنية الذرية المدمجة \fB__sync_fetch_and_add()\fP على العدادات الذرية ذات 32 و 64 بت. على سبيل المثال، يمكن تطبيقها على القيمة بأكملها إذا كانت تمثل عداداً واحداً، أو في حالة وجود بنية تحتوي على عدادات متعددة، يمكن استخدامها على عدادات فردية. وهذا مفيد غالباً لتجميع وحساب الأحداث. .RE .IP من بين استخدامات خرائط المصفوفة ما يلي: .RS .IP \[bu] 3 كمتغيرات eBPF "عالمية": مصفوفة من عنصر واحد مفتاحها هو (الفهرس) 0 وتكون القيمة فيها عبارة عن مجموعة من المتغيرات 'العالمية' التي يمكن لبرامج eBPF استخدامها للحفاظ على الحالة بين الأحداث. .IP \[bu] تجميع أحداث التتبع في مجموعة ثابتة من السلال (buckets). .IP \[bu] حساب أحداث الشبكة، مثل عدد الحزم وأحجام الحزم. .RE .TP \fBBPF_MAP_TYPE_PROG_ARRAY\fP (منذ لينكس 4.2) خريطة مصفوفة البرامج هي نوع خاص من خرائط المصفوفة التي تحتوي قيمها فقط على واصفات ملفات تشير إلى برامج eBPF أخرى. وبالتالي، يجب أن يكون كل من \fIkey_size\fP و \fIvalue_size\fP أربعة بايتات بالضبط. تُستخدم هذه الخريطة بالاقتران مع المساعد \fBbpf_tail_call\fP(). .IP هذا يعني أن برنامج eBPF الذي أُرفقت به خريطة مصفوفة برامج يمكنه الاستدعاء من جانب النواة إلى .IP .in +4n .EX void bpf_tail_call(void *context, void *prog_map, unsigned int index); .EE .in .IP وبالتالي يستبدل تدفق البرنامج الخاص به بالتدفق الموجود في البرنامج عند فتحة مصفوفة البرامج المعطاة، إن وجد. يمكن اعتبار ذلك نوعاً من جدول القفز إلى برنامج eBPF مختلف. سيعيد البرنامج المُستدعى استخدام نفس المكدس. عند تنفيذ القفزة إلى البرنامج الجديد، لن يعود إلى البرنامج القديم مرة أخرى. .IP .\" MAX_TAIL_CALL_CNT إذا لم يُعثر على برنامج eBPF عند الفهرس المعطى لمصفوفة البرامج (بسبب عدم احتواء فتحة الخريطة على واصف ملف برنامج صالح، أو لأن فهرس/مفتاح البحث المحدد خارج النطاق، أو تجاوز حد 32 استدعاءً متداخلاً)، يستمر التنفيذ مع برنامج eBPF الحالي. يمكن استخدام ذلك كمسار احتياطي للحالات المبدئية. .IP .\" تعد خريطة مصفوفة البرامج مفيدة، على سبيل المثال، في التتبع أو الشبكات، للتعامل مع استدعاءات النظام أو البروتوكولات الفردية في برامجها الفرعية الخاصة واستخدام معرفاتها كفهرس خريطة فردي. قد يؤدي هذا النهج إلى فوائد في الأداء، كما يجعل من الممكن التغلب على الحد الأقصى للتعليمات لبرنامج eBPF واحد. في البيئات الديناميكية، قد يستبدل عفريت (daemon) مساحة المستخدم بشكل ذري البرامج الفرعية الفردية في وقت التشغيل بإصدارات أحدث لتغيير سلوك البرنامج العام، على سبيل المثال، إذا تغيرت السياسات العالمية. .SS "برامج eBPF" يُستخدم الأمر \fBBPF_PROG_LOAD\fP لتحميل برنامج eBPF في النواة. القيمة المعادة لهذا الأمر هي واصف ملف جديد مرتبط ببرنامج eBPF هذا. .P .in +4n .EX char bpf_log_buf[LOG_BUF_SIZE]; \& int bpf_prog_load(enum bpf_prog_type type, const struct bpf_insn *insns, int insn_cnt, const char *license) { union bpf_attr attr = { .prog_type = type, .insns = ptr_to_u64(insns), .insn_cnt = insn_cnt, .license = ptr_to_u64(license), .log_buf = ptr_to_u64(bpf_log_buf), .log_size = LOG_BUF_SIZE, .log_level = 1, }; \& return bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); } .EE .in .P يكون \fIprog_type\fP واحداً من أنواع البرامج المتاحة: .IP .in +4n .EX enum bpf_prog_type { BPF_PROG_TYPE_UNSPEC, /* حجز 0 كنوع برنامج غير صالح */ BPF_PROG_TYPE_SOCKET_FILTER, BPF_PROG_TYPE_KPROBE, BPF_PROG_TYPE_SCHED_CLS, BPF_PROG_TYPE_SCHED_ACT, BPF_PROG_TYPE_TRACEPOINT, BPF_PROG_TYPE_XDP, BPF_PROG_TYPE_PERF_EVENT, BPF_PROG_TYPE_CGROUP_SKB, BPF_PROG_TYPE_CGROUP_SOCK, BPF_PROG_TYPE_LWT_IN, BPF_PROG_TYPE_LWT_OUT, BPF_PROG_TYPE_LWT_XMIT, BPF_PROG_TYPE_SOCK_OPS, BPF_PROG_TYPE_SK_SKB, BPF_PROG_TYPE_CGROUP_DEVICE, BPF_PROG_TYPE_SK_MSG, BPF_PROG_TYPE_RAW_TRACEPOINT, BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_PROG_TYPE_LIRC_MODE2, BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, /* انظر /usr/include/linux/bpf.h للقائمة الكاملة. */ }; .EE .in .P لمزيد من التفاصيل حول أنواع برامج eBPF، انظر أدناه. .P تُضبط الحقول المتبقية من \fIbpf_attr\fP على النحو التالي: .IP \[bu] 3 \fIinsns\fP عبارة عن مصفوفة من تعليمات \fIstruct bpf_insn\fP. .IP \[bu] \fIinsn_cnt\fP هو عدد التعليمات في البرنامج المشار إليه بواسطة \fIinsns\fP. .IP \[bu] \fIlicense\fP هي سلسلة الترخيص، والتي يجب أن تكون متوافقة مع GPL لاستدعاء الدوال المساعدة المميزة بـ \fIgpl_only\fP. (قواعد الترخيص هي نفسها المتبعة في وحدات النواة، لذا يمكن أيضًا استخدام التراخيص المزدوجة، مثل "Dual BSD/GPL".) .IP \[bu] \fIlog_buf\fP هو مؤشر إلى مخزن مؤقت خصصه المستدعِي (caller) حيث يمكن لمدقق داخل النواة تخزين سجل التحقق فيه. هذا السجل عبارة عن سلسلة متعددة الأسطر يمكن لمؤلف البرنامج فحصها لفهم كيف توصل المدقق إلى استنتاج مفاده أن برنامج eBPF غير آمن. قد يتغير تنسيق المخرجات في أي وقت مع تطور المدقق. .IP \[bu] \fIlog_size\fP هو حجم المخزن المؤقت الذي يشير إليه \fIlog_buf\fP. إذا لم يكن حجم المخزن المؤقت كبيراً بما يكفي لتخزين جميع رسائل المدقق، يُعاد \-1 ويُضبط \fIerrno\fP على \fBENOSPC\fP. .IP \[bu] \fIlog_level\fP هو مستوى إسهاب المدقق. تعني القيمة صفر أن المدقق لن يقدم سجلاً؛ في هذه الحالة، يجب أن يكون \fIlog_buf\fP مؤشراً فارغاً (null)، ويجب أن يكون \fIlog_size\fP صفراً. .P يؤدي تطبيق \fBclose\fP(2) على واصف الملف المعاد بواسطة \fBBPF_PROG_LOAD\fP إلى إلغاء تحميل برنامج eBPF (ولكن انظر الملاحظات NOTES). .P .\" .\" يمكن الوصول إلى الخرائط من برامج eBPF وتُستخدم لتبادل البيانات بين برامج eBPF وبين برامج eBPF وبرامج مساحة المستخدم. على سبيل المثال، يمكن لبرامج eBPF معالجة أحداث مختلفة (مثل kprobe والحزم) وتخزين بياناتها في خريطة، ومن ثم يمكن لبرامج مساحة المستخدم جلب البيانات من الخريطة. وعلى العكس، يمكن لبرامج مساحة المستخدم استخدام الخريطة كآلية ضبط، فتملأ الخريطة بالقيم التي يفحصها برنامج eBPF، والذي يعدل سلوكه بعد ذلك أثناء التشغيل وفقاً لتلك القيم. .SS "أنواع برامج eBPF" .\" .\" FIXME .\" Somewhere in this page we need a general introduction to the .\" bpf_context. For example, how does a BPF program access the .\" context? يحدد نوع برنامج eBPF (\fIprog_type\fP) المجموعة الفرعية من الدوال المساعدة للنواة التي قد يستدعيها البرنامج. كما يحدد نوع البرنامج مدخلات البرنامج (السياق) — تنسيق \fIstruct bpf_context\fP (وهو كتلة البيانات الممررة إلى برنامج eBPF كمعامل أول). .P على سبيل المثال، لا يمتلك برنامج التتبع نفس المجموعة الفرعية من الدوال المساعدة التي يمتلكها برنامج مرشح المقبس (على الرغم من أنه قد يكون بينهما بعض المساعدات المشتركة). وبالمثل، فإن المدخلات (السياق) لبرنامج التتبع هي مجموعة من قيم المسجلات، بينما لمرشح المقبس هي حزمة شبكة. .P قد تزداد مجموعة الدوال المتاحة لبرامج eBPF من نوع معين في المستقبل. .P أنواع البرامج التالية مدعومة: .TP \fBBPF_PROG_TYPE_SOCKET_FILTER\fP (منذ لينكس 3.19) حالياً، مجموعة الدوال لـ \fBBPF_PROG_TYPE_SOCKET_FILTER\fP هي: .IP .in +4n .EX bpf_map_lookup_elem(map_fd, void *key) /* ابحث عن مفتاح في map_fd */ bpf_map_update_elem(map_fd, void *key, void *value) /* حدّث المفتاح/القيمة */ bpf_map_delete_elem(map_fd, void *key) /* احذف مفتاحاً في map_fd */ .EE .in .IP .\" FIXME: We need some text here to explain how the program .\" accesses __sk_buff. .\" See 'struct __sk_buff' and commit 9bac3d6d548e5 .\" .\" Alexei commented: .\" Actually now in case of SOCKET_FILTER, SCHED_CLS, SCHED_ACT .\" the program can now access skb fields. .\" المعامل \fIbpf_context\fP هو مؤشر إلى \fIstruct __sk_buff\fP. .TP \fBBPF_PROG_TYPE_KPROBE\fP (منذ لينكس 4.1) .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type .\" .\" FIXME We need text here to describe 'kern_version' [سيُوثّق] .TP \fBBPF_PROG_TYPE_SCHED_CLS\fP (منذ لينكس 4.1) .\" commit 96be4325f443dbbfeb37d2a157675ac0736531a1 .\" commit e2e9b6541dd4b31848079da80fe2253daaafb549 .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type [سيُوثّق] .TP \fBBPF_PROG_TYPE_SCHED_ACT\fP (منذ لينكس 4.1) .\" commit 94caee8c312d96522bcdae88791aaa9ebcd5f22c .\" commit a8cb5f556b567974d75ea29c15181c445c541b1f .\" FIXME Document this program type .\" Describe allowed helper functions for this program type .\" Describe bpf_context for this program type [سيُوثّق] .SS أحداث بمجرد تحميل البرنامج، يمكن إرفاقه بحدث ما. تتبع الأنظمة الفرعية المختلفة للنواة طرقاً متباينة للقيام بذلك. .P .\" commit 89aa075832b0da4402acebd698d0411dcc82d03e بدءًا من لينكس 3.19، سيقوم الاستدعاء التالي بربط البرنامج \fIprog_fd\fP بالمقبس \fIsockfd\fP، الذي أُنشئ عبر استدعاء سابق لـ \fBsocket\fP(2): .P .in +4n .EX setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)); .EE .in .P .\" commit 2541517c32be2531e0da59dfd7efc1ce844644f5 بدءًا من لينكس 4.1، يمكن استخدام الاستدعاء التالي لربط برنامج eBPF المشار إليه بواسطة واصف الملف \fIprog_fd\fP بواصف ملف حدث perf، \fIevent_fd\fP، الذي أُنشئ عبر استدعاء سابق لـ \fBperf_event_open\fP(2): .P .in +4n .EX ioctl(event_fd, PERF_EVENT_IOC_SET_BPF, prog_fd); .EE .in .\" .\" .SH "قيمة الإرجاع" في حالة الاستدعاء الناجح، تعتمد قيمة الإرجاع على العملية: .TP \fBBPF_MAP_CREATE\fP واصف الملف الجديد المرتبط بخريطة eBPF. .TP \fBBPF_PROG_LOAD\fP واصف الملف الجديد المرتبط ببرنامج eBPF. .TP كل الأوامر الأخرى صفر. .P عند الخطأ، تُعاد القيمة \-1، ويُضبط \fIerrno\fP للإشارة إلى الخطأ. .SH الأخطاء .TP \fBE2BIG\fP برنامج eBPF كبير جدًا أو وصلت الخريطة إلى حد \fImax_entries\fP (العدد الأقصى للعناصر). .TP \fBEACCES\fP بالنسبة لـ \fBBPF_PROG_LOAD\fP، وعلى الرغم من أن جميع تعليمات البرنامج صالحة، إلا أنه رُفض لأنه اعتبر غير آمن. قد يكون ذلك بسبب وصوله إلى منطقة ذاكرة غير مسموح بها أو مكدس/سجل غير مهيأ، أو لأن قيود الدالة لا تطابق الأنواع الفعلية، أو بسبب وجود وصول غير محاذٍ للذاكرة. في هذه الحالة، يُنصح باستدعاء \fBbpf\fP() مجددًا مع ضبط \fIlog_level = 1\fP وفحص \fIlog_buf\fP لمعرفة السبب المحدد الذي قدمه المدقق. .TP \fBEAGAIN\fP بالنسبة لـ \fBBPF_PROG_LOAD\fP، يشير هذا إلى أن الموارد المطلوبة محجوبة. يحدث هذا عندما يكتشف المدقق إشارات معلقة أثناء فحصه لصلاحية برنامج bpf. في هذه الحالة، ما عليك سوى استدعاء \fBbpf\fP() مجددًا بنفس المعاملات. .TP \fBEBADF\fP \fIfd\fP ليس واصف ملف مفتوح. .TP \fBEFAULT\fP أحد المؤشرات (\fIkey\fP أو \fIvalue\fP أو \fIlog_buf\fP أو \fIinsns\fP) يقع خارج مساحة العناوين التي يمكن الوصول إليها. .TP \fBEINVAL\fP القيمة المحددة في \fIcmd\fP غير معروفة لهذه النواة. .TP \fBEINVAL\fP بالنسبة لـ \fBBPF_MAP_CREATE\fP، إما \fImap_type\fP أو السمات غير صالحة. .TP \fBEINVAL\fP بالنسبة لأوامر \fBBPF_MAP_*_ELEM\fP، بعض حقول \fIunion bpf_attr\fP التي لا يستخدمها هذا الأمر لم تُضبط على صفر. .TP \fBEINVAL\fP بالنسبة لـ \fBBPF_PROG_LOAD\fP، يشير إلى محاولة تحميل برنامج غير صالح. يمكن اعتبار برامج eBPF غير صالحة بسبب تعليمات غير معروفة، أو استخدام حقول محجوزة، أو قفزات خارج النطاق، أو حلقات لانهائية، أو استدعاء دوال مجهولة. .TP \fBENOENT\fP بالنسبة لأوامر \fBBPF_MAP_LOOKUP_ELEM\fP أو \fBBPF_MAP_DELETE_ELEM\fP، يشير إلى أن العنصر ذا المفتاح \fIkey\fP المعطى لم يُعثر عليه. .TP \fBENOMEM\fP تعذر تخصيص ذاكرة كافية. .TP \fBEPERM\fP أُجري الاستدعاء دون امتياز كافٍ (بدون قدرة \fBCAP_SYS_ADMIN\fP). .SH المعايير لينكس. .SH التاريخ لينكس 3.18. .SH ملاحظات .\" commit 1be7f75d1668d6296b80bf35dcf6762393530afc .\" [Linux 5.6] mtk: The list of available functions is, I think, governed .\" by the check in net/core/filter.c::bpf_base_func_proto(). قبل لينكس 4.4، كانت جميع أوامر \fBbpf\fP() تتطلب أن يمتلك المستدعِي قدرة \fBCAP_SYS_ADMIN\fP. بدءًا من لينكس 4.4 فصاعدًا، قد يقوم مستخدم غير ممتلك للامتيازات بإنشاء برامج محدودة من النوع \fBBPF_PROG_TYPE_SOCKET_FILTER\fP والخرائط المرتبطة بها. ومع ذلك، لا يجوز لهم تخزين مؤشرات النواة داخل الخرائط وهم مقيدون حاليًا بدوال المساعدة التالية: .IP \[bu] 3 get_random .PD 0 .IP \[bu] get_smp_processor_id .IP \[bu] tail_call .IP \[bu] ktime_get_ns .PD .P يمكن حظر وصول غير ذوي الامتيازات عبر كتابة القيمة 1 إلى الملف \fI/proc/sys/kernel/unprivileged_bpf_disabled\fP. .P يمكن مشاركة كائنات eBPF (الخرائط والبرامج) بين العمليات. على سبيل المثال، بعد \fBfork\fP(2)، يرث الابن واصفات الملفات التي تشير إلى نفس كائنات eBPF. بالإضافة إلى ذلك، يمكن نقل واصفات الملفات التي تشير إلى كائنات eBPF عبر مقابس نطاق يونكس. كما يمكن مضاهاة واصفات الملفات التي تشير إلى كائنات eBPF بالطريقة المعتادة، باستخدام \fBdup\fP(2) والاستدعاءات المماثلة. يُحرر تخصيص كائن eBPF فقط بعد إغلاق جميع واصفات الملفات التي تشير إلى ذلك الكائن. .P .\" There are also examples for the tc classifier, in the iproute2 .\" project, in examples/bpf يمكن كتابة برامج eBPF بلغة C مقيدة تُصرَّف (باستخدام مصرِّف \fBclang\fP) إلى رمز بايتات (bytecode) لـ eBPF. حُذفت ميزات متنوعة من لغة C المقيدة هذه، مثل الحلقات، والمتغيرات العامة، والدوال متنوعة المعاملات، والأعداد ذات الفاصلة العائمة، وتمرير الهياكل كمعاملات للدوال. يمكن العثور على بعض الأمثلة في ملفات \fIsamples/bpf/*_kern.c\fP في شجرة مصادر النواة. .P تحتوي النواة على مصرِّف في الوقت المناسب (JIT) يترجم رمز بايتات eBPF إلى رمز آلة أصيل للحصول على أداء أفضل. قبل لينكس 4.15، كان مصرِّف JIT معطلاً بشكل مبدئي، ولكن يمكن التحكم في عمله عبر كتابة إحدى السلاسل الصحيحة التالية إلى الملف \fI/proc/sys/net/core/bpf_jit_enable\fP: .TP \fB0\fP تعطيل تصريف JIT (مبدئي). .TP \fB1\fP تصريف عادي. .TP \fB2\fP وضع التنقيح. تُفرغ رموز العمليات (opcodes) المولدة بصيغة ست عشرية في سجل النواة. يمكن بعد ذلك تفكيك هذه الرموز باستخدام البرنامج \fItools/net/bpf_jit_disasm.c\fP المتوفر في شجرة مصادر النواة. .P .\" commit 290af86629b25ffd1ed6232c4e9107da031705cb بدءًا من لينكس 4.15، قد تُضبط النواة مع الخيار \fBCONFIG_BPF_JIT_ALWAYS_ON\fP. في هذه الحالة، يكون مصرِّف JIT مفعلاً دائمًا، ويُهيأ \fIbpf_jit_enable\fP إلى القيمة 1 ويكون غير قابل للتغيير. (وُفر خيار ضبط النواة هذا كتخفيف لإحدى هجمات Spectre ضد مفسر BPF.) .P يتوفر مصرِّف JIT لـ eBPF حاليًا للمعماريت التالية: .IP \[bu] 3 .\" commit 0a14842f5a3c0e88a1e59fac5c3025db39721f74 x86\-64 (منذ لينكس 3.18؛ cBPF منذ لينكس 3.0)؛ .PD 0 .IP \[bu] .\" commit ddecdfcea0ae891f782ae853771c867ab51024c2 ARM32 (منذ لينكس 3.18؛ cBPF منذ لينكس 3.4)؛ .IP \[bu] .\" commit 2809a2087cc44b55e4377d7b9be3f7f5d2569091 SPARC 32 (منذ لينكس 3.18؛ cBPF منذ لينكس 3.5)؛ .IP \[bu] .\" commit e54bcde3d69d40023ae77727213d14f920eb264a ARM\-64 (منذ لينكس 3.18)؛ .IP \[bu] .\" commit c10302efe569bfd646b4c22df29577a4595b4580 s390 (منذ لينكس 4.1؛ cBPF منذ لينكس 3.7)؛ .IP \[bu] .\" commit 0ca87f05ba8bdc6791c14878464efc901ad71e99 .\" commit 156d0e290e969caba25f1851c52417c14d141b24 PowerPC 64 (منذ لينكس 4.8؛ cBPF منذ لينكس 3.1)؛ .IP \[bu] .\" commit 7a12b5031c6b947cc13918237ae652b536243b76 SPARC 64 (منذ لينكس 4.12)؛ .IP \[bu] .\" commit 03f5781be2c7b7e728d724ac70ba10799cc710d7 x86\-32 (منذ لينكس 4.18)؛ .IP \[bu] .\" commit c6610de353da5ca6eee5b8960e838a87a90ead0c .\" commit f381bf6d82f032b7410185b35d000ea370ac706b MIPS 64 (منذ لينكس 4.18؛ cBPF منذ لينكس 3.16)؛ .IP \[bu] .\" commit 2353ecc6f91fd15b893fa01bf85a1c7a823ee4f2 riscv (منذ لينكس 5.1). .PD .SH أمثلة .\" SRC BEGIN (bpf.c) .EX .\" == atomic64_add #include \& /* bpf+sockets example: * 1. create array map of 256 elements * 2. load program that counts number of packets received * r0 = skb\->data[ETH_HLEN + offsetof(struct iphdr, protocol)] * map[r0]++ * 3. attach prog_fd to raw socket via setsockopt() * 4. print number of received TCP/UDP packets every second */ int main(int argc, char *argv[]) { int sock, map_fd, prog_fd, key; long long value = 0, tcp_cnt, udp_cnt; \& map_fd = bpf_create_map(BPF_MAP_TYPE_ARRAY, sizeof(key), sizeof(value), 256); if (map_fd < 0) { printf("failed to create map \[aq]%s\[aq]\[rs]n", strerror(errno)); /* likely not run as root */ return 1; } \& struct bpf_insn prog[] = { BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* r6 = r1 */ BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol)), /* r0 = ip\->proto */ BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, \-4), /* *(u32 *) (fp \- 4) = r0 */ BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), /* r2 = fp */ BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, \-4), /* r2 = r2 \- 4 */ BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* r1 = map_fd */ BPF_CALL_FUNC(BPF_FUNC_map_lookup_elem), /* r0 = map_lookup(r1, r2) */ BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), /* if (r0 == 0) goto pc+2 */ BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ BPF_XADD(BPF_DW, BPF_REG_0, BPF_REG_1, 0, 0), /* lock *(u64 *) r0 += r1 */ BPF_MOV64_IMM(BPF_REG_0, 0), /* r0 = 0 */ BPF_EXIT_INSN(), /* return r0 */ }; \& prog_fd = bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, prog, countof(prog), "GPL"); \& sock = open_raw_sock("lo"); \& assert(setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)) == 0); \& for (;;) { key = IPPROTO_TCP; assert(bpf_lookup_elem(map_fd, &key, &tcp_cnt) == 0); key = IPPROTO_UDP; assert(bpf_lookup_elem(map_fd, &key, &udp_cnt) == 0); printf("TCP %lld UDP %lld packets\[rs]n", tcp_cnt, udp_cnt); sleep(1); } \& return 0; } .EE .\" SRC END .P يمكن العثور على بعض الأكواد العاملة الكاملة في دليل \fIsamples/bpf\fP في شجرة مصادر النواة. .SH "انظر أيضًا" \fBseccomp\fP(2), \fBbpf\-helpers\fP(7), \fBsocket\fP(7), \fBtc\fP(8), \fBtc\-bpf\fP(8) .P شُرح كل من BPF التقليدي والممتد في ملف مصدر النواة \fIDocumentation/networking/filter.rst\fP. .PP .SH ترجمة تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي . .PP هذه الترجمة هي وثيقة مجانية؛ راجع .UR https://www.gnu.org/licenses/gpl-3.0.html رخصة جنو العامة الإصدار 3 .UE أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات. .PP إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: .MT kde-l10n-ar@kde.org .ME .