>  기사  >  시스템 튜토리얼  >  사용자 공간과 커널 공간 간의 통신을 위해 Netlink 사용

사용자 공간과 커널 공간 간의 통신을 위해 Netlink 사용

王林
王林앞으로
2024-01-16 08:48:05937검색

用户空间和内核空间通讯-Netlink 上

2001년 ForCES IETF 위원회는 Netlink에 대한 표준화 작업을 공식적으로 수행했습니다. Jamal Hadi Salim은 Netlink를 네트워크 장치의 라우팅 엔진 구성 요소와 해당 제어 및 관리 구성 요소 간의 통신을 위한 프로토콜로 정의할 것을 제안했습니다. 그러나 그의 제안은 결국 채택되지 않았고 오늘날 우리가 보는 패턴으로 대체되었습니다. Netlink는 새로운 프로토콜 도메인인 도메인으로 설계되었습니다.

리눅스의 아버지 토바스는 "리눅스는 진화이지 지능적인 설계가 아니다"라고 말한 적이 있습니다. 무슨 뜻인가요? 즉, Netlink도 Linux의 특정 설계 개념을 따릅니다. 즉, 완전한 사양 문서나 설계 문서가 없습니다. 그냥 뭐? 알다시피---"빌어먹을 소스 코드를 읽어라".

물론 이 글은 Linux에서 Netlink의 구현 메커니즘을 분석하는 것이 아니라 "Netlink란 무엇인가"와 "Netlink를 잘 활용하는 방법"이라는 주제를 여러분과 공유하기 위한 것입니다. 커널 소스만 읽으면 됩니다. 문제가 발생하면 코드를 작성해 보세요.

넷링크란 무엇인가요

Netlink를 이해하려면 몇 가지 핵심 사항을 파악해야 합니다.

1. 데이터그램용 비연결 메시징 하위 시스템

2. 공통 BSD 소켓 아키텍처를 기반으로 구현되었습니다

첫 번째 요점은 UDP 프로토콜을 생각하면 쉽습니다. UDP 프로토콜을 기반으로 Netlink를 이해하는 것은 무리가 없습니다. 유사점을 도출하고 유추를 통해 학습할 수 있고, 요약하고 연관시키며 최종적으로 지식 전달을 실현할 수 있다면 이것이 학습의 본질입니다. Netlink는 커널->사용자 및 사용자->커널 간의 양방향 및 비동기 데이터 통신을 실현할 수 있으며, 두 사용자 프로세스 간, 심지어 두 커널 하위 시스템 간 데이터 통신도 지원합니다. 이 기사에서는 후자의 두 가지를 고려하지 않고 사용자 커널 간의 데이터 통신을 구현하는 방법에 중점을 둘 것입니다.

두 번째 지점을 봤을 때 다음 그림이 떠올랐나요? 그렇다면 그것은 당신에게 지혜의 뿌리가 있다는 뜻입니다. 물론 그렇지 않더라도 상관없습니다. 지혜의 뿌리는 천천히 자랄 수 있습니다. 하하.

나중에 넷링크 소켓 프로그래밍 연습할 때 주로 소켓(), 바인드(), sendmsg()를 사용하겠습니다

및 recvmsg()와 같은 시스템 호출과 물론 소켓이 제공하는 폴링 메커니즘도 있습니다.

넷링크 통신형

Netlink는 유니캐스트와 멀티캐스트라는 두 가지 유형의 통신 방법을 지원합니다.

유니캐스트: 사용자 프로세스와 커널 하위 시스템 간의 1:1 데이터 통신에 자주 사용됩니다. 사용자 공간은 커널에 명령을 보내고 커널로부터 명령의 결과를 받습니다.

멀티캐스트: 커널 프로세스와 여러 사용자 프로세스 간의 1:N 데이터 통신에 자주 사용됩니다. 커널은 세션 개시자 역할을 하고 사용자 공간 애플리케이션은 수신자 역할을 합니다. 이 기능을 달성하기 위해 커널 공간 프로그램은 멀티캐스트 그룹을 생성한 다음 커널 프로세스에서 보낸 메시지에 관심이 있는 모든 사용자 공간 프로세스가 그룹에 참여하여 커널에서 보낸 메시지를 받습니다. 다음과 같습니다:

