Home | History | Annotate | Download | only in tc
      1 /*
      2  * m_sample.c		ingress/egress packet sampling module
      3  *
      4  *		This program is free software; you can distribute it and/or
      5  *		modify it under the terms of the GNU General Public License
      6  *		as published by the Free Software Foundation; either version
      7  *		2 of the License, or (at your option) any later version.
      8  *
      9  * Authors:	Yotam Gigi <yotamg (at) mellanox.com>
     10  *
     11  */
     12 
     13 #include <stdio.h>
     14 #include "utils.h"
     15 #include "tc_util.h"
     16 #include "tc_common.h"
     17 #include <linux/tc_act/tc_sample.h>
     18 
     19 static void explain(void)
     20 {
     21 	fprintf(stderr, "Usage: sample SAMPLE_CONF\n");
     22 	fprintf(stderr, "where:\n");
     23 	fprintf(stderr, "\tSAMPLE_CONF := SAMPLE_PARAMS | SAMPLE_INDEX\n");
     24 	fprintf(stderr, "\tSAMPLE_PARAMS := rate RATE group GROUP [trunc SIZE] [SAMPLE_INDEX]\n");
     25 	fprintf(stderr, "\tSAMPLE_INDEX := index INDEX\n");
     26 	fprintf(stderr, "\tRATE := The ratio of packets observed at the data source to the samples generated.\n");
     27 	fprintf(stderr, "\tGROUP := the psample sampling group\n");
     28 	fprintf(stderr, "\tSIZE := the truncation size\n");
     29 	fprintf(stderr, "\tINDEX := integer index of the sample action\n");
     30 }
     31 
     32 static void usage(void)
     33 {
     34 	explain();
     35 	exit(-1);
     36 }
     37 
     38 static int parse_sample(struct action_util *a, int *argc_p, char ***argv_p,
     39 			int tca_id, struct nlmsghdr *n)
     40 {
     41 	struct tc_sample p = { 0 };
     42 	bool trunc_set = false;
     43 	bool group_set = false;
     44 	bool rate_set = false;
     45 	char **argv = *argv_p;
     46 	struct rtattr *tail;
     47 	int argc = *argc_p;
     48 	__u32 trunc;
     49 	__u32 group;
     50 	__u32 rate;
     51 
     52 	if (argc <= 1) {
     53 		fprintf(stderr, "sample bad argument count %d\n", argc);
     54 		usage();
     55 		return -1;
     56 	}
     57 
     58 	if (matches(*argv, "sample") == 0) {
     59 		NEXT_ARG();
     60 	} else {
     61 		fprintf(stderr, "sample bad argument %s\n", *argv);
     62 		return -1;
     63 	}
     64 
     65 	while (argc > 0) {
     66 		if (matches(*argv, "rate") == 0) {
     67 			NEXT_ARG();
     68 			if (get_unsigned(&rate, *argv, 10) != 0) {
     69 				fprintf(stderr, "Illegal rate %s\n", *argv);
     70 				usage();
     71 				return -1;
     72 			}
     73 			rate_set = true;
     74 		} else if (matches(*argv, "group") == 0) {
     75 			NEXT_ARG();
     76 			if (get_unsigned(&group, *argv, 10) != 0) {
     77 				fprintf(stderr, "Illegal group num %s\n",
     78 					*argv);
     79 				usage();
     80 				return -1;
     81 			}
     82 			group_set = true;
     83 		} else if (matches(*argv, "trunc") == 0) {
     84 			NEXT_ARG();
     85 			if (get_unsigned(&trunc, *argv, 10) != 0) {
     86 				fprintf(stderr, "Illegal truncation size %s\n",
     87 					*argv);
     88 				usage();
     89 				return -1;
     90 			}
     91 			trunc_set = true;
     92 		} else if (matches(*argv, "help") == 0) {
     93 			usage();
     94 		} else {
     95 			break;
     96 		}
     97 
     98 		NEXT_ARG_FWD();
     99 	}
    100 
    101 	parse_action_control_dflt(&argc, &argv, &p.action, false, TC_ACT_PIPE);
    102 
    103 	if (argc) {
    104 		if (matches(*argv, "index") == 0) {
    105 			NEXT_ARG();
    106 			if (get_u32(&p.index, *argv, 10)) {
    107 				fprintf(stderr, "sample: Illegal \"index\"\n");
    108 				return -1;
    109 			}
    110 			NEXT_ARG_FWD();
    111 		}
    112 	}
    113 
    114 	if (!p.index && !group_set) {
    115 		fprintf(stderr, "param \"group\" not set\n");
    116 		usage();
    117 	}
    118 
    119 	if (!p.index && !rate_set) {
    120 		fprintf(stderr, "param \"rate\" not set\n");
    121 		usage();
    122 	}
    123 
    124 	tail = NLMSG_TAIL(n);
    125 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    126 	addattr_l(n, MAX_MSG, TCA_SAMPLE_PARMS, &p, sizeof(p));
    127 	if (rate_set)
    128 		addattr32(n, MAX_MSG, TCA_SAMPLE_RATE, rate);
    129 	if (group_set)
    130 		addattr32(n, MAX_MSG, TCA_SAMPLE_PSAMPLE_GROUP, group);
    131 	if (trunc_set)
    132 		addattr32(n, MAX_MSG, TCA_SAMPLE_TRUNC_SIZE, trunc);
    133 
    134 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
    135 
    136 	*argc_p = argc;
    137 	*argv_p = argv;
    138 	return 0;
    139 }
    140 
    141 static int print_sample(struct action_util *au, FILE *f, struct rtattr *arg)
    142 {
    143 	struct rtattr *tb[TCA_SAMPLE_MAX + 1];
    144 	struct tc_sample *p;
    145 
    146 	if (arg == NULL)
    147 		return -1;
    148 
    149 	parse_rtattr_nested(tb, TCA_SAMPLE_MAX, arg);
    150 
    151 	if (!tb[TCA_SAMPLE_PARMS] || !tb[TCA_SAMPLE_RATE] ||
    152 	    !tb[TCA_SAMPLE_PSAMPLE_GROUP]) {
    153 		fprintf(f, "[NULL sample parameters]");
    154 		return -1;
    155 	}
    156 	p = RTA_DATA(tb[TCA_SAMPLE_PARMS]);
    157 
    158 	fprintf(f, "sample rate 1/%d group %d",
    159 		rta_getattr_u32(tb[TCA_SAMPLE_RATE]),
    160 		rta_getattr_u32(tb[TCA_SAMPLE_PSAMPLE_GROUP]));
    161 
    162 	if (tb[TCA_SAMPLE_TRUNC_SIZE])
    163 		fprintf(f, " trunc_size %d",
    164 			rta_getattr_u32(tb[TCA_SAMPLE_TRUNC_SIZE]));
    165 
    166 	fprintf(f, "\n\tindex %d ref %d bind %d", p->index, p->refcnt,
    167 		p->bindcnt);
    168 
    169 	if (show_stats) {
    170 		if (tb[TCA_SAMPLE_TM]) {
    171 			struct tcf_t *tm = RTA_DATA(tb[TCA_SAMPLE_TM]);
    172 
    173 			print_tm(f, tm);
    174 		}
    175 	}
    176 	fprintf(f, "\n");
    177 	return 0;
    178 }
    179 
    180 struct action_util sample_action_util = {
    181 	.id = "sample",
    182 	.parse_aopt = parse_sample,
    183 	.print_aopt = print_sample,
    184 };
    185