Home | History | Annotate | Download | only in tc
      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