`

Linux内核中流量控制(12)

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

5.11.3.1 转换函数

/* TODO: maybe compute rate when size is too large .. or drop ? */
// 将长度转换为令牌数
static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate,
      int size)
{
// 根据大小计算合适的槽位
 int slot = size >> rate->rate.cell_log;
// 如果超过了255, 限制为255
 if (slot > 255) {
  cl->xstats.giants++;
  slot = 255;
 }
 return rate->data[slot];
}
 

// HTB哈希计算, 限制哈希结果小于16, 因为只有16个HASH表, 这个大小是定死的
static inline int htb_hash(u32 h)
{
#if HTB_HSIZE != 16
#error "Declare new hash for your HTB_HSIZE"
#endif
 h ^= h >> 8;  /* stolen from cbq_hash */
 h ^= h >> 4;
 return h & 0xf;
}

5.11.3.2 查询函数

/* find class in global hash table using given handle */
// 根据句柄handle查找HTB节点
static inline struct htb_class *htb_find(u32 handle, struct Qdisc *sch)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 struct hlist_node *p;
 struct htb_class *cl;
 if (TC_H_MAJ(handle) != sch->handle)
  return NULL;
// 根据句柄计算哈希值, 然后遍历该哈希链表
 hlist_for_each_entry(cl, p, q->hash + htb_hash(handle), hlist) {
// 查找类别ID和句柄handle相等的HTB节点返回
  if (cl->classid == handle)
   return cl;
 }
 return NULL;
}
 
5.11.3.3 分类函数

/**
 * htb_classify - classify a packet into class
 *
 * It returns NULL if the packet should be dropped or -1 if the packet
 * should be passed directly thru. In all other cases leaf class is returned.
 * We allow direct class selection by classid in priority. The we examine
 * filters in qdisc and in inner nodes (if higher filter points to the inner
 * node). If we end up with classid MAJOR:0 we enqueue the skb into special
 * internal fifo (direct). These packets then go directly thru. If we still
 * have no valid leaf we try to use MAJOR:default leaf. It still unsuccessfull
 * then finish and return direct queue.
 */
#define HTB_DIRECT (struct htb_class*)-1
// 获取HTB类别结构的ID
static inline u32 htb_classid(struct htb_class *cl)
{
// 如果类别结构有效(非空而且不是直接通过), 返回其类别ID, 否则返回TC_H_UNSPEC
// 表示没指定类别ID
 return (cl && cl != HTB_DIRECT) ? cl->classid : TC_H_UNSPEC;
}

// HTB分类操作, 对数据包进行分类, 然后根据类别进行相关操作
// 返回NULL表示没找到, 返回-1表示是直接通过(不分类)的数据包
static struct htb_class *htb_classify(struct sk_buff *skb, struct Qdisc *sch,
          int *qerr)
{
// HTB私有结构
 struct htb_sched *q = qdisc_priv(sch);
 struct htb_class *cl;
// 分类规则处理结果
 struct tcf_result res;
// 分类过滤规则表
 struct tcf_proto *tcf;
 int result;
 /* allow to select class by setting skb->priority to valid classid;
    note that nfmark can be used too by attaching filter fw with no
    rules in it */
// 如果数据包优先权值就等于流控节点和句柄handle, 属于根节点操作, 直接处理
 if (skb->priority == sch->handle)
  return HTB_DIRECT; /* X:0 (direct flow) selected */

// 查找和数据包优先权值对应的HTB叶子节点, 找到则返回
 if ((cl = htb_find(skb->priority, sch)) != NULL && cl->level == 0)
  return cl;

// 以下处理是没有找到和skb->priority直接对应的HTB叶子节点, 应该说实际应用中大部分
// 都是skb->priority为0的, 所以一般都会运行到这里
 *qerr = NET_XMIT_BYPASS;
 tcf = q->filter_list;
// 进行标准TC分类, 分类方法由TC命令定义的规则来实现
 while (tcf && (result = tc_classify(skb, tcf, &res)) >= 0) {
#ifdef CONFIG_NET_CLS_ACT
// 定义了可对分类结果进行动作的内核选项的情况
  switch (result) {
  case TC_ACT_QUEUED:
  case TC_ACT_STOLEN:
// 发送成功
   *qerr = NET_XMIT_SUCCESS;
// 丢包
  case TC_ACT_SHOT:
   return NULL;
  }
#elif defined(CONFIG_NET_CLS_POLICE)
// 没定义NET_CLS_ACT而定义了NET_CLS_POLICE的情况
// 如果分类结果是TC_POLICE_SHOT, 属于HTB直接处理
  if (result == TC_POLICE_SHOT)
   return HTB_DIRECT;
#endif
// 如果分类结果为空
  if ((cl = (void *)res.class) == NULL) {
// 如果分类结果的ID等于流控句柄, 直接处理
   if (res.classid == sch->handle)
    return HTB_DIRECT; /* X:0 (direct flow) */
// 再根据结果的类别ID查找HTB叶子节点, 找不到的话退出循环
   if ((cl = htb_find(res.classid, sch)) == NULL)
    break; /* filter selected invalid classid */
  }
// 分类找到的情况, 如果是叶子节点, 直接返回
  if (!cl->level)
   return cl; /* we hit leaf; return it */
// 如果不是叶子节点,更新过滤表, 用该类别的内部过滤规则表重新搜索,
// 从这里就可看出HTB的多层次结构, 由上层向下层细化
  /* we have got inner class; apply inner filter chain */
  tcf = cl->filter_list;
 }
// 循环外是没找到分类的情况
 /* classification failed; try to use default class */
// 用缺省类别ID查找, 看是否定义了缺省类别
 cl = htb_find(TC_H_MAKE(TC_H_MAJ(sch->handle), q->defcls), sch);
// 没找到或者是只是中间节点, 返回直接处理
 if (!cl || cl->level)
  return HTB_DIRECT; /* bad default .. this is safe bet */
 return cl;
}

5.11.3.4 激活类别

/**
 * htb_activate - inserts leaf cl into appropriate active feeds
 *
 * Routine learns (new) priority of leaf and activates feed chain
 * for the prio. It can be called on already active leaf safely.
 * It also adds leaf into droplist.
 */
// 激活类别结构, 将该类别节点作为数据包提供者, 而数据类别表提供是一个
// 有序表, 以RB树形式实现
static inline void htb_activate(struct htb_sched *q, struct htb_class *cl)
{
 BUG_TRAP(!cl->level && cl->un.leaf.q && cl->un.leaf.q->q.qlen);
// 如果类别的prio_activity参数为0才进行操作, 非0表示已经激活了
 if (!cl->prio_activity) {
// prio_activity是通过叶子节点的prio值来设置的, 至少是1, 最大是1<<7, 非0值
// leaf.aprio保存当前的leaf.prio
  cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio);
// 进行实际的激活操作
  htb_activate_prios(q, cl);
// 根据leaf.aprio添加到指定的优先权位置的丢包链表
  list_add_tail(&cl->un.leaf.drop_list,
         q->drops + cl->un.leaf.aprio);
 }
}

/**
 * htb_activate_prios - creates active classe's feed chain
 *
 * The class is connected to ancestors and/or appropriate rows
 * for priorities it is participating on. cl->cmode must be new
 * (activated) mode. It does nothing if cl->prio_activity == 0.
 */
// 激活操作, 建立数据提供树
// cl->prio_activity为0时就是一个空函数, 不过从前面看prio_activity似乎是不会为0的
static void htb_activate_prios(struct htb_sched *q, struct htb_class *cl)
{
// 父节点
 struct htb_class *p = cl->parent;
// prio_activity是作为一个掩码, 可应该只有一位为1
 long m, mask = cl->prio_activity;

// 在当前模式是HTB_MAY_BORROW情况下进入循环, 某些情况下这些类别是可以激活的
// 绝大多数情况p和mask的初始值应该都是非0值
 while (cl->cmode == HTB_MAY_BORROW && p && mask) {
// 备份mask值
  m = mask;
  while (m) {
// 掩码取反, 找第一个0位的位置, 也就是原来最低为1的位的位置
// prio越小, 等级越高, 取数据包也是先从prio值小的节点取
   int prio = ffz(~m);
// 清除该位
   m &= ~(1 << prio);
// p是父节点, 所以inner结构肯定有效, 不会使用leaf结构的
// 如果父节点的prio优先权的数据包的提供树已经存在, 在掩码中去掉该位
   if (p->un.inner.feed[prio].rb_node)
    /* parent already has its feed in use so that
       reset bit in mask as parent is already ok */
    mask &= ~(1 << prio);
// 将该类别加到父节点的prio优先权提供数据包的节点树中
   htb_add_to_id_tree(p->un.inner.feed + prio, cl, prio);
  }
// 父节点的prio_activity或上mask中的置1位, 某位为1表示该位对应的优先权的
// 数据可用
  p->prio_activity |= mask;
// 循环到上一层, 当前类别更新父节点, 父节点更新为祖父节点
  cl = p;
  p = cl->parent;
 }
// 如果cl是HTB_CAN_SEND模式, 将该类别添加到合适的ROW中
// 此时的cl可能已经不是原来的cl了,而是原cl的长辈节点了
 if (cl->cmode == HTB_CAN_SEND && mask)
  htb_add_class_to_row(q, cl, mask);
// 如果cl是HTB_CANT_SEND模式则不进行任何操作了, 因为是阻塞状态
}
 
/**
 * htb_add_to_id_tree - adds class to the round robin list
 *
 * Routine adds class to the list (actually tree) sorted by classid.
 * Make sure that class is not already on such list for given prio.
 */
static void htb_add_to_id_tree(struct rb_root *root,
          struct htb_class *cl, int prio)
{
 struct rb_node **p = &root->rb_node, *parent = NULL;

// RB树是有序表, 根据类别ID排序, 值大的到右节点, 小的到左节点
// 循环, 查找树中合适的位置插入类别节点cl
 while (*p) {
  struct htb_class *c;
  parent = *p;
  c = rb_entry(parent, struct htb_class, node[prio]);
  if (cl->classid > c->classid)
   p = &parent->rb_right;
  else
   p = &parent->rb_left;
 }
// 进行RB树的插入操作, RB树标准函数操作
 rb_link_node(&cl->node[prio], parent, p);
 rb_insert_color(&cl->node[prio], root);
}

/**
 * htb_add_class_to_row - add class to its row
 *
 * The class is added to row at priorities marked in mask.
 * It does nothing if mask == 0.
 */
static inline void htb_add_class_to_row(struct htb_sched *q,
     struct htb_class *cl, int mask)
{
// 将cl层次对应的ROW的row_mask或上新的mask, 表示有对应prio的数据了
 q->row_mask[cl->level] |= mask;
// 循环mask, 将cl插入mask每一位对应的prio的树中
 while (mask) {
// prio是mask中最低为1的位的位置
  int prio = ffz(~mask);
// 清除该位
  mask &= ~(1 << prio);
// 添加到具体的RB树中
  htb_add_to_id_tree(q->row[cl->level] + prio, cl, prio);
 }
}

5.11.3.4 关闭类别

/**
 * htb_deactivate - remove leaf cl from active feeds
 *
 * Make sure that leaf is active. In the other words it can't be called
 * with non-active leaf. It also removes class from the drop list.
 */
// 将类别叶子节点从活动的数据包提供树中去掉
static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl)
{
 BUG_TRAP(cl->prio_activity);
// 关闭
 htb_deactivate_prios(q, cl);
// 类别的活性值prio_activity清零
 cl->prio_activity = 0;
// 将类别节点从drop表断开并重新初始化list结构
 list_del_init(&cl->un.leaf.drop_list);
}

/**
 * htb_deactivate_prios - remove class from feed chain
 *
 * cl->cmode must represent old mode (before deactivation). It does
 * nothing if cl->prio_activity == 0. Class is removed from all feed
 * chains and rows.
 */
static void htb_deactivate_prios(struct htb_sched *q, struct htb_class *cl)
{
// 类别节点的父节点
 struct htb_class *p = cl->parent;
// 类别结构的优先权活性值作为掩码, 如果是0的话本函数相当于空函数
 long m, mask = cl->prio_activity;

// 在当前模式是HTB_MAY_BORROW情况下进入循环,
// 绝大多数情况p和mask的初始值应该都是非0值
 while (cl->cmode == HTB_MAY_BORROW && p && mask) {
// 备份掩码
  m = mask;
// 掩码清零
  mask = 0;
  while (m) {
// prio为m的第一个1值的位(取反后第一个0值的位)
   int prio = ffz(~m);
// 去除该位
   m &= ~(1 << prio);
// 如果该类别prio对应的rb树是父节点中正在处理的
   if (p->un.inner.ptr[prio] == cl->node + prio) {
    /* we are removing child which is pointed to from
       parent feed - forget the pointer but remember
       classid */
// 将cl的类别ID保存到last_ptr_id中prio对应位置
    p->un.inner.last_ptr_id[prio] = cl->classid;
// 清空父节点指向rb根指针
    p->un.inner.ptr[prio] = NULL;
   }
// 类别节点从与prio相应rb树中断开
   htb_safe_rb_erase(cl->node + prio, p->un.inner.feed + prio);
// 对已经空了的rb树保存其位置
   if (!p->un.inner.feed[prio].rb_node)
    mask |= 1 << prio;
  }
// 将已经空了的rb数掩码从父节点的活性值掩码中去掉
  p->prio_activity &= ~mask;
// 转到上一层处理
  cl = p;
  p = cl->parent;
 }
// 如果当前类别cl的模式是可以发送(无阻塞, 无借带宽), 将cl从ROW的相关树中断开
 if (cl->cmode == HTB_CAN_SEND && mask)
  htb_remove_class_from_row(q, cl, mask);
}
 
/**
 * htb_remove_class_from_row - removes class from its row
 *
 * The class is removed from row at priorities marked in mask.
 * It does nothing if mask == 0.
 */
// mask为0时等价于一个空函数
static inline void htb_remove_class_from_row(struct htb_sched *q,
       struct htb_class *cl, int mask)
{
 int m = 0;
 while (mask) {
// prio为mask第一个1位的位置
  int prio = ffz(~mask);
// 去掉该位
  mask &= ~(1 << prio);

// 如果流控节点的该层该prio的rb树节点指向的是cl的prio的rb树节点, 更新到树的下一个rb节点
  if (q->ptr[cl->level][prio] == cl->node + prio)
   htb_next_rb_node(q->ptr[cl->level] + prio);

// 从ROW树中断开cl
  htb_safe_rb_erase(cl->node + prio, q->row[cl->level] + prio);
// 如果该层该prio的rb树位空, 记录其位置
  if (!q->row[cl->level][prio].rb_node)
   m |= 1 << prio;
 }
// 在ROW掩码中将与rb树为空的那些prio位清空
 q->row_mask[cl->level] &= ~m;
}

5.11.4 初始化

static int htb_init(struct Qdisc *sch, struct rtattr *opt)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 struct rtattr *tb[TCA_HTB_INIT];
 struct tc_htb_glob *gopt;
 int i;
// 检查用户空间传过来的初始化数据的合法性
 if (!opt || rtattr_parse_nested(tb, TCA_HTB_INIT, opt) ||
     tb[TCA_HTB_INIT - 1] == NULL ||
     RTA_PAYLOAD(tb[TCA_HTB_INIT - 1]) < sizeof(*gopt)) {
  printk(KERN_ERR "HTB: hey probably you have bad tc tool ?\n");
  return -EINVAL;
 }
 gopt = RTA_DATA(tb[TCA_HTB_INIT - 1]);
// 检查版本信息是否匹配
 if (gopt->version != HTB_VER >> 16) {
  printk(KERN_ERR
         "HTB: need tc/htb version %d (minor is %d), you have %d\n",
         HTB_VER >> 16, HTB_VER & 0xffff, gopt->version);
  return -EINVAL;
 }
// 初始化各链表和哈希表结构
 INIT_LIST_HEAD(&q->root);
 for (i = 0; i < HTB_HSIZE; i++)
  INIT_HLIST_HEAD(q->hash + i);
 for (i = 0; i < TC_HTB_NUMPRIO; i++)
  INIT_LIST_HEAD(q->drops + i);
// 初始化定时器
 init_timer(&q->timer);
// 初始化HTB流控节点的直接发送的数据包队列
 skb_queue_head_init(&q->direct_queue);
// 直接发送队列长度初始化为网卡设备的发送队列长度, 至少为2
 q->direct_qlen = sch->dev->tx_queue_len;
 if (q->direct_qlen < 2) /* some devices have zero tx_queue_len */
  q->direct_qlen = 2;
// HTB定时函数
 q->timer.function = htb_timer;
 q->timer.data = (unsigned long)sch;
#ifdef HTB_RATECM
// 使用HTB进行流控的情况
// 速率定时器初始化, 并开始定时
 init_timer(&q->rttim);
 q->rttim.function = htb_rate_timer;
 q->rttim.data = (unsigned long)sch;
 q->rttim.expires = jiffies + HZ;
 add_timer(&q->rttim);
#endif
// 流量到定额转换参数, 是TC命令中的r2q参数
 if ((q->rate2quantum = gopt->rate2quantum) < 1)
  q->rate2quantum = 1;
// 缺省类别
 q->defcls = gopt->defcls;
 return 0;
}

// HTB定时器函数
static void htb_timer(unsigned long arg)
{
 struct Qdisc *sch = (struct Qdisc *)arg;
// 去掉流控节点的阻塞标志
 sch->flags &= ~TCQ_F_THROTTLED;
 wmb();
// 重新调度网卡
 netif_schedule(sch->dev);
}

#ifdef HTB_RATECM
// 递增试速率计算
#define RT_GEN(D,R) R+=D-(R/HTB_EWMAC);D=0
// HTB速率定时器函数
static void htb_rate_timer(unsigned long arg)
{
// HTB流控节点
 struct Qdisc *sch = (struct Qdisc *)arg;
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 struct hlist_node *p;
 struct htb_class *cl;

 /* lock queue so that we can muck with it */
 spin_lock_bh(&sch->dev->queue_lock);
// 定时一秒
 q->rttim.expires = jiffies + HZ;
// 再次添加定时器
 add_timer(&q->rttim);
 /* scan and recompute one bucket at time */
// 每次更新计算一个哈希表的数据
 if (++q->recmp_bucket >= HTB_HSIZE)
  q->recmp_bucket = 0;
// 更新recmp_bucket所对应的哈希链表中每个类别节点的字节和数据包流量率
 hlist_for_each_entry(cl,p, q->hash + q->recmp_bucket, hlist) {
  RT_GEN(cl->sum_bytes, cl->rate_bytes);
  RT_GEN(cl->sum_packets, cl->rate_packets);
 }
 spin_unlock_bh(&sch->dev->queue_lock);
}
#endif

5.11.5 丢包

/* try to drop from each class (by prio) until one succeed */
static unsigned int htb_drop(struct Qdisc *sch)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 int prio;
// 遍历各个级别的丢包链表, 最先操作的是7号链表, 最后操作的是0号链表
 for (prio = TC_HTB_NUMPRIO - 1; prio >= 0; prio--) {
  struct list_head *p;
// 遍历链表
  list_for_each(p, q->drops + prio) {
// 类别结构
   struct htb_class *cl = list_entry(p, struct htb_class,
         un.leaf.drop_list);
   unsigned int len;
// 如果该类别的叶子节点流控定义了丢包操作, 进行相应丢包操作
   if (cl->un.leaf.q->ops->drop &&
       (len = cl->un.leaf.q->ops->drop(cl->un.leaf.q))) {
// 丢包操作成功
    sch->q.qlen--;
// 子流控节点为空, 停止该类别
    if (!cl->un.leaf.q->q.qlen)
     htb_deactivate(q, cl);
    return len;
   }
  }
 }
 return 0;
}
 
5.11.6 复位

/* reset all classes */
/* always caled under BH & queue lock */
static void htb_reset(struct Qdisc *sch)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 int i;
// 遍历所有哈希表
 for (i = 0; i < HTB_HSIZE; i++) {
  struct hlist_node *p;
  struct htb_class *cl;
// 遍历链表中每个类别结构
  hlist_for_each_entry(cl, p, q->hash + i, hlist) {
   if (cl->level)
// 中间节点, 直接清零操作
    memset(&cl->un.inner, 0, sizeof(cl->un.inner));
   else {
// 叶子节点, 复位内部流控结构
    if (cl->un.leaf.q)
     qdisc_reset(cl->un.leaf.q);
// 重新初始化丢弃链表
    INIT_LIST_HEAD(&cl->un.leaf.drop_list);
   }
   cl->prio_activity = 0;
   cl->cmode = HTB_CAN_SEND;
  }
 }
// 去掉阻塞标志
 sch->flags &= ~TCQ_F_THROTTLED;
// 删除定时器
 del_timer(&q->timer);
// 删除当前直接发送的数据包队列中的所有数据包
 __skb_queue_purge(&q->direct_queue);
// 参数清零
 sch->q.qlen = 0;
 memset(q->row, 0, sizeof(q->row));
 memset(q->row_mask, 0, sizeof(q->row_mask));
 memset(q->wait_pq, 0, sizeof(q->wait_pq));
 memset(q->ptr, 0, sizeof(q->ptr));
// 初始化丢弃队列
 for (i = 0; i < TC_HTB_NUMPRIO; i++)
  INIT_LIST_HEAD(q->drops + i);
}
 
 
5.11.7 释放
 
/* always caled under BH & queue lock */
static void htb_destroy(struct Qdisc *sch)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
// 删除定时器
 del_timer_sync(&q->timer);
#ifdef HTB_RATECM
 del_timer_sync(&q->rttim);
#endif
 /* This line used to be after htb_destroy_class call below
    and surprisingly it worked in 2.4. But it must precede it
    because filter need its target class alive to be able to call
    unbind_filter on it (without Oops). */
// 释放过滤器规则表
 htb_destroy_filters(&q->filter_list);
// 遍历当前的HTB类别树, 释放类别结构
 while (!list_empty(&q->root))
  htb_destroy_class(sch, list_entry(q->root.next,
        struct htb_class, sibling));
// 释放直接处理的数据队列
 __skb_queue_purge(&q->direct_queue);
}
 

5.11.8 输出HTB参数
 
static int htb_dump(struct Qdisc *sch, struct sk_buff *skb)
{
// HTB私有数据结构
 struct htb_sched *q = qdisc_priv(sch);
 unsigned char *b = skb->tail;
 struct rtattr *rta;
 struct tc_htb_glob gopt;
 spin_lock_bh(&sch->dev->queue_lock);
// 直接发送的数据包数量
 gopt.direct_pkts = q->direct_pkts;
// HTB版本号
 gopt.version = HTB_VER;
// 类别转额度
 gopt.rate2quantum = q->rate2quantum;
// 缺省类别
 gopt.defcls = q->defcls;
 gopt.debug = 0;
// 返回数据在数据包中的具体位置
 rta = (struct rtattr *)b;
 RTA_PUT(skb, TCA_OPTIONS, 0, NULL);
// 填入选项参数
 RTA_PUT(skb, TCA_HTB_INIT, sizeof(gopt), &gopt);
 rta->rta_len = skb->tail - b;
 spin_unlock_bh(&sch->dev->queue_lock);
 return skb->len;
rtattr_failure:
 spin_unlock_bh(&sch->dev->queue_lock);
 skb_trim(skb, skb->tail - skb->data);
 return -1;
}
 
...... 待续 ......


分享到:
评论

相关推荐

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

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

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

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

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

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

    Linux内核扩展模块的P2P流量控制方法与研究.pdf

    Linux内核扩展模块的P2P流量控制方法与研究.pdf

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

    该方法摒弃了传统方法中所运用的TC命令解析,netlink传输,内核空间执行的3层结构,而直接在Linux内核的框架下,采用LQL库直接对内核进行操控,并改进了相关U32过滤器以对IP段的流量控制,从而实现对系统的智能流量控制。...

    Linux高级路由和流量控制

    15.8. 终极的流量控制:低延迟,高速上/下载 98 15.8.1. 为什么缺省设置不让人满意 99 15.8.2. 实际的脚本(CBQ) 100 15.8.3. 实际的脚本(HTB) 102 15.9. 为单个主机或子网限速 103 15.10. 一个完全NAT和QOS的范例...

    编写Linuxc操作系统设备驱动程序概述

    在Linux内核的不断升级过程中,驱动程序的结构还是相对稳定。Linux的网络系统主要是基于BSD unix的socket机制 。在系统和驱动程序之间定义有专门的数据结构(sk_buff)进行数据的传递。系统里支持对发送数据和接收数据...

    xt_fset:扩展到Linux内核netfilter子系统(iptables)(插件),使您可以通过发送ICMP包远程操作linux内核ipset(向ipset中添加或删除一些ip地址)。

    xt_fset是linux内核netfilter子系统的内核模块和iptables扩展(插件),允许您通过发送控制ICMP数据包来远程操作linux内核ipset(在ipset中添加或删除一些ip地址)。 该插件的创建是对Linux内核netfilter子系统的...

    Linux Kernel v4.19.1 Stable.zip

    Linux Kernel主要新特性包括:合并了来自Android项目的内核代码,支持新的架构TI C6X,改进了Btrfs...网络优先控制组允许管理员动态设置网络流量的优先次序;支持EFI引导固件;改进内存管理,等等。 Linux Kernel截图

    Linux的高级路由和流量控制HOWTO-中文版

    虽然这些工具能够工作,但它们在 Linux2.2 和更高版本的内核上显 得有一些落伍。比如,现在 GRE 隧道已经成为了路由的一个主要概念,但却不 能通过上述工具来配置。 使用了 iproute2,隧道的配置与其他部分完全集成了。

    lksctp-rs:Rust 的 Linux 内核 SCTP 低级绑定

    流量控制和拥塞控制 此外,它还补充说: 多路复用流:通过单个连接,您可以多路复用多个信息流。 端点的多宿主:一个端点可以有多个 IP 地址,允许网络故障转移/可靠性(注意:它需要是一台机器,或者复制端点的...

    《精通Linux 设备驱动程序开发》.(Sreekrishnan).pdf

    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 查看...

    精通LINUX设备驱动程序开发

    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 设备实例:...

    基于Linux 的防火墙技术研究

    络地址转换、流量控制及高级的包处理等。Netfilter/Iptables 系统采用模块化的架构方式,其主要模块 有:通用框架Netfilter、数据包选择系统、连接跟踪系统及NAT系统等等。 2.1 Netfilter/Iptables 系统工作原理 ...

    Linux模拟网络丢包与延迟的方法

    netem 与 tc: netem 是 Linux 2.6 及以上...tc 是 Linux 系统中的一个工具,全名为traffic control(流量控制)。tc 可以用来控制 netem 的工作模式,也就是说,如果想使用 netem ,需要至少两个条件,一个是内核中的

    DarkShell_Linux-Win集群版V2014年

    Linux支持路由内核、2.6、3.1等普通内核,路由内核支持路由三大内核、Ubuntu、admin等,独立开发的Linux穿盾CC模式,SYN稳定发包100%,自启动,无需Root权限上线即可发包。 VIP版本攻击代码实时更新,通过服务器...

    ip route2 源码 第二代网络工具

    如果你仍在使用net-tools,而且尤其需要跟上新版Linux内核中的最新最重要的网络特性的话,那么是时候转到iproute2的阵营了。原因就在于使用iproute2可以做很多net-tools无法做到的事情。对于那些想要转到使用iproute...

    Linux C 一站式学习

    7.3. 流量控制 37. socket编程 1. 预备知识 1.1. 网络字节序 1.2. socket地址的数据类型及相关函数 2. 基于TCP协议的网络程序 2.1. 最简单的TCP网络程序 2.2. 错误处理与读写控制 2.3. 把client改为交互式输入 2.4. ...

Global site tag (gtag.js) - Google Analytics