在使用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);