基于套接字设置DSCP:IP_TOS能否配置0-63全范围DSCP值?
IP_TOS套接字选项设置任意DSCP值的问题 好问题!其实你完全可以通过setsockopt(IPPROTO_IP, IP_TOS)来设置0到63之间的任意DSCP值,那些IPTOS_LOWDELAY之类的预设常量只是方便使用的“快捷方式”而已,并非唯一可选值。
为什么可以这么做?
原来的IP TOS字段是8位,RFC2474把它重新定义为:前6位是DSCP(区分服务代码点),后2位是ECN(显式拥塞通知)。而IP_TOS套接字选项的作用,就是直接设置IP头里的这个8位字段——内核并不会限制你只能用那些旧的TOS预设值,只要你传入的数值是合法的8位整数(0-255),都会被放到IP头里。
如果你想设置特定的DSCP值(0-63),只需要把DSCP值左移2位(留出后2位给ECN,通常设为0即可,因为ECN一般由内核自动处理),然后把这个结果传给IP_TOS选项就行。
示例代码
比如要设置DSCP值46(对应EF,加速转发服务):
// 目标DSCP值:EF (46) int dscp = 46; // 转换为IP_TOS需要的8位值:左移2位,ECN位设为0 int tos = dscp << 2; if (setsockopt(sockfd, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)) == -1) { perror("setsockopt failed"); // 错误处理逻辑 }
当然,你也可以直接写死对应的8位值(比如EF对应的是0xB8),效果是一样的。
关于预设常量的补充
那些IPTOS_LOWDELAY、IPTOS_THROUGHPUT等常量,其实是旧TOS定义里的常用值,映射到DSCP体系里对应特定的代码点(比如IPTOS_LOWDELAY是0x10,对应DSCP值8)。但它们只是为了兼容旧代码和方便使用,完全不限制你自定义DSCP值。
验证方法
设置完后可以用tcpdump抓包验证,查看IP头的第二个字节(也就是TOS/DSCP字段)是否符合预期:
tcpdump -i your_interface ip and host your_target_ip -v
在输出里找类似tos 0xb8的字段,0xb8就是我们刚才设置的EF对应的8位值,转换成DSCP就是0xb8 >> 2 = 46,和预期一致。
内容的提问来源于stack exchange,提问作者Ottavio Campana

