1/* Copyright (C) 2013 Cisco Systems, Inc, 2013. 2 * 3 * This program is free software; you can redistribute it and/or 4 * modify it under the terms of the GNU General Public License 5 * as published by the Free Software Foundation; either version 2 6 * of the License. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * Author: Vijay Subramanian <vijaynsu@cisco.com> 14 * Author: Mythili Prabhu <mysuryan@cisco.com> 15 * 16 */ 17 18#include <stdio.h> 19#include <stdlib.h> 20#include <unistd.h> 21#include <syslog.h> 22#include <fcntl.h> 23#include <sys/socket.h> 24#include <netinet/in.h> 25#include <arpa/inet.h> 26#include <string.h> 27#include <math.h> 28 29#include "utils.h" 30#include "tc_util.h" 31 32static void explain(void) 33{ 34 fprintf(stderr, "Usage: ... pie [ limit PACKETS ][ target TIME us]\n"); 35 fprintf(stderr, " [ tupdate TIME us][ alpha ALPHA ]"); 36 fprintf(stderr, "[beta BETA ][bytemode | nobytemode][ecn | noecn ]\n"); 37} 38 39#define ALPHA_MAX 32 40#define BETA_MAX 32 41 42static int pie_parse_opt(struct qdisc_util *qu, int argc, char **argv, 43 struct nlmsghdr *n) 44{ 45 unsigned int limit = 0; 46 unsigned int target = 0; 47 unsigned int tupdate = 0; 48 unsigned int alpha = 0; 49 unsigned int beta = 0; 50 int ecn = -1; 51 int bytemode = -1; 52 struct rtattr *tail; 53 54 while (argc > 0) { 55 if (strcmp(*argv, "limit") == 0) { 56 NEXT_ARG(); 57 if (get_unsigned(&limit, *argv, 0)) { 58 fprintf(stderr, "Illegal \"limit\"\n"); 59 return -1; 60 } 61 } else if (strcmp(*argv, "target") == 0) { 62 NEXT_ARG(); 63 if (get_time(&target, *argv)) { 64 fprintf(stderr, "Illegal \"target\"\n"); 65 return -1; 66 } 67 } else if (strcmp(*argv, "tupdate") == 0) { 68 NEXT_ARG(); 69 if (get_time(&tupdate, *argv)) { 70 fprintf(stderr, "Illegal \"tupdate\"\n"); 71 return -1; 72 } 73 } else if (strcmp(*argv, "alpha") == 0) { 74 NEXT_ARG(); 75 if (get_unsigned(&alpha, *argv, 0) || 76 (alpha > ALPHA_MAX)) { 77 fprintf(stderr, "Illegal \"alpha\"\n"); 78 return -1; 79 } 80 } else if (strcmp(*argv, "beta") == 0) { 81 NEXT_ARG(); 82 if (get_unsigned(&beta, *argv, 0) || 83 (beta > BETA_MAX)) { 84 fprintf(stderr, "Illegal \"beta\"\n"); 85 return -1; 86 } 87 } else if (strcmp(*argv, "ecn") == 0) { 88 ecn = 1; 89 } else if (strcmp(*argv, "noecn") == 0) { 90 ecn = 0; 91 } else if (strcmp(*argv, "bytemode") == 0) { 92 bytemode = 1; 93 } else if (strcmp(*argv, "nobytemode") == 0) { 94 bytemode = 0; 95 } else if (strcmp(*argv, "help") == 0) { 96 explain(); 97 return -1; 98 } else { 99 fprintf(stderr, "What is \"%s\"?\n", *argv); 100 explain(); 101 return -1; 102 } 103 argc--; 104 argv++; 105 } 106 107 tail = NLMSG_TAIL(n); 108 addattr_l(n, 1024, TCA_OPTIONS, NULL, 0); 109 if (limit) 110 addattr_l(n, 1024, TCA_PIE_LIMIT, &limit, sizeof(limit)); 111 if (tupdate) 112 addattr_l(n, 1024, TCA_PIE_TUPDATE, &tupdate, sizeof(tupdate)); 113 if (target) 114 addattr_l(n, 1024, TCA_PIE_TARGET, &target, sizeof(target)); 115 if (alpha) 116 addattr_l(n, 1024, TCA_PIE_ALPHA, &alpha, sizeof(alpha)); 117 if (beta) 118 addattr_l(n, 1024, TCA_PIE_BETA, &beta, sizeof(beta)); 119 if (ecn != -1) 120 addattr_l(n, 1024, TCA_PIE_ECN, &ecn, sizeof(ecn)); 121 if (bytemode != -1) 122 addattr_l(n, 1024, TCA_PIE_BYTEMODE, &bytemode, 123 sizeof(bytemode)); 124 125 tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; 126 return 0; 127} 128 129static int pie_print_opt(struct qdisc_util *qu, FILE *f, struct rtattr *opt) 130{ 131 struct rtattr *tb[TCA_PIE_MAX + 1]; 132 unsigned int limit; 133 unsigned int tupdate; 134 unsigned int target; 135 unsigned int alpha; 136 unsigned int beta; 137 unsigned int ecn; 138 unsigned int bytemode; 139 140 SPRINT_BUF(b1); 141 142 if (opt == NULL) 143 return 0; 144 145 parse_rtattr_nested(tb, TCA_PIE_MAX, opt); 146 147 if (tb[TCA_PIE_LIMIT] && 148 RTA_PAYLOAD(tb[TCA_PIE_LIMIT]) >= sizeof(__u32)) { 149 limit = rta_getattr_u32(tb[TCA_PIE_LIMIT]); 150 fprintf(f, "limit %up ", limit); 151 } 152 if (tb[TCA_PIE_TARGET] && 153 RTA_PAYLOAD(tb[TCA_PIE_TARGET]) >= sizeof(__u32)) { 154 target = rta_getattr_u32(tb[TCA_PIE_TARGET]); 155 fprintf(f, "target %s ", sprint_time(target, b1)); 156 } 157 if (tb[TCA_PIE_TUPDATE] && 158 RTA_PAYLOAD(tb[TCA_PIE_TUPDATE]) >= sizeof(__u32)) { 159 tupdate = rta_getattr_u32(tb[TCA_PIE_TUPDATE]); 160 fprintf(f, "tupdate %s ", sprint_time(tupdate, b1)); 161 } 162 if (tb[TCA_PIE_ALPHA] && 163 RTA_PAYLOAD(tb[TCA_PIE_ALPHA]) >= sizeof(__u32)) { 164 alpha = rta_getattr_u32(tb[TCA_PIE_ALPHA]); 165 fprintf(f, "alpha %u ", alpha); 166 } 167 if (tb[TCA_PIE_BETA] && 168 RTA_PAYLOAD(tb[TCA_PIE_BETA]) >= sizeof(__u32)) { 169 beta = rta_getattr_u32(tb[TCA_PIE_BETA]); 170 fprintf(f, "beta %u ", beta); 171 } 172 173 if (tb[TCA_PIE_ECN] && RTA_PAYLOAD(tb[TCA_PIE_ECN]) >= sizeof(__u32)) { 174 ecn = rta_getattr_u32(tb[TCA_PIE_ECN]); 175 if (ecn) 176 fprintf(f, "ecn "); 177 } 178 179 if (tb[TCA_PIE_BYTEMODE] && 180 RTA_PAYLOAD(tb[TCA_PIE_BYTEMODE]) >= sizeof(__u32)) { 181 bytemode = rta_getattr_u32(tb[TCA_PIE_BYTEMODE]); 182 if (bytemode) 183 fprintf(f, "bytemode "); 184 } 185 186 return 0; 187} 188 189static int pie_print_xstats(struct qdisc_util *qu, FILE *f, 190 struct rtattr *xstats) 191{ 192 struct tc_pie_xstats *st; 193 194 if (xstats == NULL) 195 return 0; 196 197 if (RTA_PAYLOAD(xstats) < sizeof(*st)) 198 return -1; 199 200 st = RTA_DATA(xstats); 201 /*prob is returned as a fracion of maximum integer value */ 202 fprintf(f, "prob %f delay %uus avg_dq_rate %u\n", 203 (double)st->prob / (double)0xffffffff, st->delay, 204 st->avg_dq_rate); 205 fprintf(f, "pkts_in %u overlimit %u dropped %u maxq %u ecn_mark %u\n", 206 st->packets_in, st->overlimit, st->dropped, st->maxq, 207 st->ecn_mark); 208 return 0; 209 210} 211 212struct qdisc_util pie_qdisc_util = { 213 .id = "pie", 214 .parse_qopt = pie_parse_opt, 215 .print_qopt = pie_print_opt, 216 .print_xstats = pie_print_xstats, 217}; 218