- 浏览: 321786 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
Linux内核中流量控制(18)
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
7.9 RSVP RSVP同时支持IPv4和IPv6, 分别在net/sched/cls_rsvp.c和net/sched/cls_rsvp6.c中定义, 可这两个文件只简单定义了几个按协议不同的参数, 其他处理都是相同的, 都在net/sched/cls_rsvp.h中定义, 没错,是个.h的头文件, 该方法是根据IPv4(6)数据包的地址, 协议, 端口等信息进行分类的, 不过不知道RSVP是什么的缩写。 7.9.1 数据结构和过滤器操作结构 // 根节点, 是整个RSVP规则表的入口点 struct rsvp_head { // 映射表 u32 tmap[256/32]; u32 hgenerator; u8 tgenerator; // 会话哈希表: 256个, 是用目的地址协议等信息进行哈希 struct rsvp_session *ht[256]; }; // RSVP的查找规则不是象netfilter那样直接由五元组一级查找, 而是分两级, 先根据目的信息和 // 协议, 然后再根据源信息来定位。 // // RSVP会话, 根据固定目的地址,协议和目的上层协议三元组参数来定义的连接 struct rsvp_session { // 链表中下一项 struct rsvp_session *next; // 目的地址, RSVP_DST_LEN根据是V4还是V6分别取1和4 u32 dst[RSVP_DST_LEN]; // 上层协议相关参数,如TCP/UDP的端口, AH/ESP的SPI等, 通过偏移量定位, 可设掩码 struct tc_rsvp_gpi dpi; // 协议 u8 protocol; // 通道ID u8 tunnelid; // 就两个u8, 没进行4字节对齐, 要浪费2字节了 /* 16 (src,sport) hash slots, and one wildcard source slot */ // 17个rsvp_filter哈希表头, 前16个是正常匹配, 第17个是通配用的, 根据源地址进行哈希 struct rsvp_filter *ht[16+1]; }; // RSVP过滤器结构 struct rsvp_filter { // 下一项 struct rsvp_filter *next; // 源地址, RSVP_DST_LEN如果是V4是1, V6时是4 u32 src[RSVP_DST_LEN]; // 上层协议相关参数,如TCP/UDP的端口, AH/ESP的SPI等, 通过偏移量定位, 可设掩码 struct tc_rsvp_gpi spi; // 封装通道参数, 当是封装包,如IPIP时非0 u8 tunnelhdr; // TC分类器分类结果和扩展结构 struct tcf_result res; struct tcf_exts exts; // 句柄 u32 handle; // 回指向rsvp_session结构 struct rsvp_session *sess; }; // 操作结构 static struct tcf_proto_ops RSVP_OPS = { .next = NULL, // 这是个宏定义, 根据是v4和v6取不同的值 .kind = RSVP_ID, .classify = rsvp_classify, .init = rsvp_init, .destroy = rsvp_destroy, .get = rsvp_get, .put = rsvp_put, .change = rsvp_change, .delete = rsvp_delete, .walk = rsvp_walk, .dump = rsvp_dump, .owner = THIS_MODULE, }; 7.9.2 初始化 static int rsvp_init(struct tcf_proto *tp) { struct rsvp_head *data; // 分配RSVP根节点链表头结构 data = kzalloc(sizeof(struct rsvp_head), GFP_KERNEL); if (data) { // 作为tcf_proto结构的过滤表根节点 tp->root = data; return 0; } return -ENOBUFS; } 7.9.3 分类 static int rsvp_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res) { // RSVP会话的哈希表头 struct rsvp_session **sht = ((struct rsvp_head*)tp->root)->ht; struct rsvp_session *s; struct rsvp_filter *f; unsigned h1, h2; u32 *dst, *src; u8 protocol; u8 tunnelid = 0; u8 *xprt; // 外部IP头 #if RSVP_DST_LEN == 4 // IPV6 struct ipv6hdr *nhptr = skb->nh.ipv6h; #else // IPV4 struct iphdr *nhptr = skb->nh.iph; #endif restart: #if RSVP_DST_LEN == 4 // IPV6的目的和源地址指针 src = &nhptr->saddr.s6_addr32[0]; dst = &nhptr->daddr.s6_addr32[0]; // 协议, 但问题是IPV6中的第一个nexthdr有可能是IPV6选项,而不是真正的上层协议号 protocol = nhptr->nexthdr; // 上层协议头位置 xprt = ((u8*)nhptr) + sizeof(struct ipv6hdr); #else // IPV4的目的和源地址指针 src = &nhptr->saddr; dst = &nhptr->daddr; protocol = nhptr->protocol; // 上层协议头位置, 如TCP/UDP头的位置 xprt = ((u8*)nhptr) + (nhptr->ihl<<2); if (nhptr->frag_off&__constant_htons(IP_MF|IP_OFFSET)) return -1; #endif // 计算源和地址的哈希值, 计算目的时还需要协议的通道ID h1 = hash_dst(dst, protocol, tunnelid); h2 = hash_src(src); // 遍历目的地址哈希值指定的链表 for (s = sht[h1]; s; s = s->next) { // 比较源地址是否相同 if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && // 协议是否相同 protocol == s->protocol && // 这个相当于比较TCP/UDP目的端口, AH,ESP的SPI !(s->dpi.mask & (*(u32*)(xprt+s->dpi.offset)^s->dpi.key)) #if RSVP_DST_LEN == 4 // 如果是V6还要比较地址的前3个32位, 因为V6是4个32位 && dst[0] == s->dst[0] && dst[1] == s->dst[1] && dst[2] == s->dst[2] #endif // 通道ID是否相同 && tunnelid == s->tunnelid) { // 遍历该会话按源地址哈希值指定的链表 for (f = s->ht[h2]; f; f = f->next) { // 比较源地址和源端口 if (src[RSVP_DST_LEN-1] == f->src[RSVP_DST_LEN-1] && !(f->spi.mask & (*(u32*)(xprt+f->spi.offset)^f->spi.key)) #if RSVP_DST_LEN == 4 && src[0] == f->src[0] && src[1] == f->src[1] && src[2] == f->src[2] #endif ) { // 源和目的相关参数都匹配 // 分类查找成功, 填返回参数 *res = f->res; RSVP_APPLY_RESULT(); matched: // 如果不是IP通道封装处理模式(如IPIP), 可以返回成功了 if (f->tunnelhdr == 0) return 0; // 否则是通道封装, 需要更新使用内部地址参数进行匹配 // 将通道ID赋值为返回结果的类别ID值 tunnelid = f->res.classid; // 定位内部IP头, 返回起始点重新查找 nhptr = (void*)(xprt + f->tunnelhdr - sizeof(*nhptr)); goto restart; } } // 结束循环是正常源地址匹配失败的情况 /* And wildcard bucket... */ // 遍历通配链表 for (f = s->ht[16]; f; f = f->next) { // 如果有元素的话, 直接作为结果返回 *res = f->res; RSVP_APPLY_RESULT(); goto matched; } // 如果没有通配元素, 分类失败 return -1; } } // 遍历结束, 没有匹配的, 返回失败 return -1; } 7.9.4 释放 static void rsvp_destroy(struct tcf_proto *tp) { // 将tcf_proto的规则根节点交换出来准备释放处理 struct rsvp_head *data = xchg(&tp->root, NULL); struct rsvp_session **sht; int h1, h2; // 规则表为空, 直接返回 if (data == NULL) return; // 起始链表头 sht = data->ht; // 遍历所有256个链表 for (h1=0; h1<256; h1++) { struct rsvp_session *s; // 遍历单个链表 while ((s = sht[h1]) != NULL) { // 保存链表下一项 sht[h1] = s->next; // 准备释放s // 遍历s的16个源地址哈希链表 for (h2=0; h2<=16; h2++) { struct rsvp_filter *f; // 遍历链表 while ((f = s->ht[h2]) != NULL) { s->ht[h2] = f->next; // 释放单个rsvp_filter结构 rsvp_delete_filter(tp, f); } } // 释放s结构 kfree(s); } } // 释放根节点 kfree(data); } // 释放rsvp_filter结构 static inline void rsvp_delete_filter(struct tcf_proto *tp, struct rsvp_filter *f) { // 实际是调用Qdisc_class_ops的unbind_tcf函数 tcf_unbind_filter(tp, &f->res); // 释放tcf扩展结构 tcf_exts_destroy(tp, &f->exts); // 释放rsvp_filter结构 kfree(f); } 7.9.5 获取 // 根据handle查找rsvp_session结构 static unsigned long rsvp_get(struct tcf_proto *tp, u32 handle) { // 根节点 struct rsvp_session **sht = ((struct rsvp_head*)tp->root)->ht; struct rsvp_session *s; struct rsvp_filter *f; // 取handle的最低8位作为目的地址哈希表的索引 unsigned h1 = handle&0xFF; // 取handle的8~15位作为源地址哈希表的索引 unsigned h2 = (handle>>8)&0xFF; // 源地址哈希最大是16+1个表 if (h2 > 16) return 0; // 遍历h1号目的地址链表 for (s = sht[h1]; s; s = s->next) { // 遍历h2号源地址链表 for (f = s->ht[h2]; f; f = f->next) { // 比较handle值, 相同的话返回该rsvp_session结构地址参数 if (f->handle == handle) return (unsigned long)f; } } // 没找到返回0 return 0; } 7.9.6 放下 // 空函数 static void rsvp_put(struct tcf_proto *tp, unsigned long f) { } 7.9.7 修改 // 增加和修改tc filter规则时调用 static int rsvp_change(struct tcf_proto *tp, unsigned long base, u32 handle, struct rtattr **tca, unsigned long *arg) { // 哈希根节点 struct rsvp_head *data = tp->root; struct rsvp_filter *f, **fp; struct rsvp_session *s, **sp; struct tc_rsvp_pinfo *pinfo = NULL; // 选项参数 struct rtattr *opt = tca[TCA_OPTIONS-1]; struct rtattr *tb[TCA_RSVP_MAX]; struct tcf_exts e; unsigned h1, h2; u32 *dst; int err; // 选项结构为空, 如果定义了handle, 返回非法参数错误, 否则不用进行任何操作了 if (opt == NULL) return handle ? -EINVAL : 0; // 参数解析, 解析后的参数指针保存在tb数组 if (rtattr_parse_nested(tb, TCA_RSVP_MAX, opt) < 0) return -EINVAL; // tcf_exts结构e初始化 err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &rsvp_ext_map); if (err < 0) return err; if ((f = (struct rsvp_filter*)*arg) != NULL) { /* Node exists: adjust only classid */ // 如果rsvp_filter结构已经存在 // 比较handle是否匹配 if (f->handle != handle && handle) goto errout2; if (tb[TCA_RSVP_CLASSID-1]) { // 更新类别ID f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]); tcf_bind_filter(tp, &f->res, base); } // tcf扩展结构修改后返回 tcf_exts_change(tp, &f->exts, &e); return 0; } // rsvp_filter结构不存在, 需要新建 /* Now more serious part... */ err = -EINVAL; // handle必须为0 if (handle) goto errout2; // 目的地址参数必须存在 if (tb[TCA_RSVP_DST-1] == NULL) goto errout2; err = -ENOBUFS; // 分配rsvp_filter过滤器结构空间 f = kzalloc(sizeof(struct rsvp_filter), GFP_KERNEL); if (f == NULL) goto errout2; h2 = 16; // 填充源地址参数 if (tb[TCA_RSVP_SRC-1]) { err = -EINVAL; if (RTA_PAYLOAD(tb[TCA_RSVP_SRC-1]) != sizeof(f->src)) goto errout; memcpy(f->src, RTA_DATA(tb[TCA_RSVP_SRC-1]), sizeof(f->src)); h2 = hash_src(f->src); } // 填充协议信息参数 if (tb[TCA_RSVP_PINFO-1]) { err = -EINVAL; if (RTA_PAYLOAD(tb[TCA_RSVP_PINFO-1]) < sizeof(struct tc_rsvp_pinfo)) goto errout; pinfo = RTA_DATA(tb[TCA_RSVP_PINFO-1]); f->spi = pinfo->spi; f->tunnelhdr = pinfo->tunnelhdr; } // 填充类别ID参数 if (tb[TCA_RSVP_CLASSID-1]) { err = -EINVAL; if (RTA_PAYLOAD(tb[TCA_RSVP_CLASSID-1]) != 4) goto errout; f->res.classid = *(u32*)RTA_DATA(tb[TCA_RSVP_CLASSID-1]); } err = -EINVAL; // 目的地址参数 if (RTA_PAYLOAD(tb[TCA_RSVP_DST-1]) != sizeof(f->src)) goto errout; dst = RTA_DATA(tb[TCA_RSVP_DST-1]); // 计算目的地址哈希值 h1 = hash_dst(dst, pinfo ? pinfo->protocol : 0, pinfo ? pinfo->tunnelid : 0); err = -ENOMEM; // 产生rsvp_filter结构的handle if ((f->handle = gen_handle(tp, h1 | (h2<<8))) == 0) goto errout; if (f->tunnelhdr) { // 如果是通道封装的数据包 err = -EINVAL; // 类别ID不能超过0xff if (f->res.classid > 255) goto errout; err = -ENOMEM; // 类别ID为0的话生成新的类别ID if (f->res.classid == 0 && (f->res.classid = gen_tunnel(data)) == 0) goto errout; } // 遍历链表, 查找是否已经存在相同目的地址, 协议, 通道ID和目的协议信息的rsvp_session节点 for (sp = &data->ht[h1]; (s=*sp) != NULL; sp = &s->next) { // 目的地址比较 if (dst[RSVP_DST_LEN-1] == s->dst[RSVP_DST_LEN-1] && // 协议比较 pinfo && pinfo->protocol == s->protocol && // 上层协议参数比较 memcmp(&pinfo->dpi, &s->dpi, sizeof(s->dpi)) == 0 #if RSVP_DST_LEN == 4 && dst[0] == s->dst[0] && dst[1] == s->dst[1] && dst[2] == s->dst[2] #endif // 通道ID比较 && pinfo->tunnelid == s->tunnelid) { // rsvp_session找到, 准备将新的过滤器节点插入该链表 insert: /* OK, we found appropriate session */ // 会话哈希数组中的h2号链表 fp = &s->ht[h2]; // 过滤器的session指针回指 f->sess = s; // 如果不是IP封装的, 绑定过滤器 if (f->tunnelhdr == 0) tcf_bind_filter(tp, &f->res, base); // 设置TCF扩展信息 tcf_exts_change(tp, &f->exts, &e); // 遍历h2号过滤器链表, 查找插入将新过滤器节点插入链表中的位置 for (fp = &s->ht[h2]; *fp; fp = &(*fp)->next) // 根据源协议参数进行比较, 是找第一个比新节点的mask范围大的节点, 也就是链表是根据 // mask范围排序的, mask范围越小越靠前, (mask=0xffffffff时最小) if (((*fp)->spi.mask&f->spi.mask) != f->spi.mask) break; // 将新节点插到找到的节点的前面 f->next = *fp; wmb(); *fp = f; // 新过滤器结构作为返回参数, 操作成功 *arg = (unsigned long)f; return 0; } } /* No session found. Create new one. */ // 没有合适的rsvp_session节点, 新创建一个会话节点 err = -ENOBUFS; // 分类过滤器空间 s = kzalloc(sizeof(struct rsvp_session), GFP_KERNEL); if (s == NULL) goto errout; // 复制目的地址参数 memcpy(s->dst, dst, sizeof(s->dst)); if (pinfo) { // 填写目的上层协议信息 // dst protocol info s->dpi = pinfo->dpi; // 协议 s->protocol = pinfo->protocol; // 通道ID s->tunnelid = pinfo->tunnelid; } // 遍历h1号会话链表, 查找插入将新会话节点插入链表中的位置 for (sp = &data->ht[h1]; *sp; sp = &(*sp)->next) { // 根据目的协议参数进行比较, 是找第一个比新节点的mask范围大的节点, 也就是链表是根据 // mask范围排序的, mask范围越小越靠前, (mask=0xffffffff时最小) if (((*sp)->dpi.mask&s->dpi.mask) != s->dpi.mask) break; } // 插入节点 s->next = *sp; wmb(); *sp = s; // 跳转到前面进行过滤器插入操作, 现在会话结构肯定能找到了 goto insert; errout: kfree(f); errout2: tcf_exts_destroy(tp, &e); return err; } 7.9.8 删除 // 该函数肯定是返回成功的, 不会失败 static int rsvp_delete(struct tcf_proto *tp, unsigned long arg) { struct rsvp_filter **fp, *f = (struct rsvp_filter*)arg; // 过滤器的handle unsigned h = f->handle; struct rsvp_session **sp; // 过滤器所在的会话链表 struct rsvp_session *s = f->sess; int i; // handle的8~15位是作为16个源地址HASH链表的链表定位值, 这地方没检查是否超过16了 for (fp = &s->ht[(h>>8)&0xFF]; *fp; fp = &(*fp)->next) { // 比较是否找到该过滤器节点 if (*fp == f) { tcf_tree_lock(tp); // 找到, 从链表中断开 *fp = f->next; tcf_tree_unlock(tp); // 删除该RSVP过滤器 rsvp_delete_filter(tp, f); /* Strip tree */ // 如果该会话里还有其他过滤器节点, 可以返回 for (i=0; i<=16; i++) if (s->ht[i]) return 0; /* OK, session has no flows */ // 否则, 该会话中的过滤器都为空, 也删除该会话本身 // handle的低8位作为256个会话HASH链表的定位值 // 遍历该链表 for (sp = &((struct rsvp_head*)tp->root)->ht[h&0xFF]; *sp; sp = &(*sp)->next) { // 查找该会话 if (*sp == s) { // 找到, 从链表中断开 tcf_tree_lock(tp); *sp = s->next; tcf_tree_unlock(tp); // 释放会话本身空间 kfree(s); return 0; } } // 如果没找到会话, 也没关系, 也属于删除成功 return 0; } } // 没找到该过滤器节点, 也属于成功 return 0; } 7.9.9 遍历 static void rsvp_walk(struct tcf_proto *tp, struct tcf_walker *arg) { struct rsvp_head *head = tp->root; unsigned h, h1; // 设置了停止标志, 返回 if (arg->stop) return; // 遍历256个按目的地址等参数HASH的会话链表 for (h = 0; h < 256; h++) { struct rsvp_session *s; // 遍历单个会话链表 for (s = head->ht[h]; s; s = s->next) { // 遍历16个按源地址等参数HASH的过滤器链表 for (h1 = 0; h1 <= 16; h1++) { struct rsvp_filter *f; // 遍历单个过滤器链表 for (f = s->ht[h1]; f; f = f->next) { // 比较跳过的过滤器数量 if (arg->count < arg->skip) { // 计数器也增加 arg->count++; continue; } // 执行相关操作 if (arg->fn(tp, (unsigned long)f, arg) < 0) { // 操作失败, 设置停止标志, 返回 arg->stop = 1; return; } // 处理的过滤器计数 arg->count++; } } } } } 7.9.10 输出 static int rsvp_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { // 要输出参数的rsvp过滤器 struct rsvp_filter *f = (struct rsvp_filter*)fh; struct rsvp_session *s; // 数据包要填写数据的缓冲区位置定位 unsigned char *b = skb->tail; struct rtattr *rta; struct tc_rsvp_pinfo pinfo; // 过滤器为空, 直接返回 if (f == NULL) return skb->len; // 找到会话 s = f->sess; // 过滤器的句柄 t->tcm_handle = f->handle; // 将缓冲区视为要返回的netlink属性参数结构进行填充 rta = (struct rtattr*)b; // 清零 RTA_PUT(skb, TCA_OPTIONS, 0, NULL); // 填充目的地址 RTA_PUT(skb, TCA_RSVP_DST, sizeof(s->dst), &s->dst); // 协议信息, 上层协议信息等参数 pinfo.dpi = s->dpi; pinfo.spi = f->spi; pinfo.protocol = s->protocol; pinfo.tunnelid = s->tunnelid; pinfo.tunnelhdr = f->tunnelhdr; pinfo.pad = 0; // 填充协议信息 RTA_PUT(skb, TCA_RSVP_PINFO, sizeof(pinfo), &pinfo); // 填充类别ID if (f->res.classid) RTA_PUT(skb, TCA_RSVP_CLASSID, 4, &f->res.classid); // 填充源地址信息 if (((f->handle>>8)&0xFF) != 16) RTA_PUT(skb, TCA_RSVP_SRC, sizeof(f->src), f->src); // 填充TCF扩展信息 if (tcf_exts_dump(skb, &f->exts, &rsvp_ext_map) < 0) goto rtattr_failure; // 所添加的新数据的长度 rta->rta_len = skb->tail - b; // 填充扩展的统计信息 if (tcf_exts_dump_stats(skb, &f->exts, &rsvp_ext_map) < 0) goto rtattr_failure; // 返回最后填充好的数据包总长 return skb->len; rtattr_failure: skb_trim(skb, b - skb->data); return -1; } ...... 待续 ......
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2245本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1530本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1979本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1400本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1567本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 2021本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1990本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1847本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1979本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 2001本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2686本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(12)
2011-01-10 16:21 2164本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3287本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2040本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1875本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1543本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2971本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1537本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1767本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(4)
2011-01-10 16:15 1687本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
在Linux内核中,TCP和UDP模块处理连接建立、数据传输、流量控制和拥塞控制等问题。 5. **应用层**:这一层包含各种应用协议,如HTTP、FTP、SMTP等,它们直接与用户交互。Linux内核通过socket API为上层应用提供了与...
【基于Linux内核的BT流量控制的原理与实现】 Linux操作系统以其开源、可定制的特点,在系统开发领域广泛应用,尤其在网络流量控制方面具有显著优势。针对BitTorrent(BT)这种大量占用带宽的P2P协议,Linux内核提供...
4. **网络堆栈**:从硬件接口到应用层协议的整个网络传输流程,如TCP/IP协议族、套接字API、网络设备驱动程序以及流量控制策略。 5. **设备驱动**:内核如何与硬件交互,驱动程序的工作原理,包括字符设备、块设备...
通过分析源码,我们可以了解到数据包的接收与发送过程,理解TCP连接的建立与断开、拥塞控制、流量控制等机制,这对于网络编程和网络故障排查非常有帮助。 此外,Linux内核还涉及中断处理、设备驱动、I/O管理等多个...
【基于Linux内核扩展模块的P2P流量控制】这篇文献主要探讨了如何在Linux操作系统中,通过内核扩展模块来实现对P2P流量的有效控制。P2P(Peer-to-Peer)技术的兴起改变了互联网的中心化结构,使得资源分享更为便捷,...
基于Linux内核扩展模块的P2P流量控制
基于LQL库的流量控制方法可以直接在Linux内核的框架下实现,而不需要使用传统方法中的TC命令解析、netlink传输和内核空间执行的三层结构。这可以提高流量控制的效率和可靠性,同时也可以减少流量控制的延迟和资源...
书中的内容涵盖了从内核基础到高级技术的方方面面,为那些希望提升Linux内核理解和开发能力的读者提供了宝贵的资源。在本文中,我们将探讨几个关键的知识点,包括Linux内核的基本结构、进程管理、内存管理和设备驱动...
2.6.24版本在网络方面加强了IPv6的支持,并改进了网络流量控制算法。 6. **安全与权限管理**:Linux内核采用了用户和组的概念,通过权限系统(如chmod、chown等)来控制文件访问。此外,还有SELinux(Security-...
接着,作者深入剖析了网络设备数据结构net_device,它包含了设备的配置信息、统计信息、状态标志以及各种管理列表和流量控制字段,这些细节揭示了网络设备如何在内核中被抽象和管理。 通过以上内容,我们可以看到,...
它处理网络数据的接收和发送,进行网络层的路由选择,以及传输层的拥塞控制和流量控制。 5. **设备驱动**:设备驱动程序是内核与硬件之间的桥梁,使得内核能够控制硬件设备。Linux内核支持大量设备驱动,包括块设备...
该模型内置于Linux内核中,并利用队列算法对不同服务质量(Quality of Service, QoS)需求的数据流进行分类,以提供灵活且差异化的服务。实验结果表明,采用该流量控制模型后,网络性能显著提高,并能很好地适应未来...
在Linux操作系统中,高级路由和流量控制是网络管理员和系统管理员必须掌握的关键技能。这篇文档“Linux高级路由和流量控制HOWTO中文版”由牛老师翻译,为读者提供了深入理解这些概念的宝贵资源。以下是对其中核心...
同时,还会讨论TCP的流量控制和拥塞控制机制,如滑动窗口、慢启动、快速重传和快速恢复算法等,这些都是保证网络通信质量和效率的关键。 其次,关于IP协议,书里会涉及IP地址、子网掩码、路由选择等概念,以及IP分...
TC 工具基于 Linux 内核的网络设备驱动程序,通过对网络设备的控制,来实现流量控制。TC 的工作原理可以分为以下三个阶段: 1. 流量控制方式:TC 提供了多种流量控制方式,包括 Token Bucket Filter(TBF)、...
TC(Linux 下流量控制工具)详细说明及应用实例 TC 是 Linux 下的一种流量控制工具,用于控制和管理网络流量。它提供了一个灵活的方式来管理网络带宽、延迟和丢包率等网络性能参数,以满足不同应用场景的需求。 TC...
2. **TCP/IP协议**:在传输层,TCP(传输控制协议)提供可靠的数据传输服务,通过确认、重传和流量控制确保数据的完整性和顺序。IP(互联网协议)在网络层负责数据包的路由和分片,是互联网的基础协议。 3. **套接...
Linux内核中的sock和socket数据结构是网络编程的核心组成部分,它们是实现网络通信的基础构件。在Linux操作系统中,网络通信的实现依赖于BSD套接字接口,而这一接口在内核中是通过sock和socket数据结构来实现的。 ...