<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                前面做了一大堆的準備就是為了分析下upcall調用,但是現在因為工作重心已經從OpenVswitch上轉移到了openstack,所以根本沒時間去研究OpenVswitch了。(openstack是用Python寫的,我大學沒接觸過Python,所以現在要一邊學Python一邊學openstack)后面的OpenVswitch分析更新的時間可能會有點久。 由于前面做了很多準備,所以這里不能只分析NetLink通信機制(否則可能會感覺沒意思了),首先來分析下upcall函數調用的原因。如果看了前面的源碼分析的就會知道,在什么情況下會調用upcall函數呢?就是在一個數據包查找不到相應的流表項時,才會調用upcall函數(比如一個數據包第一次進入這個內核,里面沒有為這個數據包設定相應的流表規則)。upcall函數的調用其實就是把數據包的信息下發到用戶 空間去,而由內核空間到用戶空間的通信則要用到linux中的NetLink機制。所以熟悉下NetLink通信可以知道upcall函數調用需要什么樣的參數以及整個函數的作用和功能。 現在來測試下NetLink的使用,NetLink由兩部分程序構成,一部分是用戶空間的,另外一部分是內核空間的。用戶空間的和大多數socket編程一樣,只是用的協議時AF_NETLINK,其他基本都市一樣的步驟。 下面是NetLine程序中的用戶代碼NetLinke_user.c: ~~~ #include<stdio.h> #include<stdlib.h> #include<string.h> #include <sys/types.h> #include<unistd.h> #include<sys/stat.h> #include<sys/socket.h> #include<linux/netlink.h> #define NETLINK_TEST 30 #define MAX_MSG 1024 int main(void) { /*按代碼規范所有變量都要定義在函數的開始部分,但為了便于理解,所以順序定義變量*/ /* * struct sockaddr_nl addr; * struct nlmsghdr *nlhdr; * struct iovec iov; * struct msghdr msg; * int sockId; */ //創建socket套接字 int socketId = socket(AF_NETLINK,SOCK_RAW,NETLINK_TEST); if (0 > socketId){ printf("The error in socket_create!\n"); return -1; } //套接字地址設置 struct sockaddr_nl addr; memset(&addr,0,sizeof(struct sockaddr_nl)); addr.nl_family = AF_NETLINK; //一定是這個協議 addr.nl_pid = 0; //消息是發給內核的,所以為0;或者內核多播數據給用戶空間 addr.nl_groups = 0; // 單播或者發給內核 //將打開的套接字和addr綁定 int ret = bind(socketId,(struct sockaddr*)(&addr),sizeof(addr)); if (0 > ret){ printf("The error in bind!\n"); close(socketId); return -1; } //NetLink消息頭設置 struct nlmsghdr *nlhdr = NULL; nlhdr = (struct nlmsghdr*)malloc(NLMSG_SPACE(MAX_MSG)); if (!nlhdr){ printf("The error in nlmsghdr_malloc!\n"); close(socketId); return -1; } nlhdr->nlmsg_len = NLMSG_SPACE(MAX_MSG); nlhdr->nlmsg_pid = getpid();//內核如果要返回消息會查找這個pid nlhdr->nlmsg_flags = 0; strcpy(NLMSG_DATA(nlhdr),"This is data what will be sent!\n"); //設置消息緩存指針 struct iovec iov; memset(&iov,0,sizeof(struct iovec)); iov.iov_base = (void*)nlhdr; iov.iov_len = NLMSG_SPACE(MAX_MSG); //設置消息結構體 struct msghdr msg; memset(&msg,0,sizeof(struct msghdr)); msg.msg_iov = &iov; msg.msg_iovlen = 1; //發送消息給內核 ret = sendmsg(socketId,&msg,0); if (0 > ret){ printf("The error in sendmsg!\n"); close(socketId); free(nlhdr); return -1; } /**********接受消息部分***********/ printf("begin receive message!\n"); //對接受消息的字段進行清零,因為發送時,里面存儲了發送數據 memset((char*)NLMSG_DATA(nlhdr),0,MAX_MSG); recvmsg(socketId,&msg,0); //打印接受到的消息 printf("receive message:===========\n%s\n",NLMSG_DATA(nlhdr)); //收尾工作,對資源的處理 close(socketId); free(nlhdr); return 0; } ~~~ NetLink程序內核代碼本來有兩種情況的:一、單播給某個指定的pid;二、多播個nl_gloups.下面的代碼只有單播的功能,沒有多播。多播實驗了很久也沒成功,所以就擱著了。 下面是NetLink程序中的NetLink_kernel.c內核代碼: ~~~ /*=======================KERNEL==========================================*/ #include<linux/init.h> #include<linux/module.h> #include<linux/kernel.h> #include<linux/types.h> #include<net/sock.h> #include <linux/skbuff.h> #include <linux/ip.h> #include <linux/sched.h> #include<linux/netlink.h> #define NETLINK_TEST 30 #define MAX_MSG 1024 // 內核sock struct sock* socketId = NULL; // 單播數據 char kernel_to_user_msg_unicast[] = "hello userspace uncast!"; int unicastMsgLen = NLMSG_SPACE(sizeof(kernel_to_user_msg_unicast)); // 單播,groups一定要為0,pid則為單播pid int kernel_unicast_user(u32 pid) { struct sk_buff *skb_sent = NULL; struct nlmsghdr *nlhdr = NULL; // 創建網絡數據包結構體 skb_sent = alloc_skb(unicastMsgLen,GFP_KERNEL); if (!skb_sent){ printk(KERN_ALERT"error in uncast alloc_skb!\n"); return -1; } // nlhdr = NLMSG_NEW(skb_sent,0,0,NLMSG_DONE,unicastMsgLen,0); nlhdr = nlmsg_put(skb_sent, 0, 0, 0, unicastMsgLen,0); // 填充發送數據 memcpy(NLMSG_DATA(nlhdr),kernel_to_user_msg_unicast,unicastMsgLen); // 設置控制塊 NETLINK_CB(skb_sent).pid = 0; NETLINK_CB(skb_sent).dst_group = 0; // 單播發送 if (0 > netlink_unicast(socketId,skb_sent,pid,0)){ printk(KERN_ALERT"error in netlink_unicast\n"); return -1; } return 0; } EXPORT_SYMBOL(kernel_unicast_user);// 導出函數符號 // 注冊的回調函數,處理接受到數據 static void kernel_recv_user(struct sk_buff *__skb) { struct sk_buff *skb = NULL; struct nlmsghdr *nlhdr = NULL; skb = skb_get(__skb);// 從一個緩沖區中引用指針出來 if (skb->len >= NLMSG_SPACE(0)){ //其實就是判斷是否為空 nlhdr = nlmsg_hdr(skb);// 宏nlmsg_hdr(skb)的實現為(struct nlmsghdr*)skb->data // 開始打印接受到的消息 printk(KERN_INFO"base info =======\n len:%d, type:%d, flags:%d, pid:%d\n", nlhdr->nlmsg_len,nlhdr->nlmsg_type,nlhdr->nlmsg_flags,nlhdr->nlmsg_pid); printk(KERN_INFO"data info =======\n data:%s\n",(char*)NLMSG_DATA(nlhdr)); } kernel_unicast_user(nlhdr->nlmsg_pid); } // 模塊插入時觸發的函數,一般用來做初始化用,也是模塊程序的入口 static int __init netlink_init(void) { printk(KERN_ALERT"netlink_init()!\n"); socketId = netlink_kernel_create(&init_net,NETLINK_TEST,0,kernel_recv_user,NULL,THIS_MODULE); if (!socketId){ printk(KERN_ALERT"error in sock create!\n"); return -1; } return 0; } // 模塊退出時觸發的函數,目的一般是用來清理和收尾工作 static void __exit netlink_exit(void) { printk(KERN_ALERT"netlink_exit()!\n"); netlink_kernel_release(socketId); } MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("yuzhihui"); module_init(netlink_init); module_exit(netlink_exit); ~~~ 上面的兩個程序就是linux中內核空間和用戶空間通信的實例,其實這個NetLink通信實驗并不是非常重要,對理解OpenVswitch來說,個人只是興趣所好,特意去看了下NetLink的工作原理。至于多播的功能實現,如果有知道麻煩給個鏈接。 由于時間問題,做這個實驗和寫這個blog相差了一個多月,很多當時注意到問題,或者想分享的細節都已經記不清了。所以感覺比較簡陋,當然也必不可少有些不正確之處,希望發現的可以指正,謝謝!! 轉載請注明作者和原文出處,原文地址:[http://blog.csdn.net/yuzhihui_no1?viewmode=list](http://blog.csdn.net/yuzhihui_no1?viewmode=list)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看