connectivity/networking/api/net_l2.html · connectivity/networking/api/net_l2.rst 공식 원문 ↗

Zephyr 3.7.0 · Connectivity · Networking API

L2 Layer Management

net_if 경계에서 upper stack을 driver detail과 분리하고 link별 송수신 계약을 정의합니다.

Official pathconnectivity/networking/api/net_l2.html
Source fileconnectivity/networking/api/net_l2.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

Part 1

요약·해설

Generic recv/send API, Ethernet driver flow, 802.15.4 fragmentation과 L1↔L2 adaptation contract를 설명합니다.

Boundary

net_if · net_l2

Ethernet

Whole packet

802.15.4

Fragment · Compress · Radio TX

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 B3A5D72343386ACA15D031D23D3045A51CFA462D8B5932CFF67CC81F34229A14
.. _net_l2_interface:

L2 Layer Management
###################

.. contents::
    :local:
    :depth: 2

Overview
********

The L2 stack is designed to hide the whole networking link-layer part
and the related device drivers from the upper network stack. This is made
through a :c:struct:`net_if` declared in
:zephyr_file:`include/zephyr/net/net_if.h`.

The upper layers are unaware of implementation details beyond the net_if
object and the generic API provided by the L2 layer in
:zephyr_file:`include/zephyr/net/net_l2.h` as :c:struct:`net_l2`.

Only the L2 layer can talk to the device driver, linked to the net_if
object. The L2 layer dictates the API provided by the device driver,
specific for that device, and optimized for working together.

Currently, there are L2 layers for :ref:`Ethernet <ethernet_interface>`,
:ref:`IEEE 802.15.4 Soft-MAC <ieee802154_interface>`, :ref:`CANBUS <can_api>`,
:ref:`OpenThread <thread_protocol_interface>`, Wi-Fi, and a dummy layer example
that can be used as a template for writing a new one.

L2 layer API
************

In order to create an L2 layer, or a driver for a specific L2 layer,
one needs to understand how the L3 layer interacts with it and
how the L2 layer is supposed to behave.
See also :ref:`network stack architecture <network_stack_architecture>` for
more details. The generic L2 API has these functions:

- ``recv()``: All device drivers, once they receive a packet which they put
  into a :c:type:`net_pkt`, will push this buffer to the network
  stack via :c:func:`net_recv_data`. At this point, the network
  stack does not know what to do with it. Instead, it passes the
  buffer along to the L2 stack's ``recv()`` function for handling.
  The L2 stack does what it needs to do with the packet, for example, parsing
  the link layer header, or handling link-layer only packets. The ``recv()``
  function will return ``NET_DROP`` in case of an erroneous packet,
  ``NET_OK`` if the packet was fully consumed by the L2, or ``NET_CONTINUE``
  if the network stack should then handle it.

- ``send()``: Similar to receive function, the network stack will call this
  function to actually send a network packet. All relevant link-layer content
  will be generated and added by this function.
  The ``send()`` function returns the number of bytes sent, or a negative
  error code if there was a failure sending the network packet.

- ``enable()``: This function is used to enable/disable traffic over a network
  interface. The function returns ``<0`` if error and ``>=0`` if no error.

- ``get_flags()``: This function will return the capabilities of an L2 driver,
  for example whether the L2 supports multicast or promiscuous mode.

Network Device drivers
**********************

Network device drivers fully follows Zephyr device driver model as a
basis. Please refer to :ref:`device_model_api`.

There are, however, two differences:

- The driver_api pointer must point to a valid :c:struct:`net_if_api`
  pointer.

- The network device driver must use :c:macro:`NET_DEVICE_INIT_INSTANCE()`
  or :c:macro:`ETH_NET_DEVICE_INIT()` for Ethernet devices. These
  macros will call the :c:macro:`DEVICE_DEFINE()` macro, and also
  instantiate a unique :c:struct:`net_if` related to the created
  device driver instance.