用户空间和内核空间通讯-Netlink 上

프로세스 A와 하위 시스템 1 사이의 통신은 유니캐스트이고, 프로세스 B와 C와 하위 시스템 2 사이의 통신은 멀티캐스트입니다. 위의 그림은 우리에게 메시지를 말해줍니다. 사용자 공간에서 커널로 전송된 데이터는 대기열에 포함될 필요가 없습니다. 즉, 작업이 동기적으로 완료되는 반면, 커널 공간에서 사용자 공간으로 전송된 데이터는 대기열에 있어야 하며 이는 비동기식입니다. 이를 이해하면 Netlink 기반 애플리케이션 모듈을 개발할 때 많은 우회로를 줄일 수 있습니다. 커널에 메시지를 보내고 라우팅 테이블이나 기타 정보와 같은 커널의 특정 정보를 얻어야 하는 경우, 라우팅 테이블이 너무 크면 커널이 Netlink를 통해 데이터를 반환할 때 다음을 생각해 볼 수 있습니다. 데이터 문제는 결국 출력 대기열을 봤기 때문에 눈을 감을 수는 없습니다.

Netlink 메시지 형식

Netlink 메시지는 메시지 헤더와 페이로드의 두 부분으로 구성되며, 전체 Netlink 메시지는 4바이트로 정렬되어 일반적으로 호스트 바이트 순서로 전송됩니다. 메시지 헤더는 16바이트로 고정되어 있으며 메시지 본문 길이는 가변적입니다.

用户空间和内核空间通讯-Netlink 上

Netlink 메시지 헤더

메시지 헤더는 파일에 정의되어 있으며 nlmsghdr 구조로 표시됩니다.

접거나 열려면 (여기)를 클릭하세요

  1. nlmsghdr 구조체
  2. {
  3. __u32 nlmsg_len; /* 헤더를 포함한 메시지 길이 */
  4. __u16 nlmsg_type /* 메시지 내용 */
  5. __u16 nlmsg_flags /* 추가 플래그 */
  6. __u32 nlmsg_seq; /* 시퀀스 번호 */
  7. __u32 nlmsg_pid /* 프로세스 PID 전송 */
  8. };

메시지 헤더에 있는 각 멤버의 속성에 대한 설명 및 설명:

nlmsg_len: 전체 메시지의 길이(바이트)입니다. Netlink 메시지 헤더 자체를 포함합니다.

nlmsg_type: 메시지 유형, 즉 데이터 메시지인지 제어 메시지인지입니다. 현재(커널 버전 2.6.21) Netlink는 다음과 같은 네 가지 유형의 제어 메시지만 지원합니다.

NLMSG_NOOP - 빈 메시지, 아무것도 하지 않음

NLMSG_ERROR - 메시지에 오류가 있음을 나타냅니다.

NLMSG_DONE - 커널이 Netlink 대기열을 통해 여러 메시지를 반환하는 경우 대기열의 마지막 메시지 유형은 NLMSG_DONE이며 나머지 모든 메시지의 nlmsg_flags 속성에는 NLM_F_MULTI 비트가 유효하도록 설정되어 있습니다.

NLMSG_OVERRUN-아직 사용되지 않았습니다.

nlmsg_flags: 위에서 언급한 NLM_F_MULTI와 같이 메시지에 첨부된 추가 설명 정보입니다. 발췌 내용은 다음과 같습니다:

nlmsg_flags에는 여러 값이 있다는 것을 알고 계시다면, 각 값의 역할과 의미는 구글과 소스코드를 통해 확실히 찾으실 수 있으니 여기서는 자세히 다루지 않겠습니다. 이전 2.6.21 커널의 모든 값:

用户空间和内核空间通讯-Netlink 上

