`

Linux内核中流量控制(17)

阅读更多
本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。
msn: yfydz_no1@hotmail.com
来源:http://yfydz.cublog.cn

7.6 tcf_proto_ops的一些相关操作

7.6.1 登记和撤销

/* Register(unregister) new classifier type */
// 登记新的tcf_proto_ops分类操作结构
int register_tcf_proto_ops(struct tcf_proto_ops *ops)
{
 struct tcf_proto_ops *t, **tp;
 int rc = -EEXIST;
 write_lock(&cls_mod_lock);
// 遍历当前tcf_proto_ops链表
 for (tp = &tcf_proto_base; (t = *tp) != NULL; tp = &t->next)
// 检查是否有名称相同的项, 有的话返回对象已存在错误
  if (!strcmp(ops->kind, t->kind))
   goto out;
// 添加到链表末尾, 也是dummy header算法
 ops->next = NULL;
 *tp = ops;
 rc = 0;
out:
 write_unlock(&cls_mod_lock);
 return rc;
}

// 撤销tcf_proto_ops分类结构
int unregister_tcf_proto_ops(struct tcf_proto_ops *ops)
{
 struct tcf_proto_ops *t, **tp;
 int rc = -ENOENT;
 write_lock(&cls_mod_lock);
// 遍历链表
 for (tp = &tcf_proto_base; (t=*tp) != NULL; tp = &t->next)
// 直接进行tcf_proto_ops结构地址比较, 相同的话中断循环
  if (t == ops)
   break;
 if (!t)
  goto out;
// 将找到的tp节点从链表中断开, 不用释放操作, 因为这些ops其实都是静态定义的
 *tp = t->next;
 rc = 0;
out:
 write_unlock(&cls_mod_lock);
 return rc;
}

7.6.2 tcf扩展

tcf扩展增加了对分类后数据进行某种操作的功能, 有点象netfilter的target,使用这些功能需要在配置内核时定义NET_CLS_ACT或NET_CLS_POLICE。

/* include/net/pkt_cls.h */
// tcf扩展结构, 如果没定义NET_CLS_ACT和NET_CLS_POLICE的话就是个空结构
struct tcf_exts
{
#ifdef CONFIG_NET_CLS_ACT
// 动作
 struct tc_action *action;
#elif defined CONFIG_NET_CLS_POLICE
// 策略
 struct tcf_police *police;
#endif
};
/* Map to export classifier specific extension TLV types to the
 * generic extensions API. Unsupported extensions must be set to 0.
 */
struct tcf_ext_map
{
 int action;
 int police;
};

/**
 * tcf_exts_is_predicative - check if a predicative extension is present
 * @exts: tc filter extensions handle
 *
 * Returns 1 if a predicative extension is present, i.e. an extension which
 * might cause further actions and thus overrule the regular tcf_result.
 */
// 返回扩展结构中的元素是否为空
static inline int
tcf_exts_is_predicative(struct tcf_exts *exts)
{
#ifdef CONFIG_NET_CLS_ACT
// !!是为了保证返回值0或1
 return !!exts->action;
#elif defined CONFIG_NET_CLS_POLICE
 return !!exts->police;
#else
 return 0;
#endif
}
/**
 * tcf_exts_is_available - check if at least one extension is present
 * @exts: tc filter extensions handle
 *
 * Returns 1 if at least one extension is present.
 */
// 实际就是cf_exts_is_predicative函数
static inline int
tcf_exts_is_available(struct tcf_exts *exts)
{
 /* All non-predicative extensions must be added here. */
 return tcf_exts_is_predicative(exts);
}
/**
 * tcf_exts_exec - execute tc filter extensions
 * @skb: socket buffer
 * @exts: tc filter extensions handle
 * @res: desired result
 *
 * Executes all configured extensions. Returns 0 on a normal execution,
 * a negative number if the filter must be considered unmatched or
 * a positive action code (TC_ACT_*) which must be returned to the
 * underlying layer.
 */
static inline int
tcf_exts_exec(struct sk_buff *skb, struct tcf_exts *exts,
        struct tcf_result *res)
{
#ifdef CONFIG_NET_CLS_ACT
 if (exts->action)
  return tcf_action_exec(skb, exts->action, res);
#elif defined CONFIG_NET_CLS_POLICE
 if (exts->police)
  return tcf_police(skb, exts->police);
#endif
 return 0;
}
 
/* net/sched/cls_api.c */
// 是否tcf扩展结构
void
tcf_exts_destroy(struct tcf_proto *tp, struct tcf_exts *exts)
{
#ifdef CONFIG_NET_CLS_ACT
 if (exts->action) {
// 释放tcf动作
  tcf_action_destroy(exts->action, TCA_ACT_UNBIND);
  exts->action = NULL;
 }
#elif defined CONFIG_NET_CLS_POLICE
 if (exts->police) {
// 释放tcf策略
  tcf_police_release(exts->police, TCA_ACT_UNBIND);
  exts->police = NULL;
 }
#endif
}
 
int
tcf_exts_validate(struct tcf_proto *tp, struct rtattr **tb,
           struct rtattr *rate_tlv, struct tcf_exts *exts,
           struct tcf_ext_map *map)
{
// 结构清零
 memset(exts, 0, sizeof(*exts));
 
#ifdef CONFIG_NET_CLS_ACT
 {
  int err;
  struct tc_action *act;
// 如果策略存在
  if (map->police && tb[map->police-1]) {
// 进行动作初始化, 生成新动作指针
   act = tcf_action_init_1(tb[map->police-1], rate_tlv, "police",
    TCA_ACT_NOREPLACE, TCA_ACT_BIND, &err);
   if (act == NULL)
    return err;
// TCA_OLD_COMPAT标志是策略
   act->type = TCA_OLD_COMPAT;
   exts->action = act;
  } else
// 如果动作存在
  if (map->action && tb[map->action-1]) {
// 动作初始化, 生成动作指针
   act = tcf_action_init(tb[map->action-1], rate_tlv, NULL,
    TCA_ACT_NOREPLACE, TCA_ACT_BIND, &err);
   if (act == NULL)
    return err;
// action赋值
   exts->action = act;
  }
 }
#elif defined CONFIG_NET_CLS_POLICE
// 如果策略存在
 if (map->police && tb[map->police-1]) {
  struct tcf_police *p;
// 生成新策略结构
  p = tcf_police_locate(tb[map->police-1], rate_tlv);
  if (p == NULL)
   return -EINVAL;
// police赋值
  exts->police = p;
 } else if (map->action && tb[map->action-1])
  return -EOPNOTSUPP;
#else
 if ((map->action && tb[map->action-1]) ||
     (map->police && tb[map->police-1]))
  return -EOPNOTSUPP;
#endif
 return 0;
}

// 修改扩展结构, 将src中的参数填到dst中
void
tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst,
         struct tcf_exts *src)
{
#ifdef CONFIG_NET_CLS_ACT
// 动作操作
 if (src->action) {
  struct tc_action *act;
  tcf_tree_lock(tp);
// dst和src的action进行交换, 返回原来dst->action
  act = xchg(&dst->action, src->action);
  tcf_tree_unlock(tp);
// 如果原来的action非空, 释放之
  if (act)
   tcf_action_destroy(act, TCA_ACT_UNBIND);
 }
#elif defined CONFIG_NET_CLS_POLICE
// 策略操作
 if (src->police) {
  struct tcf_police *p;
  tcf_tree_lock(tp);
// dst和src的police进行交换, 返回原来dst->police
  p = xchg(&dst->police, src->police);
  tcf_tree_unlock(tp);
// 如果原来的police非空, 释放之
  if (p)
   tcf_police_release(p, TCA_ACT_UNBIND);
 }
#endif
}

// 输出扩展结构
int
tcf_exts_dump(struct sk_buff *skb, struct tcf_exts *exts,
       struct tcf_ext_map *map)
{
#ifdef CONFIG_NET_CLS_ACT
// 输出动作
 if (map->action && exts->action) {
// 参数存在
  /*
   * again for backward compatible mode - we want
   * to work with both old and new modes of entering
   * tc data even if iproute2  was newer - jhs
   */
// 在数据包缓冲区中定位
  struct rtattr * p_rta = (struct rtattr*) skb->tail;
  if (exts->action->type != TCA_OLD_COMPAT) {
// 类型是动作
   RTA_PUT(skb, map->action, 0, NULL);
// 动作输出
   if (tcf_action_dump(skb, exts->action, 0, 0) < 0)
    goto rtattr_failure;
// 数据长度
   p_rta->rta_len = skb->tail - (u8*)p_rta;
  } else if (map->police) {
// 类型是策略
   RTA_PUT(skb, map->police, 0, NULL);
// 策略输出
   if (tcf_action_dump_old(skb, exts->action, 0, 0) < 0)
    goto rtattr_failure;
// 数据长度
   p_rta->rta_len = skb->tail - (u8*)p_rta;
  }
 }
#elif defined CONFIG_NET_CLS_POLICE
// 输出策略
 if (map->police && exts->police) {
// 策略存在
// 在数据包缓冲区中定位
  struct rtattr * p_rta = (struct rtattr*) skb->tail;
  RTA_PUT(skb, map->police, 0, NULL);
// 策略输出
  if (tcf_police_dump(skb, exts->police) < 0)
   goto rtattr_failure;
// 数据长度
  p_rta->rta_len = skb->tail - (u8*)p_rta;
 }
#endif
 return 0;
rtattr_failure: __attribute__ ((unused))
 return -1;
}
 
// 输出统计值
int
tcf_exts_dump_stats(struct sk_buff *skb, struct tcf_exts *exts,
             struct tcf_ext_map *map)
{
#ifdef CONFIG_NET_CLS_ACT
// 动作统计
 if (exts->action)
// 输出策略统计值到skb
  if (tcf_action_copy_stats(skb, exts->action, 1) < 0)
   goto rtattr_failure;
#elif defined CONFIG_NET_CLS_POLICE
// 策略统计
 if (exts->police)
// 输出策略统计值到skb
  if (tcf_police_dump_stats(skb, exts->police) < 0)
   goto rtattr_failure;
#endif
 return 0;
rtattr_failure: __attribute__ ((unused))
 return -1;
}
 
7.7 TC分类操作

下面看一下分类函数是如何被调用的, 分类操作通过tc_classify()函数完成, 在以前介绍的各种分类流控算法中都见过该函数:
/* net/sched/sch_api.c */
/* Main classifier routine: scans classifier chain attached
   to this qdisc, (optionally) tests for protocol and asks
   specific classifiers.
 */
//
int tc_classify(struct sk_buff *skb, struct tcf_proto *tp,
 struct tcf_result *res)
{
 int err = 0;
// 协议, 这里应该是数据链路层中的协议值, 如IP包就是0x0800
 u32 protocol = skb->protocol;
#ifdef CONFIG_NET_CLS_ACT
 struct tcf_proto *otp = tp;
reclassify:
#endif
 protocol = skb->protocol;
// 遍历分类规则链表
 for ( ; tp; tp = tp->next) {
// 首先要求协议匹配
  if ((tp->protocol == protocol ||
   tp->protocol == __constant_htons(ETH_P_ALL)) &&
// 然后调用tcf_proto中的分类函数进行处理, 该函数实际就是tcf_proto_ops的分类函数
// 分类结构>=0表示分类成功
   (err = tp->classify(skb, tp, res)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
// 返回结果是需要重新分类
   if ( TC_ACT_RECLASSIFY == err) {
// 将skb中的tc_verd值转换为判断值, 实际是个计数器
    __u32 verd = (__u32) G_TC_VERD(skb->tc_verd);
    tp = otp;
// 转换次数太多, 返回丢包
    if (MAX_REC_LOOP < verd++) {
     printk("rule prio %d protocol %02x reclassify is buggy packet dropped\n",
      tp->prio&0xffff, ntohs(tp->protocol));
     return TC_ACT_SHOT;
    }
// 转换回tc_verd
    skb->tc_verd = SET_TC_VERD(skb->tc_verd,verd);
// 重新分类操作
    goto reclassify;
   } else {
// 非重新分类的话, 更新tc_verd, 返回分类结果
    if (skb->tc_verd)
     skb->tc_verd = SET_TC_VERD(skb->tc_verd,0);
    return err;
   }
#else
// 如果内核没定义NET_CLS_ACT, 直接返回分类操作结果
   return err;
#endif
  }
 }
// 循环退出, 分类失败
 return -1;
}
tc_classify()的核心函数就是tp->classify()函数
 
7.8 fw过滤操作结构

fw分类方法主要是根据skb中nfmark参数来进行数据分类, 而该参数是由netfilter定义的, 如果内核里没有定义netfilter, 这该分类方法意义不大,该分类方法在 net/sched/cls_fw.c 中定义。
7.8.1 结构定义
static struct tcf_proto_ops cls_fw_ops = {
// 这个参数可以不用明确写出来, 这种定义方法参数缺省就是0了
 .next  = NULL,
// 名称
 .kind  = "fw",
// 各种操作函数
 .classify = fw_classify,
 .init  = fw_init,
 .destroy = fw_destroy,
 .get  = fw_get,
 .put  = fw_put,
 .change  = fw_change,
 .delete  = fw_delete,
 .walk  = fw_walk,
 .dump  = fw_dump,
 .owner  = THIS_MODULE,
};

// 哈希表数量, 空间限制为一页内存, x86是4K, 32系统指针是4字节, 因此应该是1024个
#define HTSIZE (PAGE_SIZE/sizeof(struct fw_filter *))
// 链表头
struct fw_head
{
 struct fw_filter *ht[HTSIZE];
 u32 mask;
};

// fw过滤器
struct fw_filter
{
 struct fw_filter *next;
 u32   id;
 struct tcf_result res;
#ifdef CONFIG_NET_CLS_IND
 char   indev[IFNAMSIZ];
#endif /* CONFIG_NET_CLS_IND */
 struct tcf_exts  exts;
};

static struct tcf_ext_map fw_ext_map = {
 .action = TCA_FW_ACT,
 .police = TCA_FW_POLICE
};

7.8.2 初始化

// 空函数
static int fw_init(struct tcf_proto *tp)
{
 return 0;
}
 
7.8.3 分类

// 计算哈希值
static __inline__ int fw_hash(u32 handle)
{
// 如果是4096, 2^12, 按8:12:12分割异或
 if (HTSIZE == 4096)
  return ((handle >> 24) & 0xFFF) ^
         ((handle >> 12) & 0xFFF) ^
         (handle & 0xFFF);
// 2048, 2^11, 按10:11:11分割异或
 else if (HTSIZE == 2048)
  return ((handle >> 22) & 0x7FF) ^
         ((handle >> 11) & 0x7FF) ^
         (handle & 0x7FF);
// 1024, 2^10, 按12:10:10分割异或
 else if (HTSIZE == 1024)
  return ((handle >> 20) & 0x3FF) ^
         ((handle >> 10) & 0x3FF) ^
         (handle & 0x3FF);
// 512, 2^9, 按5:9:9:9分割异或
 else if (HTSIZE == 512)
  return (handle >> 27) ^
         ((handle >> 18) & 0x1FF) ^
         ((handle >> 9) & 0x1FF) ^
         (handle & 0x1FF);
// 256, 2^8, 按8:8:8:8分割异或
 else if (HTSIZE == 256) {
  u8 *t = (u8 *) &handle;
  return t[0] ^ t[1] ^ t[2] ^ t[3];
 } else
  return handle & (HTSIZE - 1);
}
 
// fw分类方法, 返回负数表示分类失败, 返回0表示分类成功,分类结果在res中返回
static int fw_classify(struct sk_buff *skb, struct tcf_proto *tp,
     struct tcf_result *res)
{
// HASH链表头
 struct fw_head *head = (struct fw_head*)tp->root;
 struct fw_filter *f;
 int r;
#ifdef CONFIG_NETFILTER
// 如果定义了netfilter, 使用nfmark作为ID, 用掩码掩一下
 u32 id = skb->nfmark & head->mask;
#else
// 否则ID为0,也就是说如果内核中没定义netfilter,分类的意义不大,都是同一类数据包
 u32 id = 0;
#endif
 if (head != NULL) {
// 根据id进行hash, 遍历合适的链表
  for (f=head->ht[fw_hash(id)]; f; f=f->next) {
// 如果ID相同, 合适的话可以返回
   if (f->id == id) {
    *res = f->res;
#ifdef CONFIG_NET_CLS_IND
// 网卡设备匹配
    if (!tcf_match_indev(skb, f->indev))
     continue;
#endif /* CONFIG_NET_CLS_IND */
// 如果没有定义NET_CLS_ACT和NET_CLS_POLICE的话就是个空函数, 返回0
    r = tcf_exts_exec(skb, &f->exts, res);
    if (r < 0)
     continue;
    return r;
   }
  }
 } else {
// 老分类方法, id非0, id高16为0或和Qdisc的handle的高16位相同时, 分类成功
  /* old method */
  if (id && (TC_H_MAJ(id) == 0 || !(TC_H_MAJ(id^tp->q->handle)))) {
   res->classid = id;
   res->class = 0;
   return 0;
  }
 }
 return -1;
}

7.8.4 释放

static void fw_destroy(struct tcf_proto *tp)
{
// tcf_proto的根链表头置零, 原值保存准备用于释放
 struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL);
 struct fw_filter *f;
 int h;
// 如果链表为空, 返回
 if (head == NULL)
  return;
// 遍历所有哈希表
 for (h=0; h<HTSIZE; h++) {
// 遍历链表
  while ((f=head->ht[h]) != NULL) {
   head->ht[h] = f->next;
// 释放该filter
   fw_delete_filter(tp, f);
  }
 }
 kfree(head);
}

// 释放fw过滤器节点
static inline void
fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f)
{
// 将过滤器和tcf_proto断开, 调用Qdisc_class_ops中的unbind_tcf()成员函数
 tcf_unbind_filter(tp, &f->res);
// 释放tcf扩展元素
 tcf_exts_destroy(tp, &f->exts);
// 释放fw过滤器内存
 kfree(f);
}
 
7.8.5 获取过滤器

static unsigned long fw_get(struct tcf_proto *tp, u32 handle)
{
 struct fw_head *head = (struct fw_head*)tp->root;
 struct fw_filter *f;
 if (head == NULL)
  return 0;
// 用handle进行哈希, 遍历指定的hash表
 for (f=head->ht[fw_hash(handle)]; f; f=f->next) {
// 如果有filter的id和handle相同, 返回
  if (f->id == handle)
   return (unsigned long)f;
 }
 return 0;
}

7.8.6 放弃过滤器

// 空函数
static void fw_put(struct tcf_proto *tp, unsigned long f)
{
}

7.8.7 参数修改

// 新建, 修改都通过该函数完成
static int fw_change(struct tcf_proto *tp, unsigned long base,
       u32 handle,
       struct rtattr **tca,
       unsigned long *arg)
{
// 根哈希节点
 struct fw_head *head = (struct fw_head*)tp->root;
// fw过滤器指针
 struct fw_filter *f = (struct fw_filter *) *arg;
// 选项参数
 struct rtattr *opt = tca[TCA_OPTIONS-1];
 struct rtattr *tb[TCA_FW_MAX];
 int err;
// 如果没提供选项, 在提供了handle的情况下错误, 否则返回成功
 if (!opt)
  return handle ? -EINVAL : 0;
// 解析选项参数是否合法
 if (rtattr_parse_nested(tb, TCA_FW_MAX, opt) < 0)
  return -EINVAL;

// fw过滤器非空, 修改操作
 if (f != NULL) {
// 修改的情况下, 如果handle值非0, 而且和fw过滤器的id不同的话, 返回参数错误
  if (f->id != handle && handle)
   return -EINVAL;
// 进行参数修改操作
  return fw_change_attrs(tp, f, tb, tca, base);
 }
// 新建fw过滤器的情况, 如果handle为0, 返回参数错误
 if (!handle)
  return -EINVAL;
// 链表头为空, 第一次操作
 if (head == NULL) {
// 缺省掩码
  u32 mask = 0xFFFFFFFF;
// 如果在命令参数中定义了掩码, 获取之
  if (tb[TCA_FW_MASK-1]) {
   if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
    return -EINVAL;
   mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
  }
// 分配链表头空间
  head = kzalloc(sizeof(struct fw_head), GFP_KERNEL);
  if (head == NULL)
   return -ENOBUFS;
// 掩码
  head->mask = mask;
  tcf_tree_lock(tp);
// 作为系统的根哈希链表头
  tp->root = head;
  tcf_tree_unlock(tp);
 }
// 分配新的fw过滤器结构指针
 f = kzalloc(sizeof(struct fw_filter), GFP_KERNEL);
 if (f == NULL)
  return -ENOBUFS;
// 使用handle值作为fw过滤器的ID
 f->id = handle;
// 调用修改函数进行赋值操作
 err = fw_change_attrs(tp, f, tb, tca, base);
 if (err < 0)
  goto errout;
// 添加到合适的hash链表的头, 注意锁的使用
 f->next = head->ht[fw_hash(handle)];
 tcf_tree_lock(tp);
 head->ht[fw_hash(handle)] = f;
 tcf_tree_unlock(tp);
// 将fw过滤器作为参数返回
 *arg = (unsigned long)f;
 return 0;
errout:
 kfree(f);
 return err;
}
 
// 参数修改处理
static int
fw_change_attrs(struct tcf_proto *tp, struct fw_filter *f,
 struct rtattr **tb, struct rtattr **tca, unsigned long base)
{
 struct fw_head *head = (struct fw_head *)tp->root;
 struct tcf_exts e;
 u32 mask;
 int err;
// tcf扩展验证操作
 err = tcf_exts_validate(tp, tb, tca[TCA_RATE-1], &e, &fw_ext_map);
 if (err < 0)
  return err;
 err = -EINVAL;
// 命令参数中提供了类别ID
 if (tb[TCA_FW_CLASSID-1]) {
  if (RTA_PAYLOAD(tb[TCA_FW_CLASSID-1]) != sizeof(u32))
   goto errout;
// 类别ID赋值
  f->res.classid = *(u32*)RTA_DATA(tb[TCA_FW_CLASSID-1]);
  tcf_bind_filter(tp, &f->res, base);
 }
#ifdef CONFIG_NET_CLS_IND
// 网卡设备
 if (tb[TCA_FW_INDEV-1]) {
  err = tcf_change_indev(tp, f->indev, tb[TCA_FW_INDEV-1]);
  if (err < 0)
   goto errout;
 }
#endif /* CONFIG_NET_CLS_IND */
// FW掩码
 if (tb[TCA_FW_MASK-1]) {
  if (RTA_PAYLOAD(tb[TCA_FW_MASK-1]) != sizeof(u32))
   goto errout;
  mask = *(u32*)RTA_DATA(tb[TCA_FW_MASK-1]);
  if (mask != head->mask)
   goto errout;
 } else if (head->mask != 0xFFFFFFFF)
  goto errout;
// 将e中的数据赋值到f->exts中
 tcf_exts_change(tp, &f->exts, &e);
 return 0;
errout:
 tcf_exts_destroy(tp, &e);
 return err;
}
 
7.8.8 删除

// 将fw过滤器节点从系统哈希链表中断开, 释放节点
// 注意一定要在系统链表中真正找到该节点才进行释放操作, 否则失败
static int fw_delete(struct tcf_proto *tp, unsigned long arg)
{
// 根节点
 struct fw_head *head = (struct fw_head*)tp->root;
// 要删除的fw过滤器节点
 struct fw_filter *f = (struct fw_filter*)arg;
 struct fw_filter **fp;
 if (head == NULL || f == NULL)
  goto out;
// 根据FW过滤器节点的ID哈希, 遍历相应的哈希链表
 for (fp=&head->ht[fw_hash(f->id)]; *fp; fp = &(*fp)->next) {
// 找到该节点
  if (*fp == f) {
   tcf_tree_lock(tp);
// 将该节点从链表中断开
   *fp = f->next;
   tcf_tree_unlock(tp);
// 释放fw过滤器节点
   fw_delete_filter(tp, f);
   return 0;
  }
 }
out:
 return -EINVAL;
}

7.8.9 输出

static int fw_dump(struct tcf_proto *tp, unsigned long fh,
     struct sk_buff *skb, struct tcmsg *t)
{
 struct fw_head *head = (struct fw_head *)tp->root;
 struct fw_filter *f = (struct fw_filter*)fh;
// 准备填数据的skb缓冲区起始位置
 unsigned char  *b = skb->tail;
 struct rtattr *rta;
// fw过滤器为空,直接返回
 if (f == NULL)
  return skb->len;
// 将fw过滤器的ID作为handle
 t->tcm_handle = f->id;
// 检查一下fw过滤器是否合法
 if (!f->res.classid && !tcf_exts_is_available(&f->exts))
  return skb->len;
 rta = (struct rtattr*)b;
 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
// 如果类别ID非0, 填充之到缓冲区
 if (f->res.classid)
  RTA_PUT(skb, TCA_FW_CLASSID, 4, &f->res.classid);
#ifdef CONFIG_NET_CLS_IND
// 网卡非空,填网卡名称到缓冲区
 if (strlen(f->indev))
  RTA_PUT(skb, TCA_FW_INDEV, IFNAMSIZ, f->indev);
#endif /* CONFIG_NET_CLS_IND */
// 掩码非全1值,填充到缓冲区
 if (head->mask != 0xFFFFFFFF)
  RTA_PUT(skb, TCA_FW_MASK, 4, &head->mask);
// 扩展元素的(动作/策略)输出
 if (tcf_exts_dump(skb, &f->exts, &fw_ext_map) < 0)
  goto rtattr_failure;
// 新增的数据长度
 rta->rta_len = skb->tail - b;
// 输出统计参数
 if (tcf_exts_dump_stats(skb, &f->exts, &fw_ext_map) < 0)
  goto rtattr_failure;
// 返回数据包当前的总长度
 return skb->len;
rtattr_failure:
 skb_trim(skb, b - skb->data);
 return -1;
}
 

...... 待续 ......
分享到:
评论

相关推荐

    Linux网络体系结构 Linux内核中网络协议的设计与实现

    在Linux内核中,TCP和UDP模块处理连接建立、数据传输、流量控制和拥塞控制等问题。 5. **应用层**:这一层包含各种应用协议,如HTTP、FTP、SMTP等,它们直接与用户交互。Linux内核通过socket API为上层应用提供了与...

    基于Linux内核的BT流量控制的原理与实现.pdf

    【基于Linux内核的BT流量控制的原理与实现】 Linux操作系统以其开源、可定制的特点,在系统开发领域广泛应用,尤其在网络流量控制方面具有显著优势。针对BitTorrent(BT)这种大量占用带宽的P2P协议,Linux内核提供...

    Linux内核完全注释V3.0_linux内核_linux_

    4. **网络堆栈**:从硬件接口到应用层协议的整个网络传输流程,如TCP/IP协议族、套接字API、网络设备驱动程序以及流量控制策略。 5. **设备驱动**:内核如何与硬件交互,驱动程序的工作原理,包括字符设备、块设备...

    深入分析Linux内核源码

    通过分析源码,我们可以了解到数据包的接收与发送过程,理解TCP连接的建立与断开、拥塞控制、流量控制等机制,这对于网络编程和网络故障排查非常有帮助。 此外,Linux内核还涉及中断处理、设备驱动、I/O管理等多个...

    基于Linux内核扩展模块的P2P流量控制.pdf

    【基于Linux内核扩展模块的P2P流量控制】这篇文献主要探讨了如何在Linux操作系统中,通过内核扩展模块来实现对P2P流量的有效控制。P2P(Peer-to-Peer)技术的兴起改变了互联网的中心化结构,使得资源分享更为便捷,...

    基于Linux内核扩展模块的P2P流量控制

    基于Linux内核扩展模块的P2P流量控制

    基于Linux LQL流量控制系统的研究与实现.pdf

    基于LQL库的流量控制方法可以直接在Linux内核的框架下实现,而不需要使用传统方法中的TC命令解析、netlink传输和内核空间执行的三层结构。这可以提高流量控制的效率和可靠性,同时也可以减少流量控制的延迟和资源...

    Linux内核修炼之道精华版

    书中的内容涵盖了从内核基础到高级技术的方方面面,为那些希望提升Linux内核理解和开发能力的读者提供了宝贵的资源。在本文中,我们将探讨几个关键的知识点,包括Linux内核的基本结构、进程管理、内存管理和设备驱动...

    Linux内核源码(2.6.24)

    2.6.24版本在网络方面加强了IPv6的支持,并改进了网络流量控制算法。 6. **安全与权限管理**:Linux内核采用了用户和组的概念,通过权限系统(如chmod、chown等)来控制文件访问。此外,还有SELinux(Security-...

    深入理解linux内核word版本

    接着,作者深入剖析了网络设备数据结构net_device,它包含了设备的配置信息、统计信息、状态标志以及各种管理列表和流量控制字段,这些细节揭示了网络设备如何在内核中被抽象和管理。 通过以上内容,我们可以看到,...

    Linux内核情景分析(上下全集高清版)

    它处理网络数据的接收和发送,进行网络层的路由选择,以及传输层的拥塞控制和流量控制。 5. **设备驱动**:设备驱动程序是内核与硬件之间的桥梁,使得内核能够控制硬件设备。Linux内核支持大量设备驱动,包括块设备...

    基于Linux的网络流量控制机制

    该模型内置于Linux内核中,并利用队列算法对不同服务质量(Quality of Service, QoS)需求的数据流进行分类,以提供灵活且差异化的服务。实验结果表明,采用该流量控制模型后,网络性能显著提高,并能很好地适应未来...

    linux高级路由和流量控制HOWTO中文版(牛老师译)

    在Linux操作系统中,高级路由和流量控制是网络管理员和系统管理员必须掌握的关键技能。这篇文档“Linux高级路由和流量控制HOWTO中文版”由牛老师翻译,为读者提供了深入理解这些概念的宝贵资源。以下是对其中核心...

    《Linux内核源码剖析 TCP IP实现(上册) 樊东东 莫澜 pdf扫描版.

    同时,还会讨论TCP的流量控制和拥塞控制机制,如滑动窗口、慢启动、快速重传和快速恢复算法等,这些都是保证网络通信质量和效率的关键。 其次,关于IP协议,书里会涉及IP地址、子网掩码、路由选择等概念,以及IP分...

    TC(linux下流量控制工具)详细说明及应用实例借鉴.pdf

    TC 工具基于 Linux 内核的网络设备驱动程序,通过对网络设备的控制,来实现流量控制。TC 的工作原理可以分为以下三个阶段: 1. 流量控制方式:TC 提供了多种流量控制方式,包括 Token Bucket Filter(TBF)、...

    TC(linux下流量控制工具)详细说明及应用实例.pdf

    TC(Linux 下流量控制工具)详细说明及应用实例 TC 是 Linux 下的一种流量控制工具,用于控制和管理网络流量。它提供了一个灵活的方式来管理网络带宽、延迟和丢包率等网络性能参数,以满足不同应用场景的需求。 TC...

    linux内核协议栈源码解析(2.6.18内核)

    2. **TCP/IP协议**:在传输层,TCP(传输控制协议)提供可靠的数据传输服务,通过确认、重传和流量控制确保数据的完整性和顺序。IP(互联网协议)在网络层负责数据包的路由和分片,是互联网的基础协议。 3. **套接...

    linux内核中sock和socket数据结构

    Linux内核中的sock和socket数据结构是网络编程的核心组成部分,它们是实现网络通信的基础构件。在Linux操作系统中,网络通信的实现依赖于BSD套接字接口,而这一接口在内核中是通过sock和socket数据结构来实现的。 ...

Global site tag (gtag.js) - Google Analytics