Netlink : Multicast =================== .. tab-set:: .. tab-item:: Netlink : Multicast * In this program, you are going to learn .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to communication between kernel and user space ? .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to use user space APIs ? * `FD_ZERO `_ * `FD_SET `_ * `FD_ISSET `_ * `NLMSG_SPACE `_ .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow * How to use kernel space APIs ? * `init_waitqueue_head `_ * `wait_event_interruptible `_ * `wake_up_interruptible `_ * `kthread_run `_ * `kthread_stop `_ * `kthread_should_stop `_ * `INIT_LIST_HEAD `_ * `list_head `_ * `list_for_each_entry `_ * `list_for_each_entry_safe `_ * `list_add_tail `_ * `list_del `_ * `nlmsg_new `_ * `nlmsg_put `_ * `NETLINK_CB `_ * `nlmsg_unicast `_ * `netlink_kernel_release `_ .. panels:: :container: container pb-4 :column: col-lg-12 p-2 :card: shadow Topics in this section, * :ref:`User program : nl_user.c ` * :ref:`Kernel program : nl_kernel.c ` * :ref:`Makefile ` * :ref:`Compile and Load ` * :ref:`Summary ` .. _p2_netlinkMulticast_0: .. tab-set:: .. tab-item:: nl_user.c * To create a socket with ``socket()``, .. code-block:: c sock_fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_USER); * ``bind()`` is used to bind a name to a socket .. code-block:: c retval = bind(sock_fd, (struct sockaddr * )&src_addr, sizeof(src_addr)); * nl_pid field of the sockaddr_nl can be filled with the calling process' own pid. .. code-block:: c struct sockaddr_nl src_addr; src_addr.nl_pid = getpid(); * ``Sending a Netlink Message`` In order to send a netlink message to the kernel or other user-space processes, another struct sockaddr_nl dest_addr needs to be supplied as the destination address, the same as sending a packet with sendmsg(). If the message is destined for the kernel, both nl_pid and nl_groups should be supplied with 0. .. code-block:: c struct sockaddr_nl dest_addr; dest_addr.nl_pid = 0; dest_addr.nl_groups = 0; struct msghdr msg; msg.msg_name = (void * )&dest_addr; msg.msg_namelen = sizeof(dest_addr); * The netlink socket requires its own message header as well. This is for providing a common ground for netlink messages of all protocol types. Because the Linux kernel netlink core assumes the existence of the following header in each netlink message, an application must supply this header in each netlink message it sends: .. code-block:: c struct nlmsghdr * nlh; nlh = (struct nlmsghdr * )malloc(NLMSG_SPACE(256)); nlh->nlmsg_len = NLMSG_SPACE(256); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; * A netlink message thus consists of nlmsghdr and the message payload. Once a message has been entered, it enters a buffer pointed to by the nlh pointer. We also can send the message to the struct msghdr msg: .. code-block:: c struct iovec iov; iov.iov_base = (void * )nlh; iov.iov_len = nlh->nlmsg_len; msg.msg_iov = &iov; msg.msg_iovlen = 1; * After the above steps, a call to ``sendmsg()`` kicks out the netlink message: .. code-block:: c retval = sendmsg(sock_fd, &msg, 0); * ``recvmsg`` used for Receiving Netlink Messages, .. code-block:: c retval = recvmsg(sock_fd, &msg, 0); * ``select()`` function indicates which of the specified file descriptors is ready for reading, ready for writing, or has an error condition pending. If the specified condition is false for all of the specified file descriptors, select() blocks, up to the specified timeout interval, until the specified condition is true for at least one of the specified file descriptors or until a signal arrives that needs to be delivered. .. code-block:: c retval = select(sock_fd + 1, &read_fds, NULL, NULL, NULL); * ``FD_ZERO`` initializes the file descriptor set fdset to have zero bits for all file descriptors. .. code-block:: c FD_ZERO(&read_fds); * ``FD_SET`` sets the bit for the file descriptor fd in the file descriptor set fdset. .. code-block:: c FD_SET(sock_fd, &read_fds); * ``FD_ISSET`` returns a non-zero value if the bit for the file descriptor fd is set in the file descriptor set pointed to by fdset, and 0 otherwise. .. code-block:: c FD_ISSET(sock_fd, &read_fds); * See the full program below, .. literalinclude:: p2_netlinkMulticast/nl_user.c :language: c :linenos: :emphasize-lines: 15, 16, 17, 18, 33, 48, 50, 51, 76, 82, 87, 89 .. _p2_netlinkMulticast_1: .. tab-set:: .. tab-item:: nl_kernel.c * ``init_waitqueue_head`` are declared and initialized. .. code-block:: c init_waitqueue_head(&wq_r); init_waitqueue_head(&wq_s); * ``wait_event_interruptible`` is put to sleep (TASK_INTERRUPTIBLE) until the condition evaluates to true. .. code-block:: c wait_event_interruptible(wq_s, wq_flag != 0); wait_event_interruptible(wq_r, wq_flag != 0); * ``wake_up_interruptible`` wakes up only the processes that are in interruptible sleeps. Any process that sleeps on the wait queue using a noninterruptible function or macro will continue to sleep. .. code-block:: c wake_up_interruptible(&wq_s); wake_up_interruptible(&wq_r); * ``kthread_run`` is used to create and start a kernel thread. .. code-block:: c thread = kthread_run(recv_netlink_msg_thread, NULL, "netlink_kthread"); send_thread = kthread_run(send_netlink_msg_thread, NULL, "netlink_send_kthread"); * ``kthread_stop`` is used to stop and clean up a kernel thread created with kthread_run. .. code-block:: c kthread_stop(thread); kthread_stop(send_thread); * ``kthread_should_stop`` is to determine when thread should exit. .. code-block:: c while (!kthread_should_stop()) * ``INIT_LIST_HEAD`` is used to initialize a list_head structure. .. code-block:: c INIT_LIST_HEAD(&mesg->list); INIT_LIST_HEAD(&msg->list); INIT_LIST_HEAD(&send_list); * ``list_head`` is used to initialize the list. .. code-block:: c struct list_head(msg_list); struct list_head(send_list); * ``list_for_each_entry`` is used to iterate over list of given type. .. code-block:: c list_for_each_entry(new_node, &send_list, list) list_for_each_entry(mesg, &send_list, list) list_for_each_entry(new_node, &msg_list, list) list_for_each_entry(msg, &msg_list, list) * ``list_for_each_entry_safe`` is used to iterate over list of given type safe against removal of list entry. .. code-block:: c list_for_each_entry_safe(curr_node, next_node, &msg_list, list) list_for_each_entry_safe(curr_node, next_node, &send_list, list) * ``list_add_tail`` is used to add a new entry. .. code-block:: c list_add_tail(&mesg->list, &send_list); list_add_tail(&msg->list, &msg_list); * ``list_del`` is used to delete entry from list. .. code-block:: c list_del(&mesg->list); list_del(&msg->list); list_del(&curr_node->list); list_del(&curr_node->list); * ``nlmsg_new`` using this create a netlink message. .. code-block:: c skb_out = nlmsg_new(msg_size, 0); * ``nlmsg_put`` used to populate the message with data. .. code-block:: c nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); * ``nlmsg_unicast`` used to send the message to the user space application. .. code-block:: c res = nlmsg_unicast(socket, skb_out, pid); * ``netlink_kernel_release`` used to release the netlink socket created with ``netlink_kernel_create``. .. code-block:: c netlink_kernel_release(socket); * See the full program below, .. literalinclude:: p2_netlinkMulticast/nl_kernel.c :language: c :linenos: :emphasize-lines: 21, 22, 29, 30, 31, 37, 38, 40, 57, 58, 60, 63, 69, 72, 76, 79, 89, 90, 92, 95, 96, 101, 109, 111, 112, 114, 132, 133, 137, 138, 146, 147, 149, 152, 153, 157, 159, 170, 171, 173, 177, 178, 180, 183, 187, 190, 203, 204, 207, 212, 216, 217, 218, 221, 222, 223, 227 .. _p2_netlinkMulticast_2: .. tab-set:: .. tab-item:: Makefile .. literalinclude:: p2_netlinkMulticast/Makefile :language: c :linenos: .. _p2_netlinkMulticast_3: .. tab-set:: .. tab-item:: Compile and Load .. code-block:: c :linenos: :emphasize-lines: 1, 3, 5, 47, 49 $ make all $ sudo insmod ./nl_kernel.ko $ ./nl_user Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel Received from kernel: Hello from kernel $ sudo rmmod nl_kernel $ dmesg [ 2066.487382] Netlink kernel module initialized [ 2079.443801] kernel thread-1 : Sent message : Hello from kernel [ 2079.443900] kernel thread-1 : Received message : Message from user (send) 0 [ 2079.443904] kernel thread-1 : Received message : Message from user (send) 1 [ 2084.449653] kernel thread-1 : Sent message : Hello from kernel [ 2084.449656] kernel thread-1 : Received message : Message from user (send) 0 [ 2084.449659] kernel thread-1 : Received message : Message from user (send) 1 [ 2084.449660] kernel thread-1 : Sent message : Hello from kernel [ 2084.449662] kernel thread-1 : Sent message : Hello from kernel [ 2084.449663] kernel thread-1 : Received message : Message from user (send) 2 [ 2084.449665] kernel thread-1 : Received message : Message from user (send) 3 [ 2084.449667] kernel thread-1 : Sent message : Hello from kernel [ 2084.449668] kernel thread-1 : Received message : Message from user (send) 4 [ 2084.449670] kernel thread-1 : Received message : Message from user (send) 5 [ 2084.449672] kernel thread-1 : Sent message : Hello from kernel [ 2084.449673] kernel thread-1 : Received message : Message from user (send) 6 [ 2084.449675] kernel thread-1 : Sent message : Hello from kernel [ 2084.449677] kernel thread-1 : Received message : Message from user (send) 7 [ 2084.449679] kernel thread-1 : Sent message : Hello from kernel [ 2084.449681] kernel thread-1 : Received message : Message from user (send) 8 [ 2084.449683] kernel thread-1 : Sent message : Hello from kernel [ 2084.449685] kernel thread-1 : Received message : Message from user (send) 9 [ 2084.449686] kernel thread-1 : Sent message : Hello from kernel [ 2084.449688] kernel thread-1 : Received message : Message from user (send) 10 [ 2084.449690] kernel thread-1 : Sent message : Hello from kernel [ 2084.449692] kernel thread-1 : Received message : Message from user (send) 11 [ 2084.449694] kernel thread-1 : Sent message : Hello from kernel [ 2084.449696] kernel thread-1 : Received message : Message from user (send) 12 [ 2084.449698] kernel thread-1 : Sent message : Hello from kernel [ 2084.449699] kernel thread-1 : Received message : Message from user (send) 13 [ 2084.449701] kernel thread-1 : Sent message : Hello from kernel [ 2084.449703] kernel thread-1 : Received message : Message from user (send) 14 [ 2084.449704] kernel thread-1 : Sent message : Hello from kernel [ 2084.449706] kernel thread-1 : Sent message : Hello from kernel [ 2084.449708] kernel thread-1 : Received message : Message from user (send) 15 [ 2084.449710] kernel thread-1 : Sent message : Hello from kernel [ 2084.449712] kernel thread-1 : Received message : Message from user (send) 16 [ 2084.449714] kernel thread-1 : Sent message : Hello from kernel [ 2084.449716] kernel thread-1 : Received message : Message from user (send) 17 [ 2084.449717] kernel thread-1 : Received message : Message from user (send) 18 [ 2084.449719] kernel thread-1 : Sent message : Hello from kernel [ 2084.449721] kernel thread-1 : Received message : Message from user (send) 19 [ 2084.449723] kernel thread-1 : Sent message : Hello from kernel [ 2084.449725] kernel thread-1 : Received message : Message from user (send) 20 [ 2084.449726] kernel thread-1 : Sent message : Hello from kernel [ 2084.449728] kernel thread-1 : Received message : Message from user (send) 21 [ 2084.449730] kernel thread-1 : Sent message : Hello from kernel [ 2084.449732] kernel thread-1 : Received message : Message from user (send) 22 [ 2084.449733] kernel thread-1 : Sent message : Hello from kernel [ 2084.449735] kernel thread-1 : Received message : Message from user (send) 23 [ 2084.449737] kernel thread-1 : Sent message : Hello from kernel [ 2084.449739] kernel thread-1 : Received message : Message from user (send) 24 [ 2084.449741] kernel thread-1 : Sent message : Hello from kernel [ 2084.449743] kernel thread-1 : Received message : Message from user (send) 25 [ 2084.449745] kernel thread-1 : Sent message : Hello from kernel [ 2084.449746] kernel thread-1 : Received message : Message from user (send) 26 [ 2084.449748] kernel thread-1 : Sent message : Hello from kernel [ 2084.449750] kernel thread-1 : Received message : Message from user (send) 27 [ 2084.449752] kernel thread-1 : Sent message : Hello from kernel [ 2084.449754] kernel thread-1 : Received message : Message from user (send) 28 [ 2084.449756] kernel thread-1 : Sent message : Hello from kernel [ 2084.449758] kernel thread-1 : Received message : Message from user (send) 29 [ 2084.449760] kernel thread-1 : Sent message : Hello from kernel [ 2084.449762] kernel thread-1 : Received message : Message from user (send) 30 [ 2084.449764] kernel thread-1 : Sent message : Hello from kernel [ 2084.449766] kernel thread-1 : Received message : Message from user (send) 31 [ 2084.449767] kernel thread-1 : Sent message : Hello from kernel [ 2084.449769] kernel thread-1 : Received message : Message from user (send) 32 [ 2084.449771] kernel thread-1 : Sent message : Hello from kernel [ 2084.449773] kernel thread-1 : Received message : Message from user (send) 33 [ 2084.449774] kernel thread-1 : Sent message : Hello from kernel [ 2084.449776] kernel thread-1 : Received message : Message from user (send) 34 [ 2084.449778] kernel thread-1 : Sent message : Hello from kernel [ 2084.449780] kernel thread-1 : Received message : Message from user (send) 35 [ 2084.449781] kernel thread-1 : Sent message : Hello from kernel [ 2084.449784] kernel thread-1 : Received message : Message from user (send) 36 [ 2084.449786] kernel thread-1 : Sent message : Hello from kernel [ 2084.449787] kernel thread-1 : Received message : Message from user (send) 37 [ 2084.449789] kernel thread-1 : Sent message : Hello from kernel [ 2084.449791] kernel thread-1 : Received message : Message from user (send) 38 [ 2084.449793] kernel thread-1 : Sent message : Hello from kernel [ 2084.449795] kernel thread-1 : Received message : Message from user (send) 39 [ 2084.449796] kernel thread-1 : Sent message : Hello from kernel [ 2084.449798] kernel thread-1 : Sent message : Hello from kernel .. _p2_netlinkMulticast_4: .. tab-set:: .. tab-item:: Summary =============================== ======================================================================================================================================== User Space API Learning =============================== ======================================================================================================================================== socket To create a socket bind To bind a name to a socket select To monitor the activity on a set of sockets looking for sockets ready for reading, writing, or with an exception condition pending FD_ZERO To initialize the file descriptor set fdset to have zero bits for all file descriptors FD_SET To set the bit for the file descriptor fd in the file descriptor set fdset FD_ISSET It returns a non-zero value if the bit for the file descriptor fd is set in the file descriptor set pointed to by fdset, and 0 otherwise sendmsg To send netlink message recvmsg To receive netlink message =============================== ======================================================================================================================================== .. tab-set:: .. tab-item:: Summary =============================== ===================================================================== Kernel Space API Learning =============================== ===================================================================== init_waitqueue_head To declare and initialize wait_event_interruptible It sleep until a condition gets true wake_up_interruptible It wakes up only the processes that are in interruptible sleeps kthread_run To create and start a kernel thread kthread_stop To stop and clean up a kernel thread created with kthread_run kthread_should_stop To determine when thread should exit INIT_LIST_HEAD To initialize a list_head structure list_head To initialize the list list_for_each_entry To iterate over list of given type list_for_each_entry_safe To iterate over list of given type safe against removal of list entry list_add_tail To add a new entry list_del To delete entry from list nlmsg_new To create a netlink message nlmsg_put TO populate the message nlmsg_unicast To send the message to the user space application netlink_kernel_release To release the netlink socket =============================== ===================================================================== .. card:: See Also * Previous Chapters * :doc:`../chapter1_basics/chapter1_basics` * :doc:`../chapter2_kthreads/chapter2_kthreads` * :doc:`../chapter3_tasklets/chapter3_tasklets` * :doc:`../chapter4_workqueue/chapter4_workqueue` * :doc:`../chapter5_timer/chapter5_timer` * :doc:`../chapter8_linkedList/chapter8_linkedList` * :doc:`../chapter9_fileSystem/chapter9_fileSystem` * Other Netlink topic * :doc:`p1_netlinkUnicast`