nlmsg_seq: 메시지 시퀀스 번호. Netlink는 데이터그램을 지향하기 때문에 데이터 손실의 위험이 있지만 Netlink는 메시지가 손실되지 않도록 하는 메커니즘을 제공하므로 프로그램 개발자가 실제 필요에 따라 이를 구현할 수 있습니다. 메시지 시퀀스 번호는 일반적으로 NLM_F_ACK 유형 메시지와 함께 사용됩니다. 사용자의 애플리케이션이 보내는 모든 메시지가 커널에 의해 성공적으로 수신되었는지 확인해야 하는 경우 메시지를 보낼 때 시퀀스 번호 자체를 설정하는 사용자 프로그램이 필요합니다. 커널은 메시지를 수신하고 일련 번호를 추출한 다음 사용자 프로그램에 전송된 응답 메시지에 동일한 일련 번호를 설정합니다. TCP의 응답 및 확인 메커니즘과 다소 유사합니다.

참고: 커널이 사용자 공간에 브로드캐스트 메시지를 적극적으로 보낼 때 메시지의 이 필드는 항상 0입니다.

nlmsg_pid: 사용자 공간 프로세스와 커널 공간의 특정 하위 시스템 간에 Netlink를 통해 데이터 교환 채널이 설정되면 Netlink는 이러한 각 채널에 고유한 디지털 ID를 할당합니다. 주요 기능은 사용자 공간의 요청 메시지와 응답 메시지를 연관시키는 것입니다. 직설적으로 말하면, 사용자 공간에 여러 사용자 프로세스가 있고 커널 공간에 여러 프로세스가 있는 경우 Netlink는 각 "사용자-커널" 공간 통신 프로세스 쌍 간의 데이터 상호 작용이 일관되게 발생할 수 있도록 하는 메커니즘을 제공해야 합니다.

用户空间和内核空间通讯-Netlink 上

즉, 프로세스 A와 B가 Netlink를 통해 하위 시스템 1로부터 정보를 얻을 때 하위 시스템 1은 프로세스 A로 다시 전송된 응답 데이터가 프로세스 B로 전송되지 않도록 해야 합니다. 이는 사용자 공간 프로세스가 커널 공간에서 데이터를 얻는 시나리오에 주로 적합합니다. 일반적으로 사용자 공간 프로세스가 커널에 메시지를 보낼 때 일반적으로 시스템 호출 getpid()를 통해 현재 프로세스의 프로세스 ID를 이 변수에 할당합니다. 즉, 사용자 공간 프로세스는 원할 때 이 작업을 수행합니다. 커널로부터 응답을 받습니다. 커널에서 사용자 공간으로 활발하게 전송되는 메시지의 경우 이 필드는 0으로 설정됩니다.

Netlink 메시지 본문 Netlink의 메시지 본문은 TLV(Type-Length-Value) 형식을 채택합니다.

用户空间和内核空间通讯-Netlink 上

Netlink의 각 속성은 파일에서

struct nlattr{}로 표시됩니다.

用户空间和内核空间通讯-Netlink 上

Netlink

에서 제공하는 오류 표시 메시지 콘텐츠

Netlink를 통해 사용자 공간 애플리케이션과 커널 공간 프로세스 간 통신 중에 오류가 발생하면 Netlink는 이러한 오류를 사용자 공간에 알려야 합니다. Netlink는 오류 메시지를 별도로 캡슐화합니다. :

접거나 열려면 (여기)를 클릭하세요

nlmsgerr 구조체
  1. {
  2. int error; //errno.h 헤더 파일에 정의된 표준 오류 코드입니다. perror()
  3. 를 사용하여 설명할 수 있습니다.
  4. struct nlmsghdr msg; //구조에서 오류 값을 트리거한 메시지를 나타냅니다.
  5. };
  6. Netlink 프로그래밍 시 주의사항
Netlink 사용자-커널 통신을 기반으로 패킷 손실이 발생할 수 있는 상황은 두 가지입니다. 1. 메모리가 소진되었습니다.

2. 사용자 공간 수신 프로세스에서 버퍼 오버플로가 발생합니다. 버퍼 오버플로의 주된 이유는 다음과 같습니다. 사용자 공간 프로세스가 너무 느리게 실행되거나 수신 큐가 너무 짧습니다.

Netlink가 사용자 공간의 수신 프로세스에 메시지를 올바르게 전달할 수 없는 경우, 사용자 공간의 수신 프로세스는 recvmsg() 시스템 호출을 호출할 때 메모리 부족(ENOBUFS) 오류를 반환합니다. 즉, user->kernel의 sendmsg() 시스템 호출에서는 버퍼 오버플로 상황이 전송되지 않습니다. 이유는 앞에서 언급한 바 있습니다.

