沒看過 network driver 的 code. trace 一下看會不會蒙到
就你那行 BUG 的意思解釋在這:
112 /*
113 * Check whether we were atomic before we did preempt_disable():
114 * (used by the scheduler, *after* releasing the kernel lock)
115 */
116 #define in_atomic_preempt_off() \
117 ((preempt_count() & ~PREEMPT_ACTIVE) != PREEMPT_CHECK_OFFSET)
=> 必須確保你是在 atomic context
1576 static struct packet_type ip_packet_type __read_mostly = {
1577 .type = cpu_to_be16(ETH_P_IP),
1578 .func = ip_rcv,
1579 .gso_send_check = inet_gso_send_check,
1580 .gso_segment = inet_gso_segment,
1581 .gro_receive = inet_gro_receive,
1582 .gro_complete = inet_gro_complete,
1583 };
inet_init()
...
1686 ipv4_proc_init();
1687
1688 ipfrag_init();
1689
1690 dev_add_pack(&ip_packet_type);
1691
1692 rc = 0;
看起來 func 就是收到 data 時要執行的內容.
1203 struct packet_type {
1204 __be16 type; /* This is really htons(ether_type). */
1205 struct net_device *dev; /* NULL is wildcarded here */
1206 int (*func) (struct sk_buff *,
1207 struct net_device *,
1208 struct packet_type *,
1209 struct net_device *);
1210 struct sk_buff *(*gso_segment)(struct sk_buff *skb,
1211 int features);
1212 int (*gso_send_check)(struct sk_buff *skb);
1213 struct sk_buff **(*gro_receive)(struct sk_buff **head,
1214 struct sk_buff *skb);
1215 int (*gro_complete)(struct sk_buff *skb);
1216 void *af_packet_priv;
1217 struct list_head list;
1218 };
所以 ip_rcv 就是收到 packet 的動作對吧
377 * dev_add_pack - add packet handler
378 * @pt: packet type declaration
379 *
380 * Add a protocol handler to the networking stack. The passed &packet_type
381 * is linked into kernel lists and may not be freed until it has been
382 * removed from the kernel lists.
383 *
384 * This call does not sleep therefore it can not
385 * guarantee all CPU's that are in middle of receiving packets
386 * will see the new packet type (until the next received packet).
387 */
388
389 void dev_add_pack(struct packet_type *pt)
看了一下 網路教的 trace 是 netif_rx()--->netif_receive_skb()->deliver_skb()->packet_type.func 呼叫的
所以可能從 softirq context 或 interrupt 呼叫上來.
所以可能要注意你的 function 裡面要注意 softirq 的性質
1. 不能睡
2. softirqs on the current processor are disabled
3. 需對資料做好 locking
這就是問題了,你去呼叫 schedule 就是有 code 去睡了吧?
所以你要檢查一下你寫的 code 那邊會把 cpu 讓給別人的,
違背kernel/driver的設計, 感覺是這樣,一點淺見。
2950 /**
2951 * netif_receive_skb - process receive buffer from network
2952 * @skb: buffer to process
2953 *
2954 * netif_receive_skb() is the main receive data processing function.
2955 * It always succeeds. The buffer may be dropped during processing
2956 * for congestion control or by the protocol layers.
2957 *
2958 * This function may only be called from softirq context and interrupts
2959 * should be enabled.
2960 *
2961 * Return values (usually ignored):
2962 * NET_RX_SUCCESS: no congestion
2963 * NET_RX_DROP: packet was dropped
2964 */
2965 int netif_receive_skb(struct sk_buff *skb)
※ 引述《squallbbking (阿爽BB)》之銘言:
: 不好意思 小弟在Kernel 接收封包得地方(net/ipv4/ip_input.c)中的ip_rcv中
: 加入發送kernel socket 的函式 sock_sendmsg,目前程式可以順利發送封包至我
: 設定的目的端,但是我發現kernel中會印出"BUG : scheduling while atomic..."
: 等等一大串訊息,重點是發送一陣子後我的module就會當掉,小弟覺得是這個BUG所影響
: ,上網爬了一下文有某些外國網站有提到此問題,不過沒有明確的解決辦法,不知道
: 有沒有高手大大能替小弟解惑一下,這是滿重要的問題,拜託好心人幫忙一下了><
: 萬分感謝!!!!
: 不好意思,補上程式碼,有點長我擷取重點部分,如果還有需要請在跟我說
: ,真的非常感謝!!
: 這是kernel中修改的部分,路徑如我上文中
: int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
: *pt, struct net_device *orig_dev)
: {
: struct iphdr *iph;
: u32 len;
: //這裡開始是我增加連結MODULE的地方
: int check11;
: if(pkt_input)
: {
: pkt_input(skb);
: }
: if(multicast)
: {
: check11 = multicast(skb);
: if(check11==1)
: {
: //printk("now drop\n");
: goto drop;
: }
: }
: //以上是我增加的部分,pkt_input回傳 check11為0就送出封包,為1就goto drop
: .
: .
: .
: inhdr_error:
: IP_INC_STATS_BH(IPSTATS_MIB_INHDRERRORS);
: drop:
: kfree_skb(skb);
: out:
: return NET_RX_DROP;
: 接下來是module code
: init_module(void)部分先創此socket
: //========merge kernel socket========//
: socket_sendmeg = kmalloc(sizeof(struct socketpair) , GFP_KERNEL);
: memset(socket_sendmeg , 0 , sizeof(struct socketpair));
: if((err=sock_create(PF_PACKET , SOCK_PACKET , htons(ETH_P_IP) ,
: &socket_sendmeg->sock)))
: {
: printk("create socket err!\n");
: return 0;
: }
: createsocketmeg(pktinfm);
: 再來連結地址和類型
: void createsocketmeg(struct pktinf *pktinfm)
: {
: char DEV[]="eth1"; //140.117.157.50
: memset(&socket_sendmeg->addr,0,sizeof(struct sockaddr));
: strcpy(socket_sendmeg->addr.sa_data , DEV);
: socket_sendmeg->addr.sa_family = PF_PACKET;
: msgmeg.msg_flags=0;
: msgmeg.msg_name=&socket_sendmeg->addr;
: msgmeg.msg_namelen=sizeof(struct sockaddr);
: msgmeg.msg_control=NULL;
: msgmeg.msg_controllen=0;
: msgmeg.msg_iovlen=1;
: msgmeg.msg_control=NULL;
: };
: 最後要送出封包時,module會呼叫此函式,製作ethernet、IP、TCP的header然後
: 加入payload送出
: void C2_sendto_c1( mm_segment_t oldfs , unsigned char *megbuf , int *mbuf
: ,int pkt)
: {
: src_port_csc = 0x5000;
: dest_port_csc = pktinfm->IPC1_destport;
: ACK_NO_csc = htonl(pktinfm-> C1img_end_ack);
: //------------Ether header build---------------//
: memset(&Ethmeg , 0 , sizeof(Ethmeg));
: Get_Hw_Addr(mac_sadr_csc, mac_sor_csc);
: memcpy(Ethmeg.eth.h_source , mac_sadr_csc , ETH_ALEN);
: Get_Hw_Addr(mac_dadr_csc , mac_des_csc);
: memcpy(Ethmeg.eth.h_dest, mac_dadr_csc , ETH_ALEN);
: Ethmeg.eth.h_proto = htons(ETH_P_IP);
: memcpy(C1pkt , &Ethmeg.eth , 14);
: //------------IP header build---------------//
: memset(&Ipmeg , 0 , sizeof(Ipmeg));
: set_ip_ihl( &Ipmeg.iph );
: set_ip_version( &Ipmeg.iph ,IPVERSION);
: set_ip_tos( &Ipmeg.iph ,tos);
: tot_len_csc = 0x0028 +mbuf[pkt] ;
: set_ip_tot_len( &Ipmeg.iph ,tot_len_csc);
: pktinfm->C1img_end_ID = set_ip_id( &Ipmeg.iph ,pktinfm->C1img_end_ID);
: set_ip_frag_off( &Ipmeg.iph ,frag_off);
: set_ip_ttl( &Ipmeg.iph ,ttl_csc);
: set_ip_protocol( &Ipmeg.iph ,IPPROTO_TCP);
: set_ip_saddr( &Ipmeg.iph ,source_ip_csc);
: set_ip_daddr( &Ipmeg.iph ,dest_ip_csc);
: set_ip_check( &Ipmeg.iph);
: memcpy( C1pkt+sizeof(Ethmeg) , &Ipmeg.iph , 20);
: //------------TCP header build---------------//
: memset(&Tcpmeg , 0 , sizeof(Tcpmeg));
: set_tcp_source( &Tcpmeg.tcph ,src_port_csc);
: set_tcp_dest( &Tcpmeg.tcph ,dest_port_csc);
: seq_csc = htonl(pktinfm-> C1img_end_seq) + pktinfm-> C1img_end_len;
: set_tcp_seq( &Tcpmeg.tcph ,seq_csc);
: pktinfm-> C1img_end_seq = Tcpmeg.tcph.seq;
: pktinfm-> C1img_end_len = mbuf[pkt];
: set_tcp_ack_seq( &Tcpmeg.tcph ,ACK_NO_csc);
: set_tcp_res1( &Tcpmeg.tcph ,res1);
: set_tcp_doff( &Tcpmeg.tcph ,doff);
: set_tcp_cwr(&Tcpmeg.tcph , cwr);
: set_tcp_ece(&Tcpmeg.tcph , ece);
: set_tcp_urg(&Tcpmeg.tcph , urg);
: set_tcp_ack(&Tcpmeg.tcph , ack);
: set_tcp_psh(&Tcpmeg.tcph , psh);
: set_tcp_rst(&Tcpmeg.tcph , rst);
: set_tcp_syn(&Tcpmeg.tcph , syn);
: set_tcp_fin(&Tcpmeg.tcph , fin);
: set_tcp_window( &Tcpmeg.tcph , winmeg);
: set_tcp_urg_ptr( &Tcpmeg.tcph , Urp);
: memcpy(C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg), &Tcpmeg.tcph , 20);
: //------------payload build---------------//
: memcpy( C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+sizeof(Tcpmeg) , megbuf ,
: mbuf[pkt]);
: set_tcp_check_meg( &Tcpmeg.tcph , &Ipmeg.iph ,
: C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+sizeof(Tcpmeg));
: memcpy(C1pkt+sizeof(Ethmeg)+sizeof(Ipmeg)+16, &Tcpmeg.tcph.check , 2);
: //-------end header build----------------//
: iovmeg.iov_base= C1pkt;
: iovmeg.iov_len = sizeof(C1pkt);
: msgmeg.msg_iov = &iovmeg;
: oldfs = get_fs();
: set_fs(KERNEL_DS);
: //這裡送出封包
: sock_sendmsg(socket_sendmeg->sock , &msgmeg, sizeof(C1pkt));
: //printk("merg for C1C2\n") ;
: set_fs(oldfs);
: };
: 大致上是這樣,如有需要提供的請在跟我說,我查到說呼叫sock_sendmsg會產生此BUG
: ,不好意思文章有點長,但這問題非常重要,拜託了!!!再次萬分感謝
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 61.57.131.154