Implementing a network device driver depends on the L2 stack it
belongs to: :ref:`Ethernet <ethernet_interface>`,
:ref:`IEEE 802.15.4 <ieee802154_interface>`, etc.
In the next section, we will describe how a device driver should behave when
receiving or sending a network packet. The rest is hardware dependent
and is not detailed here.

Ethernet device driver
======================

On reception, it is up to the device driver to fill-in the network packet with
as many data buffers as required. The network packet itself is a
:c:type:`net_pkt` and should be allocated through
:c:func:`net_pkt_rx_alloc_with_buffer`. Then all data buffers will be
automatically allocated and filled by :c:func:`net_pkt_write`.

After all the network data has been received, the device driver needs to
call :c:func:`net_recv_data`. If that call fails, it will be up to the
device driver to unreference the buffer via :c:func:`net_pkt_unref`.

On sending, the device driver send function will be called, and it is up to
the device driver to send the network packet all at once, with all the buffers.

Each Ethernet device driver will need, in the end, to call
``ETH_NET_DEVICE_INIT()`` like this:

.. code-block:: c

   ETH_NET_DEVICE_INIT(..., CONFIG_ETH_INIT_PRIORITY,
                       &the_valid_net_if_api_instance, 1500);

IEEE 802.15.4 device driver
===========================

Device drivers for IEEE 802.15.4 L2 work basically the same as for
Ethernet. What has been described above, especially for ``recv()``, applies
here as well. There are two specific differences however:

- It requires a dedicated device driver API: :c:struct:`ieee802154_radio_api`,
  which overloads :c:struct:`net_if_api`. This is because 802.15.4 L2 needs more from the device
  driver than just ``send()`` and ``recv()`` functions.  This dedicated API is
  declared in :zephyr_file:`include/zephyr/net/ieee802154_radio.h`. Each and every
  IEEE 802.15.4 device driver must provide a valid pointer on such
  relevantly filled-in API structure.

- Sending a packet is slightly different than in Ethernet. Most IEEE 802.15.4
  PHYs support relatively small frames only, 127 bytes all inclusive: frame
  header, payload and frame checksum. Buffers to be sent over the radio will
  often not fit this frame size limitation, e.g. a buffer containing an IPv6
  packet will often have to be split into several fragments and IP6 packet headers
  and fragments need to be compressed using a protocol like 6LoWPAN before being
  passed on to the radio driver. Additionally the IEEE 802.15.4 standard defines
  medium access (e.g. CSMA/CA), frame retransmission, encryption and other pre-
  processing procedures (e.g. addition of information elements) that individual
  radio drivers should not have to care about. This is why the
  :c:struct:`ieee802154_radio_api` requires a tx function pointer which differs
  from the :c:struct:`net_if_api` send function pointer. Zephyr's native
  IEEE 802.15.4 L2 implementation provides a generic :c:func:`ieee802154_send`
  instead, meant to be given as :c:type:`net_if` send function. The implementation
  of :c:func:`ieee802154_send` takes care of IEEE 802.15.4 standard packet
  preparation procedures, splitting the packet into possibly compressed,
  encrypted and otherwise pre-processed fragment buffers, sending one buffer
  at a time through :c:type:`ieee802154_radio_api` tx function and unreferencing
  the network packet only when the transmission as a whole was either successful
  or failed.

Interaction between IEEE 802.15.4 radio device drivers and L2 is bidirectional:

- L2 -> L1: Methods as :c:func:`ieee802154_send` and several IEEE 802.15.4 net
  management calls will call into the driver, e.g. to send a packet over the
  radio link or re-configure the driver at runtime. These incoming calls will
  all be handled by the methods in the :c:type:`ieee802154_radio_api`.

