Change semantics of network API so that packet-absorbing calls *always*
authorMichael Brown <mcb30@etherboot.org>
Sat, 29 Apr 2006 17:17:43 +0000 (17:17 +0000)
committerMichael Brown <mcb30@etherboot.org>
Sat, 29 Apr 2006 17:17:43 +0000 (17:17 +0000)
take ownership of the packet, rather than doing so only if they return
success.  This breaks semantic compatibility with Linux's
hard_start_xmit() method, but means that we don't have to worry so much
about error cases.

Split mechanism of processing received packets (net_rx_process()) out
from policy (net_step()), preparatory to putting net_step() in a separate
object.

src/include/gpxe/netdevice.h
src/net/arp.c
src/net/ipv4.c
src/net/netdevice.c

index 6db95bb..1879bf1 100644 (file)
@@ -103,15 +103,14 @@ struct net_protocol {
        int ( * route ) ( const struct pk_buff *pkb,
                          struct net_header *nethdr );
        /**
-        * Handle received packets
+        * Process received packet
         *
         * @v pkb       Packet buffer
         * @ret rc      Return status code
         *
-        * If this method returns success, it has taken ownership of
-        * the packet buffer.
+        * This method takes ownership of the packet buffer.
         */
-       int ( * rx ) ( struct pk_buff *pkb );
+       int ( * rx_process ) ( struct pk_buff *pkb );
        /**
         * Transcribe network-layer address
         *
@@ -240,9 +239,9 @@ struct net_device {
         * This method should cause the hardware to initiate
         * transmission of the packet buffer.
         *
-        * If the method returns success, ownership of the packet
-        * buffer is transferred to the @c net_device, which must
-        * eventually call free_pkb() to release the buffer.
+        * Ownership of the packet buffer is transferred to the @c
+        * net_device, which must eventually call free_pkb() to
+        * release the buffer.
         */
        int ( * transmit ) ( struct net_device *netdev, struct pk_buff *pkb );
        /** Poll for received packet
@@ -332,9 +331,8 @@ free_netdev ( struct net_device *netdev __attribute__ (( unused )) ) {
  * @ret rc             Return status code
  *
  * Transmits the packet via the specified network device.  The
- * link-layer header must already have been filled in.  If this
- * function returns success, it has taken ownership of the packet
- * buffer.
+ * link-layer header must already have been filled in.  This function
+ * takes ownership of the packet buffer.
  */
 static inline int netdev_transmit ( struct net_device *netdev,
                                    struct pk_buff *pkb ) {
@@ -375,5 +373,6 @@ extern int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev );
 extern int net_transmit ( struct pk_buff *pkb );
 extern int net_poll ( void );
 extern struct pk_buff * net_rx_dequeue ( void );
+extern int net_rx_process ( struct pk_buff *pkb );
 
 #endif /* _GPXE_NETDEVICE_H */
index 3720acf..af7d6e1 100644 (file)
@@ -154,10 +154,8 @@ int arp_resolve ( struct net_device *netdev, const struct net_header *nethdr,
                 nethdr->dest_net_addr, net_protocol->net_addr_len );
 
        /* Transmit ARP request */
-       if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 ) {
-               free_pkb ( pkb );
+       if ( ( rc = net_transmit_via ( pkb, netdev ) ) != 0 )
                return rc;
-       }
 
        return -ENOENT;
 }
