net/netdev: Use upper half of netdev to simplify sim driver

Signed-off-by: Zhe Weng <wengzhe@xiaomi.com>
This commit is contained in:
Zhe Weng 2023-03-13 16:54:42 +08:00 committed by Xiang Xiao
parent 72b77d36e2
commit f21742899f
3 changed files with 320 additions and 245 deletions

View File

@ -66,288 +66,150 @@
#include <nuttx/kmalloc.h> #include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h> #include <nuttx/wqueue.h>
#include <nuttx/net/net.h> #include <nuttx/net/net.h>
#include <nuttx/net/netdev.h> #include <nuttx/net/netdev_lowerhalf.h>
#include <nuttx/net/pkt.h> #include <nuttx/net/pkt.h>
#include "sim_internal.h" #include "sim_internal.h"
#if CONFIG_IOB_BUFSIZE >= (MAX_NETDEV_PKTSIZE + \ #define SIM_NETDEV_BUFSIZE (MAX_NETDEV_PKTSIZE + CONFIG_NET_GUARDSIZE)
CONFIG_NET_GUARDSIZE + CONFIG_NET_LL_GUARDSIZE)
# define SIM_NETDEV_IOB_OFFLOAD /* We don't know packet length before receiving, so we can only offload it
* when netpkt's buffer is long enough.
*/
#if NETPKT_BUFLEN >= SIM_NETDEV_BUFSIZE
# define SIM_NETDEV_RECV_OFFLOAD
#endif #endif
/* Get index / buffer from dev pointer. */
#define DEVIDX(p) ((struct sim_netdev_s *)(p) - g_sim_dev)
#define DEVBUF(p) (((struct sim_netdev_s *)(p))->buf)
/****************************************************************************
* Private Types
****************************************************************************/
struct sim_netdev_s
{
struct netdev_lowerhalf_s dev;
uint8_t buf[SIM_NETDEV_BUFSIZE]; /* Used when packet buffer is fragmented */
};
/**************************************************************************** /****************************************************************************
* Private Function Prototypes * Private Function Prototypes
****************************************************************************/ ****************************************************************************/
static void netdriver_txdone_interrupt(void *priv); static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt);
static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev);
static int netdriver_ifup(struct netdev_lowerhalf_s *dev);
static int netdriver_ifdown(struct netdev_lowerhalf_s *dev);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
****************************************************************************/ ****************************************************************************/
/* Net driver worker */
static struct work_s g_avail_work[CONFIG_SIM_NETDEV_NUMBER];
static struct work_s g_recv_work[CONFIG_SIM_NETDEV_NUMBER];
/* Ethernet peripheral state */ /* Ethernet peripheral state */
static struct net_driver_s g_sim_dev[CONFIG_SIM_NETDEV_NUMBER]; static struct sim_netdev_s g_sim_dev[CONFIG_SIM_NETDEV_NUMBER];
static const struct netdev_ops_s g_ops =
{
netdriver_ifup, /* ifup */
netdriver_ifdown, /* ifdown */
netdriver_send, /* transmit */
netdriver_recv /* receive */
};
/**************************************************************************** /****************************************************************************
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
static void netdriver_send(struct net_driver_s *dev) static int netdriver_send(struct netdev_lowerhalf_s *dev, netpkt_t *pkt)
{ {
int devidx = (intptr_t)dev->d_private; unsigned int len = netpkt_getdatalen(dev, pkt);
#ifdef SIM_NETDEV_IOB_OFFLOAD
uint8_t *buf = NETLLBUF;
#else
uint8_t *buf = dev->d_buf;
#endif
UNUSED(devidx); if (netpkt_is_fragmented(pkt))
{
#ifdef CONFIG_NET_PKT netpkt_copyout(dev, DEVBUF(dev), pkt, len, 0);
/* When packet sockets are enabled, feed the tx frame into it */ sim_netdev_send(DEVIDX(dev), DEVBUF(dev), len);
}
pkt_input(dev); else
#endif {
sim_netdev_send(DEVIDX(dev), netpkt_getdata(dev, pkt), len);
sim_netdev_send(devidx, buf, dev->d_len);
} }
static void netdriver_reply(struct net_driver_s *dev) netpkt_free(dev, pkt, NETPKT_TX);
{ return OK;
/* If the receiving resulted in data that should be sent out on
* the network, the field d_len is set to a value > 0.
*/
if (dev->d_len > 0)
{
/* Send the packet */
NETDEV_TXPACKETS(dev);
netdriver_send(dev);
NETDEV_TXDONE(dev);
}
} }
static void netdriver_recv_work(void *arg) static netpkt_t *netdriver_recv(struct netdev_lowerhalf_s *dev)
{ {
struct net_driver_s *dev = arg; netpkt_t *pkt = NULL;
struct eth_hdr_s *eth; unsigned int len;
int devidx = (intptr_t)dev->d_private;
UNUSED(devidx); if (sim_netdev_avail(DEVIDX(dev)))
net_lock();
/* Retrieve all the queued RX frames from the network device
* to prevent RX data stream congestion.
*/
while (sim_netdev_avail(devidx))
{ {
#ifdef SIM_NETDEV_IOB_OFFLOAD pkt = netpkt_alloc(dev, NETPKT_RX);
if (netdev_iob_prepare(dev, false, 0) != OK) if (pkt == NULL)
{ {
netdriver_txdone_interrupt(dev); return NULL;
break;
} }
#endif
/* sim_netdev_read will return 0 on a timeout event and > 0 /* sim_netdev_read will return 0 on a timeout event and > 0
* on a data received event * on a data received event
*/ */
dev->d_len = sim_netdev_read(devidx, #ifdef SIM_NETDEV_RECV_OFFLOAD
(unsigned char *)dev->d_buf, len = sim_netdev_read(DEVIDX(dev), netpkt_getbase(pkt),
dev->d_pktsize); SIM_NETDEV_BUFSIZE);
if (dev->d_len > 0) #else
{ len = sim_netdev_read(DEVIDX(dev), DEVBUF(dev), SIM_NETDEV_BUFSIZE);
NETDEV_RXPACKETS(dev);
#ifdef SIM_NETDEV_IOB_OFFLOAD
iob_update_pktlen(dev->d_iob, dev->d_len - NET_LL_HDRLEN(dev));
#endif #endif
if (len == 0)
/* Data received event. Check for valid Ethernet header with
* destination == our MAC address
*/
eth = (struct eth_hdr_s *)dev->d_buf;
if (dev->d_len > ETH_HDRLEN)
{ {
#ifdef CONFIG_NET_PKT netpkt_free(dev, pkt, NETPKT_RX);
/* When packet sockets are enabled, feed the frame into return NULL;
* the packet tap. }
*/
pkt_input(dev); #ifdef SIM_NETDEV_RECV_OFFLOAD
#endif /* CONFIG_NET_PKT */ netpkt_reset_reserved(dev, pkt, 0); /* No overhead before data. */
netpkt_setdatalen(dev, pkt, len);
#else
netpkt_copyin(dev, pkt, DEVBUF(dev), len, 0);
#endif
}
/* We only accept IP packets of the configured type return pkt;
* and ARP packets }
*/
static int netdriver_ifup(struct netdev_lowerhalf_s *dev)
{
#ifdef CONFIG_NET_IPv4 #ifdef CONFIG_NET_IPv4
if (eth->type == HTONS(ETHTYPE_IP)) sim_netdev_ifup(DEVIDX(dev), &dev->netdev.d_ipaddr);
{
ninfo("IPv4 frame\n");
NETDEV_RXIPV4(dev);
/* Receive an IPv4 packet from the network device */
ipv4_input(dev);
/* Check for a reply to the IPv4 packet */
netdriver_reply(dev);
}
else
#endif /* CONFIG_NET_IPv4 */
#ifdef CONFIG_NET_IPv6
if (eth->type == HTONS(ETHTYPE_IP6))
{
ninfo("IPv6 frame\n");
NETDEV_RXIPV6(dev);
/* Give the IPv6 packet to the network layer */
ipv6_input(dev);
/* Check for a reply to the IPv6 packet */
netdriver_reply(dev);
}
else
#endif/* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_ARP
if (eth->type == HTONS(ETHTYPE_ARP))
{
ninfo("ARP frame\n");
NETDEV_RXARP(dev);
arp_input(dev);
/* If the above function invocation resulted in data that
* should be sent out on the network, the global variable
* d_len is set to a value > 0.
*/
if (dev->d_len > 0)
{
netdriver_send(dev);
}
}
else
#endif
{
NETDEV_RXDROPPED(dev);
nwarn("WARNING: Unsupported Ethernet type %u\n",
eth->type);
}
}
else
{
NETDEV_RXERRORS(dev);
}
}
#ifdef SIM_NETDEV_IOB_OFFLOAD
netdev_iob_release(dev);
#endif
}
net_unlock();
}
static int netdriver_txpoll(struct net_driver_s *dev)
{
/* Send the packet */
NETDEV_TXPACKETS(dev);
netdriver_send(dev);
NETDEV_TXDONE(dev);
/* If zero is returned, the polling will continue until all connections
* have been examined.
*/
return 0;
}
static int netdriver_ifup(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
UNUSED(devidx);
#ifdef CONFIG_NET_IPv4
sim_netdev_ifup(devidx, &dev->d_ipaddr);
#else /* CONFIG_NET_IPv6 */ #else /* CONFIG_NET_IPv6 */
sim_netdev_ifup(devidx, &dev->d_ipv6addr); sim_netdev_ifup(DEVIDX(dev), &dev->netdev.d_ipv6addr);
#endif /* CONFIG_NET_IPv4 */ #endif /* CONFIG_NET_IPv4 */
netdev_carrier_on(dev); netdev_lower_carrier_on(dev);
return OK; return OK;
} }
static int netdriver_ifdown(struct net_driver_s *dev) static int netdriver_ifdown(struct netdev_lowerhalf_s *dev)
{ {
int devidx = (intptr_t)dev->d_private; netdev_lower_carrier_off(dev);
sim_netdev_ifdown(DEVIDX(dev));
UNUSED(devidx);
netdev_carrier_off(dev);
sim_netdev_ifdown(devidx);
return OK;
}
static void netdriver_txavail_work(void *arg)
{
struct net_driver_s *dev = arg;
net_lock();
if (IFF_IS_UP(dev->d_flags))
{
devif_poll(dev, netdriver_txpoll);
}
net_unlock();
}
static int netdriver_txavail(struct net_driver_s *dev)
{
int devidx = (intptr_t)dev->d_private;
if (work_available(&g_avail_work[devidx]))
{
work_queue(LPWORK, &g_avail_work[devidx], netdriver_txavail_work,
dev, 0);
}
return OK; return OK;
} }
static void netdriver_txdone_interrupt(void *priv) static void netdriver_txdone_interrupt(void *priv)
{ {
struct net_driver_s *dev = (struct net_driver_s *)priv; struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv;
int devidx = (intptr_t)dev->d_private; netdev_lower_txdone(dev);
if (work_available(&g_avail_work[devidx]))
{
work_queue(LPWORK, &g_avail_work[devidx], netdriver_txavail_work,
dev, 0);
}
} }
static void netdriver_rxready_interrupt(void *priv) static void netdriver_rxready_interrupt(void *priv)
{ {
struct net_driver_s *dev = (struct net_driver_s *)priv; struct netdev_lowerhalf_s *dev = (struct netdev_lowerhalf_s *)priv;
int devidx = (intptr_t)dev->d_private; netdev_lower_rxready(dev);
if (work_available(&g_recv_work[devidx]))
{
work_queue(LPWORK, &g_recv_work[devidx], netdriver_recv_work, dev, 0);
}
} }
/**************************************************************************** /****************************************************************************
@ -356,12 +218,12 @@ static void netdriver_rxready_interrupt(void *priv)
int sim_netdriver_init(void) int sim_netdriver_init(void)
{ {
struct net_driver_s *dev; struct netdev_lowerhalf_s *dev;
int devidx; int devidx;
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++) for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
{ {
dev = &g_sim_dev[devidx]; dev = &g_sim_dev[devidx].dev;
/* Internal initialization */ /* Internal initialization */
@ -369,29 +231,17 @@ int sim_netdriver_init(void)
netdriver_txdone_interrupt, netdriver_txdone_interrupt,
netdriver_rxready_interrupt); netdriver_rxready_interrupt);
/* Allocate packet buffer */ /* 1TX + 1RX is enough for sim. */
#ifndef SIM_NETDEV_IOB_OFFLOAD dev->quota[NETPKT_TX] = 1;
dev->d_buf = kmm_malloc(dev->d_pktsize != 0 ? dev->quota[NETPKT_RX] = 1;
dev->d_pktsize : dev->ops = &g_ops;
(MAX_NETDEV_PKTSIZE +
CONFIG_NET_GUARDSIZE));
if (dev->d_buf == NULL)
{
return -ENOMEM;
}
#endif
dev->d_ifup = netdriver_ifup;
dev->d_ifdown = netdriver_ifdown;
dev->d_txavail = netdriver_txavail;
dev->d_private = (void *)(intptr_t)devidx;
/* Register the device with the OS so that socket IOCTLs can be /* Register the device with the OS so that socket IOCTLs can be
* performed * performed
*/ */
netdev_register(dev, NET_LL_ETHERNET); netdev_lower_register(dev, NET_LL_ETHERNET);
} }
return OK; return OK;
@ -399,13 +249,13 @@ int sim_netdriver_init(void)
void sim_netdriver_setmacaddr(int devidx, unsigned char *macaddr) void sim_netdriver_setmacaddr(int devidx, unsigned char *macaddr)
{ {
memcpy(g_sim_dev[devidx].d_mac.ether.ether_addr_octet, macaddr, memcpy(g_sim_dev[devidx].dev.netdev.d_mac.ether.ether_addr_octet, macaddr,
IFHWADDRLEN); IFHWADDRLEN);
} }
void sim_netdriver_setmtu(int devidx, int mtu) void sim_netdriver_setmtu(int devidx, int mtu)
{ {
g_sim_dev[devidx].d_pktsize = mtu + ETH_HDRLEN; g_sim_dev[devidx].dev.netdev.d_pktsize = mtu + ETH_HDRLEN;
} }
void sim_netdriver_loop(void) void sim_netdriver_loop(void)
@ -413,10 +263,9 @@ void sim_netdriver_loop(void)
int devidx; int devidx;
for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++) for (devidx = 0; devidx < CONFIG_SIM_NETDEV_NUMBER; devidx++)
{ {
if (work_available(&g_recv_work[devidx]) && sim_netdev_avail(devidx)) if (sim_netdev_avail(devidx))
{ {
work_queue(LPWORK, &g_recv_work[devidx], netdriver_recv_work, netdev_lower_rxready(&g_sim_dev[devidx].dev);
&g_sim_dev[devidx], 0);
} }
} }
} }

