diff options
Diffstat (limited to 'net/sched/sch_api.c')
-rw-r--r-- | net/sched/sch_api.c | 227 |
1 files changed, 96 insertions, 131 deletions
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ecc988af4a9a..8699e7006d80 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -27,14 +27,15 @@ | |||
27 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
28 | #include <linux/netdevice.h> | 28 | #include <linux/netdevice.h> |
29 | #include <linux/skbuff.h> | 29 | #include <linux/skbuff.h> |
30 | #include <linux/rtnetlink.h> | ||
31 | #include <linux/init.h> | 30 | #include <linux/init.h> |
32 | #include <linux/proc_fs.h> | 31 | #include <linux/proc_fs.h> |
33 | #include <linux/seq_file.h> | 32 | #include <linux/seq_file.h> |
34 | #include <linux/kmod.h> | 33 | #include <linux/kmod.h> |
35 | #include <linux/list.h> | 34 | #include <linux/list.h> |
36 | #include <linux/bitops.h> | 35 | #include <linux/bitops.h> |
36 | #include <linux/hrtimer.h> | ||
37 | 37 | ||
38 | #include <net/netlink.h> | ||
38 | #include <net/sock.h> | 39 | #include <net/sock.h> |
39 | #include <net/pkt_sched.h> | 40 | #include <net/pkt_sched.h> |
40 | 41 | ||
@@ -190,7 +191,7 @@ int unregister_qdisc(struct Qdisc_ops *qops) | |||
190 | (root qdisc, all its children, children of children etc.) | 191 | (root qdisc, all its children, children of children etc.) |
191 | */ | 192 | */ |
192 | 193 | ||
193 | static struct Qdisc *__qdisc_lookup(struct net_device *dev, u32 handle) | 194 | struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) |
194 | { | 195 | { |
195 | struct Qdisc *q; | 196 | struct Qdisc *q; |
196 | 197 | ||
@@ -201,16 +202,6 @@ static struct Qdisc *__qdisc_lookup(struct net_device *dev, u32 handle) | |||
201 | return NULL; | 202 | return NULL; |
202 | } | 203 | } |
203 | 204 | ||
204 | struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) | ||
205 | { | ||
206 | struct Qdisc *q; | ||
207 | |||
208 | read_lock(&qdisc_tree_lock); | ||
209 | q = __qdisc_lookup(dev, handle); | ||
210 | read_unlock(&qdisc_tree_lock); | ||
211 | return q; | ||
212 | } | ||
213 | |||
214 | static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) | 205 | static struct Qdisc *qdisc_leaf(struct Qdisc *p, u32 classid) |
215 | { | 206 | { |
216 | unsigned long cl; | 207 | unsigned long cl; |
@@ -291,6 +282,48 @@ void qdisc_put_rtab(struct qdisc_rate_table *tab) | |||
291 | } | 282 | } |
292 | } | 283 | } |
293 | 284 | ||
285 | static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) | ||
286 | { | ||
287 | struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, | ||
288 | timer); | ||
289 | struct net_device *dev = wd->qdisc->dev; | ||
290 | |||
291 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; | ||
292 | smp_wmb(); | ||
293 | if (spin_trylock(&dev->queue_lock)) { | ||
294 | qdisc_run(dev); | ||
295 | spin_unlock(&dev->queue_lock); | ||
296 | } else | ||
297 | netif_schedule(dev); | ||
298 | |||
299 | return HRTIMER_NORESTART; | ||
300 | } | ||
301 | |||
302 | void qdisc_watchdog_init(struct qdisc_watchdog *wd, struct Qdisc *qdisc) | ||
303 | { | ||
304 | hrtimer_init(&wd->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | ||
305 | wd->timer.function = qdisc_watchdog; | ||
306 | wd->qdisc = qdisc; | ||
307 | } | ||
308 | EXPORT_SYMBOL(qdisc_watchdog_init); | ||
309 | |||
310 | void qdisc_watchdog_schedule(struct qdisc_watchdog *wd, psched_time_t expires) | ||
311 | { | ||
312 | ktime_t time; | ||
313 | |||
314 | wd->qdisc->flags |= TCQ_F_THROTTLED; | ||
315 | time = ktime_set(0, 0); | ||
316 | time = ktime_add_ns(time, PSCHED_US2NS(expires)); | ||
317 | hrtimer_start(&wd->timer, time, HRTIMER_MODE_ABS); | ||
318 | } | ||
319 | EXPORT_SYMBOL(qdisc_watchdog_schedule); | ||
320 | |||
321 | void qdisc_watchdog_cancel(struct qdisc_watchdog *wd) | ||
322 | { | ||
323 | hrtimer_cancel(&wd->timer); | ||
324 | wd->qdisc->flags &= ~TCQ_F_THROTTLED; | ||
325 | } | ||
326 | EXPORT_SYMBOL(qdisc_watchdog_cancel); | ||
294 | 327 | ||
295 | /* Allocate an unique handle from space managed by kernel */ | 328 | /* Allocate an unique handle from space managed by kernel */ |
296 | 329 | ||
@@ -362,7 +395,7 @@ void qdisc_tree_decrease_qlen(struct Qdisc *sch, unsigned int n) | |||
362 | if (n == 0) | 395 | if (n == 0) |
363 | return; | 396 | return; |
364 | while ((parentid = sch->parent)) { | 397 | while ((parentid = sch->parent)) { |
365 | sch = __qdisc_lookup(sch->dev, TC_H_MAJ(parentid)); | 398 | sch = qdisc_lookup(sch->dev, TC_H_MAJ(parentid)); |
366 | cops = sch->ops->cl_ops; | 399 | cops = sch->ops->cl_ops; |
367 | if (cops->qlen_notify) { | 400 | if (cops->qlen_notify) { |
368 | cl = cops->get(sch, parentid); | 401 | cl = cops->get(sch, parentid); |
@@ -467,12 +500,16 @@ qdisc_create(struct net_device *dev, u32 handle, struct rtattr **tca, int *errp) | |||
467 | 500 | ||
468 | if (handle == TC_H_INGRESS) { | 501 | if (handle == TC_H_INGRESS) { |
469 | sch->flags |= TCQ_F_INGRESS; | 502 | sch->flags |= TCQ_F_INGRESS; |
503 | sch->stats_lock = &dev->ingress_lock; | ||
470 | handle = TC_H_MAKE(TC_H_INGRESS, 0); | 504 | handle = TC_H_MAKE(TC_H_INGRESS, 0); |
471 | } else if (handle == 0) { | 505 | } else { |
472 | handle = qdisc_alloc_handle(dev); | 506 | sch->stats_lock = &dev->queue_lock; |
473 | err = -ENOMEM; | 507 | if (handle == 0) { |
474 | if (handle == 0) | 508 | handle = qdisc_alloc_handle(dev); |
475 | goto err_out3; | 509 | err = -ENOMEM; |
510 | if (handle == 0) | ||
511 | goto err_out3; | ||
512 | } | ||
476 | } | 513 | } |
477 | 514 | ||
478 | sch->handle = handle; | 515 | sch->handle = handle; |
@@ -621,9 +658,9 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n, void *arg) | |||
621 | return err; | 658 | return err; |
622 | if (q) { | 659 | if (q) { |
623 | qdisc_notify(skb, n, clid, q, NULL); | 660 | qdisc_notify(skb, n, clid, q, NULL); |
624 | spin_lock_bh(&dev->queue_lock); | 661 | qdisc_lock_tree(dev); |
625 | qdisc_destroy(q); | 662 | qdisc_destroy(q); |
626 | spin_unlock_bh(&dev->queue_lock); | 663 | qdisc_unlock_tree(dev); |
627 | } | 664 | } |
628 | } else { | 665 | } else { |
629 | qdisc_notify(skb, n, clid, NULL, q); | 666 | qdisc_notify(skb, n, clid, NULL, q); |
@@ -756,17 +793,17 @@ graft: | |||
756 | err = qdisc_graft(dev, p, clid, q, &old_q); | 793 | err = qdisc_graft(dev, p, clid, q, &old_q); |
757 | if (err) { | 794 | if (err) { |
758 | if (q) { | 795 | if (q) { |
759 | spin_lock_bh(&dev->queue_lock); | 796 | qdisc_lock_tree(dev); |
760 | qdisc_destroy(q); | 797 | qdisc_destroy(q); |
761 | spin_unlock_bh(&dev->queue_lock); | 798 | qdisc_unlock_tree(dev); |
762 | } | 799 | } |
763 | return err; | 800 | return err; |
764 | } | 801 | } |
765 | qdisc_notify(skb, n, clid, old_q, q); | 802 | qdisc_notify(skb, n, clid, old_q, q); |
766 | if (old_q) { | 803 | if (old_q) { |
767 | spin_lock_bh(&dev->queue_lock); | 804 | qdisc_lock_tree(dev); |
768 | qdisc_destroy(old_q); | 805 | qdisc_destroy(old_q); |
769 | spin_unlock_bh(&dev->queue_lock); | 806 | qdisc_unlock_tree(dev); |
770 | } | 807 | } |
771 | } | 808 | } |
772 | return 0; | 809 | return 0; |
@@ -777,7 +814,7 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, | |||
777 | { | 814 | { |
778 | struct tcmsg *tcm; | 815 | struct tcmsg *tcm; |
779 | struct nlmsghdr *nlh; | 816 | struct nlmsghdr *nlh; |
780 | unsigned char *b = skb->tail; | 817 | unsigned char *b = skb_tail_pointer(skb); |
781 | struct gnet_dump d; | 818 | struct gnet_dump d; |
782 | 819 | ||
783 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); | 820 | nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*tcm), flags); |
@@ -811,12 +848,12 @@ static int tc_fill_qdisc(struct sk_buff *skb, struct Qdisc *q, u32 clid, | |||
811 | if (gnet_stats_finish_copy(&d) < 0) | 848 | if (gnet_stats_finish_copy(&d) < 0) |
812 | goto rtattr_failure; | 849 | goto rtattr_failure; |
813 | 850 | ||
814 | nlh->nlmsg_len = skb->tail - b; | 851 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
815 | return skb->len; | 852 | return skb->len; |
816 | 853 | ||
817 | nlmsg_failure: | 854 | nlmsg_failure: |
818 | rtattr_failure: | 855 | rtattr_failure: |
819 | skb_trim(skb, b - skb->data); | 856 | nlmsg_trim(skb, b); |
820 | return -1; | 857 | return -1; |
821 | } | 858 | } |
822 | 859 | ||
@@ -862,7 +899,6 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) | |||
862 | continue; | 899 | continue; |
863 | if (idx > s_idx) | 900 | if (idx > s_idx) |
864 | s_q_idx = 0; | 901 | s_q_idx = 0; |
865 | read_lock(&qdisc_tree_lock); | ||
866 | q_idx = 0; | 902 | q_idx = 0; |
867 | list_for_each_entry(q, &dev->qdisc_list, list) { | 903 | list_for_each_entry(q, &dev->qdisc_list, list) { |
868 | if (q_idx < s_q_idx) { | 904 | if (q_idx < s_q_idx) { |
@@ -870,13 +906,10 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) | |||
870 | continue; | 906 | continue; |
871 | } | 907 | } |
872 | if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, | 908 | if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, |
873 | cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { | 909 | cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) |
874 | read_unlock(&qdisc_tree_lock); | ||
875 | goto done; | 910 | goto done; |
876 | } | ||
877 | q_idx++; | 911 | q_idx++; |
878 | } | 912 | } |
879 | read_unlock(&qdisc_tree_lock); | ||
880 | } | 913 | } |
881 | 914 | ||
882 | done: | 915 | done: |
@@ -1015,7 +1048,7 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, | |||
1015 | { | 1048 | { |
1016 | struct tcmsg *tcm; | 1049 | struct tcmsg *tcm; |
1017 | struct nlmsghdr *nlh; | 1050 | struct nlmsghdr *nlh; |
1018 | unsigned char *b = skb->tail; | 1051 | unsigned char *b = skb_tail_pointer(skb); |
1019 | struct gnet_dump d; | 1052 | struct gnet_dump d; |
1020 | struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; | 1053 | struct Qdisc_class_ops *cl_ops = q->ops->cl_ops; |
1021 | 1054 | ||
@@ -1040,12 +1073,12 @@ static int tc_fill_tclass(struct sk_buff *skb, struct Qdisc *q, | |||
1040 | if (gnet_stats_finish_copy(&d) < 0) | 1073 | if (gnet_stats_finish_copy(&d) < 0) |
1041 | goto rtattr_failure; | 1074 | goto rtattr_failure; |
1042 | 1075 | ||
1043 | nlh->nlmsg_len = skb->tail - b; | 1076 | nlh->nlmsg_len = skb_tail_pointer(skb) - b; |
1044 | return skb->len; | 1077 | return skb->len; |
1045 | 1078 | ||
1046 | nlmsg_failure: | 1079 | nlmsg_failure: |
1047 | rtattr_failure: | 1080 | rtattr_failure: |
1048 | skb_trim(skb, b - skb->data); | 1081 | nlmsg_trim(skb, b); |
1049 | return -1; | 1082 | return -1; |
1050 | } | 1083 | } |
1051 | 1084 | ||
@@ -1099,7 +1132,6 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
1099 | s_t = cb->args[0]; | 1132 | s_t = cb->args[0]; |
1100 | t = 0; | 1133 | t = 0; |
1101 | 1134 | ||
1102 | read_lock(&qdisc_tree_lock); | ||
1103 | list_for_each_entry(q, &dev->qdisc_list, list) { | 1135 | list_for_each_entry(q, &dev->qdisc_list, list) { |
1104 | if (t < s_t || !q->ops->cl_ops || | 1136 | if (t < s_t || !q->ops->cl_ops || |
1105 | (tcm->tcm_parent && | 1137 | (tcm->tcm_parent && |
@@ -1121,7 +1153,6 @@ static int tc_dump_tclass(struct sk_buff *skb, struct netlink_callback *cb) | |||
1121 | break; | 1153 | break; |
1122 | t++; | 1154 | t++; |
1123 | } | 1155 | } |
1124 | read_unlock(&qdisc_tree_lock); | ||
1125 | 1156 | ||
1126 | cb->args[0] = t; | 1157 | cb->args[0] = t; |
1127 | 1158 | ||
@@ -1146,7 +1177,7 @@ reclassify: | |||
1146 | 1177 | ||
1147 | for ( ; tp; tp = tp->next) { | 1178 | for ( ; tp; tp = tp->next) { |
1148 | if ((tp->protocol == protocol || | 1179 | if ((tp->protocol == protocol || |
1149 | tp->protocol == __constant_htons(ETH_P_ALL)) && | 1180 | tp->protocol == htons(ETH_P_ALL)) && |
1150 | (err = tp->classify(skb, tp, res)) >= 0) { | 1181 | (err = tp->classify(skb, tp, res)) >= 0) { |
1151 | #ifdef CONFIG_NET_CLS_ACT | 1182 | #ifdef CONFIG_NET_CLS_ACT |
1152 | if ( TC_ACT_RECLASSIFY == err) { | 1183 | if ( TC_ACT_RECLASSIFY == err) { |
@@ -1175,15 +1206,31 @@ reclassify: | |||
1175 | return -1; | 1206 | return -1; |
1176 | } | 1207 | } |
1177 | 1208 | ||
1178 | static int psched_us_per_tick = 1; | 1209 | void tcf_destroy(struct tcf_proto *tp) |
1179 | static int psched_tick_per_us = 1; | 1210 | { |
1211 | tp->ops->destroy(tp); | ||
1212 | module_put(tp->ops->owner); | ||
1213 | kfree(tp); | ||
1214 | } | ||
1215 | |||
1216 | void tcf_destroy_chain(struct tcf_proto *fl) | ||
1217 | { | ||
1218 | struct tcf_proto *tp; | ||
1219 | |||
1220 | while ((tp = fl) != NULL) { | ||
1221 | fl = tp->next; | ||
1222 | tcf_destroy(tp); | ||
1223 | } | ||
1224 | } | ||
1225 | EXPORT_SYMBOL(tcf_destroy_chain); | ||
1180 | 1226 | ||
1181 | #ifdef CONFIG_PROC_FS | 1227 | #ifdef CONFIG_PROC_FS |
1182 | static int psched_show(struct seq_file *seq, void *v) | 1228 | static int psched_show(struct seq_file *seq, void *v) |
1183 | { | 1229 | { |
1184 | seq_printf(seq, "%08x %08x %08x %08x\n", | 1230 | seq_printf(seq, "%08x %08x %08x %08x\n", |
1185 | psched_tick_per_us, psched_us_per_tick, | 1231 | (u32)NSEC_PER_USEC, (u32)PSCHED_US2NS(1), |
1186 | 1000000, HZ); | 1232 | 1000000, |
1233 | (u32)NSEC_PER_SEC/(u32)ktime_to_ns(KTIME_MONOTONIC_RES)); | ||
1187 | 1234 | ||
1188 | return 0; | 1235 | return 0; |
1189 | } | 1236 | } |
@@ -1202,101 +1249,19 @@ static const struct file_operations psched_fops = { | |||
1202 | }; | 1249 | }; |
1203 | #endif | 1250 | #endif |
1204 | 1251 | ||
1205 | #ifdef CONFIG_NET_SCH_CLK_CPU | ||
1206 | psched_tdiff_t psched_clock_per_hz; | ||
1207 | int psched_clock_scale; | ||
1208 | EXPORT_SYMBOL(psched_clock_per_hz); | ||
1209 | EXPORT_SYMBOL(psched_clock_scale); | ||
1210 | |||
1211 | psched_time_t psched_time_base; | ||
1212 | cycles_t psched_time_mark; | ||
1213 | EXPORT_SYMBOL(psched_time_mark); | ||
1214 | EXPORT_SYMBOL(psched_time_base); | ||
1215 | |||
1216 | /* | ||
1217 | * Periodically adjust psched_time_base to avoid overflow | ||
1218 | * with 32-bit get_cycles(). Safe up to 4GHz CPU. | ||
1219 | */ | ||
1220 | static void psched_tick(unsigned long); | ||
1221 | static DEFINE_TIMER(psched_timer, psched_tick, 0, 0); | ||
1222 | |||
1223 | static void psched_tick(unsigned long dummy) | ||
1224 | { | ||
1225 | if (sizeof(cycles_t) == sizeof(u32)) { | ||
1226 | psched_time_t dummy_stamp; | ||
1227 | PSCHED_GET_TIME(dummy_stamp); | ||
1228 | psched_timer.expires = jiffies + 1*HZ; | ||
1229 | add_timer(&psched_timer); | ||
1230 | } | ||
1231 | } | ||
1232 | |||
1233 | int __init psched_calibrate_clock(void) | ||
1234 | { | ||
1235 | psched_time_t stamp, stamp1; | ||
1236 | struct timeval tv, tv1; | ||
1237 | psched_tdiff_t delay; | ||
1238 | long rdelay; | ||
1239 | unsigned long stop; | ||
1240 | |||
1241 | psched_tick(0); | ||
1242 | stop = jiffies + HZ/10; | ||
1243 | PSCHED_GET_TIME(stamp); | ||
1244 | do_gettimeofday(&tv); | ||
1245 | while (time_before(jiffies, stop)) { | ||
1246 | barrier(); | ||
1247 | cpu_relax(); | ||
1248 | } | ||
1249 | PSCHED_GET_TIME(stamp1); | ||
1250 | do_gettimeofday(&tv1); | ||
1251 | |||
1252 | delay = PSCHED_TDIFF(stamp1, stamp); | ||
1253 | rdelay = tv1.tv_usec - tv.tv_usec; | ||
1254 | rdelay += (tv1.tv_sec - tv.tv_sec)*1000000; | ||
1255 | if (rdelay > delay) | ||
1256 | return -1; | ||
1257 | delay /= rdelay; | ||
1258 | psched_tick_per_us = delay; | ||
1259 | while ((delay>>=1) != 0) | ||
1260 | psched_clock_scale++; | ||
1261 | psched_us_per_tick = 1<<psched_clock_scale; | ||
1262 | psched_clock_per_hz = (psched_tick_per_us*(1000000/HZ))>>psched_clock_scale; | ||
1263 | return 0; | ||
1264 | } | ||
1265 | #endif | ||
1266 | |||
1267 | static int __init pktsched_init(void) | 1252 | static int __init pktsched_init(void) |
1268 | { | 1253 | { |
1269 | struct rtnetlink_link *link_p; | ||
1270 | |||
1271 | #ifdef CONFIG_NET_SCH_CLK_CPU | ||
1272 | if (psched_calibrate_clock() < 0) | ||
1273 | return -1; | ||
1274 | #elif defined(CONFIG_NET_SCH_CLK_JIFFIES) | ||
1275 | psched_tick_per_us = HZ<<PSCHED_JSCALE; | ||
1276 | psched_us_per_tick = 1000000; | ||
1277 | #endif | ||
1278 | |||
1279 | link_p = rtnetlink_links[PF_UNSPEC]; | ||
1280 | |||
1281 | /* Setup rtnetlink links. It is made here to avoid | ||
1282 | exporting large number of public symbols. | ||
1283 | */ | ||
1284 | |||
1285 | if (link_p) { | ||
1286 | link_p[RTM_NEWQDISC-RTM_BASE].doit = tc_modify_qdisc; | ||
1287 | link_p[RTM_DELQDISC-RTM_BASE].doit = tc_get_qdisc; | ||
1288 | link_p[RTM_GETQDISC-RTM_BASE].doit = tc_get_qdisc; | ||
1289 | link_p[RTM_GETQDISC-RTM_BASE].dumpit = tc_dump_qdisc; | ||
1290 | link_p[RTM_NEWTCLASS-RTM_BASE].doit = tc_ctl_tclass; | ||
1291 | link_p[RTM_DELTCLASS-RTM_BASE].doit = tc_ctl_tclass; | ||
1292 | link_p[RTM_GETTCLASS-RTM_BASE].doit = tc_ctl_tclass; | ||
1293 | link_p[RTM_GETTCLASS-RTM_BASE].dumpit = tc_dump_tclass; | ||
1294 | } | ||
1295 | |||
1296 | register_qdisc(&pfifo_qdisc_ops); | 1254 | register_qdisc(&pfifo_qdisc_ops); |
1297 | register_qdisc(&bfifo_qdisc_ops); | 1255 | register_qdisc(&bfifo_qdisc_ops); |
1298 | proc_net_fops_create("psched", 0, &psched_fops); | 1256 | proc_net_fops_create("psched", 0, &psched_fops); |
1299 | 1257 | ||
1258 | rtnl_register(PF_UNSPEC, RTM_NEWQDISC, tc_modify_qdisc, NULL); | ||
1259 | rtnl_register(PF_UNSPEC, RTM_DELQDISC, tc_get_qdisc, NULL); | ||
1260 | rtnl_register(PF_UNSPEC, RTM_GETQDISC, tc_get_qdisc, tc_dump_qdisc); | ||
1261 | rtnl_register(PF_UNSPEC, RTM_NEWTCLASS, tc_ctl_tclass, NULL); | ||
1262 | rtnl_register(PF_UNSPEC, RTM_DELTCLASS, tc_ctl_tclass, NULL); | ||
1263 | rtnl_register(PF_UNSPEC, RTM_GETTCLASS, tc_ctl_tclass, tc_dump_tclass); | ||
1264 | |||
1300 | return 0; | 1265 | return 0; |
1301 | } | 1266 | } |
1302 | 1267 | ||