Linux 사용자 상태 와 커 널 상태의 상호작용-netlink 편
이것 은 학습 노트 로 주로 리 눅 스에 대한 것 이다. 시스템 커 널 공간 과 사용자 공간 통신 의 실현 과 분석 에서 의 소스 코드 imp 2 에 대한 분석.그 중의 소스 코드 는 아래 URL 에서 다운로드 할 수 있 습 니 다.http://www-128.ibm.com/developerworks/cn/linux/l-netlink/imp2.tar.gz
[size=3]참고 문서[/size]
《Linux 시스템 커 널 공간 과 사용자 공간 통신 의 실현 과 분석
http://www-128.ibm.com/developerworks/cn/linux/l-netlink/?ca=dwcn-newsletter-linux
《재》. Linux 아래 사용자 공간 과 커 널 공간 데이터 교환 방식
http://www-128.ibm.com/developerworks/cn/linux/l-kerns-usrs/
[size=3]이론 편[/size]
...에 있다 Linux 2.4 버 전 이후 버 전의 커 널 에 서 는 거의 모든 인 터 럽 트 과정 과 사용자 상태 프로 세 스 의 통신 이 사 용 됩 니 다. netlink 소켓 이 실 현 된 것,예 를 들 어 iprote 2 네트워크 관리 도구,커 널 과 의 상호작용 은 모두 netlink 를 사 용 했 습 니 다.유명한 커 널 패키지 필터 프레임 워 크 Netfilter 는 사용자 공간 과 의 통독 도 최신 버 전에 서 netlink 로 바 뀌 었 습 니 다.이것 은 Linux 사용자 상태 와 커 널 상태 교류 의 주요 방법 중 하나 가 될 것 입 니 다.그것 의 통신 근 거 는 프로 세 스 에 대응 하 는 표지 로 일반적으로 이 프로 세 스 로 정 해 져 있다. ID。통신 의 한 끝 이 중단 과정 에 있 을 때 이 표 지 는? 0。활용 단어 참조 netlink 소켓 으로 통신 을 하고 통신 하 는 쌍방 은 모두 사용자 상태 프로 세 스 이 며 사용 방법 은 메시지 큐 와 유사 합 니 다.그러나 통신 양측 은 한쪽 은 중단 과정 이 고 사용 방법 은 다르다.netlink 소켓 의 가장 큰 특징 은 인 터 럽 트 과정 에 대한 지원 입 니 다.커 널 공간 에서 사용자 공간 데 이 터 를 받 을 때 사용자 가 커 널 스 레 드 를 스스로 시작 하지 않 고 다른 소프트 인 터 럽 트 를 통 해 사용자 가 미리 지정 한 수신 함 수 를 호출 하 는 것 입 니 다.작업 원 리 는 그림 과 같다.
그림 에서 보 듯 이 커 널 스 레 드 가 아 닌 소프트 인 터 럽 트 를 사용 하여 데 이 터 를 받 으 면 데이터 수신 의 실시 성 을 확보 할 수 있다.
...해 야 한다 netlink 소켓 은 커 널 공간 과 사용자 공간의 통신 에 사용 할 때 사용자 공간의 생 성 방법 은 일반 소켓 과 유사 하지만 커 널 공간의 생 성 방법 은 다르다.다음 그림 은? netlink 소켓 이 이러한 통신 을 실현 할 때 만 드 는 과정:
사용자 공간
사용자 상태 응용 표준 socket 과 커 널 통신,표준 socket 사용 API 의 함수, socket(), bind(), sendmsg(), recvmsg() 화해시키다 close()쉽게 적용 netlink socket。
하 나 를 만 들 기 위해 netlink socket,사용 자 는 다음 과 같은 매개 변 수 를 사용 하여 호출 해 야 합 니 다. socket():
socket(AF_NETLINK, SOCK_RAW, netlink_type)
netlink 에 대응 하 는 프로 토 콜 클 러 스 터 는? AF_NETLINK,두 번 째 인 자 는 SOCK 이 어야 합 니 다.RAW 또는 SOCKDGRAM, 세 번 째 매개 변 수 는 netlink 프로 토 콜 형식 을 지정 합 니 다.사용자 정의 형식 일 수도 있 고 커 널 에서 미리 정 의 된 형식 을 사용 할 수도 있 습 니 다.
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_W1 1 /* 1-wire subsystem */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_INET_DIAG 4 /* INET socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16 마찬가지 로 socket 함수 가 되 돌아 오 는 소켓 은 bing 등 함수 호출 에 맡 길 수 있 습 니 다.
static int skfd;
skfd = socket(PF_NETLINK, SOCK_RAW, NL_IMP2);
if(skfd < 0)
{
printf("can not create a netlink socket
");
exit(0);
}
bid 함 수 는 프로 토 콜 주 소 를 연결 해 야 합 니 다.netlink 의 socket 주 소 는 struct 를 사용 합 니 다. sockaddr_nl 구조 설명:
struct sockaddr_nl
{
sa_family_t nl_family;
unsigned short nl_pad;
__u32 nl_pid;
__u32 nl_groups;
};
구성원 nl_family 프로 토 콜 클 러 스 터 AF_NETLINK,멤버 nl_pad 현재 사용 하지 않 았 기 때문에 항상 설정 해 야 합 니 다. 0,멤버 nl_pid 메 시 지 를 받 거나 보 내기 위 한 프로 세 스 ID,내 핵 처리 메시지 나 멀티캐스트 메 시 지 를 원한 다 면 이 필드 를 0,그렇지 않 으 면 메 시 지 를 처리 하 는 프로 세 스 로 설정 합 니 다. ID。구성원 nl_groups 멀티캐스트 그룹,bid 지정 에 사용 함수 가 이 필드 에서 지정 한 멀티캐스트 그룹 에 호출 프로 세 스 를 추가 하 는 데 사 용 됩 니 다. 0.호출 자 는 멀티캐스트 그룹 에 가입 하지 않 는 다 는 뜻 입 니 다.
struct sockaddr_nl local;
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid(); /* pid pid */
local.nl_groups = 0;
/* */
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0)
{
printf("bind() error
");
return -1;
}
사용자 공간 은 send 함수 클 러 스 터 를 호출 하여 커 널 에 메 시 지 를 보 낼 수 있 습 니 다.예 를 들 어 sendto,sendmsg 등 도 마찬가지 로 struct 를 사용 할 수 있 습 니 다. sockaddr_nl 은 send 함수 가 호출 될 때 까지 대 단 주 소 를 설명 합 니 다.로 컬 주소 와 조금 다른 것 은 대 단 이 커 널 이기 때문에 nlpid 멤버 는 0 으로 설정 해 야 합 니 다:
struct sockaddr_nl kpeer;
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0;
또 다른 문 제 는 커 널 에서 보 낸 메시지 의 구성 입 니 다.우리 가 IP 네트워크 패 킷 을 보 내 면 패 킷 구 조 는'IP 패 킷+IP 데이터'입 니 다.마찬가지 로 netlink 의 메시지 구 조 는'netlink 메시지 헤드+데이터'입 니 다.Netlink 메시지 헤더 사용 struct nlmsghdr 구조 설명:
struct nlmsghdr
{
__u32 nlmsg_len; /* Length of message */
__u16 nlmsg_type; /* Message type*/
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process PID */
};
필드 nlmsg_len 메시지 의 총 길 이 를 지정 합 니 다.이 구조의 데이터 부분 길이 와 이 구조의 크기 를 포함 합 니 다.일반적으로 저 희 는 netlink 가 제공 하 는 매크로 NLMSG 를 사용 합 니 다.LENGTH 가 이 길 이 를 계산 하려 면 NLMSGLENGTH 매크로 는 보 낼 데이터 의 길 이 를 제공 합 니 다.정렬 된 총 길 이 를 자동 으로 계산 합 니 다.
/* */
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
/* */
#define NLMSG_ALIGN(len) ( ((len)+NLMSG_ALIGNTO-1) & ~(NLMSG_ALIGNTO-1) )
뒤에 넷 링크 가 제공 하 는 매크로 도 많이 볼 수 있 습 니 다.이 매크로 들 은 넷 링크 매크로 를 작성 하 는 데 큰 편 의 를 제공 할 수 있 습 니 다.
필드 nlmsg_type 내부 정의 메시지 의 형식 을 사용 합 니 다. netlink 커 널 구현 은 투명 하기 때문에 대부분의 경우 필드 nlmsg_flags 메시지 플래그 설정 에 사용 합 니 다.일반적인 사용 에 대해 서 는 사용자 가 설정 합 니 다. 0 일부 고급 응용 프로그램(예 를 들 어 netfilter 경로 daemon 필드 nlmsg_seq 화해시키다 nlmsg_pid 추적 메 시 지 를 사용 할 때 전 자 는 순서 번 호 를 표시 하고 후 자 는 메시지 원본 프로 세 스 입 니 다. ID。
struct msg_to_kernel /* , netlink */
{
struct nlmsghdr hdr;
};
struct msg_to_kernel message;
memset(&message, 0, sizeof(message));
message.hdr.nlmsg_len = NLMSG_LENGTH(0); /* , , , , 0*/
message.hdr.nlmsg_flags = 0;
message.hdr.nlmsg_type = IMP2_U_PID; /* */
message.hdr.nlmsg_pid = local.nl_pid; /* PID*/
, 、 , :
/* */
sendto(skfd, &message, message.hdr.nlmsg_len, 0,
(struct sockaddr*)&kpeer, sizeof(kpeer));
요청 을 보 낸 후에 recv 함수 클 러 스 터 를 호출 하여 커 널 에서 데 이 터 를 받 을 수 있 습 니 다.받 은 데 이 터 는 netlink 메시지 의 첫 번 째 부분 과 전송 할 데 이 터 를 포함 합 니 다.
/* netlink */
struct u_packet_info
{
struct nlmsghdr hdr;
struct packet_info icmp_info;
};
struct u_packet_info info;
while(1)
{
kpeerlen = sizeof(struct sockaddr_nl);
/* */
rcvlen = recvfrom(skfd, &info, sizeof(struct u_packet_info),
0, (struct sockaddr*)&kpeer, &kpeerlen);
/* */
……
}
마찬가지 로 함수 close 는 열 린 netlink 를 닫 는 데 사 용 됩 니 다. socket。프로그램 에 서 는 커 널 을 처리 하 는 메 시 지 를 반복 적 으로 받 기 때문에 사용자 의 닫 힌 신 호 를 받 아야 종료 할 수 있 기 때문에 소켓 을 닫 는 작업 은 사용자 정의 신호 함수 sig 에 놓 여 있 습 니 다.int 에서 처리:
/* , */
static void sig_int(int signo)
{
struct sockaddr_nl kpeer;
struct msg_to_kernel message;
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0;
memset(&message, 0, sizeof(message));
message.hdr.nlmsg_len = NLMSG_LENGTH(0);
message.hdr.nlmsg_flags = 0;
message.hdr.nlmsg_type = IMP2_CLOSE;
message.hdr.nlmsg_pid = getpid();
/* , nlmsg_type , */
sendto(skfd, &message, message.hdr.nlmsg_len, 0, (struct sockaddr *)(&kpeer), sizeof(kpeer));
close(skfd);
exit(0);
}
이 끝 함수 에서 커 널 에"나 는 이미 종료 되 었 습 니 다"라 는 메 시 지 를 보 낸 다음 close 함수 로 netlink 소켓 을 닫 고 프로그램 을 종료 합 니 다.
[size=3]커 널 공간[/size]
응용 프로그램 커 널,커 널 공간 도 주로 세 가지 작업 을 완성 합 니 다.
netlink 소켓 만 들 기
사용자 공간 에서 보 낸 데 이 터 를 수신 처리 합 니 다.
사용자 공간 으로 데이터 전송
API 함수 netlinkkernel_create 는 netlink 를 만 드 는 데 사 용 됩 니 다. socket,동시에 리 셋 함 수 를 등록 하여 사용자 공간 을 처리 하 는 메 시 지 를 받 습 니 다:
struct sock *
netlink_kernel_create(int unit, void (*input)(struct sock *sk, int len));
매개 변수 유닛 은 NL 와 같은 netlink 프로 토 콜 형식 을 표시 합 니 다.IMP 2,매개 변수 input 는 커 널 모듈 에 정 의 된 netlink 메시지 처리 함수 입 니 다.메시지 가 이 netlink 에 도착 하면 socket 시 이 input 함수 포인터 가 인 용 됩 니 다.함수 포인터 input 의 매개 변수 sk 는 사실상 함수 netlinkkernel_create 되 돌아 오 는 struct sock 포인터,sock 은 실제 socket 의 커 널 로 데이터 구 조 를 표시 합 니 다.사용자 상태 응용 으로 만 든 socket 은 커 널 에 도 struct 가 있 습 니 다. sock 구조 로 표시 합 니 다.
static int __init init(void)
{
rwlock_init(&user_proc.lock); /* */
/* netlink socket, ML_IMP2,kernel_reveive */
nlfd = netlink_kernel_create(NL_IMP2, kernel_receive);
if(!nlfd) /* */
{
printk("can not create a netlink socket
");
return -1;
}
/* Netfilter */
return nf_register_hook(&imp2_ops);
}
module_init(init);
사용자 공간 에서 커 널 에 두 가지 사용자 정의 메시지 형식 을 보 냈 습 니 다:IMP 2U_PID 와 IMP 2CLOSE,각각 요청 과 닫 기 입 니 다.kernel_receive 함수 가 각각 이 두 가지 메 시 지 를 처리 합 니 다:
DECLARE_MUTEX(receive_sem); /* */
static void kernel_receive(struct sock *sk, int len)
{
do
{
struct sk_buff *skb;
if(down_trylock(&receive_sem)) /* */
return;
/* skb, */
while((skb = skb_dequeue(&sk->receive_queue)) != NULL)
{
{
struct nlmsghdr *nlh = NULL;
if(skb->len >= sizeof(struct nlmsghdr))
{
/* nlmsghdr */
nlh = (struct nlmsghdr *)skb->data;
if((nlh->nlmsg_len >= sizeof(struct nlmsghdr))
&& (skb->len >= nlh->nlmsg_len))
{
/* , , PID , “ ”*/
if(nlh->nlmsg_type == IMP2_U_PID) /* */
{
write_lock_bh(&user_proc.pid);
user_proc.pid = nlh->nlmsg_pid;
write_unlock_bh(&user_proc.pid);
}
else if(nlh->nlmsg_type == IMP2_CLOSE) /* */
{
write_lock_bh(&user_proc.pid);
if(nlh->nlmsg_pid == user_proc.pid)
user_proc.pid = 0;
write_unlock_bh(&user_proc.pid);
}
}
}
}
kfree_skb(skb);
}
up(&receive_sem); /* */
}while(nlfd && nlfd->receive_queue.qlen);
}
커 널 모듈 은 여러 프로 세 스 에 의 해 동시에 호출 될 수 있 기 때문에 함수 에 서 는 신 호 량 과 자 물 쇠 를 사용 하여 서로 배척 합 니 다.skb = skb_dequeue(&sk->receive_queue)소켓 가 져 오기 sk 수신 대기 열 에 있 는 메 시 지 를 struct 로 되 돌려 줍 니 다. sk_buff 의 구조,skb->data 는 실제 netlink 메 시 지 를 가리 키 고 있 습 니 다.
프로그램 에 Netfilter 갈고리 가 등록 되 어 있 습 니 다.갈고리 함 수 는 get 입 니 다.icmp,ICMP 패 킷 을 캡 처 한 후 send 호출to_user 함수 가 데 이 터 를 응용 공간 프로 세 스에 보 냅 니 다.보 낸 데 이 터 는 info 구조 변수 입 니 다.struct 입 니 다. packet_info 구조,이 구 조 는 원본/목적 주소 두 구성원 을 포함 합 니 다.Netfilter Hook 은 본문 묘사 의 중점 이 아니 라 생략 합 니 다.
send_to_user 사용자 공간 프로 세 스에 데 이 터 를 보 내 는 데 사용 되 며,호출 된 것 은 API 함수 netlink 입 니 다.unicast 완 성 된:
int netlink_unicast(struct sock *sk, struct sk_buff *skb, u32 pid, int nonblock);
매개 변수 sk 는 함수 netlinkkernel_create()가 되 돌아 오 는 소켓,인자 skb 는 보 낼 메 시 지 를 저장 합 니 다.data 필드 는 보 낼 netlink 메시지 구 조 를 가리 키 고 skb 제어 블록 은 메시지 의 주소 정 보 를 저장 합 니 다. 매개 변수 pid 는 메 시 지 를 받 는 프로 세 스 의 pid 입 니 다.매개 변수 nonblock 은 이 함수 가 차단 되 지 않 았 는 지 여 부 를 표시 합 니 다.1 이면 이 함 수 는 캐 시 를 받 지 않 았 을 때 바로 돌아 갑 니 다.0 이면 이 함 수 는 캐 시 를 받 지 않 았 을 때 잠 을 잘 수 있 습 니 다.
사용자 공간 프로 세 스에 보 낸 메 시 지 는 세 부분 을 포함 합 니 다:netlink 메시지 헤드,데이터 부분 과 제어 필드,제어 필드 는 커 널 이 netlink 메 시 지 를 보 낼 때 설정 해 야 할 목표 주소 와 소스 주 소 를 포함 하고 커 널 의 메 시 지 는 skbuff 가 관리 하 는, linux/netlink.h 에서 NETLINK 정의CB 매크로 에서 메시지 의 주소 설정 을 편리 하 게 합 니 다:
#define NETLINK_CB(skb) (*(struct netlink_skb_parms*)&((skb)->cb))
예 를 들 면:
NETLINK_CB(skb).pid = 0;
NETLINK_CB(skb).dst_pid = 0;
NETLINK_CB(skb).dst_group = 1;
필드 pid 는 메시지 발송 자 프로 세 스 ID,즉 원본 주 소 를 표시 합 니 다.커 널 에 대해 서 는... 0, dst_pid 메시지 수신 자 프로 세 스 표시 ID,즉 대상 주소 입 니 다.대상 이 그룹 이나 커 널 이면 설정 합 니 다. 그렇지 않 으 면 dst_group 대상 그룹 주 소 를 표시 합 니 다.대상 이 특정한 프로 세 스 나 커 널 이 라면 dstgroup 으로 설정 해 야 합 니 다. 0。
static int send_to_user(struct packet_info *info)
{
int ret;
int size;
unsigned char *old_tail;
struct sk_buff *skb;
struct nlmsghdr *nlh;
struct packet_info *packet;
/* : */
size = NLMSG_SPACE(sizeof(*info));
/* */
skb = alloc_skb(size, GFP_ATOMIC);
old_tail = skb->tail;
/* netlink */
nlh = NLMSG_PUT(skb, 0, 0, IMP2_K_MSG, size-sizeof(*nlh));
/* , */
packet = NLMSG_DATA(nlh);
/* */
memset(packet, 0, sizeof(struct packet_info));
/* */
packet->src = info->src;
packet->dest = info->dest;
/* skb , netlink */
nlh->nlmsg_len = skb->tail - old_tail;
/* */
NETLINK_CB(skb).dst_groups = 0;
/* */
read_lock_bh(&user_proc.lock);
ret = netlink_unicast(nlfd, skb, user_proc.pid, MSG_DONTWAIT);
read_unlock_bh(&user_proc.lock);
}
함수 초기 화 netlink 메시지 의 첫 번 째 부분 은 데이터 영역 을 채 우 고 제어 필드 를 설정 합 니 다.이 세 부분 은 모두 skb 에 포함 되 어 있 습 니 다.buff 중,마지막 으로 netlink 호출유 니 캐 스 트 함수 가 데 이 터 를 보 냅 니 다.
함수 에서 netlink 의 중요 한 매크로 NLMSG 를 호출 하 였 습 니 다.PUT,netlink 초기 화 에 사용 메시지 첫 부분:
#define NLMSG_PUT(skb, pid, seq, type, len) \
({ if (skb_tailroom(skb) < (int)NLMSG_SPACE(len)) goto nlmsg_failure; \
__nlmsg_put(skb, pid, seq, type, len); })
static __inline__ struct nlmsghdr *
__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
{
struct nlmsghdr *nlh;
int size = NLMSG_LENGTH(len);
nlh = (struct nlmsghdr*)skb_put(skb, NLMSG_ALIGN(size));
nlh->nlmsg_type = type;
nlh->nlmsg_len = size;
nlh->nlmsg_flags = 0;
nlh->nlmsg_pid = pid;
nlh->nlmsg_seq = seq;
return nlh;
}
이 매크로 의 주의해 야 할 부분 은 nlmsg 를 호출 한 것 입 니 다.failure 탭 이 므 로 프로그램 에서 이 탭 을 정의 해 야 합 니 다.
커 널 에 함수 sock 사용release 함수 netlink 방출kernel_create()가 만 든 netlink socket:
void sock_release(struct socket * sock);
프로그램 이 종료 모듈 에서 netlink 를 방출 합 니 다. sockets 와 netfilter hook:
static void __exit fini(void)
{
if(nlfd)
{
sock_release(nlfd->socket); /* netlink socket*/
}
nf_unregister_hook(&imp2_ops); /* netfilter */
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
용감한 바로 가기 및 우분투 응용 프로그램안녕하세요 여러분, 이 기사에서는 모든 사이트에서 pwa를 생성하고 실행기 응용 프로그램으로 추가하는 방법을 설명하고 싶습니다. 일부 웹사이트는 PWA로 설치를 허용하지 않지만 유사한 애플리케이션을 원합니다. 1. ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.