1/* 2 * m_csum.c checksum updating 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: Gregoire Baron <baronchon@n7mm.org> 10 */ 11 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include <unistd.h> 16 17#include <linux/tc_act/tc_csum.h> 18 19#include "utils.h" 20#include "tc_util.h" 21 22static void 23explain(void) 24{ 25 fprintf(stderr, "Usage: ... csum <UPDATE>\n" 26 "Where: UPDATE := <TARGET> [<UPDATE>]\n" 27 " TARGET := { ip4h | icmp | igmp |" 28 " tcp | udp | udplite | <SWEETS> }\n" 29 " SWEETS := { and | or | \'+\' }\n"); 30} 31 32static void 33usage(void) 34{ 35 explain(); 36 exit(-1); 37} 38 39static int 40parse_csum_args(int *argc_p, char ***argv_p, struct tc_csum *sel) 41{ 42 int argc = *argc_p; 43 char **argv = *argv_p; 44 45 if (argc <= 0) 46 return -1; 47 48 while(argc > 0) { 49 if ((matches(*argv, "iph") == 0) || 50 (matches(*argv, "ip4h") == 0) || 51 (matches(*argv, "ipv4h") == 0)) 52 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IPV4HDR; 53 54 else if (matches(*argv, "icmp") == 0) 55 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_ICMP; 56 57 else if (matches(*argv, "igmp") == 0) 58 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_IGMP; 59 60 else if (matches(*argv, "tcp") == 0) 61 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_TCP; 62 63 else if (matches(*argv, "udp") == 0) 64 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDP; 65 66 else if (matches(*argv, "udplite") == 0) 67 sel->update_flags |= TCA_CSUM_UPDATE_FLAG_UDPLITE; 68 69 else if ((matches(*argv, "and") == 0) || 70 (matches(*argv, "or") == 0) || 71 (matches(*argv, "+") == 0)) 72 ; /* just ignore: ... csum iph and tcp or udp */ 73 else 74 break; 75 argc--; 76 argv++; 77 } 78 79 *argc_p = argc; 80 *argv_p = argv; 81 82 return 0; 83} 84 85static int 86parse_csum(struct action_util *a, int *argc_p, 87 char ***argv_p, int tca_id, struct nlmsghdr *n) 88{ 89 struct tc_csum sel; 90 91 int argc = *argc_p; 92 char **argv = *argv_p; 93 int ok = 0; 94 struct rtattr *tail; 95 96 memset(&sel, 0, sizeof(sel)); 97 98 while (argc > 0) { 99 if (matches(*argv, "csum") == 0) { 100 NEXT_ARG(); 101 if (parse_csum_args(&argc, &argv, &sel)) { 102 fprintf(stderr, "Illegal csum construct (%s)\n", 103 *argv); 104 explain(); 105 return -1; 106 } 107 ok++; 108 continue; 109 } else if (matches(*argv, "help") == 0) { 110 usage(); 111 } 112 else { 113 break; 114 } 115 } 116 117 if (!ok) { 118 explain(); 119 return -1; 120 } 121 122 if (sel.update_flags == 0) { 123 fprintf(stderr, "Illegal csum construct, empty <UPDATE> list\n"); 124 return -1; 125 } 126 127 if (argc) { 128 if (matches(*argv, "reclassify") == 0) { 129 sel.action = TC_ACT_RECLASSIFY; 130 argc--; 131 argv++; 132 } else if (matches(*argv, "pipe") == 0) { 133 sel.action = TC_ACT_PIPE; 134 argc--; 135 argv++; 136 } else if (matches(*argv, "drop") == 0 || 137 matches(*argv, "shot") == 0) { 138 sel.action = TC_ACT_SHOT; 139 argc--; 140 argv++; 141 } else if (matches(*argv, "continue") == 0) { 142 sel.action = TC_ACT_UNSPEC; 143 argc--; 144 argv++; 145 } else if (matches(*argv, "pass") == 0) { 146 sel.action = TC_ACT_OK; 147 argc--; 148 argv++; 149 } 150 } 151 152 if (argc) { 153 if (matches(*argv, "index") == 0) { 154 NEXT_ARG(); 155 if (get_u32(&sel.index, *argv, 10)) { 156 fprintf(stderr, "Illegal \"index\" (%s) <csum>\n", 157 *argv); 158 return -1; 159 } 160 argc--; 161 argv++; 162 } 163 } 164 165 tail = NLMSG_TAIL(n); 166 addattr_l(n, MAX_MSG, tca_id, NULL, 0); 167 addattr_l(n, MAX_MSG, TCA_CSUM_PARMS, &sel, sizeof(sel)); 168 tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail; 169 170 *argc_p = argc; 171 *argv_p = argv; 172 173 return 0; 174} 175 176static int 177print_csum(struct action_util *au, FILE * f, struct rtattr *arg) 178{ 179 struct tc_csum *sel; 180 181 struct rtattr *tb[TCA_CSUM_MAX + 1]; 182 183 char *uflag_1 = ""; 184 char *uflag_2 = ""; 185 char *uflag_3 = ""; 186 char *uflag_4 = ""; 187 char *uflag_5 = ""; 188 char *uflag_6 = ""; 189 SPRINT_BUF(action_buf); 190 191 int uflag_count = 0; 192 193 if (arg == NULL) 194 return -1; 195 196 parse_rtattr_nested(tb, TCA_CSUM_MAX, arg); 197 198 if (tb[TCA_CSUM_PARMS] == NULL) { 199 fprintf(f, "[NULL csum parameters]"); 200 return -1; 201 } 202 sel = RTA_DATA(tb[TCA_CSUM_PARMS]); 203 204 if (sel->update_flags & TCA_CSUM_UPDATE_FLAG_IPV4HDR) { 205 uflag_1 = "iph"; 206 uflag_count++; 207 } 208 #define CSUM_UFLAG_BUFFER(flag_buffer, flag_value, flag_string) \ 209 do { \ 210 if (sel->update_flags & flag_value) { \ 211 flag_buffer = uflag_count > 0 ? \ 212 ", " flag_string : flag_string; \ 213 uflag_count++; \ 214 } \ 215 } while(0) 216 CSUM_UFLAG_BUFFER(uflag_2, TCA_CSUM_UPDATE_FLAG_ICMP, "icmp"); 217 CSUM_UFLAG_BUFFER(uflag_3, TCA_CSUM_UPDATE_FLAG_IGMP, "igmp"); 218 CSUM_UFLAG_BUFFER(uflag_4, TCA_CSUM_UPDATE_FLAG_TCP, "tcp"); 219 CSUM_UFLAG_BUFFER(uflag_5, TCA_CSUM_UPDATE_FLAG_UDP, "udp"); 220 CSUM_UFLAG_BUFFER(uflag_6, TCA_CSUM_UPDATE_FLAG_UDPLITE, "udplite"); 221 if (!uflag_count) { 222 uflag_1 = "?empty"; 223 } 224 225 fprintf(f, "csum (%s%s%s%s%s%s) action %s\n", 226 uflag_1, uflag_2, uflag_3, 227 uflag_4, uflag_5, uflag_6, 228 action_n2a(sel->action, action_buf, sizeof(action_buf))); 229 fprintf(f, "\tindex %d ref %d bind %d", sel->index, sel->refcnt, sel->bindcnt); 230 231 if (show_stats) { 232 if (tb[TCA_CSUM_TM]) { 233 struct tcf_t *tm = RTA_DATA(tb[TCA_CSUM_TM]); 234 print_tm(f,tm); 235 } 236 } 237 fprintf(f, "\n"); 238 239 return 0; 240} 241 242struct action_util csum_action_util = { 243 .id = "csum", 244 .parse_aopt = parse_csum, 245 .print_aopt = print_csum, 246}; 247