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 STRING\n"
     85 		"STRING being an arbitrary string\n"
     86 		"example: \"simple blah\"\n");
     87 }
     88 
     89 static void usage(void)
     90 {
     91 	explain();
     92 	exit(-1);
     93 }
     94 
     95 static int
     96 parse_simple(struct action_util *a, int *argc_p, char ***argv_p, int tca_id,
     97 	     struct nlmsghdr *n)
     98 {
     99 	struct tc_defact sel = {};
    100 	int argc = *argc_p;
    101 	char **argv = *argv_p;
    102 	int ok = 0;
    103 	struct rtattr *tail;
    104 	char *simpdata = NULL;
    105 
    106 
    107 	while (argc > 0) {
    108 		if (matches(*argv, "simple") == 0) {
    109 			NEXT_ARG();
    110 			simpdata = *argv;
    111 			ok = 1;
    112 			argc--;
    113 			argv++;
    114 			break;
    115 		} else if (matches(*argv, "help") == 0) {
    116 			usage();
    117 		} else {
    118 			break;
    119 		}
    120 
    121 	}
    122 
    123 	if (!ok) {
    124 		explain();
    125 		return -1;
    126 	}
    127 
    128 	if (argc) {
    129 		if (matches(*argv, "index") == 0) {
    130 			NEXT_ARG();
    131 			if (get_u32(&sel.index, *argv, 10)) {
    132 				fprintf(stderr, "simple: Illegal \"index\"\n");
    133 				return -1;
    134 			}
    135 			argc--;
    136 			argv++;
    137 		}
    138 	}
    139 
    140 	if (strlen(simpdata) > (SIMP_MAX_DATA - 1)) {
    141 		fprintf(stderr, "simple: Illegal string len %zu <%s> \n",
    142 			strlen(simpdata), simpdata);
    143 		return -1;
    144 	}
    145 
    146 	sel.action = TC_ACT_PIPE;
    147 
    148 	tail = NLMSG_TAIL(n);
    149 	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
    150 	addattr_l(n, MAX_MSG, TCA_DEF_PARMS, &sel, sizeof(sel));
    151 	addattr_l(n, MAX_MSG, TCA_DEF_DATA, simpdata, SIMP_MAX_DATA);
    152 	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
    153 
    154 	*argc_p = argc;
    155 	*argv_p = argv;
    156 	return 0;
    157 }
    158 
    159 static int print_simple(struct action_util *au, FILE * f, struct rtattr *arg)
    160 {
    161 	struct tc_defact *sel;
    162 	struct rtattr *tb[TCA_DEF_MAX + 1];
    163 	char *simpdata;
    164 
    165 	if (arg == NULL)
    166 		return -1;
    167 
    168 	parse_rtattr_nested(tb, TCA_DEF_MAX, arg);
    169 
    170 	if (tb[TCA_DEF_PARMS] == NULL) {
    171 		fprintf(f, "[NULL simple parameters]");
    172 		return -1;
    173 	}
    174 	sel = RTA_DATA(tb[TCA_DEF_PARMS]);
    175 
    176 	if (tb[TCA_DEF_DATA] == NULL) {
    177 		fprintf(f, "[missing simple string]");
    178 		return -1;
    179 	}
    180 
    181 	simpdata = RTA_DATA(tb[TCA_DEF_DATA]);
    182 
    183 	fprintf(f, "Simple <%s>\n", simpdata);
    184 	fprintf(f, "\t index %d ref %d bind %d", sel->index,
    185 		sel->refcnt, sel->bindcnt);
    186 
    187 	if (show_stats) {
    188 		if (tb[TCA_DEF_TM]) {
    189 			struct tcf_t *tm = RTA_DATA(tb[TCA_DEF_TM]);
    190 			print_tm(f, tm);
    191 		}
    192 	}
    193 	fprintf(f, "\n");
    194 
    195 	return 0;
    196 }
    197 
    198 struct action_util simple_action_util = {
    199 	.id = "simple",
    200 	.parse_aopt = parse_simple,
    201 	.print_aopt = print_simple,
    202 };
    203