View File

@ -633,6 +633,46 @@ int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev)
return OK; return OK;
} }
/****************************************************************************
* Name: netdev_lower_carrier_on
*
* Description:
* Notifies the networking layer about an available carrier.
* (e.g. a cable was plugged in)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_on(FAR struct netdev_lowerhalf_s *dev)
{
return netdev_carrier_on(&dev->netdev);
}
/****************************************************************************
* Name: netdev_lower_carrier_off
*
* Description:
* Notifies the networking layer about an disappeared carrier.
* (e.g. a cable was unplugged)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_off(FAR struct netdev_lowerhalf_s *dev)
{
return netdev_carrier_off(&dev->netdev);
}
/**************************************************************************** /****************************************************************************
* Name: netdev_lower_rxready * Name: netdev_lower_rxready
* *
@ -779,6 +819,54 @@ int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
return iob_copyout(dest, pkt, len, offset - NET_LL_HDRLEN(&dev->netdev)); return iob_copyout(dest, pkt, len, offset - NET_LL_HDRLEN(&dev->netdev));
} }
/****************************************************************************
* Name: netpkt_getdata/getbase
*
* Description:
* Get the pointer of data/base in a netpkt, used when NETPKT_BUFLEN is
* big enough to fit a full packet in.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
*
* Returned Value:
* Pointer data/base, NULL on failure.
*
****************************************************************************/
FAR uint8_t *netpkt_getdata(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt)
{
return IOB_DATA(pkt) - NET_LL_HDRLEN(&dev->netdev);
}
FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt)
{
return pkt->io_data;
}
/****************************************************************************
* Name: netpkt_setdatalen
*
* Description:
* Set the length of data in netpkt, used when data is written into
* netpkt by data/base pointer, no need to set this length after
* copyin.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The length of data in netpkt
*
****************************************************************************/
void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len)
{
iob_update_pktlen(pkt, len - NET_LL_HDRLEN(&dev->netdev));
}
/**************************************************************************** /****************************************************************************
* Name: netpkt_getdatalen * Name: netpkt_getdatalen
* *
@ -799,3 +887,39 @@ unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev,
{ {
return pkt->io_pktlen + NET_LL_HDRLEN(&dev->netdev); return pkt->io_pktlen + NET_LL_HDRLEN(&dev->netdev);
} }
/****************************************************************************
* Name: netpkt_reset_reserved
*
* Description:
* Reset the reserved length (the starting point of data) of netpkt
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The reserved length
*
****************************************************************************/
void netpkt_reset_reserved(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len)
{
iob_reserve(pkt, len + NET_LL_HDRLEN(&dev->netdev));
}
/****************************************************************************
* Name: netpkt_is_fragmented
*
* Description:
* Returns whether the netpkt is fragmented into different blocks.
* In other words, NETPKT_BUFLEN < reserved + total data
*
* Input Parameters:
* pkt - The net packet
*
****************************************************************************/
bool netpkt_is_fragmented(FAR netpkt_t *pkt)
{
return pkt->io_flink != NULL;
}

