linux/net/core/dev.c 中找到 dev_queue_xmit() 和 netif_rx()/ netif_receive_skb() 函数
net_device{}结构,对应于每一个网络接口设备。
包含很多可以直接获取网卡信息的函数和变量,网卡操作的函数,
指向该网卡驱动程序的许多函数入口,包括发送接收数据帧到缓冲区等。
接收:到缓冲区后便由 netif_rx(在net/core/dev.c)把它们组成 sk_buff 形式挂到系统接收的backlog队列交由上层协议处理。
发送:上层协议处理下来的 sk_buff 。由 dev_queue_xmit() 函数放入网络缓冲区,交给网卡驱动程序的发送程序处理。
struct net_device {
char name[IFNAMSIZ];
unsigned long mem_end; /* shared mem end */
unsigned long mem_start; /* shared mem start */
unsigned long base_addr; /* device I/O address */
int irq; /* device IRQ number */
unsigned long state;
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
struct list_head close_list;
netdev_features_t features;
netdev_features_t hw_features;
netdev_features_t wanted_features;
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
const struct forwarding_accel_ops *fwd_ops;
const struct header_ops *header_ops;
unsigned int flags; /* interface flags (a la BSD) */
unsigned int priv_flags; /* Like ‘flags‘ but invisible to userspace.
* See if.h for definitions. */
unsigned short gflags;
unsigned short padded; /* How much padding added by alloc_netdev() alloc_netdev()时加入的pad的大小 */
unsigned char operstate; /* RFC2863 operstate */
unsigned char link_mode; /* mapping policy to operstate */
unsigned char if_port; /* Selectable AUI, TP,.多端口设备使用哪一个端口.*/
unsigned char dma; /* DMA channel */
unsigned int mtu; /* interface MTU value */
unsigned short type; /* interface hardware type */
unsigned short hard_header_len; /* hardware hdr length */
unsigned short needed_headroom;
unsigned short needed_tailroom;
unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
unsigned char addr_assign_type; /* hw address assignment type */
unsigned char addr_len; /* hardware address length */
struct kset *queues_kset;
int watchdog_timeo; /* used by dev_watchdog() */
};
struct net_device_ops {
(*ndo_open)(struct net_device *dev);
(*ndo_start_xmit) ...
}
struct sk_buff { struct sk_buff *next; struct sk_buff *prev;
struct sock *sk; /* 报文的socket */
struct net_device *dev; /* */ ...
union {unsigned char *raw;} mac; /* MAC层报文帧头的指针 */
unsigned int len, /* 套接字缓存所代表的报文长度 */
unsigned char *head, *data;}
发送
int dev_queue_xmit(struct sk_buff *skb) //向下发送数据
->struct net_device *dev = skb->dev;
rc = dev_hard_start_xmit(skb, dev, txq);
-> rc = ops->ndo_start_xmit(skb, dev); /* 被dev_queue_xmit()回调, */
ndo_start_xmit() 位于net_device->net_device_ops, 需要网络驱动实现:
struct net_device_ops cpsw_netdev_ops = {
.ndo_start_xmit = cpsw_ndo_start_xmit, ...}
cpsw_ndo_start_xmit(struct sk_buff *skb,struct net_device *ndev)
-->cpsw_tx_packet_submit()
-->cpdma_chan_submit(priv->txch, skb, skb->data, skb->len, 1, GFP_KERNEL);
直接用中断接收
int netif_rx(struct sk_buff *skb) //在驱动程序的中断中 被调用
-> ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
使用 napi poll 接收方式:
1.
static int __devinit cpsw_probe(struct platform_device *pdev)
-> priv->rxch = cpdma_chan_create(priv->dma, rx_chan_num(0), cpsw_rx_handler); /* dma 接收中断 */
-> netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT);
netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT); /* 指定poll函数 */
SET_NETDEV_DEV(ndev, &pdev->dev); ret = register_netdev(ndev); /* register the network device */
2. 接收中断
void cpsw_rx_handler(void *token, int len, int status){
if (likely(status >= 0)) {
skb_put(skb, len); /* add data to a buffer */
netif_receive_skb(skb); ..}/* process receive buffer from network */
}
struct napi_struct { /* NAPI scheduling 类似tasklet 但是使用weight */
struct list_head poll_list; int weight;
int (*poll)(struct napi_struct *, int); ...} /* 轮询函数 */
netif_receive_skb(skb); //须用 netif_receive_skb把Packets 传递到 kernel , 而不是 netif_rx()
budget 参数提供了允许我们传递到内核的最大包数。
poll()方法能够在给定的范围内处理所有可用的数据包,接收中断应该重新使能。
netif_rx_complete() 关闭 polling
if (likely(status >= 0))
net_device{}结构,对应于每一个网络接口设备。
包含很多可以直接获取网卡信息的函数和变量,网卡操作的函数,
指向该网卡驱动程序的许多函数入口,包括发送接收数据帧到缓冲区等。
接收:到缓冲区后便由 netif_rx(在net/core/dev.c)把它们组成 sk_buff 形式挂到系统接收的backlog队列交由上层协议处理。
发送:上层协议处理下来的 sk_buff 。由 dev_queue_xmit() 函数放入网络缓冲区,交给网卡驱动程序的发送程序处理。
struct net_device {
char name[IFNAMSIZ];
unsigned long mem_end; /* shared mem end */
unsigned long mem_start; /* shared mem start */
unsigned long base_addr; /* device I/O address */
int irq; /* device IRQ number */
unsigned long state;
struct list_head dev_list;
struct list_head napi_list;
struct list_head unreg_list;
struct list_head close_list;
netdev_features_t features;
netdev_features_t hw_features;
netdev_features_t wanted_features;
const struct net_device_ops *netdev_ops;
const struct ethtool_ops *ethtool_ops;
const struct forwarding_accel_ops *fwd_ops;
const struct header_ops *header_ops;
unsigned int flags; /* interface flags (a la BSD) */
unsigned int priv_flags; /* Like ‘flags‘ but invisible to userspace.
* See if.h for definitions. */
unsigned short gflags;
unsigned short padded; /* How much padding added by alloc_netdev() alloc_netdev()时加入的pad的大小 */
unsigned char operstate; /* RFC2863 operstate */
unsigned char link_mode; /* mapping policy to operstate */
unsigned char if_port; /* Selectable AUI, TP,.多端口设备使用哪一个端口.*/
unsigned char dma; /* DMA channel */
unsigned int mtu; /* interface MTU value */
unsigned short type; /* interface hardware type */
unsigned short hard_header_len; /* hardware hdr length */
unsigned short needed_headroom;
unsigned short needed_tailroom;
unsigned char perm_addr[MAX_ADDR_LEN]; /* permanent hw address */
unsigned char addr_assign_type; /* hw address assignment type */
unsigned char addr_len; /* hardware address length */
struct kset *queues_kset;
int watchdog_timeo; /* used by dev_watchdog() */
};
struct net_device_ops {
(*ndo_open)(struct net_device *dev);
(*ndo_start_xmit) ...
}
struct sk_buff { struct sk_buff *next; struct sk_buff *prev;
struct sock *sk; /* 报文的socket */
struct net_device *dev; /* */ ...
union {unsigned char *raw;} mac; /* MAC层报文帧头的指针 */
unsigned int len, /* 套接字缓存所代表的报文长度 */
unsigned char *head, *data;}
发送
int dev_queue_xmit(struct sk_buff *skb) //向下发送数据
->struct net_device *dev = skb->dev;
rc = dev_hard_start_xmit(skb, dev, txq);
-> rc = ops->ndo_start_xmit(skb, dev); /* 被dev_queue_xmit()回调, */
ndo_start_xmit() 位于net_device->net_device_ops, 需要网络驱动实现:
struct net_device_ops cpsw_netdev_ops = {
.ndo_start_xmit = cpsw_ndo_start_xmit, ...}
cpsw_ndo_start_xmit(struct sk_buff *skb,struct net_device *ndev)
-->cpsw_tx_packet_submit()
-->cpdma_chan_submit(priv->txch, skb, skb->data, skb->len, 1, GFP_KERNEL);
直接用中断接收
int netif_rx(struct sk_buff *skb) //在驱动程序的中断中 被调用
-> ret = enqueue_to_backlog(skb, get_cpu(), &qtail);
使用 napi poll 接收方式:
1.
static int __devinit cpsw_probe(struct platform_device *pdev)
-> priv->rxch = cpdma_chan_create(priv->dma, rx_chan_num(0), cpsw_rx_handler); /* dma 接收中断 */
-> netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT);
netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT); /* 指定poll函数 */
SET_NETDEV_DEV(ndev, &pdev->dev); ret = register_netdev(ndev); /* register the network device */
2. 接收中断
void cpsw_rx_handler(void *token, int len, int status){
if (likely(status >= 0)) {
skb_put(skb, len); /* add data to a buffer */
netif_receive_skb(skb); ..}/* process receive buffer from network */
}
struct napi_struct { /* NAPI scheduling 类似tasklet 但是使用weight */
struct list_head poll_list; int weight;
int (*poll)(struct napi_struct *, int); ...} /* 轮询函数 */
netif_receive_skb(skb); //须用 netif_receive_skb把Packets 传递到 kernel , 而不是 netif_rx()
budget 参数提供了允许我们传递到内核的最大包数。
poll()方法能够在给定的范围内处理所有可用的数据包,接收中断应该重新使能。
netif_rx_complete() 关闭 polling
if (likely(status >= 0))