Home | History | Annotate | Download | only in tc
      1 /*
      2  * m_simple.c	simple action
      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:	J Hadi Salim <jhs (at) mojatatu.com>
     10  *
     11  * Pedagogical example. Adds a string that will be printed every time
     12  * the simple instance is hit.
     13  * Use this as a skeleton action and keep modifying it to meet your needs.
     14  * Look at linux/tc_act/tc_defact.h for the different components ids and
     15  * definitions used in  this actions
     16  *
     17  * example use, yell "Incoming ICMP!" every time you see an incoming ICMP on
     18  * eth0. Steps are:
     19  * 1) Add an ingress qdisc point to eth0
     20  * 2) Start a chain on ingress of eth0 that first matches ICMP then invokes
     21  *    the simple action to shout.
     22  * 3) display stats and show that no packet has been seen by the action
     23  * 4) Send one ping packet to google (expect to receive a response back)
     24  * 5) grep the logs to see the logged message
     25  * 6) display stats again and observe increment by 1
     26  *
     27   hadi@noma1:$ tc qdisc add dev eth0 ingress
     28   hadi@noma1:$tc filter add dev eth0 parent ffff: protocol ip prio 5 \
     29 	 u32 match ip protocol 1 0xff flowid 1:1 action simple "Incoming ICMP"
     30 
     31   hadi@noma1:$ sudo tc -s filter ls  dev eth0 parent ffff:
     32    filter protocol ip pref 5 u32
     33    filter protocol ip pref 5 u32 fh 800: ht divisor 1
     34    filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
     35      match 00010000/00ff0000 at 8
     36 	action order 1: Simple <Incoming ICMP>
     37 	 index 4 ref 1 bind 1 installed 29 sec used 29 sec
     38 	 Action statistics:
     39 		Sent 0 bytes 0 pkt (dropped 0, overlimits 0 requeues 0)
     40 		backlog 0b 0p requeues 0
     41 
     42 
     43   hadi@noma1$ ping -c 1 www.google.ca
     44   PING www.google.ca (74.125.225.120) 56(84) bytes of data.
     45   64 bytes from ord08s08-in-f24.1e100.net (74.125.225.120): icmp_req=1 ttl=53 time=31.3 ms
     46 
     47   --- www.google.ca ping statistics ---
     48   1 packets transmitted, 1 received, 0% packet loss, time 0ms
     49   rtt min/avg/max/mdev = 31.316/31.316/31.316/0.000 ms
     50 
     51   hadi@noma1$ dmesg | grep simple
     52   [135354.473951] simple: Incoming ICMP_1
     53 
     54   hadi@noma1$ sudo tc/tc -s filter ls  dev eth0 parent ffff:
     55   filter protocol ip pref 5 u32
     56   filter protocol ip pref 5 u32 fh 800: ht divisor 1
     57   filter protocol ip pref 5 u32 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1:1
     58     match 00010000/00ff0000 at 8
     59 	action order 1: Simple <Incoming ICMP>
     60 	 index 4 ref 1 bind 1 installed 206 sec used 67 sec
     61 	Action statistics:
     62 	Sent 84 bytes 1 pkt (dropped 0, overlimits 0 requeues 0)
     63 	backlog 0b 0p requeues 0
     64 */
     65 
     66 #include <stdio.h>
     67 #include <stdlib.h>
     68 #include <unistd.h>
     69 #include <syslog.h>
     70 #include <fcntl.h>
     71 #include <sys/socket.h>
     72 #include <netinet/in.h>
     73 #include <arpa/inet.h>
     74 #include <string.h>
     75 #include "utils.h"
     76 #include "tc_util.h"
     77 #include <linux/tc_act/tc_defact.h>
     78 
     79 #ifndef SIMP_MAX_DATA
     80 #define SIMP_MAX_DATA   32
     81 #endif
     82 static void explain(void)
     83 {
     84 	fprintf(stderr, "Usage:... simple [sdata STRING] [index INDEX] [CONTROL]\n");
     85 	fprintf(stderr, "\tSTRING being an arbitrary string\n"
     86 		"\tINDEX := optional index value used\n"
     87 		"\tCONTROL := reclassify|pipe|drop|continue|ok\n");
     88 }
     89 
     90 static void usage(void)
     91 {
     92 	explain();
     93 	exit(-1);
     94 }
     95 
     96 static int
     97 parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
     98 	     struct nlmsghdr *n)
     99 {
    100 	struct tc_defact sel = {};
    101 	int argc = *argc_p;
    102 	char **argv = *argv_p;
    103 	int ok = 0;
    104 	struct rtattr *tail;
    105 	char *simpdata = NULL;
    106 
    107 	while (argc > 0) {
    108 		if (matches(*argv, "simple") == 0) {
    109 			NEXT_ARG();
    110 		} else if (matches(*argv, "sdata") == 0) {
    111 			NEXT_ARG();
    112 			ok += 1;
    113 			simpdata = *argv;
    114 			argc--;
    115 			argv++;
    116 		} else if (matches(*argv, "help") == 0) {
    117 			usage();
    118 		} else {
    119 			break;
    120 		}
    121 	}
    122 
    123 	if (argc) {
    124 		if (matches(*argv, "index") == 0) {
    125 			NEXT_ARG();
    126 			if (get_u32(&sel.index, *argv, 10)) {
    127 				fprintf(stderr, "simple: Illegal \"index\" (%s)\n",
    128 					*argv);
    129 				return -1;
    130 			}
    131 			ok += 1;
    132 			argc--;
    133 			argv++;
    134 		}
    135 	}
    136 
    137 	if (!ok) {
    138 		explain();
    139 		return -1;
    140 	}
    141 
    142 	if (simpdata && (strlen(simpdata) > (SIMP_MAX_DATA - 1))) {
    143 		fprintf(stderr, "simple: Illegal string len %zu <%s>\n",
    144 			strlen(simpdata), simpdata);
    145 		return -1;
    146 	}
    147 
    148 	sel.action = TC_ACT_PIPE;
    149 
    150 	tail = NLMSG_TAIL(n);
    151 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    152 	addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel));
    153 	if (simpdata)
    154 		addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
    155 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
    156 
    157 	*argc_p = argc;
    158 	*argv_p = argv;
    159 	return 0;
    160 }
    161 
    162 static int print_simple(struct action_util *au, FILE *f, struct rtattr *arg)
    163 {
    164 	struct tc_defact *sel;
    165 	struct rtattr *tb[TCA_DEF_MAX + 1];
    166 	char *simpdata;
    167 
    168 	if (arg == NULL)
    169 		return -1;
    170 
    171 	parse_rtattr_nested(tb, TCA_DEF_MAX, arg);
    172 
    173 	if (tb[TCA_DEF_PARMS] == NULL) {
    174 		fprintf(f, "[NULL simple parameters]");
    175 		return -1;
    176 	}
    177 	sel = RTA_DATA(tb[TCA_DEF_PARMS]);
    178 
    179 	if (tb[TCA_DEF_DATA] == NULL) {
    180 		fprintf(f, "[missing simple string]");
    181 		return -1;
    182 	}
    183 
    184 	simpdata = RTA_DATA(tb[TCA_DEF_DATA]);
    185 
    186 	fprintf(f, "Simple <%s>\n", simpdata);
    187 	fprintf(f, "\t index %u ref %d bind %d", sel->index,
    188 		sel->refcnt, sel->bindcnt);
    189 
    190 	if (show_stats) {
    191 		if (tb[TCA_DEF_TM]) {
    192 			struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]);
    193 
    194 			print_tm(f, tm);
    195 		}
    196 	}
    197 	fprintf(f, "\n");
    198 
    199 	return 0;
    200 }
    201 
    202 struct action_util simple_action_util = {
    203 	.id = "simple",
    204 	.parse_aopt = parse_simple,
    205 	.print_aopt = print_simple,
    206 };
    207