2

The userspace application running on HOST works without any issue but the same application fails to run in LXC container with error ECONNREFUSED;
The userspace application fails with ECONNREFUSED during sendmsg to netlink

Linux kernel 3.4 with namespace support and LXC with 1.0.2 version is used.

Registering myApp.ko kernel module as below

    netlink_kernel_create(&init_net, ..... );

and userspace app fails during sendmsg to the netlink socket;

    sock = socket(PF_NETLINK, SOCK_RAW, ....);

Userspace application is running insider C1 container and it make use of getpid(); for nlMsg->nlmsg->pid

    nlMsg->nlmsg_pid = getpid();

Netlink register handler on receiving the msg is not even called in Kernel but userspace application running inside container fails with "Connection Refused" during sendmsg();

Is there something I need to address to run the same userspace app in container? I tried even giving constant number to pid variable rather than using getpid(); but then also hitting the same issue;

  socket(PF_NETLINK, SOCK_RAW, 31)        = 4

  bind(4, {sa_family=AF_NETLINK, pid=812, groups=00000000}, 12) = 0

  sendmsg(4, {msg_name(12)={sa_family=AF_NETLINK, pid=0, groups=00000000}, msg_iov(1)=[{"\20\0\0\0\2\0\0\0\0\0\0\0,\3\0\0", 16}], msg_controllen=0, msg_flags=0}, 0) = -1 **ECONNREFUSED** (Connection refused)
Viswesn
  • 4,674
  • 2
  • 28
  • 45

1 Answers1

1

Finally, I find the solution; We need to add now extra code to support Netlink to be namespace aware.

Example (Just template)

 struct my_nlns_sock {
    struct list_head list;
    struct sock *sk;
 }
 static LIST_HEAD(my_nlns_sock_list);
 static DEFINE_SPINLOCK(my_nlns_sock_lock); 

 static int __net_init my_nlns_start(struct net *net)
 {
    struct my_nlns_sock *nlsk;

    nlsk = kzalloc(sizeof(*nlsk), GFP_KERNEL);
    if (!nlsk)
        return -ENOMEM;

    nlsk->sk = netlink_kernel_create(net, ...);
    spin_lock_bh(&my_nlns_sock_lock);
    list_add_tail(&nlsk->list, &my_nlns_sock_list);
    spin_unlock_bh(&my_nlns_sock_lock);
 }

 static void my_nlns_exit(struct net *net)
 {
     struct my_nlns_sock *nlsk;

     spin_lock_bh(&my_nlns_sock_lock);
     list_for_each_entry(nlsk, &my_nlns_sock_list, list) {
          if (sock_net(nlsk->sk) == net)
               goto found;
     }
     spin_unlock_bh(&rfal_nl_sock_lock);
     return;
 found:
      list_del(&nlsk->list);
      spin_unlock_bh(&my_nlns_sock_lock);
      netlink_kernel_release(nlsk->sk);
      kfree(nlsk);
 }
 int my_nlns_recv_data(struct sk_buff skbFrom)
 {
     struct my_nlns_sock *nlsk;

     spin_lock_bh(&my_nlns_sock_lock);
     list_for_each_entry(nlsk, &my_nlns_sock_list, list) {
     if (sock_net(nlsk->sk) == net)
           goto found;
     }
     spin_unlock_bh(&my_nlns_sock_lock);
     return;
  found:
        /* Do with data */
  }
Viswesn
  • 4,674
  • 2
  • 28
  • 45
  • In my_nlns_recv_data(), below line should be added to retrieve net namespace from sbkFrom: struct net *net = sock_net(skb->sk); – Jing Qiu Oct 22 '20 at 18:18
  • @Viswesn Thanks for this. It is a very solid answer, but it is not quite clear to me how this is creating on the kernel side the awareness of the namespace. Can you provide more comments or information about what this code does? – Thecave3 Jun 30 '22 at 23:52