@@ -230,7 +228,7 @@ static int arp_rx ( struct pk_buff *pkb ) {
        if ( arphdr->ar_op != htons ( ARPOP_REQUEST ) )
                goto done;
 
-       /* Change request to a reply, and send it */
+       /* Change request to a reply */
        DBG ( "ARP reply: %s %s => %s %s\n", net_protocol->name,
              net_protocol->ntoa ( arp_target_pa ( arphdr ) ),
              ll_protocol->name, ll_protocol->ntoa ( netdev->ll_addr ) );
@@ -238,8 +236,10 @@ static int arp_rx ( struct pk_buff *pkb ) {
        memswap ( arp_sender_ha ( arphdr ), arp_target_ha ( arphdr ),
                 arphdr->ar_hln + arphdr->ar_pln );
        memcpy ( arp_target_ha ( arphdr ), netdev->ll_addr, arphdr->ar_hln );
-       if ( net_transmit_via ( pkb, netdev ) == 0 )
-               pkb = NULL;
+
+       /* Send reply */
+       net_transmit_via ( pkb, netdev );
+       pkb = NULL;
 
  done:
        free_pkb ( pkb );
@@ -286,7 +286,7 @@ arp_ntoa ( const void *net_addr __attribute__ (( unused )) ) {
 struct net_protocol arp_protocol = {
        .name = "ARP",
        .net_proto = htons ( ETH_P_ARP ),
-       .rx = arp_rx,
+       .rx_process = arp_rx,
        .route = arp_route,
        .ntoa = arp_ntoa,
 };
index 2fc5067..ecb44a2 100644 (file)
@@ -163,8 +163,7 @@ static int ipv4_rx ( struct pk_buff *pkb ) {
                pkb_empty ( pkb );
                pkb_put ( pkb, uip_len );
                memcpy ( pkb->data, uip_buf, uip_len );
-               if ( net_transmit ( pkb ) != 0 )
-                       free_pkb ( pkb );
+               net_transmit ( pkb );
        } else {
                free_pkb ( pkb );
        }
@@ -231,7 +230,7 @@ struct net_protocol ipv4_protocol = {
        .name = "IP",
        .net_proto = htons ( ETH_P_IP ),
        .net_addr_len = sizeof ( struct in_addr ),
-       .rx = ipv4_rx,
+       .rx_process = ipv4_rx,
        .route = ipv4_route,
        .ntoa = ipv4_ntoa,
 };
index 59861d0..19db792 100644 (file)
@@ -23,6 +23,7 @@
 #include <gpxe/if_ether.h>
 #include <gpxe/pkbuff.h>
 #include <gpxe/tables.h>
+#include <gpxe/process.h>
 #include <gpxe/netdevice.h>
 
 /** @file
@@ -66,9 +67,8 @@ static LIST_HEAD ( rx_queue );
  * @v netdev           Network device
  * @v pkb              Packet buffer
  *
- * The packet is added to the RX queue.  Ownership of the packet is
- * transferred to the RX queue; the caller must not touch the packet
- * buffer after calling netdev_rx().
+ * The packet is added to the RX queue.  This function takes ownership
+ * of the packet buffer.
  */
 void netdev_rx ( struct net_device *netdev, struct pk_buff *pkb ) {
        DBG ( "Packet received\n" );
@@ -137,9 +137,8 @@ find_netdev_by_net_addr ( struct net_protocol *net_protocol,
  * Transmits the packet via the specified network device.  The packet
  * must begin with a network-layer header, and the @c net_protocol
  * field must have been filled in.  If @c netdev is NULL, the network
- * device is identified via the packet contents, if possible.  If this
- * function returns success, it has taken ownership of the packet
- * buffer.
+ * device is identified via the packet contents, if possible.  This
+ * function takes ownership of the packet buffer.
  */
 int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
        struct net_protocol *net_protocol;
@@ -155,6 +154,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
                DBG ( "Could not route to %s address %s\n",
                      net_protocol->name,
                      net_protocol->ntoa ( nethdr.dest_net_addr ) );
+               free_pkb ( pkb );
                return rc;
        }
 
@@ -166,6 +166,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
                        DBG ( "No network device for %s address %s\n",
                              net_protocol->name,
                              net_protocol->ntoa ( nethdr.source_net_addr ) );
+                       free_pkb ( pkb );
                        return -EHOSTUNREACH;
                }
        }
@@ -177,6 +178,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
                DBG ( "No link-layer route to %s address %s\n",
                      net_protocol->name,
                      net_protocol->ntoa ( nethdr.dest_net_addr ) );
+               free_pkb ( pkb );
                return rc;
        }
 
@@ -184,7 +186,7 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
        pkb_push ( pkb, ll_protocol->ll_header_len );
        ll_protocol->fill_llh ( &llhdr, pkb );
 
-       /* Transmit packet */
+       /* Hand off packet to network device */
        if ( ( rc = netdev->transmit ( netdev, pkb ) ) != 0 ) {
                DBG ( "Device failed to transmit packet\n" );
                return rc;
@@ -200,9 +202,8 @@ int net_transmit_via ( struct pk_buff *pkb, struct net_device *netdev ) {
  * @v pkb              Packet buffer
  * @ret rc             Return status code
  *
- * Transmits the packet via the appropriate network device.  If this
- * function returns success, it has taken ownership of the packet
- * buffer.
+ * Transmits the packet via the appropriate network device.  This
+ * function takes ownership of the packet buffer.
  */
 int net_transmit ( struct pk_buff *pkb ) {
        return net_transmit_via ( pkb, NULL );
@@ -244,41 +245,83 @@ struct pk_buff * net_rx_dequeue ( void ) {
        return NULL;
 }
 
-void net_run ( void ) {
-       struct pk_buff *pkb;
+/**
+ * Process received packet
+ *
+ * @v pkb              Packet buffer
+ * @ret rc             Return status code
+ *
+ * Processes a packet received from the network (and, usually, removed
+ * from the RX queue by net_rx_dequeue()).  This call takes ownership
+ * of the packet buffer.
+ */
+int net_rx_process ( struct pk_buff *pkb ) {
        struct ll_protocol *ll_protocol;
        struct ll_header llhdr;
        struct net_protocol *net_protocol;
+       int rc;
 
-       while ( ( pkb = net_rx_dequeue () ) ) {
+       /* Parse link-layer header */
+       ll_protocol = pkb->ll_protocol;
+       ll_protocol->parse_llh ( pkb, &llhdr );
+       
+       /* Identify network-layer protocol */
+       net_protocol = find_net_protocol ( llhdr.net_proto );
+       if ( ! net_protocol ) {
+               DBG ( "Unknown network-layer protocol %x\n",
+                     ntohs ( llhdr.net_proto ) );
+               free_pkb ( pkb );
+               return -EPROTONOSUPPORT;
+       }
+       pkb->net_protocol = net_protocol;
+       
+       /* Strip off link-layer header */
+       pkb_pull ( pkb, ll_protocol->ll_header_len );
+       
+       /* Hand off to network layer */
+       if ( ( rc = net_protocol->rx_process ( pkb ) ) != 0 ) {
+               DBG ( "Network-layer protocol dropped packet\n" );
+               return rc;
+       }
 
-               /* Parse link-layer header */
-               ll_protocol = pkb->ll_protocol;
-               ll_protocol->parse_llh ( pkb, &llhdr );
+       return 0;
+}
 
-               /* Identify network-layer protocol */
-               net_protocol = find_net_protocol ( llhdr.net_proto );
-               if ( ! net_protocol ) {
-                       DBG ( "Unknown network-layer protocol %x\n",
-                             ntohs ( llhdr.net_proto ) );
-                       free_pkb ( pkb );
-                       continue;
-               }
-               pkb->net_protocol = net_protocol;
 
-               /* Strip off link-layer header */
-               pkb_pull ( pkb, ll_protocol->ll_header_len );
 
-               /* Hand off to network layer */
-               if ( net_protocol->rx ( pkb ) != 0 ) {
-                       DBG ( "Network-layer protocol refused packet\n" );
-                       free_pkb ( pkb );
-                       continue;
-               }
+/**
+ * Single-step the network stack
+ *
+ * @v process          Network stack process
+ *
+ * This polls all interfaces for any received packets, and processes
+ * any packets that are received during this poll.
+ */
+static void net_step ( struct process *process ) {
+       struct pk_buff *pkb;
+
+       /* Poll for new packets */
+       net_poll();
 
+       /* Handle any received packets */
+       while ( ( pkb = net_rx_dequeue () ) ) {
+               net_rx_process ( pkb );
                DBG ( "Processed received packet\n" );
        }
+
+       /* Re-schedule ourself */
+       schedule ( process );
 }
 
+/** Networking stack process */
+static struct process net_process = {
+       .step = net_step,
+};
+
+static void init_net ( void ) {
+       schedule ( &net_process );
+}
 
+#include <init.h>
 
+INIT_FN ( INIT_RPC, init_net, NULL, NULL );