pfRing透明工作模式

特别声明: 文中所述内容纯属个人理解,如有错误,请大家指正。欢迎交流

pf_ring有三种透明模式(transparent_mode),为0时走的是Linux标准的NAPI包处理流程。为1时,包既走Linux标准包处理流程,也copy给pf_ring一份。为2时,驱动只将包拷贝给pf_ring,内核则不会接收到这些包。

从性能角度而言,三种模式的效率依次升高。

(1)通用网卡驱动

对于通用网卡驱动,只有transparent_mode=0有效。

以linux-2.6.32.43为例,说明此模式下的数据处理流程:

NAPI igb_poll (drivers/net/igb/igb_main.c 4372)
调用  igb_clean_rx_irq_adv  (drivers/net/igb/igb_main.c 4381)
调用  igb_receive_skb  (drivers/net/igb/igb_main.c 4760)
调用  napi_gro_receive (drivers/net/igb/igb_main.c 4568)

待完成

后续就到了大家的老熟人:netif_receive_skb

点击(此处)折叠或打开

  1. list_for_each_entry_rcu(ptype, &ptype_all, list) {
  2. if (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  3. ptype->dev == orig_dev) {
  4. if (pt_prev)
  5. ret = deliver_skb(skb, pt_prev, orig_dev);
  6. pt_prev = ptype;
  7. }
  8. }
  9. #ifdef CONFIG_NET_CLS_ACT
  10. skb = handle_ing(skb, &pt_prev, &ret, orig_dev);
  11. if (!skb)
  12. goto out;
  13. ncls:
  14. #endif
  15. skb = handle_bridge(skb, &pt_prev, &ret, orig_dev);
  16. if (!skb)
  17. goto out;
  18. skb = handle_macvlan(skb, &pt_prev, &ret, orig_dev);
  19. if (!skb)
  20. goto out;
  21. type = skb->protocol;
  22. list_for_each_entry_rcu(ptype,
  23. &ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
  24. if (ptype->type == type &&
  25. (ptype->dev == null_or_orig || ptype->dev == skb->dev ||
  26. ptype->dev == orig_dev)) {
  27. if (pt_prev)
  28. ret = deliver_skb(skb, pt_prev, orig_dev);
  29. pt_prev = ptype;
  30. }
  31. }
  32. if (pt_prev) {
  33. ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
  34. } else {
  35. kfree_skb(skb);
  36. /* Jamal, now you will not able to escape explaining
  37. * me how you were going to use this. :-)
  38. */
  39. ret = NET_RX_DROP;
  40. }

联系pf_ring的device_handler注册函数


点击(此处)折叠或打开

  1. void register_device_handler(void) {
  2. if(transparent_mode != standard_linux_path) return;
  3. prot_hook.func = packet_rcv;
  4. prot_hook.type = htons(ETH_P_ALL);
  5. dev_add_pack(&prot_hook);
  6. }
net_if_receive_skb会遍历所有type为ETH_P_ALL的处理函数,并调用回调处理函数packet_recv

至此,我们的pf_ring已经能从内核中获取包了。

模式1的流程图如下:

pfRing透明工作模式_第1张图片

对于pfring定制的驱动,以pf_ring 5.4.0为例,对于模式1和2,其流程如下:
NAPI  igb_poll (drivers/PF_RING_aware/intel/igb/igb-3.2.10/src/igb_main.c 5866)
调用  igb_clean_rx_irq (drivers/PF_RING_aware/intel/igb/igb-3.2.10/src/igb_main.c 5879)
igb_clean_rx_irq这个函数是关键:


点击(此处)折叠或打开

  1. #ifdef HAVE_PF_RING
  2. {
  3. if(pf_ring_handle_skb(q_vector, skb) <= 0) {
  4. #endif
  5. #ifdef HAVE_VLAN_RX_REGISTER
  6. igb_receive_skb(q_vector, skb);
  7. #else
  8. napi_gro_receive(&q_vector->napi, skb);
  9. #endif
  10. #ifdef HAVE_PF_RING
  11. }

只有当 pf_ring_handle_skb的返回值为<=0的值,才会调用napi_gro_receive函数。而pf_ring_handle_skb在什么时候会返回<=0的值呢?

看看它的定义:drivers/PF_RING_aware/intel/ixgbe/ixgbe-3.7.17/src/ixgbe_main.c 1697

点击(此处)折叠或打开

  1. #ifdef HAVE_PF_RING
  2. static int pf_ring_handle_skb(struct ixgbe_q_vector *q_vector, struct sk_buff *skb) {
  3. int debug = 0;
  4. struct pfring_hooks *hook = (struct pfring_hooks*)skb->dev->pfring_ptr;
  5. if(unlikely(debug)) printk(KERN_INFO "[PF_RING] pf_ring_handle_skb()\n");
  6. if(hook && (hook->magic == PF_RING)) {
  7. /* Wow: PF_RING is alive & kickin' ! */
  8. if(unlikely(debug))
  9. printk(KERN_INFO "[PF_RING] alive [%s][len=%d]\n", skb->dev->name, skb->len);
  10. if(*hook->transparent_mode != standard_linux_path) {
  11. u_int8_t skb_reference_in_use;
  12. int rc = hook->ring_handler(skb, 1, 1, &skb_reference_in_use,
  13. q_vector->rx.ring->queue_index,
  14. q_vector->adapter->num_rx_queues);
  15. if(rc > 0 /* Packet handled by PF_RING */) {
  16. if(*hook->transparent_mode == driver2pf_ring_non_transparent) {
  17. /* PF_RING has already freed the memory */
  18. return(rc);
  19. }
  20. }
  21. return(0);
  22. } else {
  23. if(unlikely(debug)) printk(KERN_INFO "[PF_RING] not present on %s\n", skb->dev->name);
  24. return(0);
  25. }
  26. }
  27. return(-1);
  28. }
  29. #endif

当模式设置为 standard_linux_path(transparent_mode=0)时,返回0,当设置为 driver2pf_ring_non_transparent( transparent_mode=2 )时,才可能返回大于0的值。

模式1和2的流程图如下图所示:

pfRing透明工作模式_第2张图片


从这里可以看到,当设置为模式0和模式1时,内核依然会处理这些包,而设置为2时,包只由pf_ring处理。

(3)效率提升
从上面的分析看以看出,模式0网络处理路径最长,效率也是最低的;模式1路径较短,效率比模式0要高,但内核中的处理工作依然较多;(3)模式2路径最短,内核中的处理工作较少。

你可能感兴趣的:(PFRING)