Jamal Hadi Salim | d3e5112 | 2016-05-07 09:35:23 -0400 | [diff] [blame] | 1 | /* |
| 2 | * m_ife.c IFE actions module |
| 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@mojatatu.com) |
| 10 | * |
| 11 | */ |
| 12 | |
| 13 | #include <stdio.h> |
| 14 | #include <stdlib.h> |
| 15 | #include <unistd.h> |
| 16 | #include <syslog.h> |
| 17 | #include <fcntl.h> |
| 18 | #include <sys/socket.h> |
| 19 | #include <netinet/in.h> |
| 20 | #include <arpa/inet.h> |
| 21 | #include <string.h> |
| 22 | #include <linux/netdevice.h> |
| 23 | |
| 24 | #include "rt_names.h" |
| 25 | #include "utils.h" |
| 26 | #include "tc_util.h" |
| 27 | #include <linux/tc_act/tc_ife.h> |
| 28 | |
| 29 | static void ife_explain(void) |
| 30 | { |
| 31 | fprintf(stderr, |
| 32 | "Usage:... ife {decode|encode} {ALLOW|USE} [dst DMAC] [src SMAC] [type TYPE] [CONTROL] [index INDEX]\n"); |
| 33 | fprintf(stderr, |
| 34 | "\tALLOW := Encode direction. Allows encoding specified metadata\n" |
| 35 | "\t\t e.g \"allow mark\"\n" |
| 36 | "\tUSE := Encode direction. Enforce Static encoding of specified metadata\n" |
| 37 | "\t\t e.g \"use mark 0x12\"\n" |
| 38 | "\tDMAC := 6 byte Destination MAC address to encode\n" |
| 39 | "\tSMAC := optional 6 byte Source MAC address to encode\n" |
| 40 | "\tTYPE := optional 16 bit ethertype to encode\n" |
| 41 | "\tCONTROL := reclassify|pipe|drop|continue|ok\n" |
| 42 | "\tINDEX := optional IFE table index value used\n"); |
| 43 | fprintf(stderr, "encode is used for sending IFE packets\n"); |
| 44 | fprintf(stderr, "decode is used for receiving IFE packets\n"); |
| 45 | } |
| 46 | |
| 47 | static void ife_usage(void) |
| 48 | { |
| 49 | ife_explain(); |
| 50 | exit(-1); |
| 51 | } |
| 52 | |
| 53 | static int parse_ife(struct action_util *a, int *argc_p, char ***argv_p, |
| 54 | int tca_id, struct nlmsghdr *n) |
| 55 | { |
| 56 | int argc = *argc_p; |
| 57 | char **argv = *argv_p; |
| 58 | int ok = 0; |
| 59 | struct tc_ife p; |
| 60 | struct rtattr *tail; |
| 61 | struct rtattr *tail2; |
| 62 | char dbuf[ETH_ALEN]; |
| 63 | char sbuf[ETH_ALEN]; |
| 64 | __u16 ife_type = 0; |
| 65 | __u32 ife_prio = 0; |
| 66 | __u32 ife_prio_v = 0; |
| 67 | __u32 ife_mark = 0; |
| 68 | __u32 ife_mark_v = 0; |
| 69 | char *daddr = NULL; |
| 70 | char *saddr = NULL; |
| 71 | |
| 72 | memset(&p, 0, sizeof(p)); |
| 73 | p.action = TC_ACT_PIPE; /* good default */ |
| 74 | |
| 75 | if (argc <= 0) |
| 76 | return -1; |
| 77 | |
| 78 | while (argc > 0) { |
| 79 | if (matches(*argv, "ife") == 0) { |
| 80 | NEXT_ARG(); |
| 81 | continue; |
| 82 | } else if (matches(*argv, "decode") == 0) { |
| 83 | p.flags = IFE_DECODE; /* readability aid */ |
| 84 | ok++; |
| 85 | } else if (matches(*argv, "encode") == 0) { |
| 86 | p.flags = IFE_ENCODE; |
| 87 | ok++; |
| 88 | } else if (matches(*argv, "allow") == 0) { |
| 89 | NEXT_ARG(); |
| 90 | if (matches(*argv, "mark") == 0) { |
| 91 | ife_mark = IFE_META_SKBMARK; |
| 92 | } else if (matches(*argv, "prio") == 0) { |
| 93 | ife_prio = IFE_META_PRIO; |
| 94 | } else { |
| 95 | fprintf(stderr, "Illegal meta define <%s>\n", |
| 96 | *argv); |
| 97 | return -1; |
| 98 | } |
| 99 | } else if (matches(*argv, "use") == 0) { |
| 100 | NEXT_ARG(); |
| 101 | if (matches(*argv, "mark") == 0) { |
| 102 | NEXT_ARG(); |
| 103 | if (get_u32(&ife_mark_v, *argv, 0)) |
| 104 | invarg("ife mark val is invalid", |
| 105 | *argv); |
| 106 | } else if (matches(*argv, "prio") == 0) { |
| 107 | NEXT_ARG(); |
| 108 | if (get_u32(&ife_prio_v, *argv, 0)) |
| 109 | invarg("ife prio val is invalid", |
| 110 | *argv); |
| 111 | } else { |
| 112 | fprintf(stderr, "Illegal meta use type <%s>\n", |
| 113 | *argv); |
| 114 | return -1; |
| 115 | } |
| 116 | } else if (matches(*argv, "type") == 0) { |
| 117 | NEXT_ARG(); |
| 118 | if (get_u16(&ife_type, *argv, 0)) |
| 119 | invarg("ife type is invalid", *argv); |
| 120 | fprintf(stderr, "IFE type 0x%x\n", ife_type); |
| 121 | } else if (matches(*argv, "dst") == 0) { |
| 122 | NEXT_ARG(); |
| 123 | daddr = *argv; |
| 124 | if (sscanf(daddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", |
| 125 | dbuf, dbuf + 1, dbuf + 2, |
| 126 | dbuf + 3, dbuf + 4, dbuf + 5) != 6) { |
| 127 | fprintf(stderr, "Invalid mac address %s\n", |
| 128 | daddr); |
| 129 | } |
| 130 | fprintf(stderr, "dst MAC address <%s>\n", daddr); |
| 131 | |
| 132 | } else if (matches(*argv, "src") == 0) { |
| 133 | NEXT_ARG(); |
| 134 | saddr = *argv; |
| 135 | if (sscanf(saddr, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", |
| 136 | sbuf, sbuf + 1, sbuf + 2, |
| 137 | sbuf + 3, sbuf + 4, sbuf + 5) != 6) { |
| 138 | fprintf(stderr, "Invalid mac address %s\n", |
| 139 | saddr); |
| 140 | } |
| 141 | fprintf(stderr, "src MAC address <%s>\n", saddr); |
| 142 | } else if (matches(*argv, "help") == 0) { |
| 143 | ife_usage(); |
| 144 | } else { |
| 145 | break; |
| 146 | } |
| 147 | |
| 148 | argc--; |
| 149 | argv++; |
| 150 | } |
| 151 | |
| 152 | if (argc) { |
| 153 | if (matches(*argv, "reclassify") == 0) { |
| 154 | p.action = TC_ACT_RECLASSIFY; |
| 155 | argc--; |
| 156 | argv++; |
| 157 | } else if (matches(*argv, "pipe") == 0) { |
| 158 | p.action = TC_ACT_PIPE; |
| 159 | argc--; |
| 160 | argv++; |
| 161 | } else if (matches(*argv, "drop") == 0 || |
| 162 | matches(*argv, "shot") == 0) { |
| 163 | p.action = TC_ACT_SHOT; |
| 164 | argc--; |
| 165 | argv++; |
| 166 | } else if (matches(*argv, "continue") == 0) { |
| 167 | p.action = TC_ACT_UNSPEC; |
| 168 | argc--; |
| 169 | argv++; |
Jamal Hadi Salim | 43726b7 | 2016-05-07 09:39:36 -0400 | [diff] [blame] | 170 | } else if (matches(*argv, "pass") == 0 || |
| 171 | matches(*argv, "ok") == 0) { |
Jamal Hadi Salim | d3e5112 | 2016-05-07 09:35:23 -0400 | [diff] [blame] | 172 | p.action = TC_ACT_OK; |
| 173 | argc--; |
| 174 | argv++; |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | if (argc) { |
| 179 | if (matches(*argv, "index") == 0) { |
| 180 | NEXT_ARG(); |
| 181 | if (get_u32(&p.index, *argv, 10)) { |
| 182 | fprintf(stderr, "ife: Illegal \"index\"\n"); |
| 183 | return -1; |
| 184 | } |
Jamal Hadi Salim | a78a2db | 2016-05-22 13:11:16 -0400 | [diff] [blame] | 185 | ok++; |
Jamal Hadi Salim | d3e5112 | 2016-05-07 09:35:23 -0400 | [diff] [blame] | 186 | argc--; |
| 187 | argv++; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | if (!ok) { |
| 192 | fprintf(stderr, "IFE requires decode/encode specified\n"); |
| 193 | ife_usage(); |
| 194 | } |
| 195 | |
| 196 | tail = NLMSG_TAIL(n); |
| 197 | addattr_l(n, MAX_MSG, tca_id, NULL, 0); |
| 198 | addattr_l(n, MAX_MSG, TCA_IFE_PARMS, &p, sizeof(p)); |
| 199 | |
| 200 | if (!(p.flags & IFE_ENCODE)) |
| 201 | goto skip_encode; |
| 202 | |
| 203 | if (daddr) |
| 204 | addattr_l(n, MAX_MSG, TCA_IFE_DMAC, dbuf, ETH_ALEN); |
| 205 | if (ife_type) |
| 206 | addattr_l(n, MAX_MSG, TCA_IFE_TYPE, &ife_type, 2); |
| 207 | if (saddr) |
| 208 | addattr_l(n, MAX_MSG, TCA_IFE_SMAC, sbuf, ETH_ALEN); |
| 209 | |
| 210 | tail2 = NLMSG_TAIL(n); |
| 211 | addattr_l(n, MAX_MSG, TCA_IFE_METALST, NULL, 0); |
| 212 | if (ife_mark || ife_mark_v) { |
| 213 | if (ife_mark_v) |
| 214 | addattr_l(n, MAX_MSG, IFE_META_SKBMARK, &ife_mark_v, 4); |
| 215 | else |
| 216 | addattr_l(n, MAX_MSG, IFE_META_SKBMARK, NULL, 0); |
| 217 | } |
| 218 | if (ife_prio || ife_prio_v) { |
| 219 | if (ife_prio_v) |
| 220 | addattr_l(n, MAX_MSG, IFE_META_PRIO, &ife_prio_v, 4); |
| 221 | else |
| 222 | addattr_l(n, MAX_MSG, IFE_META_PRIO, NULL, 0); |
| 223 | } |
| 224 | |
| 225 | tail2->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail2; |
| 226 | |
| 227 | skip_encode: |
| 228 | tail->rta_len = (void *)NLMSG_TAIL(n) - (void *)tail; |
| 229 | |
| 230 | *argc_p = argc; |
| 231 | *argv_p = argv; |
| 232 | return 0; |
| 233 | } |
| 234 | |
| 235 | static int print_ife(struct action_util *au, FILE *f, struct rtattr *arg) |
| 236 | { |
| 237 | struct tc_ife *p = NULL; |
| 238 | struct rtattr *tb[TCA_IFE_MAX + 1]; |
| 239 | __u16 ife_type = 0; |
| 240 | __u32 mmark = 0; |
| 241 | __u32 mhash = 0; |
| 242 | __u32 mprio = 0; |
| 243 | int has_optional = 0; |
| 244 | SPRINT_BUF(b1); |
| 245 | SPRINT_BUF(b2); |
| 246 | |
| 247 | if (arg == NULL) |
| 248 | return -1; |
| 249 | |
| 250 | parse_rtattr_nested(tb, TCA_IFE_MAX, arg); |
| 251 | |
| 252 | if (tb[TCA_IFE_PARMS] == NULL) { |
| 253 | fprintf(f, "[NULL ife parameters]"); |
| 254 | return -1; |
| 255 | } |
| 256 | p = RTA_DATA(tb[TCA_IFE_PARMS]); |
| 257 | |
| 258 | fprintf(f, "ife %s action %s ", |
| 259 | (p->flags & IFE_ENCODE) ? "encode" : "decode", |
| 260 | action_n2a(p->action, b1, sizeof(b1))); |
| 261 | |
| 262 | if (tb[TCA_IFE_TYPE]) { |
| 263 | ife_type = rta_getattr_u16(tb[TCA_IFE_TYPE]); |
| 264 | has_optional = 1; |
| 265 | fprintf(f, "type 0x%X ", ife_type); |
| 266 | } |
| 267 | |
| 268 | if (has_optional) |
| 269 | fprintf(f, "\n\t "); |
| 270 | |
| 271 | if (tb[TCA_IFE_METALST]) { |
| 272 | struct rtattr *metalist[IFE_META_MAX + 1]; |
| 273 | int len = 0; |
| 274 | |
| 275 | parse_rtattr_nested(metalist, IFE_META_MAX, |
| 276 | tb[TCA_IFE_METALST]); |
| 277 | |
| 278 | if (metalist[IFE_META_SKBMARK]) { |
| 279 | len = RTA_PAYLOAD(metalist[IFE_META_SKBMARK]); |
| 280 | if (len) { |
| 281 | mmark = rta_getattr_u32(metalist[IFE_META_SKBMARK]); |
| 282 | fprintf(f, "use mark %d ", mmark); |
| 283 | } else |
| 284 | fprintf(f, "allow mark "); |
| 285 | } |
| 286 | |
| 287 | if (metalist[IFE_META_HASHID]) { |
| 288 | len = RTA_PAYLOAD(metalist[IFE_META_HASHID]); |
| 289 | if (len) { |
| 290 | mhash = rta_getattr_u32(metalist[IFE_META_HASHID]); |
| 291 | fprintf(f, "use hash %d ", mhash); |
| 292 | } else |
| 293 | fprintf(f, "allow hash "); |
| 294 | } |
| 295 | |
| 296 | if (metalist[IFE_META_PRIO]) { |
| 297 | len = RTA_PAYLOAD(metalist[IFE_META_PRIO]); |
| 298 | if (len) { |
| 299 | mprio = rta_getattr_u32(metalist[IFE_META_PRIO]); |
| 300 | fprintf(f, "use prio %d ", mprio); |
| 301 | } else |
| 302 | fprintf(f, "allow prio "); |
| 303 | } |
| 304 | |
| 305 | } |
| 306 | |
| 307 | if (tb[TCA_IFE_DMAC]) { |
| 308 | has_optional = 1; |
| 309 | fprintf(f, "dst %s ", |
| 310 | ll_addr_n2a(RTA_DATA(tb[TCA_IFE_DMAC]), |
| 311 | RTA_PAYLOAD(tb[TCA_IFE_DMAC]), 0, b2, |
| 312 | sizeof(b2))); |
| 313 | |
| 314 | } |
| 315 | |
| 316 | if (tb[TCA_IFE_SMAC]) { |
| 317 | has_optional = 1; |
| 318 | fprintf(f, "src %s ", |
| 319 | ll_addr_n2a(RTA_DATA(tb[TCA_IFE_SMAC]), |
| 320 | RTA_PAYLOAD(tb[TCA_IFE_SMAC]), 0, b2, |
| 321 | sizeof(b2))); |
| 322 | } |
| 323 | |
| 324 | fprintf(f, "\n\t index %d ref %d bind %d", p->index, p->refcnt, |
| 325 | p->bindcnt); |
| 326 | if (show_stats) { |
| 327 | if (tb[TCA_IFE_TM]) { |
| 328 | struct tcf_t *tm = RTA_DATA(tb[TCA_IFE_TM]); |
| 329 | |
| 330 | print_tm(f, tm); |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | fprintf(f, "\n"); |
| 335 | |
| 336 | return 0; |
| 337 | } |
| 338 | |
| 339 | struct action_util ife_action_util = { |
| 340 | .id = "ife", |
| 341 | .parse_aopt = parse_ife, |
| 342 | .print_aopt = print_ife, |
| 343 | }; |