}
第一步加tapA的流程:
iface_configure_qos
->netdev_linux_set_policing(tapA, rate=0, burst=0)
由于此时netdev->cache_valid=0,
因此会走一遍tc_add_del_ingress_qdisc(netdev_, false);这就是add-port时会将端口的tc规则删除的原因
全部走完后,netdev->cache_valid |= VALID_POLICING
由于该端口属于system口,因此加完后,内核会发一个RTM_NEWLINK的消息过来
netdev_linux_update
-->netdev_linux_changed: netdev->cache_valid =
VALID_DRVINFO
第二步加tapB的流程:
同样的最后tapB网卡: netdev->cache_valid =
VALID_DRVINFO
但是tapB网卡增加的时候,会继续在函数iface_configure_qos对tapA网卡进行操作
此时的tapA流程:
iface_configure_qos
->netdev_linux_set_policing(tapA, rate=0, burst=0)
由于netdev->cache_valid 并没有置位VALID_POLICING,
因此会直接走函数tc_add_del_ingress_qdisc(netdev_, false);
然后在最后将netdev->cache_valid |=
VALID_POLICING
第三步删tapA网卡:
同样的删除tapA后,会继续在函数iface_configure_qos对tapB网卡进行操作
此时的tapB由于netdev->cache_valid 并没有置位VALID_POLICING, 因此会直接走函数tc_add_del_ingress_qdisc(netdev_,
false);
这就是tapB网卡的ingress规则被删除的原因
如果反过来删tapB网卡,受影响的tapA网卡由于标志位VALID_POLICING被置上,因此判断当前的rate和burst和存储的一样,直接go
out
跳过了del ingress qdisc的接口。
其他的更多网卡情况可以照此分析。
至此,问题的原因已经找到了,但是怎么解决?
其实到目前为止,openvswitch社区一直没有一个很明确的方法来解决这个问题,只是在讨论当中。
此处,笔者给出自己的一个方案,算抛装引玉吧
@@ -689,6 +689,8 @@ netdev_linux_update(struct netdev_linux *dev,
{
if (rtnetlink_type_is_rtnlgrp_link(change->nlmsg_type)){
if (change->nlmsg_type == RTM_NEWLINK) {
+ int old_flag = dev->cache_valid;
+
/* Keep drv-info, in4, in6. */
netdev_linux_changed(dev, change->ifi_flags,
VALID_DRVINFO | VALID_IN4 | VALID_IN6);
@@ -706,6 +708,10 @@ netdev_linux_update(struct netdev_linux *dev,
dev->ether_addr_error = 0;
}
+ if (old_flag & VALID_POLICING){
+ dev->cache_valid |= VALID_POLICING;
+ }
+
dev->ifindex = change->if_index;
dev->cache_valid |= VALID_IFINDEX;
dev->get_ifindex_error = 0;
@@ -1991,6 +1997,10 @@ netdev_linux_set_policing(struct netdev *netdev_,
: !kbits_burst ? 1000 /* Default to 1000 kbits if 0. */
: kbits_burst); /* Stick with user-specified value. */
+ if (!kbits_rate && !(netdev->cache_valid & VALID_POLICING)){
+ return 0;
+ }
+
ovs_mutex_lock(&netdev->mutex);
if (netdev->cache_valid & VALID_POLICING) {
error = netdev->netdev_policing_error;
@@ -2025,6 +2035,8 @@ netdev_linux_set_policing(struct netdev *netdev_,
netdev_name, ovs_strerror(error));
goto out;
}
+
+ netdev->cache_valid |= VALID_POLICING;
}
netdev->kbits_rate = kbits_rate;
@@ -2033,7 +2045,6 @@ netdev_linux_set_policing(struct netdev *netdev_,
out:
if (!error || error == ENODEV) {
netdev->netdev_policing_error = error;
- netdev->cache_valid |= VALID_POLICING;
}
ovs_mutex_unlock(&netdev->mutex);
return error;
简单点来说,就是把flag VALID_POLICING作为ingress policing是否使能的标志