- 浏览: 314542 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
7.12 route route分类是根据数据包的路由信息进行分类的, 路由信息中会带tclassid参数用于分类, 代码在net/sched/cls_route.c中定义, 只支持IPV4。 7.12.1 数据结构和过滤器操作结构 // route 快速映射结构, 相当于分类结果的cache struct route4_fastmap { struct route4_filter *filter; u32 id; int iif; }; // route头结构 struct route4_head { // 16个快速映射结构 struct route4_fastmap fastmap[16]; // 257个bucket链表 struct route4_bucket *table[256+1]; }; struct route4_bucket { /* 16 FROM buckets + 16 IIF buckets + 1 wildcard bucket */ struct route4_filter *ht[16+16+1]; }; // route过滤器结构 struct route4_filter { // 链表中的下一项 struct route4_filter *next; // ID u32 id; // 网卡索引号 int iif; // 分类结构 struct tcf_result res; // TCF扩展 struct tcf_exts exts; // 句柄 u32 handle; // 所在的bucket struct route4_bucket *bkt; }; #define ROUTE4_FAILURE ((struct route4_filter*)(-1L)) static struct tcf_ext_map route_ext_map = { .police = TCA_ROUTE4_POLICE, .action = TCA_ROUTE4_ACT }; static struct tcf_ext_map tcindex_ext_map = { .police = TCA_TCINDEX_POLICE, .action = TCA_TCINDEX_ACT }; // 分类操作结构 static struct tcf_proto_ops cls_route4_ops = { .next = NULL, .kind = "route", .classify = route4_classify, .init = route4_init, .destroy = route4_destroy, .get = route4_get, .put = route4_put, .change = route4_change, .delete = route4_delete, .walk = route4_walk, .dump = route4_dump, .owner = THIS_MODULE, }; 7.12.2 一些哈希函数 // 快速映射表位置哈希 static __inline__ int route4_fastmap_hash(u32 id, int iif) { // 取ID的低4位, 结果在0~15之间 return id&0xF; } // 进入方向路由哈希 static __inline__ int route4_hash_to(u32 id) { // 取ID的低8位, 结果在0~255之间 return id&0xFF; } // 来源方向路由哈希 static __inline__ int route4_hash_from(u32 id) { // 取ID的16~19位, 结果在0~15之间 return (id>>16)&0xF; } // 网卡索引号哈希 static __inline__ int route4_hash_iif(int iif) { // 取网卡索引号的16~19位再加16, 结果在16~31之间 return 16 + ((iif>>16)&0xF); } // 外卡哈希, 返回外卡哈希表号:32 static __inline__ int route4_hash_wild(void) { return 32; } // 插入哈希, 从哈希表中删除时计算 static inline u32 to_hash(u32 id) { // 取低8位 u32 h = id&0xFF; // 第15位为1的话哈希值增加256 if (id&0x8000) h += 256; // 结果范围应该是0~511 return h; } // 来源哈希, 插入哈希表时计算 static inline u32 from_hash(u32 id) { // 高16位清零 id &= 0xFFFF; // 低16位全1的话返回32, 外卡值 if (id == 0xFFFF) return 32; // 如果第15位为0 if (!(id & 0x8000)) { // 超过255的话返回256 if (id > 255) return 256; // 否则返回低4位, 范围为0~15 return id&0xF; } // 第15位为1 // 返回低4位加16, 范围为16~31 return 16 + (id&0xF); } 7.12.3 初始化 // 空函数 static int route4_init(struct tcf_proto *tp) { return 0; } 7.12.4 分类 // 分类结果处理宏 #define ROUTE4_APPLY_RESULT() \ { \ // 要返回的分类结果 *res = f->res; \ if (tcf_exts_is_available(&f->exts)) { \ // 执行TCF扩展操作 int r = tcf_exts_exec(skb, &f->exts, res); \ if (r < 0) { \ // 操作失败, 不需要将结果进cache, 继续循环 dont_cache = 1; \ continue; \ } \ return r; \ } else if (!dont_cache) \ // 将结果进cache, route4_set_fastmap(head, id, iif, f); \ return 0; \ } static int route4_classify(struct sk_buff *skb, struct tcf_proto *tp, struct tcf_result *res) { // route头节点 struct route4_head *head = (struct route4_head*)tp->root; struct dst_entry *dst; struct route4_bucket *b; struct route4_filter *f; u32 id, h; int iif, dont_cache = 0; // 如果数据包路由项为空, 分类失败 if ((dst = skb->dst) == NULL) goto failure; // 类别ID id = dst->tclassid; // 如果头节点空, 用老方法分类 if (head == NULL) goto old_method; // 网卡索引号 iif = ((struct rtable*)dst)->fl.iif; // 根据ID和网卡索引号计算快速映射哈希值 h = route4_fastmap_hash(id, iif); // 如果快速映射表中元素和此ID和网卡匹配, 而且过滤结构有效 if (id == head->fastmap[h].id && iif == head->fastmap[h].iif && (f = head->fastmap[h].filter) != NULL) { // 如果是错误分类, 返回失败 if (f == ROUTE4_FAILURE) goto failure; // 否则返回分类结构, 分类成功 *res = f->res; return 0; } // 单独根据ID计算路由to哈希值 h = route4_hash_to(id); restart: // 如果该哈希值对应的表有效 if ((b = head->table[h]) != NULL) { // 根据ID哈希, 遍历合适的链表 for (f = b->ht[route4_hash_from(id)]; f; f = f->next) // 如果ID匹配, 成功返回 if (f->id == id) ROUTE4_APPLY_RESULT(); // 根据网卡索引哈希, 遍历合适链表 for (f = b->ht[route4_hash_iif(iif)]; f; f = f->next) // 如果网卡索引匹配, 成功返回 if (f->iif == iif) ROUTE4_APPLY_RESULT(); // 还没找到, 如果外卡链表存在的话, 也成功返回 for (f = b->ht[route4_hash_wild()]; f; f = f->next) ROUTE4_APPLY_RESULT(); } // 哈希值对应的表为空的情况 // 如果哈希值太小, 更新其值后重新查找 if (h < 256) { h = 256; id &= ~0xFFFF; goto restart; } // 否则分类失败 // 如果需要保存在cache中, 将ID和网卡索引号保存到快速索引表中 if (!dont_cache) route4_set_fastmap(head, id, iif, ROUTE4_FAILURE); failure: return -1; old_method: // 老分类方法 // 如果ID有效, 而且ID高16位为0或高16位和handle的高16位相同 if (id && (TC_H_MAJ(id) == 0 || !(TC_H_MAJ(id^tp->q->handle)))) { // 将ID作为类别ID返回 res->classid = id; res->class = 0; return 0; } return -1; } 7.12.5 释放 static void route4_destroy(struct tcf_proto *tp) { // 将根节点换出来准备释放 struct route4_head *head = xchg(&tp->root, NULL); int h1, h2; // 如果根节点空, 直接返回 if (head == NULL) return; // 遍历257个表 for (h1=0; h1<=256; h1++) { struct route4_bucket *b; // 如果链表头非空 if ((b = head->table[h1]) != NULL) { // 遍历bucket结构的33个filter链表 for (h2=0; h2<=32; h2++) { struct route4_filter *f; // 遍历每个链表 while ((f = b->ht[h2]) != NULL) { // 断开节点 b->ht[h2] = f->next; // 删除filter route4_delete_filter(tp, f); } } // 释放bucket kfree(b); } } // 释放根节点 kfree(head); } static inline void route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f) { // 解除绑定 tcf_unbind_filter(tp, &f->res); // 释放TCF扩展结构 tcf_exts_destroy(tp, &f->exts); // 释放过滤器空间 kfree(f); } 7.12.6 获取 // 根据handle查找route4_filter结构 static unsigned long route4_get(struct tcf_proto *tp, u32 handle) { // 根节点 struct route4_head *head = (struct route4_head*)tp->root; struct route4_bucket *b; struct route4_filter *f; unsigned h1, h2; // 根节点空的话返回0 if (!head) return 0; // 根据handle计算哈希值 h1 = to_hash(handle); // 超过256的话返回0 if (h1 > 256) return 0; // 根据handle的高16位计算哈希找bucket h2 = from_hash(handle>>16); // 超过32的话返回0 if (h2 > 32) return 0; // 如果bucket非空 if ((b = head->table[h1]) != NULL) { // 遍历链表 for (f = b->ht[h2]; f; f = f->next) // 查找handle匹配的filter节点返回 if (f->handle == handle) return (unsigned long)f; } return 0; } 7.12.7 放下 // 空函数 static void route4_put(struct tcf_proto *tp, unsigned long f) { } 7.12.8 修改 // 增加和修改tc filter规则时调用 static int route4_change(struct tcf_proto *tp, unsigned long base, u32 handle, struct rtattr **tca, unsigned long *arg) { // 根节点 struct route4_head *head = tp->root; struct route4_filter *f, *f1, **fp; struct route4_bucket *b; // 输入的选项参数 struct rtattr *opt = tca[TCA_OPTIONS-1]; struct rtattr *tb[TCA_ROUTE4_MAX]; unsigned int h, th; u32 old_handle = 0; int err; // 选项参数空, 返回 if (opt == NULL) return handle ? -EINVAL : 0; // 解析选项参数, 结果保存到tb数组 if (rtattr_parse_nested(tb, TCA_ROUTE4_MAX, opt) < 0) return -EINVAL; // 过滤器参数非空, 是修改操作 if ((f = (struct route4_filter*)*arg) != NULL) { // 比较handle是否正确 if (f->handle != handle && handle) return -EINVAL; // 如果已经在某bucket的链表里, 保存handle if (f->bkt) old_handle = f->handle; // 设置过滤器参数, 函数最后一个参数为0表示是修改 err = route4_set_parms(tp, base, f, handle, head, tb, tca[TCA_RATE-1], 0); // 操作失败, 返回错误 if (err < 0) return err; // 成功则跳转重新插入, 将f从原链表中断开的操作也在后面进行 goto reinsert; } // 过滤器参数空, 是新建操作 err = -ENOBUFS; if (head == NULL) { // 如果根节点为空, 分配更节点空间 head = kzalloc(sizeof(struct route4_head), GFP_KERNEL); if (head == NULL) goto errout; tcf_tree_lock(tp); // 将其作为tcf_proto的根参数指针 tp->root = head; tcf_tree_unlock(tp); } // 分配新的过滤器空间 f = kzalloc(sizeof(struct route4_filter), GFP_KERNEL); if (f == NULL) goto errout; // 设置过滤器参数, 函数最后一个参数为1表示是新建 err = route4_set_parms(tp, base, f, handle, head, tb, tca[TCA_RATE-1], 1); // 失败的话转失败处理 if (err < 0) goto errout; reinsert: // 重新插入操作, 将过滤器f插入合适的bucket链表, 对于修改操作, 因为参数变了, // 所以要重新插入到合适的bucket中 // 计算from哈希 h = from_hash(f->handle >> 16); // 遍历相应的哈希链表查找插入位置, 该链表是按handle值排序, 小的在前, 大的在后 for (fp = &f->bkt->ht[h]; (f1=*fp) != NULL; fp = &f1->next) if (f->handle < f1->handle) break; // 将新节点插入链表 f->next = f1; tcf_tree_lock(tp); *fp = f; // 如果handle发生了变化, 需要将该过滤器从原来的链表中断开 // 不过找哪个哈希表的过程确挺费解的 if (old_handle && f->handle != old_handle) { // 计算老handle的to哈希 th = to_hash(old_handle); // 计算老handle高16位的from哈希 h = from_hash(old_handle >> 16); // to哈希链表非空 if ((b = head->table[th]) != NULL) { // 遍历链表 for (fp = &b->ht[h]; *fp; fp = &(*fp)->next) { // 查找过滤器节点 if (*fp == f) { // 从链表中断开 *fp = f->next; break; } } } } tcf_tree_unlock(tp); // 复位快速映射数组, 全部清零 route4_reset_fastmap(tp->q->dev, head, f->id); // 返回f的地址 *arg = (unsigned long)f; return 0; errout: kfree(f); return err; } // 设置过滤器参数 static int route4_set_parms(struct tcf_proto *tp, unsigned long base, struct route4_filter *f, u32 handle, struct route4_head *head, struct rtattr **tb, struct rtattr *est, int new) { int err; u32 id = 0, to = 0, nhandle = 0x8000; struct route4_filter *fp; unsigned int h1; struct route4_bucket *b; struct tcf_exts e; // TCF扩展验证 err = tcf_exts_validate(tp, tb, est, &e, &route_ext_map); if (err < 0) return err; err = -EINVAL; // 判断类别ID是否合法 if (tb[TCA_ROUTE4_CLASSID-1]) if (RTA_PAYLOAD(tb[TCA_ROUTE4_CLASSID-1]) < sizeof(u32)) goto errout; // 解析TO参数 if (tb[TCA_ROUTE4_TO-1]) { if (new && handle & 0x8000) goto errout; if (RTA_PAYLOAD(tb[TCA_ROUTE4_TO-1]) < sizeof(u32)) goto errout; to = *(u32*)RTA_DATA(tb[TCA_ROUTE4_TO-1]); // TO参数不能超过255 if (to > 0xFF) goto errout; // 将TO参数作为nhandle的低0~8位 nhandle = to; } // 如果存在FROM参数 if (tb[TCA_ROUTE4_FROM-1]) { // 解析FROM参数 if (tb[TCA_ROUTE4_IIF-1]) goto errout; if (RTA_PAYLOAD(tb[TCA_ROUTE4_FROM-1]) < sizeof(u32)) goto errout; id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_FROM-1]); // FROM参数也不能超过255 if (id > 0xFF) goto errout; // 将FROM参数作为nhandle的16~23位 nhandle |= id << 16; } else if (tb[TCA_ROUTE4_IIF-1]) { // 否则如果存在网卡参数 if (RTA_PAYLOAD(tb[TCA_ROUTE4_IIF-1]) < sizeof(u32)) goto errout; id = *(u32*)RTA_DATA(tb[TCA_ROUTE4_IIF-1]); // 网卡参数不能超过0x7ffff if (id > 0x7FFF) goto errout; // 将网卡参数作为nhandle的16~30位, 同时第15位置1 nhandle |= (id | 0x8000) << 16; } else // 否则nhandle高16位全1 nhandle |= 0xFFFF << 16; if (handle && new) { // 如果是新建而且handle非0 // 更新nhandle, 前面的计算全部费了 nhandle |= handle & 0x7F00; // 对于新建的filter, handle只能是在16~22位可以为1 if (nhandle != handle) goto errout; } // 计算新handle的to哈希 h1 = to_hash(nhandle); // 如果对应哈希值的bucket为空 if ((b = head->table[h1]) == NULL) { err = -ENOBUFS; // 分配bucket空间 b = kzalloc(sizeof(struct route4_bucket), GFP_KERNEL); if (b == NULL) goto errout; tcf_tree_lock(tp); // 赋值到bucket头数组 head->table[h1] = b; tcf_tree_unlock(tp); } else { // 否则计算高16位的from哈希 unsigned int h2 = from_hash(nhandle >> 16); err = -EEXIST; // 遍历bucket中相应的链表, 查找是否已经有相同的handle, 找到的话返回错误 for (fp = b->ht[h2]; fp; fp = fp->next) if (fp->handle == f->handle) goto errout; } tcf_tree_lock(tp); // 如果TO参数存在的话, ID取TO参数 if (tb[TCA_ROUTE4_TO-1]) f->id = to; // 如果FROM参数存在的话, ID放到ID的高16位 if (tb[TCA_ROUTE4_FROM-1]) f->id = to | id<<16; else if (tb[TCA_ROUTE4_IIF-1]) f->iif = id; // 过滤器的新handle f->handle = nhandle; // 过滤器所在的bucket f->bkt = b; tcf_tree_unlock(tp); // 设置类别ID, 绑定过滤器 if (tb[TCA_ROUTE4_CLASSID-1]) { f->res.classid = *(u32*)RTA_DATA(tb[TCA_ROUTE4_CLASSID-1]); tcf_bind_filter(tp, &f->res, base); } // TCF扩展修改操作 tcf_exts_change(tp, &f->exts, &e); return 0; errout: tcf_exts_destroy(tp, &e); return err; } 7.12.9 删除 static int route4_delete(struct tcf_proto *tp, unsigned long arg) { // 更节点 struct route4_head *head = (struct route4_head*)tp->root; // f是要删除的节点 struct route4_filter **fp, *f = (struct route4_filter*)arg; unsigned h = 0; struct route4_bucket *b; int i; // 根节点或要删除的节点为空, 参数错误 if (!head || !f) return -EINVAL; // 获取过滤器节点的handle和所在的bucket h = f->handle; b = f->bkt; // 遍历该bucket的链表 for (fp = &b->ht[from_hash(h>>16)]; *fp; fp = &(*fp)->next) { // 查找f节点 if (*fp == f) { // 找到 tcf_tree_lock(tp); // 将该节点从链表中断开 *fp = f->next; tcf_tree_unlock(tp); // 复位快速映射表, 是将fastmap数组全部清零了, 好象是连坐一样 route4_reset_fastmap(tp->q->dev, head, f->id); // 释放该过滤器f route4_delete_filter(tp, f); /* Strip tree */ // 检查该f所在bucket是否已经空了 for (i=0; i<=32; i++) if (b->ht[i]) return 0; /* OK, session has no flows */ // 如果空了, 就准备删除该bucket tcf_tree_lock(tp); // 哈希表头置空 head->table[to_hash(h)] = NULL; tcf_tree_unlock(tp); // 释放bucket kfree(b); return 0; } } return 0; } 7.12.10 遍历 static void route4_walk(struct tcf_proto *tp, struct tcf_walker *arg) { // 根节点 struct route4_head *head = tp->root; unsigned h, h1; // 根节点空的话设置停止标志 if (head == NULL) arg->stop = 1; // 设置了停止标志时直接返回 if (arg->stop) return; // 遍历257个bucket for (h = 0; h <= 256; h++) { struct route4_bucket *b = head->table[h]; // 如果该bucket非空 if (b) { // 遍历33个链表 for (h1 = 0; h1 <= 32; h1++) { struct route4_filter *f; // 遍历链表 for (f = b->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.12.11 输出 static int route4_dump(struct tcf_proto *tp, unsigned long fh, struct sk_buff *skb, struct tcmsg *t) { // 要输出的route过滤器节点 struct route4_filter *f = (struct route4_filter*)fh; // skb数据包缓冲区定位 unsigned char *b = skb->tail; struct rtattr *rta; u32 id; // 过滤器空, 返回 if (f == NULL) return skb->len; // 填写handle t->tcm_handle = f->handle; // 结构定位 rta = (struct rtattr*)b; RTA_PUT(skb, TCA_OPTIONS, 0, NULL); // 输出ROUTE_TO if (!(f->handle&0x8000)) { id = f->id&0xFF; RTA_PUT(skb, TCA_ROUTE4_TO, sizeof(id), &id); } if (f->handle&0x80000000) { // handle最高位为1 if ((f->handle>>16) != 0xFFFF) // handle高16非全1的话输出网卡索引号 RTA_PUT(skb, TCA_ROUTE4_IIF, sizeof(f->iif), &f->iif); } else { // handle最高位为0 // ID高16位是ROUTE_FROM id = f->id>>16; RTA_PUT(skb, TCA_ROUTE4_FROM, sizeof(id), &id); } // 类别ID if (f->res.classid) RTA_PUT(skb, TCA_ROUTE4_CLASSID, 4, &f->res.classid); // TCF扩展输出 if (tcf_exts_dump(skb, &f->exts, &route_ext_map) < 0) goto rtattr_failure; rta->rta_len = skb->tail - b; // TCF扩展统计 if (tcf_exts_dump_stats(skb, &f->exts, &route_ext_map) < 0) goto rtattr_failure; return skb->len; rtattr_failure: skb_trim(skb, b - skb->data); return -1; } 7.13 小结 分类操作结构分析告一段落, 基本的特点就是对节点操作时都不直接操作, 而是先在链表中查找确认后才操作, 这也是sched各种代码的共同特征, 为什么不能直接操作呢? 难道是怕在get操作时获取的结构指针在后来操作时已经被删除了? 不过的确这些结构中不是所有都有引用计数的原子操作; 另外一点就是handle的取值, 每个操作结构所对应的handle各个位的定义是不同, 同时进行各种哈希操作也不同, 这些都需要注意, 不过在此不仔细比较各类型的handle的不同了, 有兴趣的自己去分析。 ...... 待续 ......
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2205本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(23)
2011-01-10 16:30 1488本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1933本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1520本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 1974本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1565Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1940本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1797本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(15)
2011-01-10 16:24 1884本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(14)
2011-01-10 16:23 1955本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(13)
2011-01-10 16:22 2631本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(12)
2011-01-10 16:21 2106本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3229本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(10)
2011-01-10 16:20 2002本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(9)
2011-01-10 16:19 1829本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(8)
2011-01-10 16:18 1494本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2922本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1491本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1725本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(4)
2011-01-10 16:15 1643本文档的Copyleft归yfydz所有,使用GPL发布,可以 ...
相关推荐
基于Linux内核扩展模块的P2P流量控制
基于Linux内核的BT流量控制的原理与实现.pdf
基于Linux内核扩展模块的P2P流量控制.pdf
Linux内核扩展模块的P2P流量控制方法与研究.pdf
该方法摒弃了传统方法中所运用的TC命令解析,netlink传输,内核空间执行的3层结构,而直接在Linux内核的框架下,采用LQL库直接对内核进行操控,并改进了相关U32过滤器以对IP段的流量控制,从而实现对系统的智能流量控制。...
15.8. 终极的流量控制:低延迟,高速上/下载 98 15.8.1. 为什么缺省设置不让人满意 99 15.8.2. 实际的脚本(CBQ) 100 15.8.3. 实际的脚本(HTB) 102 15.9. 为单个主机或子网限速 103 15.10. 一个完全NAT和QOS的范例...
在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。Linux的网络系统主要是基于BSD unix的socket机制 。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据...
xt_fset是linux内核netfilter子系统的内核模块和iptables扩展(插件),允许您通过发送控制ICMP数据包来远程操作linux内核ipset(在ipset中添加或删除一些ip地址)。 该插件的创建是对Linux内核netfilter子系统的...
Linux Kernel主要新特性包括:合并了来自Android项目的内核代码,支持新的架构TI C6X,改进了Btrfs...网络优先控制组允许管理员动态设置网络流量的优先次序;支持EFI引导固件;改进内存管理,等等。 Linux Kernel截图
虽然这些工具能够工作,但它们在 Linux2.2 和更高版本的内核上显 得有一些落伍。比如,现在 GRE 隧道已经成为了路由的一个主要概念,但却不 能通过上述工具来配置。 使用了 iproute2,隧道的配置与其他部分完全集成了。
流量控制和拥塞控制 此外,它还补充说: 多路复用流:通过单个连接,您可以多路复用多个信息流。 端点的多宿主:一个端点可以有多个 IP 地址,允许网络故障转移/可靠性(注意:它需要是一台机器,或者复制端点的...
15.2.3 流量控制315 15.3 缓冲区管理和并发控制315 15.4 设备实例:以太网nic316 15.5 isa网络驱动程序321 15.6 atm321 15.7 网络吞吐量322 15.7.1 驱动程序性能322 15.7.2 协议性能323 15.8 查看...
311 15.1.6 统计 312 15.1.7 配置 313 15.1.8 总线相关内容 314 15.2 与协议层会话 314 15.2.1 接收路径 314 15.2.2 发送路径 315 15.2.3 流量控制 315 15.3 缓冲区管理和并发控制 315 15.4 设备实例:...
络地址转换、流量控制及高级的包处理等。Netfilter/Iptables 系统采用模块化的架构方式,其主要模块 有:通用框架Netfilter、数据包选择系统、连接跟踪系统及NAT系统等等。 2.1 Netfilter/Iptables 系统工作原理 ...
netem 与 tc: netem 是 Linux 2.6 及以上...tc 是 Linux 系统中的一个工具,全名为traffic control(流量控制)。tc 可以用来控制 netem 的工作模式,也就是说,如果想使用 netem ,需要至少两个条件,一个是内核中的
如果你仍在使用net-tools,而且尤其需要跟上新版Linux内核中的最新最重要的网络特性的话,那么是时候转到iproute2的阵营了。原因就在于使用iproute2可以做很多net-tools无法做到的事情。对于那些想要转到使用iproute...
Linux支持路由内核、2.6、3.1等普通内核,路由内核支持路由三大内核、Ubuntu、admin等,独立开发的Linux穿盾CC模式,SYN稳定发包100%,自启动,无需Root权限上线即可发包。 VIP版本攻击代码实时更新,通过服务器...