目前遇到问题如下:IPv6 http以及ping 不通主机 同一个网段!
为了找出原因:想用systemtap 但是编译对应环境的systemtap 失败,x86正常 但是 arm-linux 失败,没办法只能选择使用kprobe了
排查的问题的时候,使用tcpdump 抓包能抓到包, 然后就通了!!
使用kprobe debug 了一下 netif_receive_skb ; 发现没有收到报文!!
#define NIP6(addr) ntohs((addr).s6_addr16[0]), ntohs((addr).s6_addr16[1]), ntohs((addr).s6_addr16[2]), ntohs((addr).s6_addr16[3]), ntohs((addr).s6_addr16[4]), ntohs((addr).s6_addr16[5]), ntohs((addr).s6_addr16[6]), ntohs((addr).s6_addr16[7]) #define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" static void print_skb_ipv6(const struct sk_buff* skb) { struct ipv6hdr* ip6h; struct tcphdr* th; struct in6_addr ip6_sip, ip6_dip; int sport, dport; ip6h = ipv6_hdr(skb); ip6_sip = ip6h->saddr; ip6_dip = ip6h->daddr; if (ip6h->nexthdr != NEXTHDR_TCP && ip6h->nexthdr != NEXTHDR_ICMP ) { return; } if (ip6h->nexthdr == NEXTHDR_ICMP) { printk(" Source: "NIP6_FMT" Dest: " NIP6_FMT" icmp ------> ", NIP6(ip6_sip), NIP6(ip6_dip)); return; } //skb->transport_header = skb->network_header + sizeof(*ip6h); th = tcp_hdr(skb); sport = ntohs(th->source); dport = ntohs(th->dest); printk("tcp Source: "NIP6_FMT" sport:%d --->Dest: "NIP6_FMT" dport:%d --->n", NIP6(ip6_sip), sport, NIP6(ip6_dip), dport); return; } static int ipv6_rcv_hook(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { print_skb_ipv6(skb); jprobe_return(); return 0; } static struct jprobe ipv6_recv_probe; static int probe_netif_receive_skb_fun(struct sk_buff *skb) { __be16 type; type = skb->protocol; if (type == htons(ETH_P_IPV6)) { struct ipv6hdr *hdr; hdr = (struct ipv6hdr *)(skb->data); if (hdr->nexthdr == NEXTHDR_ICMP ) { printk(" dev source: "NIP6_FMT" Dest: " NIP6_FMT" dev_netif_receive icmp------> ", NIP6(hdr->saddr), NIP6(hdr->daddr)); }else if(hdr->nexthdr == NEXTHDR_TCP) { printk(" dev source: "NIP6_FMT" Dest: " NIP6_FMT" dev_netif_receive tcp------> ", NIP6(hdr->saddr), NIP6(hdr->daddr)); }else { printk("dev source: "NIP6_FMT" Dest: " NIP6_FMT" dev_netif_receive ipporttype:0x%x---0x%x---> ", NIP6(hdr->saddr), NIP6(hdr->daddr), hdr->nexthdr , ntohs(hdr->nexthdr)); } } jprobe_return(); return 0; } static struct jprobe probe_netif_receive_skb; int kp_init(void) { int retval; ipv6_recv_probe.kp.addr = (kprobe_opcode_t*)kallsyms_lookup_name("ipv6_rcv"); ipv6_recv_probe.entry = (kprobe_opcode_t*)ipv6_rcv_hook; retval = register_jprobe(&ipv6_recv_probe); pr_notice("init register_jprobe %d ", retval); probe_netif_receive_skb.kp.addr = (kprobe_opcode_t*)kallsyms_lookup_name("netif_receive_skb"); probe_netif_receive_skb.entry = (kprobe_opcode_t*)probe_netif_receive_skb_fun; retval = register_jprobe(&probe_netif_receive_skb); pr_notice("init probe_netif_receive_skb register_jprobe %d ", retval); return 0; } void kp_exit(void) { unregister_jprobe(&ipv6_recv_probe); unregister_jprobe(&probe_netif_receive_skb); pr_notice("module removed "); }
所以此时认为是 驱动将报文丢弃! 由于tcpdump会将驱动dev的属性设置为
hw->addr_ctrl.user_set_promisc = false; if (netdev->flags & IFF_PROMISC) { hw->addr_ctrl.user_set_promisc = true; fctrl |= (NGBE_PSR_CTL_UPE | NGBE_PSR_CTL_MPE); /* pf don't want packets routing to vf, so clear UPE */ vmolr |= NGBE_PSR_VM_L2CTL_MPE; vlnctrl &= ~NGBE_PSR_VLAN_CTL_VFE; }
在 set_rx_mode 属性中可以看到 #define NGBE_PSR_VM_L2CTL_MPE 0x00001000U /* multicast promiscuous */
设置 抓取组播报文!! 由于ipv6 中的邻居协议 探测 ip 对应的mac 时, 其nd 邻居协议发送探测报文对应的使用 组播mac ,所以可能驱动不设置的时候 会将 报文丢弃!!
/* This is useful for sniffing bad packets. */ if (netdev->features & NETIF_F_RXALL) { vmolr |= (NGBE_PSR_VM_L2CTL_UPE | NGBE_PSR_VM_L2CTL_MPE); vlnctrl &= ~NGBE_PSR_VLAN_CTL_VFE; /* receive bad packets */ wr32m(hw, NGBE_RSEC_CTL, NGBE_RSEC_CTL_SAVE_MAC_ERR, NGBE_RSEC_CTL_SAVE_MAC_ERR);
驱动中还有 rxall 标志!! 所以设置为rx_all 在测试其是否正常!
目前看 设置此标志后!! 能够解决问题
后续在 分析这里面使用到的 hook_napi 技术