- 浏览: 321827 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
JQ_AK47:
...
Linux下直接发送以太包 -
winsen2009:
谢谢分享,如果能再来一个列子就更好了,刚接触看完还是不懂的用
UNPv1_r3读书笔记: SCTP编程
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn
8.7 ipt动作操作结构 ipt是借用了netfilter的目标操作, 根据netfilter的target结果作为是否接受还是丢弃数据包, 不过感觉意义不大, 因为这破坏了协议栈的分层处理, 要丢包的话直接在上层就丢了就算了。代码在net/sched/act_ipt.c中定义。 8.7.1 数据结构和动作操作结构 /* include/net/tc_act/tc_ipt.h */ // ipt动作结构 struct tcf_ipt { // 通用结构 struct tcf_common common; // hook点 u32 tcfi_hook; // target名称 char *tcfi_tname; // target指针 struct xt_entry_target *tcfi_t; }; #define to_ipt(pc) \ container_of(pc, struct tcf_ipt, common) /* net/sched/act_ipt.c */ static struct tcf_hashinfo ipt_hash_info = { .htab = tcf_ipt_ht, .hmask = IPT_TAB_MASK, .lock = &ipt_lock, }; // ipt动作操作结构 static struct tc_action_ops act_ipt_ops = { // 名称 .kind = "ipt", .hinfo = &ipt_hash_info, // 类型 .type = TCA_ACT_IPT, .capab = TCA_CAP_NONE, .owner = THIS_MODULE, .act = tcf_ipt, .dump = tcf_ipt_dump, .cleanup = tcf_ipt_cleanup, // 查找, 通用函数 .lookup = tcf_hash_search, .init = tcf_ipt_init, // 遍历, 通用函数 .walk = tcf_generic_walker }; 8.7.2 初始化 static int tcf_ipt_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_IPT_MAX]; struct tcf_ipt *ipt; struct tcf_common *pc; struct ipt_entry_target *td, *t; char *tname; int ret = 0, err; u32 hook = 0; u32 index = 0; // 解析输入参数 if (rta == NULL || rtattr_parse_nested(tb, TCA_IPT_MAX, rta) < 0) return -EINVAL; // 需要有hook参数 if (tb[TCA_IPT_HOOK-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_HOOK-1]) < sizeof(u32)) return -EINVAL; // 需要有target参数 if (tb[TCA_IPT_TARG-1] == NULL || RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < sizeof(*t)) return -EINVAL; // netfilter目标 td = (struct ipt_entry_target *)RTA_DATA(tb[TCA_IPT_TARG-1]); // 检查target参数大小是否合法 if (RTA_PAYLOAD(tb[TCA_IPT_TARG-1]) < td->u.target_size) return -EINVAL; // 索引号 if (tb[TCA_IPT_INDEX-1] != NULL && RTA_PAYLOAD(tb[TCA_IPT_INDEX-1]) >= sizeof(u32)) index = *(u32 *)RTA_DATA(tb[TCA_IPT_INDEX-1]); // 根据索引号查找common节点, 绑定到a节点(priv) pc = tcf_hash_check(index, a, bind, &ipt_hash_info); if (!pc) { // 如果为空, 创建新的common节点 pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, &ipt_idx_gen, &ipt_hash_info); if (unlikely(!pc)) return -ENOMEM; ret = ACT_P_CREATED; } else { // ovr是替代标志, 如果不是替代操作, 对象已经存在, 操作失败 if (!ovr) { // 释放 tcf_ipt_release(to_ipt(pc), bind); return -EEXIST; } } // ipt = to_ipt(pc); // hook点 hook = *(u32 *)RTA_DATA(tb[TCA_IPT_HOOK-1]); err = -ENOMEM; // 分配缓冲区保存目标名称 tname = kmalloc(IFNAMSIZ, GFP_KERNEL); if (unlikely(!tname)) goto err1; // 解析iptables表的名称, 缺省为mangle表 if (tb[TCA_IPT_TABLE - 1] == NULL || rtattr_strlcpy(tname, tb[TCA_IPT_TABLE-1], IFNAMSIZ) >= IFNAMSIZ) strcpy(tname, "mangle"); // 分配目标空间 t = kmalloc(td->u.target_size, GFP_KERNEL); if (unlikely(!t)) goto err2; // 复制目标结构相关参数 memcpy(t, td, td->u.target_size); // 初始化目标 if ((err = ipt_init_target(t, tname, hook)) < 0) goto err3; spin_lock_bh(&ipt->tcf_lock); if (ret != ACT_P_CREATED) { // 如果不是新建, 释放老节点参数 ipt_destroy_target(ipt->tcfi_t); kfree(ipt->tcfi_tname); kfree(ipt->tcfi_t); } // 参数赋值 ipt->tcfi_tname = tname; ipt->tcfi_t = t; ipt->tcfi_hook = hook; spin_unlock_bh(&ipt->tcf_lock); // 新建节点, 插入哈希表 if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &ipt_hash_info); return ret; 错误处理, 释放各种动态分配的参数 err3: kfree(t); err2: kfree(tname); err1: kfree(pc); return err; } // 初始化目标 static int ipt_init_target(struct ipt_entry_target *t, char *table, unsigned int hook) { struct ipt_target *target; int ret = 0; // 根据名称查找target target = xt_find_target(AF_INET, t->u.user.name, t->u.user.revision); // 找不到则失败 if (!target) return -ENOENT; t->u.kernel.target = target; // target通用检查, 检查合适的大小, 表名, hook, 协议等信息 ret = xt_check_target(target, AF_INET, t->u.target_size - sizeof(*t), table, hook, 0, 0); if (ret) return ret; // 执行target自己的检查函数 if (t->u.kernel.target->checkentry && !t->u.kernel.target->checkentry(table, NULL, t->u.kernel.target, t->data, hook)) { module_put(t->u.kernel.target->me); ret = -EINVAL; } return ret; } 8.7.3 动作 static int tcf_ipt(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) { int ret = 0, result = 0; // 动作结构 struct tcf_ipt *ipt = a->priv; if (skb_cloned(skb)) { // 如果是克隆包, 重新分配数据空间形成一个独立的数据包 if (pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) return TC_ACT_UNSPEC; } spin_lock(&ipt->tcf_lock); // 统计参数更新 ipt->tcf_tm.lastuse = jiffies; ipt->tcf_bstats.bytes += skb->len; ipt->tcf_bstats.packets++; /* yes, we have to worry about both in and out dev worry later - danger - this API seems to have changed from earlier kernels */ /* iptables targets take a double skb pointer in case the skb * needs to be replaced. We don't own the skb, so this must not * happen. The pskb_expand_head above should make sure of this */ // 执行target函数 ret = ipt->tcfi_t->u.kernel.target->target(&skb, skb->dev, NULL, ipt->tcfi_hook, ipt->tcfi_t->u.kernel.target, ipt->tcfi_t->data); switch (ret) { case NF_ACCEPT: // 接受 result = TC_ACT_OK; break; case NF_DROP: // 拒绝 result = TC_ACT_SHOT; ipt->tcf_qstats.drops++; break; case IPT_CONTINUE: // 继续 result = TC_ACT_PIPE; break; default: // 缺省也是接受 if (net_ratelimit()) printk("Bogus netfilter code %d assume ACCEPT\n", ret); result = TC_POLICE_OK; break; } spin_unlock(&ipt->tcf_lock); return result; } 8.7.4 输出 static int tcf_ipt_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { // 数据包缓冲区位置 unsigned char *b = skb->tail; // ipt动作结构 struct tcf_ipt *ipt = a->priv; struct ipt_entry_target *t; struct tcf_t tm; struct tc_cnt c; /* for simple targets kernel size == user size ** user name = target name ** for foolproof you need to not assume this */ // 分配target结构, 只是用于中转处理 t = kmalloc(ipt->tcfi_t->u.user.target_size, GFP_ATOMIC); if (unlikely(!t)) goto rtattr_failure; // 统计值 c.bindcnt = ipt->tcf_bindcnt - bind; c.refcnt = ipt->tcf_refcnt - ref; // 拷贝target结构 memcpy(t, ipt->tcfi_t, ipt->tcfi_t->u.user.target_size); // 拷贝target名称 strcpy(t->u.user.name, ipt->tcfi_t->u.kernel.target->name); // target RTA_PUT(skb, TCA_IPT_TARG, ipt->tcfi_t->u.user.target_size, t); // 索引号 RTA_PUT(skb, TCA_IPT_INDEX, 4, &ipt->tcf_index); // hook点 RTA_PUT(skb, TCA_IPT_HOOK, 4, &ipt->tcfi_hook); // 统计值 RTA_PUT(skb, TCA_IPT_CNT, sizeof(struct tc_cnt), &c); // 网卡名称 RTA_PUT(skb, TCA_IPT_TABLE, IFNAMSIZ, ipt->tcfi_tname); // 时间参数 tm.install = jiffies_to_clock_t(jiffies - ipt->tcf_tm.install); tm.lastuse = jiffies_to_clock_t(jiffies - ipt->tcf_tm.lastuse); tm.expires = jiffies_to_clock_t(ipt->tcf_tm.expires); RTA_PUT(skb, TCA_IPT_TM, sizeof (tm), &tm); // 释放刚分配的target kfree(t); return skb->len; rtattr_failure: skb_trim(skb, b - skb->data); kfree(t); return -1; } 8.7.5 清除 // 只是tcf_ipt_release的转换函数 static int tcf_ipt_cleanup(struct tc_action *a, int bind) { // ipt动作结构 struct tcf_ipt *ipt = a->priv; return tcf_ipt_release(ipt, bind); } // ipt释放操作 static int tcf_ipt_release(struct tcf_ipt *ipt, int bind) { int ret = 0; if (ipt) { // 减少绑定数 if (bind) ipt->tcf_bindcnt--; // 减少引用数 ipt->tcf_refcnt--; // 绑定数和引用数都为0后释放ipt动作结构 if (ipt->tcf_bindcnt <= 0 && ipt->tcf_refcnt <= 0) { // 释放目标 ipt_destroy_target(ipt->tcfi_t); // 释放target名称 kfree(ipt->tcfi_tname); // 释放target空间 kfree(ipt->tcfi_t); // 释放动作结构节点 tcf_hash_destroy(&ipt->common, &ipt_hash_info); ret = ACT_P_DELETED; } } return ret; } static void ipt_destroy_target(struct ipt_entry_target *t) { // 调用target的destroy函数, 其实有此成员函数的target不多 if (t->u.kernel.target->destroy) t->u.kernel.target->destroy(t->u.kernel.target, t->data); // 减少module计数 module_put(t->u.kernel.target->me); } 8.8 gact(Generic actions) gact定义一个通用的TC动作处理结果方法, 代码在net/sched/act_gact.c中定义. 8.8.1 数据结构和动作操作结构 /* include/net/tc_act/tc_gact.h */ // GACT动作结构 struct tcf_gact { struct tcf_common common; #ifdef CONFIG_GACT_PROB u16 tcfg_ptype; u16 tcfg_pval; int tcfg_paction; #endif }; #define to_gact(pc) \ container_of(pc, struct tcf_gact, common) /* include/linux/tc_act/tc_gact.h */ #define TCA_ACT_GACT 5 struct tc_gact { // TC通用数据 tc_gen; }; #define tc_gen \ __u32 index; \ __u32 capab; \ int action; \ int refcnt; \ int bindcnt struct tc_gact_p { #define PGACT_NONE 0 #define PGACT_NETRAND 1 #define PGACT_DETERM 2 #define MAX_RAND (PGACT_DETERM + 1 ) __u16 ptype; __u16 pval; int paction; }; /* net/sched/act_gact.c */ // GACT哈希表信息结构 static struct tcf_hashinfo gact_hash_info = { .htab = tcf_gact_ht, .hmask = GACT_TAB_MASK, .lock = &gact_lock, }; // gact动作操作结构 static struct tc_action_ops act_gact_ops = { .kind = "gact", // 哈希表信息 .hinfo = &gact_hash_info, .type = TCA_ACT_GACT, .capab = TCA_CAP_NONE, .owner = THIS_MODULE, .act = tcf_gact, .dump = tcf_gact_dump, .cleanup = tcf_gact_cleanup, // 通用函数 .lookup = tcf_hash_search, .init = tcf_gact_init, // 通用函数 .walk = tcf_generic_walker }; 8.8.2 初始化 static int tcf_gact_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_GACT_MAX]; struct tc_gact *parm; struct tcf_gact *gact; struct tcf_common *pc; int ret = 0; // 解析输入参数, 结果保存到tb数组, 失败则返回 if (rta == NULL || rtattr_parse_nested(tb, TCA_GACT_MAX, rta) < 0) return -EINVAL; // 解析参数 if (tb[TCA_GACT_PARMS - 1] == NULL || RTA_PAYLOAD(tb[TCA_GACT_PARMS - 1]) < sizeof(*parm)) return -EINVAL; parm = RTA_DATA(tb[TCA_GACT_PARMS - 1]); // PROB参数 if (tb[TCA_GACT_PROB-1] != NULL) #ifdef CONFIG_GACT_PROB if (RTA_PAYLOAD(tb[TCA_GACT_PROB-1]) < sizeof(struct tc_gact_p)) return -EINVAL; #else return -EOPNOTSUPP; #endif // 根据索引号查找common结构 pc = tcf_hash_check(parm->index, a, bind, &gact_hash_info); if (!pc) { // 没找到的话新建一个 pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind, &gact_idx_gen, &gact_hash_info); if (unlikely(!pc)) return -ENOMEM; ret = ACT_P_CREATED; } else { // 找到的话检查是否是替代操作, 否则失败, 对象已经存在 if (!ovr) { tcf_hash_release(pc, bind, &gact_hash_info); return -EEXIST; } } // 获取GACT结构指针 gact = to_gact(pc); spin_lock_bh(&gact->tcf_lock); // 填写GACT结构参数 // 动作结果 gact->tcf_action = parm->action; #ifdef CONFIG_GACT_PROB if (tb[TCA_GACT_PROB-1] != NULL) { struct tc_gact_p *p_parm = RTA_DATA(tb[TCA_GACT_PROB-1]); gact->tcfg_paction = p_parm->paction; gact->tcfg_pval = p_parm->pval; gact->tcfg_ptype = p_parm->ptype; } #endif spin_unlock_bh(&gact->tcf_lock); // 如果是新建节点, 插入哈希表 if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &gact_hash_info); return ret; } 8.8.3 动作 static int tcf_gact(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) { // GACT动作结构为a的私有数据 struct tcf_gact *gact = a->priv; // 缺省动作是拒绝 int action = TC_ACT_SHOT; spin_lock(&gact->tcf_lock); #ifdef CONFIG_GACT_PROB // 如果定义了GACT_PROB内核选项 // gact_rand是一个动作函数指针数组, 对应一些动作函数, 会有些随机因素在里面 if (gact->tcfg_ptype && gact_rand[gact->tcfg_ptype] != NULL) action = gact_rand[gact->tcfg_ptype](gact); else action = gact->tcf_action; #else // 否则就直接是TC规则中定义的动作类型 action = gact->tcf_action; #endif // 统计数更新 gact->tcf_bstats.bytes += skb->len; gact->tcf_bstats.packets++; // 如果是丢包, 增加丢包数 if (action == TC_ACT_SHOT) gact->tcf_qstats.drops++; // 结构上次使用时间 gact->tcf_tm.lastuse = jiffies; spin_unlock(&gact->tcf_lock); return action; } 其中gact_rand数组定义如下: typedef int (*g_rand)(struct tcf_gact *gact); static g_rand gact_rand[MAX_RAND]= { NULL, gact_net_rand, gact_determ }; // 随机动作 static int gact_net_rand(struct tcf_gact *gact) { // pval作为一个随机处理因素, 在非0情况下会有一定随机性选择tcfg_paction动作, // 其他情况下选择tcfg_action if (!gact->tcfg_pval || net_random() % gact->tcfg_pval) return gact->tcf_action; return gact->tcfg_paction; } // 确定性动作 static int gact_determ(struct tcf_gact *gact) { // pval作为一个处理因素, 在非0情况下会有一定根据当前统计数选择tcfg_paction动作, // 其他情况下选择tcfg_action if (!gact->tcfg_pval || gact->tcf_bstats.packets % gact->tcfg_pval) return gact->tcf_action; return gact->tcfg_paction; } 8.8.4 输出 static int tcf_gact_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { // 数据包缓冲区起始位置 unsigned char *b = skb->tail; // GACT选项结构 struct tc_gact opt; // GACT动作结构 struct tcf_gact *gact = a->priv; // 时间参数 struct tcf_t t; // 填充GACT选项参数 opt.index = gact->tcf_index; opt.refcnt = gact->tcf_refcnt - ref; opt.bindcnt = gact->tcf_bindcnt - bind; opt.action = gact->tcf_action; // 将选项参数拷贝到skb缓冲区 RTA_PUT(skb, TCA_GACT_PARMS, sizeof(opt), &opt); #ifdef CONFIG_GACT_PROB // 填充GACT_PROB情况下相关数据 if (gact->tcfg_ptype) { struct tc_gact_p p_opt; p_opt.paction = gact->tcfg_paction; p_opt.pval = gact->tcfg_pval; p_opt.ptype = gact->tcfg_ptype; RTA_PUT(skb, TCA_GACT_PROB, sizeof(p_opt), &p_opt); } #endif // 填写时间 t.install = jiffies_to_clock_t(jiffies - gact->tcf_tm.install); t.lastuse = jiffies_to_clock_t(jiffies - gact->tcf_tm.lastuse); t.expires = jiffies_to_clock_t(gact->tcf_tm.expires); // 拷贝到skb缓冲区 RTA_PUT(skb, TCA_GACT_TM, sizeof(t), &t); // 返回当前数据长度, 注意这里都没有计算netlink信息长度参数 return skb->len; rtattr_failure: skb_trim(skb, b - skb->data); return -1; } 8.8.5 清除 // 只是相当于tcf_hash_release的包裹函数 static int tcf_gact_cleanup(struct tc_action *a, int bind) { struct tcf_gact *gact = a->priv; if (gact) return tcf_hash_release(&gact->common, bind, &gact_hash_info); return 0; } 8.9 simple simple定义一个简单的TC动作处理结果方法实例, 代码在net/sched/act_simple.c中定义. 8.9.1 数据结构和动作操作结构 /* net/sched/act_simple.c */ // simple哈希表信息结构 static struct tcf_hashinfo simp_hash_info = { .htab = tcf_simp_ht, .hmask = SIMP_TAB_MASK, .lock = &simp_lock, }; // simple动作操作结构 // 没有lookup函数 static struct tc_action_ops act_simp_ops = { .kind = "simple", .hinfo = &simp_hash_info, .type = TCA_ACT_SIMP, .capab = TCA_CAP_NONE, .owner = THIS_MODULE, .act = tcf_simp, .dump = tcf_simp_dump, .cleanup = tcf_simp_cleanup, .init = tcf_simp_init, // 通用函数 .walk = tcf_generic_walker, }; 8.9.2 初始化 static int tcf_simp_init(struct rtattr *rta, struct rtattr *est, struct tc_action *a, int ovr, int bind) { struct rtattr *tb[TCA_DEF_MAX]; // 缺省动作结构, simple由于很简单, 没定义自己的动作结构, 直接用缺省的 struct tc_defact *parm; struct tcf_defact *d; struct tcf_common *pc; void *defdata; u32 datalen = 0; int ret = 0; // 解析输入参数, 结果保存到tb数组, 失败则返回 if (rta == NULL || rtattr_parse_nested(tb, TCA_DEF_MAX, rta) < 0) return -EINVAL; // 解析参数 if (tb[TCA_DEF_PARMS - 1] == NULL || RTA_PAYLOAD(tb[TCA_DEF_PARMS - 1]) < sizeof(*parm)) return -EINVAL; // 参数指针 parm = RTA_DATA(tb[TCA_DEF_PARMS - 1]); defdata = RTA_DATA(tb[TCA_DEF_DATA - 1]); if (defdata == NULL) return -EINVAL; // 数据长度 datalen = RTA_PAYLOAD(tb[TCA_DEF_DATA - 1]); if (datalen <= 0) return -EINVAL; // 根据索引号查找common结构 pc = tcf_hash_check(parm->index, a, bind, &simp_hash_info); if (!pc) { // 没找到的话新建一个 pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, &simp_idx_gen, &simp_hash_info); if (unlikely(!pc)) return -ENOMEM; d = to_defact(pc); // 分配缺省数据, 复制defdata参数 ret = alloc_defdata(d, datalen, defdata); if (ret < 0) { kfree(pc); return ret; } // 新建标志 ret = ACT_P_CREATED; } else { // 转换为缺省动作结构 d = to_defact(pc); // 找到的话检查是否是替代操作, 否则失败, 对象已经存在 if (!ovr) { // 释放simple动作结构 tcf_simp_release(d, bind); return -EEXIST; } // 是替代操作, 进行重新分配结构操作 realloc_defdata(d, datalen, defdata); } spin_lock_bh(&d->tcf_lock); // 设置动作 d->tcf_action = parm->action; spin_unlock_bh(&d->tcf_lock); // 如果是新建节点, 插入哈希表 if (ret == ACT_P_CREATED) tcf_hash_insert(pc, &simp_hash_info); return ret; } // 分配缺省数据 static int alloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) { // 分配空间 d->tcfd_defdata = kmalloc(datalen, GFP_KERNEL); if (unlikely(!d->tcfd_defdata)) return -ENOMEM; // 设置数据长度 d->tcfd_datalen = datalen; // 拷贝数据 memcpy(d->tcfd_defdata, defdata, datalen); return 0; } // 重新分配 static int realloc_defdata(struct tcf_defact *d, u32 datalen, void *defdata) { // 释放原来的defdata kfree(d->tcfd_defdata); // 重新分配新的defdata return alloc_defdata(d, datalen, defdata); } 8.9.3 动作 static int tcf_simp(struct sk_buff *skb, struct tc_action *a, struct tcf_result *res) { // simple只是用缺省动作结构, 为a的私有数据 struct tcf_defact *d = a->priv; spin_lock(&d->tcf_lock); // 更新结构时间参数 d->tcf_tm.lastuse = jiffies; // 更新数据包统计值 d->tcf_bstats.bytes += skb->len; d->tcf_bstats.packets++; /* print policy string followed by _ then packet count * Example if this was the 3rd packet and the string was "hello" * then it would look like "hello_3" (without quotes) **/ printk("simple: %s_%d\n", (char *)d->tcfd_defdata, d->tcf_bstats.packets); spin_unlock(&d->tcf_lock); // 返回动作结果 return d->tcf_action; } 8.9.4 输出 static inline int tcf_simp_dump(struct sk_buff *skb, struct tc_action *a, int bind, int ref) { unsigned char *b = skb->tail; struct tcf_defact *d = a->priv; struct tc_defact opt; struct tcf_t t; // 填写基本选项参数 // 索引号 opt.index = d->tcf_index; // 引用数 opt.refcnt = d->tcf_refcnt - ref; // 绑定数 opt.bindcnt = d->tcf_bindcnt - bind; // 动作 opt.action = d->tcf_action; RTA_PUT(skb, TCA_DEF_PARMS, sizeof(opt), &opt); // 拷贝defdata RTA_PUT(skb, TCA_DEF_DATA, d->tcfd_datalen, d->tcfd_defdata); // 填写时间参数 // 建立时间 t.install = jiffies_to_clock_t(jiffies - d->tcf_tm.install); // 上次使用时间 t.lastuse = jiffies_to_clock_t(jiffies - d->tcf_tm.lastuse); // 到期时间 t.expires = jiffies_to_clock_t(d->tcf_tm.expires); RTA_PUT(skb, TCA_DEF_TM, sizeof(t), &t); return skb->len; rtattr_failure: skb_trim(skb, b - skb->data); return -1; } 8.9.5 清除 // 就是tcf_simp_release的包裹函数 static inline int tcf_simp_cleanup(struct tc_action *a, int bind) { struct tcf_defact *d = a->priv; if (d) return tcf_simp_release(d, bind); return 0; } // 释放simple动作结构 static int tcf_simp_release(struct tcf_defact *d, int bind) { int ret = 0; if (d) { // 减少绑定数 if (bind) d->tcf_bindcnt--; // 减少引用数 d->tcf_refcnt--; // 绑定数和引用数都到0 if (d->tcf_bindcnt <= 0 && d->tcf_refcnt <= 0) { // 释放defdata的缓冲区 kfree(d->tcfd_defdata); // 释放节点 tcf_hash_destroy(&d->common, &simp_hash_info); ret = 1; } } return ret; } ...... 待续 ......
发表评论
-
Linux内核中流量控制(24)
2011-01-10 16:33 2245本文档的Copyleft归yfydz所 ... -
Linux内核中流量控制(22)
2011-01-10 16:29 1980本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(21)
2011-01-10 16:28 1401本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(20)
2011-01-10 16:27 1567本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(19)
2011-01-10 16:27 2022本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(18)
2011-01-10 16:26 1616Linux内核中流量控制(18) ... -
Linux内核中流量控制(17)
2011-01-10 16:25 1991本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(16)
2011-01-10 16:25 1849本文档的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 2166本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(11)
2011-01-10 16:21 3289本文档的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 1544本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(7)
2011-01-10 16:18 2973本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(6)
2011-01-10 16:17 1539本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(5)
2011-01-10 16:16 1767本文档的Copyleft归yfydz所有,使用GPL发布,可以 ... -
Linux内核中流量控制(4)
2011-01-10 16:15 1688本文档的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数据结构来实现的。 ...