HedongGao commented on code in PR #21502:
URL: https://github.com/apache/nuttx/pull/21502#discussion_r4501404223
##########
drivers/net/netdev_upperhalf.c:
##########
@@ -1318,7 +1321,15 @@ static int netdev_upper_ifup(FAR struct net_driver_s
*dev)
if (upper->lower->ops->ifup)
{
- return upper->lower->ops->ifup(upper->lower);
+ ret = upper->lower->ops->ifup(upper->lower);
+ if (ret < 0)
+ {
+ return ret;
+ }
+
+ /* Register netdev drivers */
+
+ return netdev_drivers_init(upper->lower);
Review Comment:
Fixed in 345df5f. `netdev_upper_ifup()` now returns the lower half's `ifup`
result; a failure to bind the netdev drivers is only logged with `nwarn()`.
virtio-net now implements `txpoll` (d331d6d, it reuses `virtio_net_txfree()`).
Verified on `qemu-armv8a:notenet` (virtio-net): `ifup eth0` prints `OK` and
`ping -c 3 10.0.2.2` gets 3/3 replies. On the previous revision the same config
printed `ifup eth0...Failed` and ping failed with errno 101, as you described.
##########
drivers/note/notenet_driver.c:
##########
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * drivers/note/notenet_driver.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/net/netpoll.h>
+#include <nuttx/note/note_driver.h>
+#include <nuttx/note/notenet_driver.h>
+#include <nuttx/panic_notifier.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/wqueue.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#define NOTENET_WORK_DELAY MSEC2TICK(CONFIG_DRIVERS_NOTENET_WORK_DELAY)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct notenet_driver_s
+{
+ struct note_driver_s driver; /* Note driver part, must be first element */
+ spinlock_t lock; /* Lock */
+ FAR netpkt_t *pkt; /* Allocated net packet */
+ size_t next; /* The next index (where data is added) */
+ struct work_s work; /* Used for deferred callback work */
+ struct netpoll_s np; /* Netpoll */
+ struct notifier_block nb; /* Panic notifier */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static bool notenetdev_transfer(FAR struct notenet_driver_s *drv);
+static void notenetdev_work(FAR void *priv);
+static void note_netdev_add(FAR struct note_driver_s *driver,
+ FAR const void *note, size_t notelen);
+static int netdev_note_panic_callback(FAR struct notifier_block *nb,
+ unsigned long action,
+ FAR void *data);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct note_driver_ops_s g_notenetdev_ops =
+{
+ note_netdev_add
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+struct notenet_driver_s g_notenet =
+{
+ {
+#ifdef CONFIG_SCHED_INSTRUMENTATION_FILTER
+ "net",
+ {
+ {
+ CONFIG_SCHED_INSTRUMENTATION_FILTER_DEFAULT_MODE,
+# ifdef CONFIG_SMP
+ CONFIG_SCHED_INSTRUMENTATION_CPUSET
+# endif
+ },
+ },
+#endif
+ &g_notenetdev_ops
+ },
+ .lock = SP_UNLOCKED
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: notenetdev_transfer
+ ****************************************************************************/
+
+static bool notenetdev_transfer(FAR struct notenet_driver_s *drv)
+{
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+
+ if (drv->next == 0)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return true;
+ }
+
+ /* Send IOB */
+
+ ret = netpoll_udp_pkt_send(&drv->np, drv->pkt);
+ if (ret < 0)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return false;
+ }
+
+ /* Get IOB - blocking */
+
+ drv->pkt = netpoll_udp_pkt_alloc(&drv->np);
+ drv->next = 0;
+
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+
+ return true;
+}
+
+/****************************************************************************
+ * Name: notenetdev_work
+ ****************************************************************************/
+
+static void notenetdev_work(FAR void *arg)
+{
+ FAR struct notenet_driver_s *drv = arg;
+
+ if (!notenetdev_transfer(drv))
+ {
+ work_queue(HPWORK, &drv->work, notenetdev_work, arg,
+ NOTENET_WORK_DELAY);
+ }
+}
+
+/****************************************************************************
+ * Name: note_netdev_add
+ *
+ * Description:
+ * Add the variable length note to the transport layer
+ *
+ * Input Parameters:
+ * note - The note buffer
+ * notelen - The buffer length
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * We are within a critical section.
+ *
+ ****************************************************************************/
+
+static void note_netdev_add(FAR struct note_driver_s *driver,
+ FAR const void *note, size_t notelen)
+{
+ FAR struct notenet_driver_s *drv =
+ (FAR struct notenet_driver_s *)driver;
+ clock_t delay = NOTENET_WORK_DELAY;
+ size_t maxlen = netpoll_get_maxlen(&drv->np);
+ size_t space;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+
+ /* Ignore data if device is not ready */
+
+ if (!drv->pkt)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return;
+ }
+
+try:
+ if (drv->next + notelen > maxlen)
+ {
+ /* Unlock before entering notenetdev_transfer,
+ * it is already locked internally
+ */
+
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ notenetdev_transfer(drv);
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+ goto try;
Review Comment:
Fixed in 345df5f. `note_netdev_add()` no longer sends and no longer loops:
when the note does not fit (or no packet is available, or the IOB copy fails)
the note is dropped and the work is kicked, the same way `noterpmsg_add()`
handles a full buffer. When `transmit()` refuses the packet, the packet is
freed.
Verified: `ifup eth0`, `ifdown eth0`, wait 5 s, `ps` answers. On the
previous revision (with a virtio-net `txpoll` added) the console stopped
answering after `ifdown eth0`.
##########
drivers/note/notenet_driver.c:
##########
@@ -0,0 +1,301 @@
+/****************************************************************************
+ * drivers/note/notenet_driver.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <nuttx/net/netpoll.h>
+#include <nuttx/note/note_driver.h>
+#include <nuttx/note/notenet_driver.h>
+#include <nuttx/panic_notifier.h>
+#include <nuttx/spinlock.h>
+#include <nuttx/wqueue.h>
+
+/****************************************************************************
+ * Pre-processor definitions
+ ****************************************************************************/
+
+#define NOTENET_WORK_DELAY MSEC2TICK(CONFIG_DRIVERS_NOTENET_WORK_DELAY)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+struct notenet_driver_s
+{
+ struct note_driver_s driver; /* Note driver part, must be first element */
+ spinlock_t lock; /* Lock */
+ FAR netpkt_t *pkt; /* Allocated net packet */
+ size_t next; /* The next index (where data is added) */
+ struct work_s work; /* Used for deferred callback work */
+ struct netpoll_s np; /* Netpoll */
+ struct notifier_block nb; /* Panic notifier */
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static bool notenetdev_transfer(FAR struct notenet_driver_s *drv);
+static void notenetdev_work(FAR void *priv);
+static void note_netdev_add(FAR struct note_driver_s *driver,
+ FAR const void *note, size_t notelen);
+static int netdev_note_panic_callback(FAR struct notifier_block *nb,
+ unsigned long action,
+ FAR void *data);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct note_driver_ops_s g_notenetdev_ops =
+{
+ note_netdev_add
+};
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+struct notenet_driver_s g_notenet =
+{
+ {
+#ifdef CONFIG_SCHED_INSTRUMENTATION_FILTER
+ "net",
+ {
+ {
+ CONFIG_SCHED_INSTRUMENTATION_FILTER_DEFAULT_MODE,
+# ifdef CONFIG_SMP
+ CONFIG_SCHED_INSTRUMENTATION_CPUSET
+# endif
+ },
+ },
+#endif
+ &g_notenetdev_ops
+ },
+ .lock = SP_UNLOCKED
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: notenetdev_transfer
+ ****************************************************************************/
+
+static bool notenetdev_transfer(FAR struct notenet_driver_s *drv)
+{
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+
+ if (drv->next == 0)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return true;
+ }
+
+ /* Send IOB */
+
+ ret = netpoll_udp_pkt_send(&drv->np, drv->pkt);
+ if (ret < 0)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return false;
+ }
+
+ /* Get IOB - blocking */
+
+ drv->pkt = netpoll_udp_pkt_alloc(&drv->np);
+ drv->next = 0;
+
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+
+ return true;
+}
+
+/****************************************************************************
+ * Name: notenetdev_work
+ ****************************************************************************/
+
+static void notenetdev_work(FAR void *arg)
+{
+ FAR struct notenet_driver_s *drv = arg;
+
+ if (!notenetdev_transfer(drv))
+ {
+ work_queue(HPWORK, &drv->work, notenetdev_work, arg,
+ NOTENET_WORK_DELAY);
+ }
+}
+
+/****************************************************************************
+ * Name: note_netdev_add
+ *
+ * Description:
+ * Add the variable length note to the transport layer
+ *
+ * Input Parameters:
+ * note - The note buffer
+ * notelen - The buffer length
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * We are within a critical section.
+ *
+ ****************************************************************************/
+
+static void note_netdev_add(FAR struct note_driver_s *driver,
+ FAR const void *note, size_t notelen)
+{
+ FAR struct notenet_driver_s *drv =
+ (FAR struct notenet_driver_s *)driver;
+ clock_t delay = NOTENET_WORK_DELAY;
+ size_t maxlen = netpoll_get_maxlen(&drv->np);
+ size_t space;
+ irqstate_t flags;
+
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+
+ /* Ignore data if device is not ready */
+
+ if (!drv->pkt)
+ {
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ return;
+ }
+
+try:
+ if (drv->next + notelen > maxlen)
+ {
+ /* Unlock before entering notenetdev_transfer,
+ * it is already locked internally
+ */
+
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+ notenetdev_transfer(drv);
+ flags = spin_lock_irqsave_notrace(&drv->lock);
+ goto try;
+ }
+
+ /* Copy data to packet */
+
+ netpoll_pkt_copy(&drv->np, drv->pkt, note, notelen, drv->next);
+ drv->next += notelen;
+
+ /* Start work immediately when data more then 75% */
+
+ space = maxlen - drv->next;
+ if (space < maxlen / 4)
+ {
+ delay = 0;
+ }
+
+ spin_unlock_irqrestore_notrace(&drv->lock, flags);
+
+ if (work_available(&drv->work))
+ {
+ work_queue(HPWORK, &drv->work, notenetdev_work, drv, delay);
+ }
+}
+
+/****************************************************************************
+ * Name: netdev_note_panic_callback
+ *
+ * Description:
+ * This is panic callback for note driver.
+ *
+ ****************************************************************************/
+
+static int netdev_note_panic_callback(FAR struct notifier_block *nb,
+ unsigned long action,
+ FAR void *data)
+{
+ FAR struct notenet_driver_s *note =
+ container_of(nb, struct notenet_driver_s, nb);
+
+ if (action == PANIC_KERNEL_FINAL)
+ {
+ notenetdev_transfer(note);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: notenet_init
+ *
+ * Description:
+ * Register a netdev channel to note.
+ *
+ * Input Parameters:
+ * dev - The lower half netdev driver structure to be bound.
+ *
+ * Returned Value:
+ * Zero on success. A negated errno value is returned on a failure.
+ *
+ ****************************************************************************/
+
+int notenet_init(FAR struct netdev_lowerhalf_s *dev)
+{
+ FAR struct notenet_driver_s *note = &g_notenet;
+ irqstate_t flags;
+ int ret;
+
+ flags = spin_lock_irqsave_notrace(¬e->lock);
+
+ /* Initialize netpoll */
+
+ ret = netpoll_udp_init(¬e->np, dev,
+ CONFIG_DRIVERS_NOTENET_PORT,
+ CONFIG_DRIVERS_NOTENET_IPADDR,
+ CONFIG_DRIVERS_NOTENET_PORT,
+ CONFIG_DRIVERS_NOTENET_MAC);
+ if (ret < 0)
+ {
+ goto errout;
+ }
+
+ /* Register panic notifier */
+
+ note->nb.notifier_call = netdev_note_panic_callback;
+ panic_notifier_chain_register(¬e->nb);
+
+ /* Allocate iob */
+
+ note->pkt = netpoll_udp_pkt_alloc(¬e->np);
Review Comment:
Fixed. `notenet_init()` binds only once (`bound` flag): a second `ifup` on
the same device returns `OK` without touching the packet or registering the
panic notifier again (345df5f). `netpoll_pkt_alloc()` now retries `txpoll` a
bounded number of times and returns `NULL` (eb5ab3f), and every caller handles
`NULL`.
Verified: 10 `ifdown`/`ifup` cycles, then ping still works and `free` shows
no growth.
##########
net/netpoll/netpoll_udp.c:
##########
@@ -0,0 +1,414 @@
+/****************************************************************************
+ * net/netpoll/netpoll_udp.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <netinet/ether.h>
+#include <nuttx/net/netpoll.h>
+#include <nuttx/net/udp.h>
+
+#include "inet/inet.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: netpoll_udp_build_header
+ *
+ * Description:
+ * Fill packet with UDP header
+ *
+ * Input Parameters:
+ * np - pointer to netpoll data
+ * pkt - packet to send
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static void netpoll_udp_build_header(FAR struct netpoll_s *np,
+ FAR netpkt_t *pkt)
+{
+ FAR struct netdev_lowerhalf_s *lower = np->lower;
+ FAR struct eth_hdr_s *eth;
+ FAR struct ipv4_hdr_s *ipv4;
+ FAR struct udp_hdr_s *udp;
+ FAR uint8_t *data;
+ size_t offset = 0;
+
+ /* Get IO data */
+
+ data = netpkt_getdata(lower, pkt);
+
+ /* Fill MAC header */
+
+ eth = (FAR struct eth_hdr_s *)&data[offset];
+ eth->type = htons(ETHTYPE_IP);
+ memcpy(eth->dest, np->destmac, sizeof(eth->dest));
+ memcpy(eth->src, &lower->netdev.d_mac, sizeof(eth->src));
+
+ /* Fill IPv4 header */
+
+ offset += ETH_HDRLEN;
+ ipv4 = (FAR struct ipv4_hdr_s *)&data[offset];
+ ipv4_build_header(ipv4, pkt->io_len, IP_PROTO_UDP, &lower->netdev.d_ipaddr,
+ &np->destipaddr, IP_TTL_DEFAULT, 0, NULL);
+
+ /* Fill UDP header */
+
+ offset += IPv4_HDRLEN;
+ udp = (FAR struct udp_hdr_s *)&data[offset];
+
+ udp->srcport = np->srcport;
+ udp->destport = np->destport;
+ udp->udplen = htons(pkt->io_len - IPv4_HDRLEN);
+ udp->udpchksum = 0;
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: netpoll_udp_init
+ *
+ * Description:
+ * Initialize netpoll with UDP.
+ *
+ * Input Parameters:
+ * np - pointer to netpoll data
+ * lower - pointer to netdev lower
+ * srcport - source port number
+ * destipaddr - destination IP address
+ * destport - destination port number
+ * destmac - MAC address octets in string format: "ff:ff:ff:ff:ff:ff".
+ * Default: "ff:ff:ff:ff:ff:ff"
+ *
+ * Returned Value:
+ * Returns OK on success
+ *
+ ****************************************************************************/
+
+int netpoll_udp_init(FAR struct netpoll_s *np,
+ FAR struct netdev_lowerhalf_s *lower,
+ uint16_t srcport, in_addr_t destipaddr,
+ uint16_t destport, FAR const char *destmac)
+{
+ struct ether_addr addr;
+
+ if (lower->ops->txpoll == NULL)
+ {
+ return -EINVAL;
+ }
+
+ memset(np, 0, sizeof(struct netpoll_s));
+
+ if (destmac == NULL)
+ {
+ destmac = "ff:ff:ff:ff:ff:ff";
+ }
+
+ /* Decode MAC */
+
+ if (!ether_aton_r(destmac, &addr))
+ {
+ return -EINVAL;
+ }
+
+ memcpy(np->destmac, addr.ether_addr_octet, ETHER_ADDR_LEN);
+
+ /* Parameters */
+
+ np->srcport = htons(srcport);
+ np->destipaddr = htonl(destipaddr);
+ np->destport = htons(destport);
+
+ /* Store lower half reference */
+
+ np->lower = lower;
+
+ /* Store header length for later */
+
+ np->hdrlen = NET_LL_HDRLEN(&lower->netdev) + IPv4UDP_HDRLEN;
+
+ /* Get maximum UDP packet length for this device */
+
+ np->maxlen = NETDEV_PKTSIZE(&lower->netdev) - np->hdrlen;
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: netpoll_udp_pkt_alloc
+ *
+ * Description:
+ * Allocate UDP packet.
+ *
+ * Input Parameters:
+ * np - pointer to netpoll data
+ *
+ * Returned Value:
+ * Pointer to packet on success; NULL on failure.
+ *
+ ****************************************************************************/
+
+FAR netpkt_t *netpoll_udp_pkt_alloc(FAR struct netpoll_s *np)
+{
+ FAR struct netdev_lowerhalf_s *lower = np->lower;
+ FAR netpkt_t *pkt;
+
+ /* Get packet */
+
+ pkt = netpoll_pkt_alloc(lower);
+ if (!pkt)
+ {
+ return NULL;
+ }
+
+ /* Initialize packet with header length */
+
+ netpkt_setdatalen(lower, pkt, np->hdrlen);
+
+ return pkt;
+}
+
+/****************************************************************************
+ * Name: netpoll_udp_pkt_send
+ *
+ * Description:
+ * Send packet as UDP packet with netpoll.
+ *
+ * Input Parameters:
+ * np - pointer to netpoll data
+ * pkt - packet to send
+ *
+ * Returned Value:
+ * Length of header if success, negative value on failure
+ *
+ * Assumption:
+ * Packet is ready to send, all packet headers are complete, only UDP
+ * payload len can change.
+ *
+ ****************************************************************************/
+
+int netpoll_udp_pkt_send(FAR struct netpoll_s *np, FAR netpkt_t *pkt)
+{
+ FAR struct netdev_lowerhalf_s *lower = np->lower;
+ int ret;
+
+ /* Don't send data if device is not ready */
+
+ if (!IFF_IS_RUNNING(lower->netdev.d_flags))
+ {
+ return -ENODEV;
+ }
+
+ /* Fill header */
+
+ netpoll_udp_build_header(np, pkt);
+
+ /* Transmit packet */
+
+ ret = lower->ops->transmit(lower, pkt);
Review Comment:
Fixed as you suggested. Sending now only happens from the work
(`notenetdev_work()`), which holds `netdev_lock()` around `transmit()`, the
same lock the upper half holds in `netdev_upper_txavail_work()`. The packet is
detached from the note buffer under the spinlock and sent after the spinlock is
released, since `netdev_lock()` is a mutex. The only inline send is the
`PANIC_KERNEL_FINAL` notifier. `netpoll_udp_pkt_send()` documents this and
asserts it: `DEBUGASSERT(OSINIT_IS_PANIC() ||
nxrmutex_is_hold(&lower->netdev.d_lock))` (eb5ab3f).
Verified on `qemu-armv8a:netnsh_smp` (4 CPUs) with
`CONFIG_DEBUG_ASSERTIONS=y` and notenet enabled: pings of 1400 bytes at 10 ms
intervals together with note traffic, plus `ifdown`/`ifup`; no assertion, 0%
loss.
##########
net/netpoll/netpoll_udp.c:
##########
@@ -0,0 +1,414 @@
+/****************************************************************************
+ * net/netpoll/netpoll_udp.c
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership. The
+ * ASF licenses this file to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include <nuttx/config.h>
+
+#include <netinet/ether.h>
+#include <nuttx/net/netpoll.h>
+#include <nuttx/net/udp.h>
+
+#include "inet/inet.h"
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: netpoll_udp_build_header
+ *
+ * Description:
+ * Fill packet with UDP header
+ *
+ * Input Parameters:
+ * np - pointer to netpoll data
+ * pkt - packet to send
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ ****************************************************************************/
+
+static void netpoll_udp_build_header(FAR struct netpoll_s *np,
+ FAR netpkt_t *pkt)
+{
+ FAR struct netdev_lowerhalf_s *lower = np->lower;
+ FAR struct eth_hdr_s *eth;
+ FAR struct ipv4_hdr_s *ipv4;
+ FAR struct udp_hdr_s *udp;
+ FAR uint8_t *data;
+ size_t offset = 0;
+
+ /* Get IO data */
+
+ data = netpkt_getdata(lower, pkt);
+
+ /* Fill MAC header */
+
+ eth = (FAR struct eth_hdr_s *)&data[offset];
+ eth->type = htons(ETHTYPE_IP);
+ memcpy(eth->dest, np->destmac, sizeof(eth->dest));
+ memcpy(eth->src, &lower->netdev.d_mac, sizeof(eth->src));
+
+ /* Fill IPv4 header */
+
+ offset += ETH_HDRLEN;
+ ipv4 = (FAR struct ipv4_hdr_s *)&data[offset];
+ ipv4_build_header(ipv4, pkt->io_len, IP_PROTO_UDP, &lower->netdev.d_ipaddr,
Review Comment:
Fixed in eb5ab3f: both lengths use `pkt->io_pktlen`.
Verified with `CONFIG_IOB_BUFSIZE=196`, capturing with QEMU `filter-dump`
and checking `ip.len == frame.len - 14` and `udp.length == ip.len - 20` in
tshark: 92 note frames, all spanning several IOBs, 0 mismatches. The previous
revision gave 27 mismatches out of 54 frames (IPv4 length 164, UDP length 144),
matching your numbers.
##########
net/Kconfig:
##########
@@ -67,6 +67,15 @@ config NET_DEFAULT_MAX_PORT
---help---
Default Network max port
+config NET_NETPOLL
Review Comment:
Fixed in eb5ab3f: `depends on NET_IPv4 && NET_ETHERNET`.
##########
drivers/net/Make.defs:
##########
@@ -27,7 +27,7 @@ ifeq ($(CONFIG_NET),y)
# Include network interface drivers
ifeq ($(CONFIG_MM_IOB),y)
- CSRCS += netdev_upperhalf.c
+ CSRCS += netdev_upperhalf.c netdev_drivers.c
Review Comment:
Fixed in 345df5f: `netdev_drivers.c` is built (Make.defs and CMakeLists.txt)
and called from `netdev_upper_ifup()` only when `CONFIG_DRIVERS_NOTENET` is set.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]