在使用weave时遇到的问题:在新的内核版本中 CentOS Linux (3.10.0-327.10.1.el7.x86_64) 7 (Core) ,在MTU为1450的主机上,weave的fast data
path路径不可用,该功能是在weave 1.2.0上引入的。启动后一直为sleeve模式。该问题和内核的版本相关,
问题分析:
Weave的fast data path路径使用到了odp技术,也就是内核中的OVS模块,在Container中直接发送数据包到ovs模块,由ovs模块进行封装后发送。fast data path需要内核中的openvswitch.ko模块的支持。在启动Weave时,会自动选择使用sleeve模式还是fastdp模式,这里通过发送心跳包来决定的,在云主机上通过 docker logs weave的日志可以看到,下面的信息,其中:fastdp timed out waiting for vxlan heartbeat
这个heartbeat的数据包,是一个UDP包,目的端口号为6784,在主机上接口的MTU值为1450,但是在发送UDP的heartbeat数据包时,发送的还是1474字节,这样就会对报文在IP层进行分片,但在主机上发现心跳报文发送不出,在MTU的值修改为1500后,就可以发送出去,在MTU为1450的情况下,会出现下面的ICMP的错误报文。
发送icmp报文是在ip_fragment函数中做的
点击(此处)折叠或打开
-
if (unlikely(((iph->frag_off & htons(IP_DF)) && !skb->ignore_df) ||
-
(IPCB(skb)->frag_max_size &&
-
IPCB(skb)->frag_max_size > mtu))) {
-
IP_INC_STATS(dev_net(dev), IPSTATS_MIB_FRAGFAILS);
-
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
-
htonl(mtu));
-
kfree_skb(skb);
-
return -EMSGSIZE;
- }
在net/openvswitch/vport-vxlan.c文件中对报文中的iph->frag_off进行了设置
点击(此处)折叠或打开
-
df = tun_key->tun_flags & TUNNEL_DONT_FRAGMENT ?
- htons(IP_DF) : 0;
-
skb->ignore_df = 1;
在iptunnel_xmit 函数中把iph->frag_off = df;赋值给了frag_off。但是skb->ignore_df在iptunnel_xmit函数中调用skb_scrub_packet进行了清除。
点击(此处)折叠或打开
-
void skb_scrub_packet(struct sk_buff *skb, bool xnet)
-
{
-
if (xnet)
-
skb_orphan(skb);
-
skb->tstamp.tv64 = 0;
-
skb->pkt_type = PACKET_HOST;
-
skb->skb_iif = 0;
-
skb->ignore_df = 0;
-
skb_dst_drop(skb);
-
skb->mark = 0;
-
secpath_reset(skb);
-
nf_reset(skb);
-
nf_reset_trace(skb);
- }
所以在ip_fragment中的判断skb->ignore_df为0。但在新的内核中
点击(此处)折叠或打开
-
int iptunnel_xmit(struct net *net, struct rtable *rt,
-
struct sk_buff *skb,
-
__be32 src, __be32 dst, __u8 proto,
-
__u8 tos, __u8 ttl, __be16 df)
-
{
-
int pkt_len = skb->len;
-
struct iphdr *iph;
-
int err;
-
-
nf_reset(skb);
-
secpath_reset(skb);/*调用的该函数,该函数并没有对skb->ignore_df 进行清除。
-
在static inline void
-
secpath_reset(struct sk_buff *skb)
-
{
-
#ifdef CONFIG_XFRM
-
secpath_put(skb->sp);
-
skb->sp = NULL;
-
#endif
-
} */
-
skb_clear_hash(skb);
- skb_dst_drop(skb);