Tuesday, April 29, 2025

Linux Kernel Networking - random topics

netif_start_queue()   

clears __QUEUE_STATE_DRV_XOFF flags of  TX queue 0.  __QUEUE_STATE_DRV_XOFF is used by drivers to stop the queue. __QUEUE_STATE_STACK_XOFF is used by stack to stop the transmit queue independently. 


Input Packet Queues, the Softnet_data Structure

packet qeueing structure contains an internal data structure called softnet_data. 

 a)   struct sk_buff_head input_pkt_queue : 

 b) struct list_head poll_list;    Poll_list is a list of network interfaces to be processed. It is used by backlog processing.

Queuing Layer Initialization

   for_each_possible_cpu(i) {
               struct softnet_data *sd = &per_cpu(softnet_data, i);
                skb_queue_head_init(&sd->input_pkt_queue);
                skb_queue_head_init(&sd->process_queue);
                INIT_LIST_HEAD(&sd->poll_list);
                sd->output_queue_tailp = &sd->output_queue;
                spin_lock_init(&sd->defer_lock);
                gro_init(&sd->backlog.gro);
                sd->backlog.poll = process_backlog;
                sd->backlog.weight = weight_p;
                INIT_LIST_HEAD(&sd->backlog.poll_list);
                open_softirq(NET_TX_SOFTIRQ, net_tx_action);
                open_softirq(NET_RX_SOFTIRQ, net_rx_action);

        }

net_rx_action

{

     struct softnet_data *sd = this_cpu_ptr(&softnet_data);
     local_irq_disable();
     list_splice_init(&sd->poll_list, &list);
     local_irq_enable();
     n = list_first_entry(&list, struct napi_struct, poll_list);
     budget -= napi_poll(n, &repoll);
     net_rps_action_and_irq_enable()
}



net_rps_action_and_irq_enable()
{
    struct softnet_data *remsd = sd->rps_ipi_list;
    net_rps_send_ipi()
}

process_backlog()

{
 struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
     if (sd->rps_ipi_list) {
               // send IPI
     }
     while ((skb = __skb_dequeue(&sd->process_queue)))  {
         __netif_receive_skb(skb);
     }
      skb_queue_splice_tail_init(&sd->input_pkt_queue,
                                                   &sd->process_queue);
}


raise_softirq_irqoff

{
        __raise_softirq_irqoff(nr);
        /*
         * If we're in an interrupt or softirq, we're done
         * (this also catches softirq-disabled code). We will
         * actually run the softirq once we return from
         * the irq or softirq.
         *
         * Otherwise we wake up ksoftirqd to make sure we
         * schedule the softirq soon.
         */
        if (!in_interrupt() && should_wake_ksoftirqd())
                wakeup_softirqd();
}


napi_schedule()

{

    ___napi_schedule(this_cpu_ptr(&softnet_data), n) 
       {
           if (test_bit(NAPI_STATE_THREADED, &napi->state)) { 
            // if threaded NAPI, invoke NAPI process; else 
           } else {
              list_add_tail(&napi->poll_list, &sd->poll_list);
              if (!sd->in_net_rx_action)
                       raise_softirq_irqoff(NET_RX_SOFTIRQ);
          }

}



__raise_softirq_irqoff

set local_softirq_pending_ref 's corresponding BH flag. 


run_ksoftirqd()
{
          handle_softirqs() 
          {
                //will iterate thru pending softirq list and execute actions.
                pending = local_softirq_pending();

                while ((softirq_bit = ffs(pending))) {

                    h->action();  // action is set when open_softirq() is called 

                }


napi_schedule_rps()

After we queue packet to another CPU's input queue,  we need to make sure this queue is serviced soon.
If this is another cpu queue, link it to our rps_ipi_list, and make sure we will process rps_ipi_list from net_rx_action(). If this is our own queue, NAPI schedule our backlog, Note that this also raises NET_RX_SOFTIRQ. 


 enqueue_to_backlog()

enqueue_to_backlog is called to queue an skb to a per CPU backlog queue of a CPU. 

     sd = &per_cpu(softnet_data, cpu);
     backlog_lock_irq_save(sd, &flags);
     qlen = skb_queue_len(&sd->input_pkt_queue);
     if (qlen <= max_backlog) {
          if (!__test_and_set_bit(NAPI_STATE_SCHED,   &sd->backlog.state))
                                napi_schedule_rps(sd);
     }     
     __skb_queue_tail(&sd->input_pkt_queue, skb);
    backlog_unlock_irq_restore(sd, &flags); 



netif_rx()

netif_rx() receives packet from driver driver and enqueues to stack to process via backlog NAPI. This function can be invoked from interrupt and process context.  This function calls local_bh_disable() if not interrupt context. 

netif_rx() --> netif_rx_internal() 

                          |
                 if (rps) enabled, get_rps_cpu() and enqueue_to_backlog()
                else case  enqueue_to_backlog() of this cpu
                             |
                       Please see enqueue_to_backlog() and process_backlog()


netif_receive_skb

                    netif_receive_skb_internal() 
                        |
                    if (rps) enabled, enqueue_to_backlog of get_rps_cpu()
                     else __netif_receive_skb()
                        |
                 __netif_receive_skb_core()
                        |
                    ipv4_rcv/ipv6_rcv


Monday, October 19, 2015



Auto Login to Ubunutu machine from windows using putty



1. Login to ubuntu machine
2. ssh-keygen -t rsa ( dont enter any passphrase)
  public and private key would be generated in ~/.ssh.  id_rsa and id_rsa.pub.

3. Copy  id_rsa.pub to ~/.ssh/authorized_keys

4. Uncomment the line Authorized_key in /etc/ssh/sshd_config

5. service ssh restart

4. Copy id_rsa to windows machine

5. Download putty-keygen 

6. Load the copied id_rsa into putty-keygen and save as private key

7. Open putty and load the private key.