View File

@ -174,6 +174,40 @@ int netdev_lower_register(FAR struct netdev_lowerhalf_s *dev,
int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev); int netdev_lower_unregister(FAR struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Name: netdev_lower_carrier_on
*
* Description:
* Notifies the networking layer about an available carrier.
* (e.g. a cable was plugged in)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_on(FAR struct netdev_lowerhalf_s *dev);
/****************************************************************************
* Name: netdev_lower_carrier_off
*
* Description:
* Notifies the networking layer about an disappeared carrier.
* (e.g. a cable was unplugged)
*
* Input Parameters:
* dev - The lower half device driver structure
*
* Returned Value:
* 0:Success; negated errno on failure
*
****************************************************************************/
int netdev_lower_carrier_off(FAR struct netdev_lowerhalf_s *dev);
/**************************************************************************** /****************************************************************************
* Name: netdev_lower_rxready * Name: netdev_lower_rxready
* *
@ -278,6 +312,44 @@ int netpkt_copyin(FAR struct netdev_lowerhalf_s *dev, FAR netpkt_t *pkt,
int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest, int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
FAR const netpkt_t *pkt, unsigned int len, int offset); FAR const netpkt_t *pkt, unsigned int len, int offset);
/****************************************************************************
* Name: netpkt_getdata/getbase
*
* Description:
* Get the pointer of data/base in a netpkt, used when NETPKT_BUFLEN is
* big enough to fit a full packet in.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
*
* Returned Value:
* Pointer data/base, NULL on failure.
*
****************************************************************************/
FAR uint8_t *netpkt_getdata(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt);
FAR uint8_t *netpkt_getbase(FAR netpkt_t *pkt);
/****************************************************************************
* Name: netpkt_setdatalen
*
* Description:
* Set the length of data in netpkt, used when data is written into
* netpkt by data/base pointer, no need to set this length after
* copyin.
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The length of data in netpkt
*
****************************************************************************/
void netpkt_setdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len);
/**************************************************************************** /****************************************************************************
* Name: netpkt_getdatalen * Name: netpkt_getdatalen
* *
@ -296,4 +368,34 @@ int netpkt_copyout(FAR struct netdev_lowerhalf_s *dev, FAR uint8_t *dest,
unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev, unsigned int netpkt_getdatalen(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt); FAR netpkt_t *pkt);
/****************************************************************************
* Name: netpkt_reset_reserved
*
* Description:
* Reset the reserved length (the starting point of data) of netpkt
*
* Input Parameters:
* dev - The lower half device driver structure
* pkt - The net packet
* len - The reserved length
*
****************************************************************************/
void netpkt_reset_reserved(FAR struct netdev_lowerhalf_s *dev,
FAR netpkt_t *pkt, unsigned int len);
/****************************************************************************
* Name: netpkt_is_fragmented
*
* Description:
* Returns whether the netpkt is fragmented into different blocks.
* In other words, NETPKT_BUFLEN < reserved + total data
*
* Input Parameters:
* pkt - The net packet
*
****************************************************************************/
bool netpkt_is_fragmented(FAR netpkt_t *pkt);
#endif /* __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H */ #endif /* __INCLUDE_NUTTX_NET_NETDEV_LOWERHALF_H */