linux内核网络技术内幕《三》“每日读书”

向量定义

在某些情况下数据结构定义的末端会包含一个可选区块以下是一个实例

struct abc {

int age;

char *name[20];

.....

char placeholder[0];

}

可选区块placeholder开始注意placeholder定义大小0向量也就是说abc分配带有可选区域placeholder指向区块起始不需要可选区块placeholder只是一个指向结构尾端指针而已不耗用人和空间因此如果abc好几段代码所用到每段代码都可以使用相同基本定义但是可以根据需求不同方式abc定义予以个别化

条件指示指令 (#ifdef 及其系列指令)

有时候必须一些条件指令传给编译器大量使用条件指示指令降低代码可读性但是我们可以说linux并没有滥用这些指令条件指示指令各种不同原因出现但是我们感兴趣那些用于检查内核是否支持特定功能条件指示指令例如make xconfig这类配置工具可以确认功能是否被编译

例如#ifdef 或者 #if defined用于指示C预处理程序完成检查功能

从数据结构定义引入或者排除字段

struct sk_buff

{

#ifdef CONFIG_NETFILTER_DEBUG

unsigned int nf_debug;

#endif

};

这个例子中Netfilter调试功能需要sk_buff结构中nf_debug字段内核不支持Netfilter调试就不需要引入这个字段引入字段每个网络数据包而言只会消耗更多内存

函数引入或者排除一些代码片段

int ip_route_input()

{

#ifndef CONFIG_IP_ROUTE_FWMARK

#endif

}

三十三说明路由缓存查询函数ip_route_input 只有内核编译支持"IP:use netfilter MARK value as routing key"功能才会检查防火墙标记

#ifdef CONFIG_IP_MULTIPLE_TABLES

struct fib_table *fib_hash_init(int id)

#else

struct fib_table * __init fib_hash_init(int id)

{}

在这例子内核不支持策略路由这些指示用于__init标志加至原型

函数选择适当定义

#ifndef CONFIG_IP_MULTIPLE_TABLES

static inline struct fib_table *fib_get_table(int id)

{

if (id != RT_TABLE_LOCAL)

return ip_fib_main_table;

return ip_fib_local_table;

}

#else

static inline struct fib_table *fib_get_table(int id)

{

if (id == 0)

id = RT_TABLE_MAIN;

return fib_tables(id);

}

#endif

注意这种前一种情况不同之处前一种情况中函数位于#ifdef #endif之外现在这种情况每个块包含一个完整函数定义

变量定义或者初始化可以使用条件编译

知道某些函数或者存在多个定义很重要前面例子类似这些函数定义预处理程序编译期间决定的,

条件检查编译期间最优化

多数情况下内核某些外部值比较一个变量了解是否满足给定条件结果极有可能可预测这是很常见那些强制检查检查代码内核分别使用likelyunlikely进行返回值或者包裹比较这些利用gcc编译器一项功能这个功能就是依据该项信息使代码编译最优化

以下一个实例假设需要调用do_something函数,调用失败你必须handle_error 函数进行处理

err = do_something(x,y,z);

假设do_something很少失败可以以下方式重写代码

err = do_something(x,y,z);

if (unlikely(err))

handle_error(err);

likelyunlikely 可能优化实例之一就是处理IP报头里面选项IP选项使用只限于一些特定情况因此内核可以安全假设多数IP封装数据包不会携带IP选项内核转发IP封包转发IP封包最后一个阶段ip_forward_finish 负责函数使用unlikely 检查是否处理ip 选项条件包裹起来

一个简单例子

include <stdio.h>

int func()

{

return 1;

}

int main()

{

if (func() == 0) {

printf("I am OK\n");

} else {

printf("I am no OK\n");

}

return 0;

}

编译之后

like.o:  file format elf64-x86-64

Disassembly of section .text:

0000000000000000 <_Z4funcv>:

0: f3 0f 1e fa endbr64

4: 55  push  %rbp

5: 48 89 e5  mov %rsp,%rbp

8: b8 01 00 00 00  mov $0x1,%eax

d: 5d  pop %rbp

e: c3  retq

000000000000000f <main>:

f: f3 0f 1e fa endbr64

13: 55  push  %rbp

14: 48 89 e5  mov %rsp,%rbp

17: e8 00 00 00 00  callq 1c <main+0xd>

1c: 85 c0 test  %eax,%eax

1e: 0f 94 c0  sete  %al //al = zf 直接判断zf

21: 84 c0 test  %al,%al

23: 74 0e je  33 <main+0x24> //jump if equal to 0 这里就是if (func() == 0)判断

25: 48 8d 3d 00 00 00 00  lea 0x0(%rip),%rdi # 2c <main+0x1d>

2c: e8 00 00 00 00  callq 31 <main+0x22>

31: eb 0c jmp 3f <main+0x30>

33: 48 8d 3d 00 00 00 00  lea 0x0(%rip),%rdi # 3a <main+0x2b>

3a: e8 00 00 00 00  callq 3f <main+0x30>

3f: b8 00 00 00 00  mov $0x0,%eax

44: 5d  pop %rbp

45: c3  retq

改一下C代码

define likely(x) __builtin_expect(!!(x), 1)

define unlikely(x) __builtin_expect(!!(x), 0)

int func()

{

return 1;

}

int main()

{

if (unlikely(func() == 0)) {

printf("I am OK\n");

} else {

printf("I am no OK\n");

}

return 0;

}

#define likely(x) __builtin_expect(!!(x), 1)

#define unlikely(x) __builtin_expect(!!(x), 0)

int func()

{

0: f3 0f 1e fa endbr64

4: 55  push  %rbp

5: 48 89 e5  mov %rsp,%rbp

return 1;

8: b8 01 00 00 00  mov $0x1,%eax

}

d: 5d  pop %rbp

e: c3  retq

000000000000000f <main>:

int main()

{

f: f3 0f 1e fa endbr64

13: 55  push  %rbp

14: 48 89 e5  mov %rsp,%rbp

if (unlikely(func() == 0)) {

17: e8 00 00 00 00  callq 1c <main+0xd>

1c: 85 c0 test  %eax,%eax

1e: 0f 94 c0  sete  %al

21: 0f b6 c0  movzbl %al,%eax

24: 48 85 c0  test  %rax,%rax

27: 0f 95 c0  setne %al // zf取反送入al

2a: 84 c0 test  %al,%al

2c: 74 0e je  3c <main+0x2d>

printf("I am OK\n");

2e: 48 8d 3d 00 00 00 00  lea 0x0(%rip),%rdi # 35 <main+0x26>

35: e8 00 00 00 00  callq 3a <main+0x2b>

3a: eb 0c jmp 48 <main+0x39>

} else {

printf("I am no OK\n");

3c: 48 8d 3d 00 00 00 00  lea 0x0(%rip),%rdi # 43 <main+0x34>

43: e8 00 00 00 00  callq 48 <main+0x39>

}

return 0;

48: b8 00 00 00 00  mov $0x0,%eax

}

4d: 5d  pop %rbp

4e: c3  retq

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值