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