물론, 블로킹 소켓 통신을 사용하면 메모리 고갈의 숨겨진 위험이 없습니다. 이유는 무엇입니까? 빨리 구글에 가서 블로킹 소켓이 뭔지 찾아보세요. 생각 없이 배우면 헛되고, 생각 없이 배우지 않으면 위태로워진다.

Netlink의 주소 구조

TCP 블로그 게시물에서 인터넷 프로그래밍 과정에서 사용되는 주소 구조와 표준 주소 구조에 대해 언급했는데, Netlink 주소 구조와의 관계는 다음과 같습니다.

struct sockaddr_nl{}의 자세한 정의와 설명은 다음과 같습니다.

用户空间和内核空间通讯-Netlink 上

접거나 열려면 (여기)를 클릭하세요

  1. struct sockaddr_nl
  2. {
  3. sa_family_t nl_family; /*이 필드는 항상 AF_NETLINK입니다 */
  4. unsigned short nl_pad /* 현재 사용되지 않음, 0*/
  5. 으로 채워짐
  6. __u32 nl_pid /* 프로세스 pid */
  7. __u32 nl_groups; /* 멀티캐스트 그룹 마스크 */
  8. };

nl_pid: 이 속성은 메시지를 보내거나 받는 프로세스 ID입니다. 앞서 말했듯이 Netlink는 사용자-커널 공간 통신을 구현할 수 있을 뿐만 아니라 사용자 공간의 두 프로세스 간 또는 내부의 두 프로세스 간 실시간 통신을 가능하게 합니다. 커널 공간. 이 속성이 0이면 일반적으로 다음 두 가지 상황에 적용됩니다.

먼저 우리가 보내려는 대상은 커널입니다. 즉, 사용자 공간에서 커널 공간으로 보낼 때 우리가 구성하는 Netlink 주소 구조의 nl_pid는 일반적으로 0으로 설정됩니다. 여기서 설명해야 할 한 가지는 Netlink 사양에서 PID의 전체 이름은 Port-ID(32비트)이며 주요 기능은 netlink 기반 소켓 채널을 고유하게 식별하는 것입니다. 일반적으로 nl_pid는 현재 프로세스의 프로세스 ID로 설정됩니다. 그러나 프로세스의 여러 스레드가 동시에 netlink 소켓을 사용하는 경우 nl_pid 설정은 일반적으로 다음과 같이 구현됩니다.

접거나 열려면 (여기)를 클릭하세요

  1. pthread_self() << getpid();

둘째, 멀티캐스트 메시지가 커널에서 사용자 공간으로 전송될 때 사용자 공간 프로세스가 멀티캐스트 그룹에 있으면 해당 주소 구조의 nl_pid도 0으로 설정되고 동시에 다음과 결합되어야 합니다. 기타 정보는 아래에 소개되어 있습니다.

nl_groups: 사용자 공간 프로세스가 멀티캐스트 그룹에 참여하려는 경우, 바인딩() 시스템 호출을 실행해야 합니다. 이 필드는 발신자가 참여하기를 원하는 멀티캐스트 그룹 번호의 mask를 지정합니다(그룹 번호가 아니라는 점에 유의하세요. 이 필드에 대해서는 나중에 자세히 설명하겠습니다). 이 필드가 0이면 발신자가 멀티캐스트 그룹에 참여하기를 원하지 않는다는 의미입니다. Netlink 프로토콜 도메인에 속하는 각 프로토콜에 대해 최대 32개의 멀티캐스트 그룹을 지원할 수 있으며(nl_groups의 길이는 32비트이므로) 각 멀티캐스트 그룹은 1비트로 표시됩니다.

Netlink의 나머지 지식 포인트에 대해서는 나중에 실습 세션에서 유용할 때 논의하겠습니다.

끝나지 않았습니다. 계속하세요...

위 내용은 사용자 공간과 커널 공간 간의 통신을 위해 Netlink 사용의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 linuxprobe.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제