net

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)) 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值