当ofp应用启动后,可以在bash里运行如下命令
1 | telnet 127.0.0.1 2345 |
来实时查看网络情况。交互输入help或route help之类。
refer to: https://github.com/OpenFastPath/ofp/blob/master/docs/ofp-user-guide.adoc
人,技术,生活。
当ofp应用启动后,可以在bash里运行如下命令
1 | telnet 127.0.0.1 2345 |
来实时查看网络情况。交互输入help或route help之类。
refer to: https://github.com/OpenFastPath/ofp/blob/master/docs/ofp-user-guide.adoc
1. 创建线程不要直接用pthread_create,而要用odph_odpthreads_create。
2. 每个线程函数的开始处都要调用ofp_init_local初始化。
3. 之前调用系统socket和epoll之类的函数都要替换成ofp定义的,包括宏和结构体。如
1 2 | // sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sock = ofp_socket(OFP_AF_INET, OFP_SOCK_STREAM, OFP_IPPROTO_TCP); |
默认编译OpenFastPath时慢平面是启用的,慢平面的功能之一是通过netlink方式向内核查询路由表,这是用内核公开的接口,不需要另开发内核驱动。
慢平面的一个局限,比方电脑只有一张网卡,而这块网卡已被dpdk绑定,网络包就不会在内核中被解析,此时慢平面的路由功能也就无效,所以干脆通过
1 | ./configure ... --enable-sp=no |
将慢平面功能去掉。
而此时我们跑在ofp上的应用就没有路由表了么?
不是的。首先应用的本机ip地址是通过
1 | myApp -i 0 -f ofp.cli |
中的ofp.cli配置的。如
1 2 3 | debug 0 loglevel set debug ifconfig fp0 192.168.56.33/24 |
中的192.168.56.33就是本机地址。
而通过arp协议获取其它机器ip与mac关系的路由表是由
1 | ofp_start_cli_thread(instance, app_init_params.linux_core_id, params.cli_file); |
这个线程在dpdk绑定的网卡上进行解析维护。
一个很好的例子就是ofp/example/webserver。
ofp和dpdk都可完全编译成静态库运行,不要为了LD_PRELOAD的那一点便利一门心思去编译出动态库。在自已的源码中加一层宏翻译,静态库与epoll api兼容性也很好。
github上的odp与dpdk-odp的区别是前者现在只包含了odp-linux,一种对linux系统api的包装,后者是对dpdk的包装,所以高性能选后者。原话见
doc/users-guide/users-guide.adoc
refer to:
https://github.com/OpenFastPath/ofp
https://github.com/OpenDataPlane/odp-dpdk
https://my.oschina.net/u/4361425/blog/3269917
1 2 3 4 5 6 7 8 9 10 11 12 13 | odp_init_t init_param; odp_init_param_init(&init_param); init_param.not_used.feat.ipsec = 1; init_param.not_used.feat.crypto = 1; init_param.not_used.feat.compress = 1; init_param.not_used.feat.tm = 1; if (0 != odp_init_global(&instance, &init_param, NULL)) { DBG(("init odp global failed.\n")); return 0; } |
ubuntu下gtk库是默认已安装的,开发部署很方便,以下是我写的自绘控件例子:
EuhatChildWnd.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #pragma once struct _cairo_surface; struct _GtkWidget; class EuhatChildWnd { public: EuhatChildWnd(int width, int height); ~EuhatChildWnd(); void clear(); void drawBrush(struct _GtkWidget *widget, double x, double y); struct _GtkWidget *drawingArea_; struct _cairo_surface *surface_; double xFrom_; double yFrom_; }; |
Maybe a CRITICAL_SECTION struct memory is copied to another class member, so two CRITICAL_SECTION variables hold the same value.
1 2 3 4 5 6 7 8 9 | #define PRINT_MACRO_HELPER(_x) #_x #define PRINT_MACRO(_x) #_x " = " PRINT_MACRO_HELPER(_x) #define DEFINED_PI 3.14 #define DEFINED_NULL #pragma message(PRINT_MACRO(DEFINED_PI)) #pragma message(PRINT_MACRO(DEFINED_NULL)) #pragma message(PRINT_MACRO(UNDEFINED)) //#error print stop here. |
refer to: https://blog.csdn.net/xshbx/article/details/7981564
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | #include <string> #include <vector> #include <sstream> using namespace std; wstring copySpanStr(const wchar_t* start, const wchar_t* end) { wchar_t* buf = (wchar_t*)malloc((end - start + 1) * sizeof(wchar_t)); wchar_t* pTo = buf; for (const wchar_t* p = start; p != end; p++) { if (*p == L'\\' && p + 1 != end) { p++; *pTo++ = *p; } else *pTo++ = *p; } *pTo = 0; wstring out = buf; free(buf); return out; } int getParams(const wchar_t* str, vector<wstring>& out) { int isInQMark = 0; int isInSpace = 1; const wchar_t* tokenStart = str; for (const wchar_t* p = str; ; p++) { if (*p == L'"') { if (!isInQMark) { isInQMark = 1; tokenStart = p + 1; } else { isInQMark = 0; out.push_back(copySpanStr(tokenStart, p)); } } else if (*p == L'\\') { if (*(p + 1) != 0) p++; } else if (*p == L' ' || *p == 0) { if (!isInQMark) { if (!isInSpace) { isInSpace = 1; if (tokenStart != p) { out.push_back(copySpanStr(tokenStart, p)); tokenStart = p; } } else { } } } else { if (!isInQMark) { if (!isInSpace) { } else { isInSpace = 0; tokenStart = p; } } } if (*p == 0) break; } return out.size(); } wstring strReplaceCh2Str(const wchar_t* in, wchar_t fromCh, const wchar_t* toStr) { const wchar_t* p = in; wstringstream ss; const wchar_t* pToStr; for (; *p != 0; p++) { if (*p == fromCh) { for (pToStr = toStr; *pToStr != 0; pToStr++) { ss << *pToStr; } } else ss << *p; } return ss.str(); } int main() { wstring path = strReplaceCh2Str(L"c:\\aa.txt", L'\\', L"\\\\"); wstring msg = strReplaceCh2Str(L"\"优孩\"是EuhatExpert的中文名。", L'\"', L"\\\""); wstring cmd = L"EuhatExample.exe subCmd \"" + path + L"\" \"" + msg + L"\" 1234 5678"; vector<wstring> params; getParams(cmd.c_str(), params); return 0; } |
如果外部工程ExeB调了动态库DllA中的函数,当ExeB运行时,DllA中的全局类实例一定会初始化,但不一定非得在ExeB中调DllA中的函数后DllA中的全局类实例才会初始化,比如在DllA中代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | class DllA01() { public: DllA01() { MessageBoxA(NULL, "init", NULL, 0); } ~DllA01() { MessageBoxA(NULL, "fini", NULL, 0); } void test(void) { MessageBoxA(NULL, "test", NULL, 0); } }; __declspec(dllexport) DllA01 gA01; extern "C" __declspec(dllexport) void dllA01Test(void) { MessageBoxA(NULL, "dllA01Test", NULL, 0); } |
在ExeB中加入
1 2 3 4 | #pragma comment(lib, "DllA.lib") #pragma comment(linker, "/include:__imp__dllA01Test") //#pragma comment(linker, "/include:__imp_?gA01@@3VDllA01@@A") //#pragma comment(linker, "/ENTRY:foo") |
比如在vc2008里Debug时函数的传入参数都变成0xCCCCCCCC之类,需对工程属性设置一下:
C/C++->优化->优化->禁用