网络报文到达主机后,最终会到达协议栈的netif_receive_skb函数,该函数会通过设备对象的rx_handler函数把报文交给OVS处理。 而该rx_handler函数其实就是OVS 定义的netdev_frame_hook函数,本篇内容就是从netdev_frame_hook函数开始,分析报文在datapath中的整个主处理过程。
1、netdev_frame_hook函数
该函数为OVS与内核桥接点,所以函数定义受内核定义影响
static rx_handler_result_t netdev_frame_hook(struct sk_buff **pskb)
{
struct sk_buff *skb = *pskb;
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return RX_HANDLER_PASS;
port_receive(skb);
return RX_HANDLER_CONSUMED;
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) || \
defined HAVE_RHEL_OVS_HOOK
/* Called with rcu_read_lock and bottom-halves disabled. */
static struct sk_buff *netdev_frame_hook(struct sk_buff *skb)
{
if (unlikely(skb->pkt_type == PACKET_LOOPBACK))
return skb;
port_receive(skb);
return NULL;
}
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32)
/*
* Used as br_handle_frame_hook. (Cannot run bridge at the same time, even on
* different set of devices!)
*/
/* Called with rcu_read_lock and bottom-halves disabled. */
static struct sk_buff *netdev_frame_hook(struct net_bridge_port *p,
struct sk_buff *skb)
{
port_receive(skb);
return NULL;
}
#else
#error
#endif
2、port_receive函数
#ifndef HAVE_METADATA_DST
#define port_receive(skb) netdev_port_receive(skb, NULL)
#else
#define port_receive(skb) netdev_port_receive(skb, skb_tunnel_info(skb)) //报文中包含隧道信息,说明协议栈支持隧道报文了
#endif
3、netdev_port_receive函数
/* Must be called with rcu_read_lock. */
void netdev_port_receive(struct sk_buff *skb, struct ip_tunnel_info *tun_info)
{
struct vport *vport;
vport = ovs_netdev_get_vport(skb->dev); //通过netdev设备获得vport对象,是实现在datapath中转发的基础
if (unlikely(!vport))
goto error;
if (unlikely(skb_warn_if_lro(skb)))
goto error;