1 /* 2 * m_skbedit.c SKB Editing module 3 * 4 * Copyright (c) 2008, Intel Corporation. 5 * 6 * This program is free software; you can redistribute it and/or modify it 7 * under the terms and conditions of the GNU General Public License, 8 * version 2, as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope it will be useful, but WITHOUT 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 13 * more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, see <http://www.gnu.org/licenses>. 17 * 18 * Authors: Alexander Duyck <alexander.h.duyck (at) intel.com> 19 * 20 */ 21 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <string.h> 26 #include "utils.h" 27 #include "tc_util.h" 28 #include <linux/tc_act/tc_skbedit.h> 29 #include <linux/if_packet.h> 30 31 static void explain(void) 32 { 33 fprintf(stderr, "Usage: ... skbedit <[QM] [PM] [MM] [PT]>\n" 34 "QM = queue_mapping QUEUE_MAPPING\n" 35 "PM = priority PRIORITY\n" 36 "MM = mark MARK\n" 37 "PT = ptype PACKETYPE\n" 38 "PACKETYPE = is one of:\n" 39 " host, otherhost, broadcast, multicast\n" 40 "QUEUE_MAPPING = device transmit queue to use\n" 41 "PRIORITY = classID to assign to priority field\n" 42 "MARK = firewall mark to set\n"); 43 } 44 45 static void 46 usage(void) 47 { 48 explain(); 49 exit(-1); 50 } 51 52 static int 53 parse_skbedit(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, 54 struct nlmsghdr *n) 55 { 56 int argc = *argc_p; 57 char **argv = *argv_p; 58 int ok = 0; 59 struct rtattr *tail; 60 unsigned int tmp; 61 __u16 queue_mapping, ptype; 62 __u32 flags = 0, priority, mark; 63 struct tc_skbedit sel = { 0 }; 64 65 if (matches(*argv, "skbedit") != 0) 66 return -1; 67 68 NEXT_ARG(); 69 70 while (argc > 0) { 71 if (matches(*argv, "queue_mapping") == 0) { 72 flags |= SKBEDIT_F_QUEUE_MAPPING; 73 NEXT_ARG(); 74 if (get_unsigned(&tmp, *argv, 10) || tmp > 65535) { 75 fprintf(stderr, "Illegal queue_mapping\n"); 76 return -1; 77 } 78 queue_mapping = tmp; 79 ok++; 80 } else if (matches(*argv, "priority") == 0) { 81 flags |= SKBEDIT_F_PRIORITY; 82 NEXT_ARG(); 83 if (get_tc_classid(&priority, *argv)) { 84 fprintf(stderr, "Illegal priority\n"); 85 return -1; 86 } 87 ok++; 88 } else if (matches(*argv, "mark") == 0) { 89 flags |= SKBEDIT_F_MARK; 90 NEXT_ARG(); 91 if (get_u32(&mark, *argv, 0)) { 92 fprintf(stderr, "Illegal mark\n"); 93 return -1; 94 } 95 ok++; 96 } else if (matches(*argv, "ptype") == 0) { 97 98 NEXT_ARG(); 99 if (matches(*argv, "host") == 0) { 100 ptype = PACKET_HOST; 101 } else if (matches(*argv, "broadcast") == 0) { 102 ptype = PACKET_BROADCAST; 103 } else if (matches(*argv, "multicast") == 0) { 104 ptype = PACKET_MULTICAST; 105 } else if (matches(*argv, "otherhost") == 0) { 106 ptype = PACKET_OTHERHOST; 107 } else { 108 fprintf(stderr, "Illegal ptype (%s)\n", 109 *argv); 110 return -1; 111 } 112 flags |= SKBEDIT_F_PTYPE; 113 ok++; 114 } else if (matches(*argv, "help") == 0) { 115 usage(); 116 } else { 117 break; 118 } 119 argc--; 120 argv++; 121 } 122 123 parse_action_control_dflt(&argc, &argv, &sel.action, 124 false, TC_ACT_PIPE); 125 126 if (argc) { 127 if (matches(*argv, "index") == 0) { 128 NEXT_ARG(); 129 if (get_u32(&sel.index, *argv, 10)) { 130 fprintf(stderr, "Pedit: Illegal \"index\"\n"); 131 return -1; 132 } 133 argc--; 134 argv++; 135 ok++; 136 } 137 } 138 139 if (!ok) { 140 explain(); 141 return -1; 142 } 143 144 145 tail = NLMSG_TAIL(n); 146 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 147 addattr_l(n, MAX_MSG, TCA_SKBEDIT_PARMS, &sel, sizeof(sel)); 148 if (flags & SKBEDIT_F_QUEUE_MAPPING) 149 addattr_l(n, MAX_MSG, TCA_SKBEDIT_QUEUE_MAPPING, 150 &queue_mapping, sizeof(queue_mapping)); 151 if (flags & SKBEDIT_F_PRIORITY) 152 addattr_l(n, MAX_MSG, TCA_SKBEDIT_PRIORITY, 153 &priority, sizeof(priority)); 154 if (flags & SKBEDIT_F_MARK) 155 addattr_l(n, MAX_MSG, TCA_SKBEDIT_MARK, 156 &mark, sizeof(mark)); 157 if (flags & SKBEDIT_F_PTYPE) 158 addattr_l(n, MAX_MSG, TCA_SKBEDIT_PTYPE, 159 &ptype, sizeof(ptype)); 160 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 161 162 *argc_p = argc; 163 *argv_p = argv; 164 return 0; 165 } 166 167 static int print_skbedit(struct action_util *au, FILE *f, struct rtattr *arg) 168 { 169 struct rtattr *tb[TCA_SKBEDIT_MAX + 1]; 170 171 SPRINT_BUF(b1); 172 __u32 *priority; 173 __u32 *mark; 174 __u16 *queue_mapping, *ptype; 175 struct tc_skbedit *p = NULL; 176 177 if (arg == NULL) 178 return -1; 179 180 parse_rtattr_nested(tb, TCA_SKBEDIT_MAX, arg); 181 182 if (tb[TCA_SKBEDIT_PARMS] == NULL) { 183 fprintf(f, "[NULL skbedit parameters]"); 184 return -1; 185 } 186 p = RTA_DATA(tb[TCA_SKBEDIT_PARMS]); 187 188 fprintf(f, " skbedit"); 189 190 if (tb[TCA_SKBEDIT_QUEUE_MAPPING] != NULL) { 191 queue_mapping = RTA_DATA(tb[TCA_SKBEDIT_QUEUE_MAPPING]); 192 fprintf(f, " queue_mapping %u", *queue_mapping); 193 } 194 if (tb[TCA_SKBEDIT_PRIORITY] != NULL) { 195 priority = RTA_DATA(tb[TCA_SKBEDIT_PRIORITY]); 196 fprintf(f, " priority %s", sprint_tc_classid(*priority, b1)); 197 } 198 if (tb[TCA_SKBEDIT_MARK] != NULL) { 199 mark = RTA_DATA(tb[TCA_SKBEDIT_MARK]); 200 fprintf(f, " mark %d", *mark); 201 } 202 if (tb[TCA_SKBEDIT_PTYPE] != NULL) { 203 ptype = RTA_DATA(tb[TCA_SKBEDIT_PTYPE]); 204 if (*ptype == PACKET_HOST) 205 fprintf(f, " ptype host"); 206 else if (*ptype == PACKET_BROADCAST) 207 fprintf(f, " ptype broadcast"); 208 else if (*ptype == PACKET_MULTICAST) 209 fprintf(f, " ptype multicast"); 210 else if (*ptype == PACKET_OTHERHOST) 211 fprintf(f, " ptype otherhost"); 212 else 213 fprintf(f, " ptype %d", *ptype); 214 } 215 216 print_action_control(f, " ", p->action, ""); 217 218 fprintf(f, "\n\t index %u ref %d bind %d", 219 p->index, p->refcnt, p->bindcnt); 220 221 if (show_stats) { 222 if (tb[TCA_SKBEDIT_TM]) { 223 struct tcf_t *tm = RTA_DATA(tb[TCA_SKBEDIT_TM]); 224 225 print_tm(f, tm); 226 } 227 } 228 229 fprintf(f, "\n "); 230 231 return 0; 232 } 233 234 struct action_util skbedit_action_util = { 235 .id = "skbedit", 236 .parse_aopt = parse_skbedit, 237 .print_aopt = print_skbedit, 238 }; 239