msn: [email protected]
5.15. qdisc的netlink控制
各網絡卡的qdisc的使用者層操作控制是通過rtnetlink介面實現使用者空間和核心之間的通訊的: rtnetlink_link, rtnetlink是專門針對路由控制的netlink介面.
/* include/linux/rtnetlink.h */
struct rtnetlink_link
;// 全域性陣列, 具體在 net/core/rtnetlink.c中定義
extern struct rtnetlink_link * rtnetlink_links[nproto];
其中的兩個成員定義如下:
/* net/core/rtnetlink.c */
void __init rtnetlink_init(void)
其中link_rtnetlink_table是乙個陣列, 定義為:
static struct rtnetlink_link link_rtnetlink_table[rtm_nr_msgtypes] =
,[rtm_setlink - rtm_base] = ,
[rtm_getaddr - rtm_base] = ,
[rtm_getroute - rtm_base] = ,
[rtm_newneigh - rtm_base] = ,
[rtm_delneigh - rtm_base] = ,
[rtm_getneigh - rtm_base] = ,
#ifdef config_fib_rules
[rtm_newrule - rtm_base] = ,
[rtm_delrule - rtm_base] = ,
#endif
[rtm_getrule - rtm_base] = ,
[rtm_getneightbl - rtm_base] = ,
[rtm_setneightbl - rtm_base] = ,
};5.15.1 初始化
初始化過程是定義對應tc的qdisc和class的操作命令的處理函式:
/* net/sched/sch_api.c */
static int __init pktsched_init(void)
else
} else
/* it may be default qdisc, ignore it */
// 如果找到的qdisc的控制代碼為0, 放棄q
if (q && q->handle == 0)
q = null;
if (!q || !tcm->tcm_handle || q->handle != tcm->tcm_handle) else
}} else
// 到這裡是屬於qdisc修改操作
/* change qdisc parameters */
// 沒找到qdisc節點, 返回錯誤
if (q == null)
return -enoent;
// 找到qdisc節點, 但設定了nlm_f_excl(排斥)標誌, 返回物件存在錯誤
if (n->nlmsg_flags&nlm_f_excl)
return -eexist;
// 檢查找到的qdisc節點的名稱和tc中指定的是否匹配
if (tca[tca_kind-1] && rtattr_strcmp(tca[tca_kind-1], q->ops->id))
return -einval;
// 修改qdisc引數
err = qdisc_change(q, tca);
if (err == 0)
qdisc_notify(skb, n, clid, null, q);
return err;
create_n_graft:
// 建立新qdisc節點
// 如果tc命令中沒有建立標誌, 返回錯誤
if (!(n->nlmsg_flags&nlm_f_create))
return -enoent;
// 建立新qdisc節點
if (clid == tc_h_ingress)
q = qdisc_create(dev, tcm->tcm_parent, tca, &err);
else
q = qdisc_create(dev, tcm->tcm_handle, tca, &err);
if (q == null)
graft:
// 嫁接操作
if (1)
return err;
}// qdisc通告
qdisc_notify(skb, n, clid, old_q, q);
if (old_q)
}return 0;
}5.15.2.2 獲取/刪除qdisc
/** delete/get qdisc.
*/static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg)
else
} else
if (!q)
return -enoent;
if (tcm->tcm_handle && q->handle != tcm->tcm_handle)
return -einval;
} else
// 檢查找到的qdisc名稱和tc命令中指定的是否一致
if (tca[tca_kind-1] && rtattr_strcmp(tca[tca_kind-1], q->ops->id))
return -einval;
// 刪除qdisc操作
if (n->nlmsg_type == rtm_delqdisc)
} else
return 0;
}// 傳送qdisc通知資訊, new是處理後新qdisc節點資訊, old是處理前老節點資訊
static int qdisc_notify(struct sk_buff *oskb, struct nlmsghdr *n,
u32 clid, struct qdisc *old, struct qdisc *new)
if (new)
// 傳送資料報
if (skb->len)
return rtnetlink_send(skb, pid, rtnlgrp_tc, n->nlmsg_flags&nlm_f_echo);
err_out:
// 錯誤處理, 釋放資料報
kfree_skb(skb);
return -einval;
}5.15.2.3 輸出網絡卡qdisc引數
static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb)
// 填充qdisc資訊到資料報
if (tc_fill_qdisc(skb, q, q->parent, netlink_cb(cb->skb).pid,
cb->nlh->nlmsg_seq, nlm_f_multi, rtm_newqdisc) <= 0)
q_idx++;
}read_unlock(&qdisc_tree_lock);
}done:
read_unlock(&dev_base_lock);
// 返回處理的所有網絡卡數和qdisc數
cb->args[0] = idx;
cb->args[1] = q_idx;
return skb->len;
}// 填充qdisc資訊到skb資料報
static int tc_fill_qdisc(struct sk_buff *skb, struct qdisc *q, u32 clid,
u32 pid, u32 seq, u16 flags, int event)
5.16 qdisc小結
關於流控(qdisc)的分析就此告一段落, 後面將繼續分析分類(class), 過濾(filter)和動作(action)的處理過程.
...... 待續 ......
Linux核心中流量控制 5
嚴禁用於任何商業用途。msn yfydz no1 hotmail.com 5.5 sfq stochastic fairness queueing discipline sfq演算法是個比較簡單的演算法,速度也比較快,演算法維護一定數量的資料報佇列,入隊是將資料報進 行雜湊後插入某佇列,出隊則是輪詢...
Linux核心中流量控制 9
msn yfydz no1 hotmail.com 5.9 ingress ingress流控方法是針對輸入資料進行流控處理的,在net sched sch ingress.c中定義,使用時要求在核心配置中定義config net cls act或config netfilter,不過從 實現看起來...
置頂 Linux 流量控制
在如今的網路界,也許tc知道的人並不多了,這篇文章做留戀吧。以前研究tc時記錄下的講解與配置檔案。tc filter add dev eth0 parent 1 0 protocol ip prio 4 handle 4 fw classid 1 14 tc filter add dev eth0 ...