- L1 -> L2: There are several situations in which the driver needs to initiate
  calls into the L2/MAC layer. Zephyr's IEEE 802.15.4 L1 -> L2 adaptation API
  employs an "inversion-of-control" pattern in such cases avoids duplication of
  complex logic across independent driver implementations and ensures
  implementation agnostic loose coupling and clean separation of concerns between
  MAC (L2) and PHY (L1) whenever reverse information transfer or close co-operation
  between hardware and L2 is required. During driver initialization, for example,
  the driver calls :c:func:`ieee802154_init` to pass the interface's MAC address
  as well as other hardware-related configuration to L2. Similarly, drivers may
  indicate performance or timing critical radio events to L2 that require close
  integration with the hardware (e.g. :c:func:`ieee802154_handle_ack`). Calls
  from L1 into L2 are not implemented as methods in :c:type:`ieee802154_radio_api`
  but are standalone functions declared and documented as such in
  :zephyr_file:`include/zephyr/net/ieee802154_radio.h`. The API documentation will
  clearly state which functions must be implemented by all L2 stacks as part
  of the L1 -> L2 "inversion-of-control" adaptation API.

Note: Standalone functions in :zephyr_file:`include/zephyr/net/ieee802154_radio.h`
that are not explicitly documented as callbacks are considered to be helper functions
within the PHY (L1) layer implemented independently of any specific L2 stack, see for
example :c:func:`ieee802154_is_ar_flag_set`.

As all net interfaces, IEEE 802.15.4 device driver implementations will have to call
``NET_DEVICE_INIT_INSTANCE()`` in the end:

.. code-block:: c

   NET_DEVICE_INIT_INSTANCE(...,
                            the_device_init_prio,
			    &the_valid_ieee802154_radio_api_instance,
			    IEEE802154_L2,
			    NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);

API Reference
*************

.. doxygengroup:: net_l2

Part 3

한국어 전문 번역

L2 Layer Management

Overview

L2 stack은 networking link-layer 전체와 관련 device driver를 upper network stack에서 숨기도록 설계됐습니다. include/zephyr/net/net_if.h의 net_if structure가 이 경계를 만듭니다.

Upper layer는 net_if object와 include/zephyr/net/net_l2.h의 net_l2 generic API 바깥의 implementation detail을 알지 못합니다.

Device driver는 net_if object에 연결되고 L2 layer만 driver와 통신합니다. L2 layer가 해당 device에 맞고 함께 동작하도록 최적화된 driver API를 규정합니다.

현재 Ethernet, IEEE 802.15.4 Soft-MAC, CANBUS, OpenThread, Wi-Fi용 L2 layer가 있으며 새 layer 작성 template로 사용할 dummy layer example도 있습니다.

L2 layer API

L2 layer나 특정 L2 driver를 만들려면 L3 layer와의 interaction 및 L2의 expected behavior를 이해해야 합니다. Generic L2 API 함수는 다음과 같습니다.

  • recv():Device driver가 받은 packet을 net_pkt에 넣고 net_recv_data()로 stack에 올리면 network stack은 L2의 recv()에 전달합니다. L2는 link-layer header parse나 L2-only packet 처리를 수행합니다. Error packet이면 NET_DROP, L2가 완전히 소비했으면 NET_OK, 이후 network stack 처리가 필요하면 NET_CONTINUE를 반환합니다.
  • send():Network stack이 실제 packet 송신을 요청합니다. 필요한 모든 link-layer content를 만들고 추가하며, 보낸 byte 수 또는 실패 시 음수 error code를 반환합니다.
  • enable():Network interface traffic을 enable·disable합니다. Error이면 <0, error가 없으면 >=0을 반환합니다.
  • get_flags():Multicast나 promiscuous mode 같은 L2 driver capability를 반환합니다.

Network Device drivers

Network device driver는 Zephyr device-driver model을 기본으로 그대로 따르지만 두 가지 차이가 있습니다.

  • driver_api pointer가 유효한 net_if_api structure를 가리켜야 합니다.
  • Network device driver는 NET_DEVICE_INIT_INSTANCE()를 사용하고 Ethernet device는 ETH_NET_DEVICE_INIT()을 사용해야 합니다. 이 macro는 DEVICE_DEFINE()을 호출하는 동시에 생성된 driver instance에 연결된 고유 net_if를 instantiate합니다.

Network device driver 구현은 속한 L2 stack에 따라 달라집니다. 다음 설명은 packet 수신·송신 시 driver behavior이며 나머지는 hardware에 의존합니다.

Ethernet device driver

