Home | History | Annotate | Download | only in sch
      1 /*
      2  * lib/route/sch/dsmark.c	DSMARK
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2003-2008 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup qdisc_api
     14  * @ingroup class_api
     15  * @defgroup dsmark Differentiated Services Marker (DSMARK)
     16  * @{
     17  */
     18 
     19 #include <netlink-local.h>
     20 #include <netlink-tc.h>
     21 #include <netlink/netlink.h>
     22 #include <netlink/utils.h>
     23 #include <netlink/route/qdisc.h>
     24 #include <netlink/route/qdisc-modules.h>
     25 #include <netlink/route/class.h>
     26 #include <netlink/route/class-modules.h>
     27 #include <netlink/route/sch/dsmark.h>
     28 
     29 /** @cond SKIP */
     30 #define SCH_DSMARK_ATTR_INDICES		0x1
     31 #define SCH_DSMARK_ATTR_DEFAULT_INDEX	0x2
     32 #define SCH_DSMARK_ATTR_SET_TC_INDEX	0x4
     33 
     34 #define SCH_DSMARK_ATTR_MASK		0x1
     35 #define SCH_DSMARK_ATTR_VALUE		0x2
     36 /** @endcond */
     37 
     38 static inline struct rtnl_dsmark_qdisc *dsmark_qdisc(struct rtnl_qdisc *qdisc)
     39 {
     40 	return (struct rtnl_dsmark_qdisc *) qdisc->q_subdata;
     41 }
     42 
     43 static inline struct rtnl_dsmark_qdisc *
     44 dsmark_qdisc_alloc(struct rtnl_qdisc *qdisc)
     45 {
     46 	if (!qdisc->q_subdata)
     47 		qdisc->q_subdata = calloc(1, sizeof(struct rtnl_dsmark_qdisc));
     48 
     49 	return dsmark_qdisc(qdisc);
     50 }
     51 
     52 static struct nla_policy dsmark_policy[TCA_DSMARK_MAX+1] = {
     53 	[TCA_DSMARK_INDICES]		= { .type = NLA_U16 },
     54 	[TCA_DSMARK_DEFAULT_INDEX]	= { .type = NLA_U16 },
     55 	[TCA_DSMARK_SET_TC_INDEX]	= { .type = NLA_FLAG },
     56 	[TCA_DSMARK_VALUE]		= { .type = NLA_U8 },
     57 	[TCA_DSMARK_MASK]		= { .type = NLA_U8 },
     58 };
     59 
     60 static int dsmark_qdisc_msg_parser(struct rtnl_qdisc *qdisc)
     61 {
     62 	int err;
     63 	struct nlattr *tb[TCA_DSMARK_MAX + 1];
     64 	struct rtnl_dsmark_qdisc *dsmark;
     65 
     66 	err = tca_parse(tb, TCA_DSMARK_MAX, (struct rtnl_tca *) qdisc,
     67 			dsmark_policy);
     68 	if (err < 0)
     69 		return err;
     70 
     71 	dsmark = dsmark_qdisc_alloc(qdisc);
     72 	if (!dsmark)
     73 		return -NLE_NOMEM;
     74 
     75 	if (tb[TCA_DSMARK_INDICES]) {
     76 		dsmark->qdm_indices = nla_get_u16(tb[TCA_DSMARK_INDICES]);
     77 		dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
     78 	}
     79 
     80 	if (tb[TCA_DSMARK_DEFAULT_INDEX]) {
     81 		dsmark->qdm_default_index =
     82 				nla_get_u16(tb[TCA_DSMARK_DEFAULT_INDEX]);
     83 		dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
     84 	}
     85 
     86 	if (tb[TCA_DSMARK_SET_TC_INDEX]) {
     87 		dsmark->qdm_set_tc_index = 1;
     88 		dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
     89 	}
     90 
     91 	return 0;
     92 }
     93 
     94 static inline struct rtnl_dsmark_class *dsmark_class(struct rtnl_class *class)
     95 {
     96 	return (struct rtnl_dsmark_class *) class->c_subdata;
     97 }
     98 
     99 static inline struct rtnl_dsmark_class *
    100 dsmark_class_alloc(struct rtnl_class *class)
    101 {
    102 	if (!class->c_subdata)
    103 		class->c_subdata = calloc(1, sizeof(struct rtnl_dsmark_class));
    104 
    105 	return dsmark_class(class);
    106 }
    107 
    108 static int dsmark_class_msg_parser(struct rtnl_class *class)
    109 {
    110 	int err;
    111 	struct nlattr *tb[TCA_DSMARK_MAX + 1];
    112 	struct rtnl_dsmark_class *dsmark;
    113 
    114 	err = tca_parse(tb, TCA_DSMARK_MAX, (struct rtnl_tca *) class,
    115 			dsmark_policy);
    116 	if (err < 0)
    117 		return err;
    118 
    119 	dsmark = dsmark_class_alloc(class);
    120 	if (!dsmark)
    121 		return -NLE_NOMEM;
    122 
    123 	if (tb[TCA_DSMARK_MASK]) {
    124 		dsmark->cdm_bmask = nla_get_u8(tb[TCA_DSMARK_MASK]);
    125 		dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
    126 	}
    127 
    128 	if (tb[TCA_DSMARK_VALUE]) {
    129 		dsmark->cdm_value = nla_get_u8(tb[TCA_DSMARK_VALUE]);
    130 		dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
    131 	}
    132 
    133 	return 0;
    134 }
    135 
    136 static void dsmark_qdisc_dump_line(struct rtnl_qdisc *qdisc,
    137 				   struct nl_dump_params *p)
    138 {
    139 	struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc);
    140 
    141 	if (dsmark && (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES))
    142 		nl_dump(p, " indices 0x%04x", dsmark->qdm_indices);
    143 }
    144 
    145 static void dsmark_qdisc_dump_details(struct rtnl_qdisc *qdisc,
    146 				      struct nl_dump_params *p)
    147 {
    148 	struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc);
    149 
    150 	if (!dsmark)
    151 		return;
    152 
    153 	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
    154 		nl_dump(p, " default index 0x%04x", dsmark->qdm_default_index);
    155 
    156 	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
    157 		nl_dump(p, " set-tc-index");
    158 }
    159 
    160 static void dsmark_class_dump_line(struct rtnl_class *class,
    161 				   struct nl_dump_params *p)
    162 {
    163 	struct rtnl_dsmark_class *dsmark = dsmark_class(class);
    164 
    165 	if (!dsmark)
    166 		return;
    167 
    168 	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
    169 		nl_dump(p, " value 0x%02x", dsmark->cdm_value);
    170 
    171 	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
    172 		nl_dump(p, " mask 0x%02x", dsmark->cdm_bmask);
    173 }
    174 
    175 static struct nl_msg *dsmark_qdisc_get_opts(struct rtnl_qdisc *qdisc)
    176 {
    177 	struct rtnl_dsmark_qdisc *dsmark = dsmark_qdisc(qdisc);
    178 	struct nl_msg *msg;
    179 
    180 	if (!dsmark)
    181 		return NULL;
    182 
    183 	msg = nlmsg_alloc();
    184 	if (!msg)
    185 		goto nla_put_failure;
    186 
    187 	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
    188 		NLA_PUT_U16(msg, TCA_DSMARK_INDICES, dsmark->qdm_indices);
    189 
    190 	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
    191 		NLA_PUT_U16(msg, TCA_DSMARK_DEFAULT_INDEX,
    192 			    dsmark->qdm_default_index);
    193 
    194 	if (dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
    195 		NLA_PUT_FLAG(msg, TCA_DSMARK_SET_TC_INDEX);
    196 
    197 	return msg;
    198 
    199 nla_put_failure:
    200 	nlmsg_free(msg);
    201 	return NULL;
    202 }
    203 
    204 static struct nl_msg *dsmark_class_get_opts(struct rtnl_class *class)
    205 {
    206 	struct rtnl_dsmark_class *dsmark = dsmark_class(class);
    207 	struct nl_msg *msg;
    208 
    209 	if (!dsmark)
    210 		return NULL;
    211 
    212 	msg = nlmsg_alloc();
    213 	if (!msg)
    214 		goto nla_put_failure;
    215 
    216 	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
    217 		NLA_PUT_U8(msg, TCA_DSMARK_MASK, dsmark->cdm_bmask);
    218 
    219 	if (dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
    220 		NLA_PUT_U8(msg, TCA_DSMARK_VALUE, dsmark->cdm_value);
    221 
    222 	return msg;
    223 
    224 nla_put_failure:
    225 	nlmsg_free(msg);
    226 	return NULL;
    227 }
    228 
    229 /**
    230  * @name Class Attribute Access
    231  * @{
    232  */
    233 
    234 /**
    235  * Set bitmask of DSMARK class.
    236  * @arg class		DSMARK class to be modified.
    237  * @arg mask		New bitmask.
    238  * @return 0 on success or a negative error code.
    239  */
    240 int rtnl_class_dsmark_set_bitmask(struct rtnl_class *class, uint8_t mask)
    241 {
    242 	struct rtnl_dsmark_class *dsmark;
    243 
    244 	dsmark = dsmark_class(class);
    245 	if (!dsmark)
    246 		return -NLE_NOMEM;
    247 
    248 	dsmark->cdm_bmask = mask;
    249 	dsmark->cdm_mask |= SCH_DSMARK_ATTR_MASK;
    250 
    251 	return 0;
    252 }
    253 
    254 /**
    255  * Get bitmask of DSMARK class.
    256  * @arg class		DSMARK class.
    257  * @return Bitmask or a negative error code.
    258  */
    259 int rtnl_class_dsmark_get_bitmask(struct rtnl_class *class)
    260 {
    261 	struct rtnl_dsmark_class *dsmark;
    262 
    263 	dsmark = dsmark_class(class);
    264 	if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_MASK)
    265 		return dsmark->cdm_bmask;
    266 	else
    267 		return -NLE_NOATTR;
    268 }
    269 
    270 /**
    271  * Set value of DSMARK class.
    272  * @arg class		DSMARK class to be modified.
    273  * @arg value		New value.
    274  * @return 0 on success or a negative errror code.
    275  */
    276 int rtnl_class_dsmark_set_value(struct rtnl_class *class, uint8_t value)
    277 {
    278 	struct rtnl_dsmark_class *dsmark;
    279 
    280 	dsmark = dsmark_class(class);
    281 	if (!dsmark)
    282 		return -NLE_NOMEM;
    283 
    284 	dsmark->cdm_value = value;
    285 	dsmark->cdm_mask |= SCH_DSMARK_ATTR_VALUE;
    286 
    287 	return 0;
    288 }
    289 
    290 /**
    291  * Get value of DSMARK class.
    292  * @arg class		DSMARK class.
    293  * @return Value or a negative error code.
    294  */
    295 int rtnl_class_dsmark_get_value(struct rtnl_class *class)
    296 {
    297 	struct rtnl_dsmark_class *dsmark;
    298 
    299 	dsmark = dsmark_class(class);
    300 	if (dsmark && dsmark->cdm_mask & SCH_DSMARK_ATTR_VALUE)
    301 		return dsmark->cdm_value;
    302 	else
    303 		return -NLE_NOATTR;
    304 }
    305 
    306 /** @} */
    307 
    308 /**
    309  * @name Qdisc Attribute Access
    310  * @{
    311  */
    312 
    313 /**
    314  * Set indices of DSMARK qdisc.
    315  * @arg qdisc		DSMARK qdisc to be modified.
    316  * @arg indices		New indices.
    317  */
    318 int rtnl_qdisc_dsmark_set_indices(struct rtnl_qdisc *qdisc, uint16_t indices)
    319 {
    320 	struct rtnl_dsmark_qdisc *dsmark;
    321 
    322 	dsmark = dsmark_qdisc(qdisc);
    323 	if (!dsmark)
    324 		return -NLE_NOMEM;
    325 
    326 	dsmark->qdm_indices = indices;
    327 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_INDICES;
    328 
    329 	return 0;
    330 }
    331 
    332 /**
    333  * Get indices of DSMARK qdisc.
    334  * @arg qdisc		DSMARK qdisc.
    335  * @return Indices or a negative error code.
    336  */
    337 int rtnl_qdisc_dsmark_get_indices(struct rtnl_qdisc *qdisc)
    338 {
    339 	struct rtnl_dsmark_qdisc *dsmark;
    340 
    341 	dsmark = dsmark_qdisc(qdisc);
    342 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_INDICES)
    343 		return dsmark->qdm_indices;
    344 	else
    345 		return -NLE_NOATTR;
    346 }
    347 
    348 /**
    349  * Set default index of DSMARK qdisc.
    350  * @arg qdisc		DSMARK qdisc to be modified.
    351  * @arg default_index	New default index.
    352  * @return 0 on success or a negative error code.
    353  */
    354 int rtnl_qdisc_dsmark_set_default_index(struct rtnl_qdisc *qdisc,
    355 					uint16_t default_index)
    356 {
    357 	struct rtnl_dsmark_qdisc *dsmark;
    358 
    359 	dsmark = dsmark_qdisc(qdisc);
    360 	if (!dsmark)
    361 		return -NLE_NOMEM;
    362 
    363 	dsmark->qdm_default_index = default_index;
    364 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_DEFAULT_INDEX;
    365 
    366 	return 0;
    367 }
    368 
    369 /**
    370  * Get default index of DSMARK qdisc.
    371  * @arg qdisc		DSMARK qdisc.
    372  * @return Default index or a negative error code.
    373  */
    374 int rtnl_qdisc_dsmark_get_default_index(struct rtnl_qdisc *qdisc)
    375 {
    376 	struct rtnl_dsmark_qdisc *dsmark;
    377 
    378 	dsmark = dsmark_qdisc(qdisc);
    379 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_DEFAULT_INDEX)
    380 		return dsmark->qdm_default_index;
    381 	else
    382 		return -NLE_NOATTR;
    383 }
    384 
    385 /**
    386  * Set set-tc-index flag of DSMARK qdisc.
    387  * @arg qdisc		DSMARK qdisc to be modified.
    388  * @arg flag		Flag indicating whether to enable or disable.
    389  * @return 0 on success or a negative error code.
    390  */
    391 int rtnl_qdisc_dsmark_set_set_tc_index(struct rtnl_qdisc *qdisc, int flag)
    392 {
    393 	struct rtnl_dsmark_qdisc *dsmark;
    394 
    395 	dsmark = dsmark_qdisc(qdisc);
    396 	if (!dsmark)
    397 		return -NLE_NOMEM;
    398 
    399 	dsmark->qdm_set_tc_index = !!flag;
    400 	dsmark->qdm_mask |= SCH_DSMARK_ATTR_SET_TC_INDEX;
    401 
    402 	return 0;
    403 }
    404 
    405 /**
    406  * Get set-tc-index flag of DSMARK qdisc.
    407  * @arg qdisc		DSMARK qdisc to be modified.
    408  * @return 1 or 0 to indicate wehther the flag is enabled or a negative
    409  *         error code.
    410  */
    411 int rtnl_qdisc_dsmark_get_set_tc_index(struct rtnl_qdisc *qdisc)
    412 {
    413 	struct rtnl_dsmark_qdisc *dsmark;
    414 
    415 	dsmark = dsmark_qdisc(qdisc);
    416 	if (dsmark && dsmark->qdm_mask & SCH_DSMARK_ATTR_SET_TC_INDEX)
    417 		return dsmark->qdm_set_tc_index;
    418 	else
    419 		return -NLE_NOATTR;
    420 }
    421 
    422 /** @} */
    423 
    424 static struct rtnl_qdisc_ops dsmark_qdisc_ops = {
    425 	.qo_kind		= "dsmark",
    426 	.qo_msg_parser		= dsmark_qdisc_msg_parser,
    427 	.qo_dump = {
    428 	    [NL_DUMP_LINE]	= dsmark_qdisc_dump_line,
    429 	    [NL_DUMP_DETAILS]	= dsmark_qdisc_dump_details,
    430 	},
    431 	.qo_get_opts		= dsmark_qdisc_get_opts,
    432 };
    433 
    434 static struct rtnl_class_ops dsmark_class_ops = {
    435 	.co_kind		= "dsmark",
    436 	.co_msg_parser		= dsmark_class_msg_parser,
    437 	.co_dump[NL_DUMP_LINE]	= dsmark_class_dump_line,
    438 	.co_get_opts		= dsmark_class_get_opts,
    439 };
    440 
    441 static void __init dsmark_init(void)
    442 {
    443 	rtnl_qdisc_register(&dsmark_qdisc_ops);
    444 	rtnl_class_register(&dsmark_class_ops);
    445 }
    446 
    447 static void __exit dsmark_exit(void)
    448 {
    449 	rtnl_qdisc_unregister(&dsmark_qdisc_ops);
    450 	rtnl_class_unregister(&dsmark_class_ops);
    451 }
    452 
    453 /** @} */
    454