加入收藏 | 设为首页 | 会员中心 | 我要投稿 常州站长网 (https://www.0519zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核实践 - 如何添加网络协议[二]:实现

发布时间:2016-09-28 18:42:11 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核版本:2.6.34 实现思路: 报文在网络协议栈中的流动,对于接收来讲,是 对报文的脱壳的过程,由于报文是已知的输入,只要逐个解析协议号;对于发送来讲,是各层发送函数的嵌套调用,由于没有已 知的输入,只能按事先设计好的协议进行层层构造

在接收函数brcm_skb_rcv()中对于成功接收的报文会增加流量统计:

rx_stats = per_cpu_ptr(brcm_dev_info(skb->dev)->brcm_rx_stats,     
  smp_processor_id());     
rx_stats->rx_packets++;     
rx_stats->rx_bytes += skb->len;

在发送函数brcm_dev_hard_start_xmit()中对于发送的报文会增加相应流量 统计:

if (likely(ret == NET_XMIT_SUCCESS)) {     
txq->tx_packets++;     
txq->tx_bytes += len;     
} else 
 txq->tx_dropped++;

而brcm_netdev_ops->ndo_get_stats()即brcm_dev_get_stats()函数,则会将brcm网卡设 备中记录的发送和接收流量信息汇总成通用的格式net_device_stats,像ifconfig等命令使用的就是net_device_stats转换后的 结果。

完整收发函数

有了这些后接收函数brcm_skb_recv()就可以完整了,其中关于报头 brcm_hdr的处理可以略过,由于是空想的协议,含义是可以自己设定的:

int 

brcm_skb_recv(struct sk_buff *skb, struct net_device *dev,     
    struct packet_type *ptype, struct net_device *orig_dev)     
{
 struct brcm_hdr *bhdr;
 struct brcm_rx_stats *rx_stats;
 int op, brcm_port;

 skb = skb_share_check(skb, GFP_ATOMIC);
 if(!skb)
  goto err_free;
 bhdr = (struct brcm_hdr *)skb->data;
 op = bhdr->brcm_tag.brcm_53242_op;
 brcm_port = bhdr->brcm_tag.brcm_53242_src_portid- 23;     

 rcu_read_lock();     

 // drop wrong brcm tag packet     
 if (op != BRCM_RCV_OP || brcm_port < 1      
  || brcm_port > 27)      
  goto err_unlock;     

 skb->dev = find_brcm_dev(dev, brcm_port);     
 if (!skb->dev) {     
  goto err_unlock;     
 }     

 rx_stats = per_cpu_ptr(brcm_dev_info(skb->dev)->brcm_rx_stats,     
          smp_processor_id());     
 rx_stats->rx_packets++;     
 rx_stats->rx_bytes += skb->len;     
 skb_pull_rcsum(skb, BRCM_HLEN);     
         
 switch (skb->pkt_type) {     
 case PACKET_BROADCAST: /* Yeah, stats collect these together.. */ 
  /* stats->broadcast ++; // no such counter :-( */ 
  break;     

 case PACKET_MULTICAST:     
  rx_stats->multicast++;     
  break;     

 case PACKET_OTHERHOST:     
  /* Our lower layer thinks this is not local, let's make sure.    
   * This allows the VLAN to have a different MAC than the    
   * underlying device, and still route correctly.    
   */ 
  if (!compare_ether_addr(eth_hdr(skb)->h_dest,     
     skb->dev->dev_addr))     
   skb->pkt_type = PACKET_HOST;     
  break;     
 default:     
  break;     
 }     

 // set protocol     
 skb->protocol = bhdr->brcm_encapsulated_proto;     
         
 // reorder skb     
 skb = brcm_check_reorder_header(skb);     
 if (!skb) {     
  rx_stats->rx_errors++;     
  goto err_unlock;     
 }     
          
 netif_rx(skb);     
 rcu_read_unlock();     
 return NET_RX_SUCCESS;     
         
err_unlock:     
 rcu_read_unlock();     
         
err_free:     
 kfree_skb(skb);     
 return NET_RX_DROP;     
}

(编辑:常州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读