net_pkt_rx_alloc_with_buffer()로 수신 net_pkt을 할당하고 필요한 수만큼 data buffer를 채우는 책임은 driver에 있습니다. net_pkt_write()가 data buffer를 자동 할당하고 채웁니다.

Network data를 모두 받은 뒤 net_recv_data()를 호출합니다. 호출 실패 시 driver가 net_pkt_unref()로 buffer reference를 해제해야 합니다.

송신 시 driver send function이 호출되며 driver는 모든 buffer를 포함한 network packet 전체를 한 번에 보내야 합니다.

각 Ethernet driver는 마지막에 다음과 같이 ETH_NET_DEVICE_INIT()을 호출합니다.

ETH_NET_DEVICE_INIT(..., CONFIG_ETH_INIT_PRIORITY,
                    &the_valid_net_if_api_instance, 1500);

IEEE 802.15.4 device driver

recv()를 포함한 기본 동작은 Ethernet과 같지만 두 가지 차이가 있습니다.

  • net_if_api를 확장한 전용 ieee802154_radio_api가 필요합니다. 802.15.4 L2가 send()·recv()보다 많은 driver 기능을 요구하기 때문입니다. API는 include/zephyr/net/ieee802154_radio.h에 있고 모든 802.15.4 driver가 채워진 structure의 유효 pointer를 제공해야 합니다.
  • 송신 방식이 Ethernet과 다릅니다. 대부분의 802.15.4 PHY는 header·payload·checksum을 모두 합쳐 127-byte frame만 지원합니다. IPv6 packet 같은 큰 buffer는 여러 fragment로 나누고 6LoWPAN 같은 protocol로 IPv6 header와 fragment를 compress해야 합니다. CSMA/CA, retransmission, encryption, information element 추가 같은 preprocessing도 개별 radio driver가 담당하지 않아야 합니다.

ieee802154_radio_api의 tx function pointer가 net_if_api send와 다른 이유가 여기에 있습니다. Native L2의 generic ieee802154_send()가 net_if send function으로 동작해 표준 packet preparation, compression·encryption·fragmentation을 수행하고 radio API tx로 buffer를 하나씩 보냅니다. 전체 전송 성공 또는 실패가 확정된 뒤에만 network packet reference를 해제합니다.

IEEE 802.15.4 radio driver와 L2의 interaction은 양방향입니다.

  • L2 → L1:ieee802154_send()와 network-management call이 packet 송신이나 runtime reconfiguration을 위해 driver를 호출합니다. ieee802154_radio_api method가 처리합니다.
  • L1 → L2:Driver가 L2/MAC call을 시작해야 하는 상황에는 inversion-of-control adaptation API를 사용합니다. Driver마다 복잡한 logic을 중복하지 않고 MAC(L2)과 PHY(L1)를 느슨하게 결합합니다. Initialization 때 ieee802154_init()으로 MAC address와 hardware configuration을 L2에 전달하고 ieee802154_handle_ack() 같은 함수로 timing-critical radio event를 알릴 수 있습니다.

L1→L2 call은 ieee802154_radio_api method가 아니라 include/zephyr/net/ieee802154_radio.h에 선언된 standalone function입니다. API 문서는 모든 L2 stack이 inversion-of-control callback으로 구현해야 하는 함수를 명확히 표시합니다.

include/zephyr/net/ieee802154_radio.h의 standalone function 가운데 callback으로 명시되지 않은 것은 특정 L2와 독립적으로 PHY(L1) layer 안에 구현하는 helper입니다. 예를 들면 ieee802154_is_ar_flag_set()입니다.

모든 network interface와 마찬가지로 IEEE 802.15.4 driver도 마지막에 NET_DEVICE_INIT_INSTANCE()를 호출합니다.

NET_DEVICE_INIT_INSTANCE(...,
                         the_device_init_prio,
    &the_valid_ieee802154_radio_api_instance,
    IEEE802154_L2,
    NET_L2_GET_CTX_TYPE(IEEE802154_L2), 125);

API Reference

Doxygen group net_l2가 API reference를 제공합니다.

Source

출처

영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.