libnl  3.2.3
/build/buildd/libnl3-3.2.3/lib/route/qdisc/htb.c
00001 /*
00002  * lib/route/qdisc/htb.c        HTB Qdisc
00003  *
00004  *      This library is free software; you can redistribute it and/or
00005  *      modify it under the terms of the GNU Lesser General Public
00006  *      License as published by the Free Software Foundation version 2.1
00007  *      of the License.
00008  *
00009  * Copyright (c) 2003-2011 Thomas Graf <tgraf@suug.ch>
00010  * Copyright (c) 2005-2006 Petr Gotthard <petr.gotthard@siemens.com>
00011  * Copyright (c) 2005-2006 Siemens AG Oesterreich
00012  */
00013 
00014 /**
00015  * @ingroup qdisc
00016  * @ingroup class
00017  * @defgroup qdisc_htb Hierachical Token Bucket (HTB)
00018  * @{
00019  */
00020 
00021 #include <netlink-local.h>
00022 #include <netlink-tc.h>
00023 #include <netlink/netlink.h>
00024 #include <netlink/cache.h>
00025 #include <netlink/utils.h>
00026 #include <netlink/route/tc-api.h>
00027 #include <netlink/route/qdisc.h>
00028 #include <netlink/route/class.h>
00029 #include <netlink/route/link.h>
00030 #include <netlink/route/qdisc/htb.h>
00031 
00032 /** @cond SKIP */
00033 #define SCH_HTB_HAS_RATE2QUANTUM        0x01
00034 #define SCH_HTB_HAS_DEFCLS              0x02
00035 
00036 #define SCH_HTB_HAS_PRIO                0x001
00037 #define SCH_HTB_HAS_RATE                0x002
00038 #define SCH_HTB_HAS_CEIL                0x004
00039 #define SCH_HTB_HAS_RBUFFER             0x008
00040 #define SCH_HTB_HAS_CBUFFER             0x010
00041 #define SCH_HTB_HAS_QUANTUM             0x020
00042 #define SCH_HTB_HAS_LEVEL               0x040
00043 /** @endcond */
00044 
00045 static struct nla_policy htb_policy[TCA_HTB_MAX+1] = {
00046         [TCA_HTB_INIT]  = { .minlen = sizeof(struct tc_htb_glob) },
00047         [TCA_HTB_PARMS] = { .minlen = sizeof(struct tc_htb_opt) },
00048 };
00049 
00050 static int htb_qdisc_msg_parser(struct rtnl_tc *tc, void *data)
00051 {
00052         struct nlattr *tb[TCA_HTB_MAX + 1];
00053         struct rtnl_htb_qdisc *htb = data;
00054         int err;
00055 
00056         if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00057                 return err;
00058         
00059         if (tb[TCA_HTB_INIT]) {
00060                 struct tc_htb_glob opts;
00061 
00062                 nla_memcpy(&opts, tb[TCA_HTB_INIT], sizeof(opts));
00063                 htb->qh_rate2quantum = opts.rate2quantum;
00064                 htb->qh_defcls = opts.defcls;
00065                 htb->qh_direct_pkts = opts.direct_pkts;
00066 
00067                 htb->qh_mask = (SCH_HTB_HAS_RATE2QUANTUM | SCH_HTB_HAS_DEFCLS);
00068         }
00069 
00070         return 0;
00071 }
00072 
00073 static int htb_class_msg_parser(struct rtnl_tc *tc, void *data)
00074 {
00075         struct nlattr *tb[TCA_HTB_MAX + 1];
00076         struct rtnl_htb_class *htb = data;
00077         int err;
00078 
00079         if ((err = tca_parse(tb, TCA_HTB_MAX, tc, htb_policy)) < 0)
00080                 return err;
00081         
00082         if (tb[TCA_HTB_PARMS]) {
00083                 struct tc_htb_opt opts;
00084 
00085                 nla_memcpy(&opts, tb[TCA_HTB_PARMS], sizeof(opts));
00086                 htb->ch_prio = opts.prio;
00087                 rtnl_copy_ratespec(&htb->ch_rate, &opts.rate);
00088                 rtnl_copy_ratespec(&htb->ch_ceil, &opts.ceil);
00089                 htb->ch_rbuffer = rtnl_tc_calc_bufsize(opts.buffer,
00090                                                        opts.rate.rate);
00091                 htb->ch_cbuffer = rtnl_tc_calc_bufsize(opts.cbuffer,
00092                                                        opts.ceil.rate);
00093                 htb->ch_quantum = opts.quantum;
00094                 htb->ch_level = opts.level;
00095 
00096                 rtnl_tc_set_mpu(tc, htb->ch_rate.rs_mpu);
00097                 rtnl_tc_set_overhead(tc, htb->ch_rate.rs_overhead);
00098 
00099                 htb->ch_mask = (SCH_HTB_HAS_PRIO | SCH_HTB_HAS_RATE |
00100                                 SCH_HTB_HAS_CEIL | SCH_HTB_HAS_RBUFFER |
00101                                 SCH_HTB_HAS_CBUFFER | SCH_HTB_HAS_QUANTUM |
00102                                 SCH_HTB_HAS_LEVEL);
00103         }
00104 
00105         return 0;
00106 }
00107 
00108 static void htb_qdisc_dump_line(struct rtnl_tc *tc, void *data,
00109                                 struct nl_dump_params *p)
00110 {
00111         struct rtnl_htb_qdisc *htb = data;
00112 
00113         if (!htb)
00114                 return;
00115 
00116         if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00117                 nl_dump(p, " r2q %u", htb->qh_rate2quantum);
00118 
00119         if (htb->qh_mask & SCH_HTB_HAS_DEFCLS) {
00120                 char buf[64];
00121                 nl_dump(p, " default-class %s",
00122                         rtnl_tc_handle2str(htb->qh_defcls, buf, sizeof(buf)));
00123         }
00124 }
00125 
00126 static void htb_class_dump_line(struct rtnl_tc *tc, void *data,
00127                                 struct nl_dump_params *p)
00128 {
00129         struct rtnl_htb_class *htb = data;
00130 
00131         if (!htb)
00132                 return;
00133 
00134         if (htb->ch_mask & SCH_HTB_HAS_RATE) {
00135                 double r, rbit;
00136                 char *ru, *rubit;
00137 
00138                 r = nl_cancel_down_bytes(htb->ch_rate.rs_rate, &ru);
00139                 rbit = nl_cancel_down_bits(htb->ch_rate.rs_rate*8, &rubit);
00140 
00141                 nl_dump(p, " rate %.2f%s/s (%.0f%s) log %u",
00142                         r, ru, rbit, rubit, 1<<htb->ch_rate.rs_cell_log);
00143         }
00144 }
00145 
00146 static void htb_class_dump_details(struct rtnl_tc *tc, void *data,
00147                                    struct nl_dump_params *p)
00148 {
00149         struct rtnl_htb_class *htb = data;
00150 
00151         if (!htb)
00152                 return;
00153 
00154         /* line 1 */
00155         if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00156                 double r, rbit;
00157                 char *ru, *rubit;
00158 
00159                 r = nl_cancel_down_bytes(htb->ch_ceil.rs_rate, &ru);
00160                 rbit = nl_cancel_down_bits(htb->ch_ceil.rs_rate*8, &rubit);
00161 
00162                 nl_dump(p, " ceil %.2f%s/s (%.0f%s) log %u",
00163                         r, ru, rbit, rubit, 1<<htb->ch_ceil.rs_cell_log);
00164         }
00165 
00166         if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00167                 nl_dump(p, " prio %u", htb->ch_prio);
00168 
00169         if (htb->ch_mask & SCH_HTB_HAS_RBUFFER) {
00170                 double b;
00171                 char *bu;
00172 
00173                 b = nl_cancel_down_bytes(htb->ch_rbuffer, &bu);
00174                 nl_dump(p, " rbuffer %.2f%s", b, bu);
00175         }
00176 
00177         if (htb->ch_mask & SCH_HTB_HAS_CBUFFER) {
00178                 double b;
00179                 char *bu;
00180 
00181                 b = nl_cancel_down_bytes(htb->ch_cbuffer, &bu);
00182                 nl_dump(p, " cbuffer %.2f%s", b, bu);
00183         }
00184 
00185         if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00186                 nl_dump(p, " quantum %u", htb->ch_quantum);
00187 }
00188 
00189 static int htb_qdisc_msg_fill(struct rtnl_tc *tc, void *data,
00190                               struct nl_msg *msg)
00191 {
00192         struct rtnl_htb_qdisc *htb = data;
00193         struct tc_htb_glob opts = {0};
00194 
00195         opts.version = TC_HTB_PROTOVER;
00196         opts.rate2quantum = 10;
00197 
00198         if (htb) {
00199                 if (htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00200                         opts.rate2quantum = htb->qh_rate2quantum;
00201 
00202                 if (htb->qh_mask & SCH_HTB_HAS_DEFCLS)
00203                         opts.defcls = htb->qh_defcls;
00204         }
00205 
00206         return nla_put(msg, TCA_HTB_INIT, sizeof(opts), &opts);
00207 }
00208 
00209 static int htb_class_msg_fill(struct rtnl_tc *tc, void *data,
00210                               struct nl_msg *msg)
00211 {
00212         struct rtnl_htb_class *htb = data;
00213         uint32_t mtu, rtable[RTNL_TC_RTABLE_SIZE], ctable[RTNL_TC_RTABLE_SIZE];
00214         struct tc_htb_opt opts;
00215         int buffer, cbuffer;
00216 
00217         if (!htb || !(htb->ch_mask & SCH_HTB_HAS_RATE))
00218                 BUG();
00219 
00220         memset(&opts, 0, sizeof(opts));
00221 
00222         /* if not set, zero (0) is used as priority */
00223         if (htb->ch_mask & SCH_HTB_HAS_PRIO)
00224                 opts.prio = htb->ch_prio;
00225 
00226         mtu = rtnl_tc_get_mtu(tc);
00227 
00228         rtnl_tc_build_rate_table(tc, &htb->ch_rate, rtable);
00229         rtnl_rcopy_ratespec(&opts.rate, &htb->ch_rate);
00230 
00231         if (htb->ch_mask & SCH_HTB_HAS_CEIL) {
00232                 rtnl_tc_build_rate_table(tc, &htb->ch_ceil, ctable);
00233                 rtnl_rcopy_ratespec(&opts.ceil, &htb->ch_ceil);
00234         } else {
00235                 /*
00236                  * If not set, configured rate is used as ceil, which implies
00237                  * no borrowing.
00238                  */
00239                 memcpy(&opts.ceil, &opts.rate, sizeof(struct tc_ratespec));
00240         }
00241 
00242         if (htb->ch_mask & SCH_HTB_HAS_RBUFFER)
00243                 buffer = htb->ch_rbuffer;
00244         else
00245                 buffer = opts.rate.rate / nl_get_user_hz() + mtu; /* XXX */
00246 
00247         opts.buffer = rtnl_tc_calc_txtime(buffer, opts.rate.rate);
00248 
00249         if (htb->ch_mask & SCH_HTB_HAS_CBUFFER)
00250                 cbuffer = htb->ch_cbuffer;
00251         else
00252                 cbuffer = opts.ceil.rate / nl_get_user_hz() + mtu; /* XXX */
00253 
00254         opts.cbuffer = rtnl_tc_calc_txtime(cbuffer, opts.ceil.rate);
00255 
00256         if (htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00257                 opts.quantum = htb->ch_quantum;
00258 
00259         NLA_PUT(msg, TCA_HTB_PARMS, sizeof(opts), &opts);
00260         NLA_PUT(msg, TCA_HTB_RTAB, sizeof(rtable), &rtable);
00261         NLA_PUT(msg, TCA_HTB_CTAB, sizeof(ctable), &ctable);
00262 
00263         return 0;
00264 
00265 nla_put_failure:
00266         return -NLE_MSGSIZE;
00267 }
00268 
00269 static struct rtnl_tc_ops htb_qdisc_ops;
00270 static struct rtnl_tc_ops htb_class_ops;
00271 
00272 static struct rtnl_htb_qdisc *htb_qdisc_data(struct rtnl_qdisc *qdisc)
00273 {
00274         return rtnl_tc_data_check(TC_CAST(qdisc), &htb_qdisc_ops);
00275 }
00276 
00277 static struct rtnl_htb_class *htb_class_data(struct rtnl_class *class)
00278 {
00279         return rtnl_tc_data_check(TC_CAST(class), &htb_class_ops);
00280 }
00281 
00282 /**
00283  * @name Attribute Modifications
00284  * @{
00285  */
00286 
00287 /**
00288  * Return rate/quantum ratio of HTB qdisc
00289  * @arg qdisc           htb qdisc object
00290  *
00291  * @return rate/quantum ratio or 0 if unspecified
00292  */
00293 uint32_t rtnl_htb_get_rate2quantum(struct rtnl_qdisc *qdisc)
00294 {
00295         struct rtnl_htb_qdisc *htb;
00296 
00297         if ((htb = htb_qdisc_data(qdisc)) &&
00298             htb->qh_mask & SCH_HTB_HAS_RATE2QUANTUM)
00299                 return htb->qh_rate2quantum;
00300 
00301         return 0;
00302 }
00303 
00304 int rtnl_htb_set_rate2quantum(struct rtnl_qdisc *qdisc, uint32_t rate2quantum)
00305 {
00306         struct rtnl_htb_qdisc *htb;
00307 
00308         if (!(htb = htb_qdisc_data(qdisc)))
00309                 return -NLE_OPNOTSUPP;
00310 
00311         htb->qh_rate2quantum = rate2quantum;
00312         htb->qh_mask |= SCH_HTB_HAS_RATE2QUANTUM;
00313 
00314         return 0;
00315 }
00316 
00317 /**
00318  * Return default class of HTB qdisc
00319  * @arg qdisc           htb qdisc object
00320  *
00321  * Returns the classid of the class where all unclassified traffic
00322  * goes to.
00323  *
00324  * @return classid or TC_H_UNSPEC if unspecified.
00325  */
00326 uint32_t rtnl_htb_get_defcls(struct rtnl_qdisc *qdisc)
00327 {
00328         struct rtnl_htb_qdisc *htb;
00329 
00330         if ((htb = htb_qdisc_data(qdisc)) &&
00331             htb->qh_mask & SCH_HTB_HAS_DEFCLS)
00332                 return htb->qh_defcls;
00333 
00334         return TC_H_UNSPEC;
00335 }
00336 
00337 /**
00338  * Set default class of the htb qdisc to the specified value
00339  * @arg qdisc           qdisc to change
00340  * @arg defcls          new default class
00341  */
00342 int rtnl_htb_set_defcls(struct rtnl_qdisc *qdisc, uint32_t defcls)
00343 {
00344         struct rtnl_htb_qdisc *htb;
00345 
00346         if (!(htb = htb_qdisc_data(qdisc)))
00347                 return -NLE_OPNOTSUPP;
00348 
00349         htb->qh_defcls = defcls;
00350         htb->qh_mask |= SCH_HTB_HAS_DEFCLS;
00351 
00352         return 0;
00353 }
00354 
00355 uint32_t rtnl_htb_get_prio(struct rtnl_class *class)
00356 {
00357         struct rtnl_htb_class *htb;
00358 
00359         if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_PRIO)
00360                 return htb->ch_prio;
00361 
00362         return 0;
00363 }
00364 
00365 int rtnl_htb_set_prio(struct rtnl_class *class, uint32_t prio)
00366 {
00367         struct rtnl_htb_class *htb;
00368 
00369         if (!(htb = htb_class_data(class)))
00370                 return -NLE_OPNOTSUPP;
00371 
00372         htb->ch_prio = prio;
00373         htb->ch_mask |= SCH_HTB_HAS_PRIO;
00374 
00375         return 0;
00376 }
00377 
00378 /**
00379  * Return rate of HTB class
00380  * @arg class           htb class object
00381  *
00382  * @return Rate in bytes/s or 0 if unspecified.
00383  */
00384 uint32_t rtnl_htb_get_rate(struct rtnl_class *class)
00385 {
00386         struct rtnl_htb_class *htb;
00387 
00388         if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_RATE)
00389                 return htb->ch_rate.rs_rate;
00390 
00391         return 0;
00392 }
00393 
00394 /**
00395  * Set rate of HTB class
00396  * @arg class           htb class object
00397  * @arg rate            new rate in bytes per second
00398  *
00399  * @return 0 on success or a negative error code.
00400  */
00401 int rtnl_htb_set_rate(struct rtnl_class *class, uint32_t rate)
00402 {
00403         struct rtnl_htb_class *htb;
00404 
00405         if (!(htb = htb_class_data(class)))
00406                 return -NLE_OPNOTSUPP;
00407 
00408         htb->ch_rate.rs_cell_log = UINT8_MAX; /* use default value */
00409         htb->ch_rate.rs_rate = rate;
00410         htb->ch_mask |= SCH_HTB_HAS_RATE;
00411 
00412         return 0;
00413 }
00414 
00415 /**
00416  * Return ceil rate of HTB class
00417  * @arg class           htb class object
00418  *
00419  * @return Ceil rate in bytes/s or 0 if unspecified
00420  */
00421 uint32_t rtnl_htb_get_ceil(struct rtnl_class *class)
00422 {
00423         struct rtnl_htb_class *htb;
00424 
00425         if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_CEIL)
00426                 return htb->ch_ceil.rs_rate;
00427 
00428         return 0;
00429 }
00430 
00431 /**
00432  * Set ceil rate of HTB class
00433  * @arg class           htb class object
00434  * @arg ceil            new ceil rate number of bytes per second
00435  *
00436  * @return 0 on success or a negative error code.
00437  */
00438 int rtnl_htb_set_ceil(struct rtnl_class *class, uint32_t ceil)
00439 {
00440         struct rtnl_htb_class *htb;
00441 
00442         if (!(htb = htb_class_data(class)))
00443                 return -NLE_OPNOTSUPP;
00444 
00445         htb->ch_ceil.rs_cell_log = UINT8_MAX; /* use default value */
00446         htb->ch_ceil.rs_rate = ceil;
00447         htb->ch_mask |= SCH_HTB_HAS_CEIL;
00448 
00449         return 0;
00450 }
00451 
00452 /**
00453  * Return burst buffer size of HTB class
00454  * @arg class           htb class object
00455  *
00456  * @return Burst buffer size or 0 if unspecified
00457  */
00458 uint32_t rtnl_htb_get_rbuffer(struct rtnl_class *class)
00459 {
00460         struct rtnl_htb_class *htb;
00461 
00462         if ((htb = htb_class_data(class)) &&
00463              htb->ch_mask & SCH_HTB_HAS_RBUFFER)
00464                 return htb->ch_rbuffer;
00465 
00466         return 0;
00467 }
00468 
00469 /**
00470  * Set size of the rate bucket of HTB class.
00471  * @arg class           HTB class to be modified.
00472  * @arg rbuffer         New size in bytes.
00473  */
00474 int rtnl_htb_set_rbuffer(struct rtnl_class *class, uint32_t rbuffer)
00475 {
00476         struct rtnl_htb_class *htb;
00477 
00478         if (!(htb = htb_class_data(class)))
00479                 return -NLE_OPNOTSUPP;
00480 
00481         htb->ch_rbuffer = rbuffer;
00482         htb->ch_mask |= SCH_HTB_HAS_RBUFFER;
00483 
00484         return 0;
00485 }
00486 
00487 /**
00488  * Return ceil burst buffer size of HTB class
00489  * @arg class           htb class object
00490  *
00491  * @return Ceil burst buffer size or 0 if unspecified
00492  */
00493 uint32_t rtnl_htb_get_cbuffer(struct rtnl_class *class)
00494 {
00495         struct rtnl_htb_class *htb;
00496 
00497         if ((htb = htb_class_data(class)) &&
00498              htb->ch_mask & SCH_HTB_HAS_CBUFFER)
00499                 return htb->ch_cbuffer;
00500 
00501         return 0;
00502 }
00503 
00504 /**
00505  * Set size of the ceil bucket of HTB class.
00506  * @arg class           HTB class to be modified.
00507  * @arg cbuffer         New size in bytes.
00508  */
00509 int rtnl_htb_set_cbuffer(struct rtnl_class *class, uint32_t cbuffer)
00510 {
00511         struct rtnl_htb_class *htb;
00512 
00513         if (!(htb = htb_class_data(class)))
00514                 return -NLE_OPNOTSUPP;
00515 
00516         htb->ch_cbuffer = cbuffer;
00517         htb->ch_mask |= SCH_HTB_HAS_CBUFFER;
00518 
00519         return 0;
00520 }
00521 
00522 /**
00523  * Return quantum of HTB class
00524  * @arg class           htb class object
00525  *
00526  * See XXX[quantum def]
00527  *
00528  * @return Quantum or 0 if unspecified.
00529  */
00530 uint32_t rtnl_htb_get_quantum(struct rtnl_class *class)
00531 {
00532         struct rtnl_htb_class *htb;
00533 
00534         if ((htb = htb_class_data(class)) &&
00535             htb->ch_mask & SCH_HTB_HAS_QUANTUM)
00536                 return htb->ch_quantum;
00537 
00538         return 0;
00539 }
00540 
00541 /**
00542  * Set quantum of HTB class (overwrites value calculated based on r2q)
00543  * @arg class           htb class object
00544  * @arg quantum         new quantum in number of bytes
00545  *
00546  * See XXX[quantum def]
00547  *
00548  * @return 0 on success or a negative error code.
00549  */
00550 int rtnl_htb_set_quantum(struct rtnl_class *class, uint32_t quantum)
00551 {
00552         struct rtnl_htb_class *htb;
00553 
00554         if (!(htb = htb_class_data(class)))
00555                 return -NLE_OPNOTSUPP;
00556 
00557         htb->ch_quantum = quantum;
00558         htb->ch_mask |= SCH_HTB_HAS_QUANTUM;
00559 
00560         return 0;
00561 }
00562 
00563 /**
00564  * Return level of HTB class
00565  * @arg class           htb class object
00566  *
00567  * Returns the level of the HTB class. Leaf classes are assigned level
00568  * 0, root classes have level (TC_HTB_MAXDEPTH - 1). Interior classes
00569  * have a level of one less than their parent.
00570  *
00571  * @return Level or -NLE_OPNOTSUPP
00572  */
00573 int rtnl_htb_get_level(struct rtnl_class *class)
00574 {
00575         struct rtnl_htb_class *htb;
00576 
00577         if ((htb = htb_class_data(class)) && htb->ch_mask & SCH_HTB_HAS_LEVEL)
00578                 return htb->ch_level;
00579 
00580         return -NLE_OPNOTSUPP;
00581 }
00582 
00583 /**
00584  * Set level of HTB class
00585  * @arg class           htb class object
00586  * @arg level           new level of HTB class
00587  *
00588  * Sets the level of a HTB class. Note that changing the level of a HTB
00589  * class does not change the level of its in kernel counterpart. This
00590  * function is provided only to create HTB objects which can be compared
00591  * against or filtered upon.
00592  *
00593  * @return 0 on success or a negative error code.
00594  */
00595 int rtnl_htb_set_level(struct rtnl_class *class, int level)
00596 {
00597         struct rtnl_htb_class *htb;
00598 
00599         if (!(htb = htb_class_data(class)))
00600                 return -NLE_OPNOTSUPP;
00601 
00602         htb->ch_level = level;
00603         htb->ch_mask |= SCH_HTB_HAS_LEVEL;
00604 
00605         return 0;
00606 }
00607 
00608 /** @} */
00609 
00610 static struct rtnl_tc_ops htb_qdisc_ops = {
00611         .to_kind                = "htb",
00612         .to_type                = RTNL_TC_TYPE_QDISC,
00613         .to_size                = sizeof(struct rtnl_htb_qdisc),
00614         .to_msg_parser          = htb_qdisc_msg_parser,
00615         .to_dump[NL_DUMP_LINE]  = htb_qdisc_dump_line,
00616         .to_msg_fill            = htb_qdisc_msg_fill,
00617 };
00618 
00619 static struct rtnl_tc_ops htb_class_ops = {
00620         .to_kind                = "htb",
00621         .to_type                = RTNL_TC_TYPE_CLASS,
00622         .to_size                = sizeof(struct rtnl_htb_class),
00623         .to_msg_parser          = htb_class_msg_parser,
00624         .to_dump = {
00625             [NL_DUMP_LINE]      = htb_class_dump_line,
00626             [NL_DUMP_DETAILS]   = htb_class_dump_details,
00627         },
00628         .to_msg_fill            = htb_class_msg_fill,
00629 };
00630 
00631 static void __init htb_init(void)
00632 {
00633         rtnl_tc_register(&htb_qdisc_ops);
00634         rtnl_tc_register(&htb_class_ops);
00635 }
00636 
00637 static void __exit htb_exit(void)
00638 {
00639         rtnl_tc_unregister(&htb_qdisc_ops);
00640         rtnl_tc_unregister(&htb_class_ops);
00641 }
00642 
00643 /** @} */