internal_port作用
OVS没有使用内核提供的桥,重新造了一套和桥等同的模块叫dp,为啥叫dp?叫switch不行么。
有一种情况是不可避免的:机器只有一张物理网卡,既要跑OVS,又要跑内核协议栈,怎么处理?
internal_port就是解决这个问题的,所以就至少要有两个能力:从dp上面把该送到本机的报文送上去,把本机发出去的报文最终通过物理口发出去。
internal_port创建
用户态通过命令创建dp(ovs_dp_cmd_new)时,会创建一个和dp同名字的端口,端口类型为OVS_VPORT_TYPE_INTERNAL
也就是说internal类型的端口原则上是不能通过外部命令创建的
parms.name = nla_data(a[OVS_DP_ATTR_NAME]);
parms.type = OVS_VPORT_TYPE_INTERNAL;
parms.options = NULL;
parms.dp = dp;
parms.port_no = OVSP_LOCAL;
parms.upcall_portids = a[OVS_DP_ATTR_UPCALL_PID];
vport = new_vport(&parms);
internal_port收方向
挂在dp上的硬件网卡收到包(netdev_frame_hook)后
查询流表根据action选择不同的后续流程
对于internal_port来说是action为OVS_ACTION_ATTR_OUTPUT,调用do_output,接下来调用send函数,对于internal_port来说就是internal_dev_recv
收流程调用堆栈
internal_dev_recv函数
skb->pkt_type = PACKET_HOST和linux内核原生的桥一样,指示该报文为本机关注报文
netif_rx函数会调用netif_receive_skb接着调用网络协议栈,就像真正的物理口收到报文一样送到协议栈。
总结下就是:internal_port收包是把包送给主机协议栈了
internal_port发方向
这里的发指的是主机协议栈通过该接口发送报文出去,创建设备时注册了发送函数:internal_dev_xmit
static const struct net_device_ops internal_dev_netdev_ops = {
.ndo_open = internal_dev_open,
.ndo_stop = internal_dev_stop,
.ndo_start_xmit = internal_dev_xmit,
.ndo_set_mac_address = eth_mac_addr,
#if !defined(HAVE_NET_DEVICE_WITH_MAX_MTU) && !defined(HAVE_RHEL7_MAX_MTU)
.ndo_change_mtu = internal_dev_change_mtu,
#endif
.ndo_get_stats64 = (void *)internal_get_stats,
};
internal_dev_xmit:
函数实现比较简单,直接调用ovs_vport_receive函数,走dp那一套流程,计算flow_key根据action做后续动作,最终会调用物理网卡发送出去,对于ovs来说就是OVS_VPORT_TYPE_NETDEV这种类型的发送函数dev_queue_xmit