summaryrefslogtreecommitdiff
path: root/tc/f_u32.c
diff options
context:
space:
mode:
authorStephen Hemminger <stephen.hemminger@vyatta.com>2009-04-15 15:39:34 -0700
committerStephen Hemminger <stephen.hemminger@vyatta.com>2009-04-15 15:39:34 -0700
commitb4d41f41b6d601f876f442ae19ccdb4f0c3552c5 (patch)
tree8032e8f020268126fc615616191e59b61ce02c33 /tc/f_u32.c
parentb9ab720e33748cd022f095620e75ca7eba24a965 (diff)
downloadiproute2-b4d41f41b6d601f876f442ae19ccdb4f0c3552c5.tar.gz
Add u32 extension to match on ether source/destination
Use existing u32 mechanism to match based on Ethernet header. No need for protocol that already exists.
Diffstat (limited to 'tc/f_u32.c')
-rw-r--r--tc/f_u32.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/tc/f_u32.c b/tc/f_u32.c
index e5b8231f..7044db26 100644
--- a/tc/f_u32.c
+++ b/tc/f_u32.c
@@ -405,6 +405,48 @@ static int parse_ip6_addr(int *argc_p, char ***argv_p,
return res;
}
+static int parse_ether_addr(int *argc_p, char ***argv_p,
+ struct tc_u32_sel *sel, int off)
+{
+ int res = -1;
+ int argc = *argc_p;
+ char **argv = *argv_p;
+ __u8 addr[6];
+ int offmask = 0;
+ __u32 key;
+ int i;
+
+ if (argc < 1)
+ return -1;
+
+ if (sscanf(*argv, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ addr + 0, addr + 1, addr + 2,
+ addr + 3, addr + 4, addr + 5) != 6) {
+ fprintf(stderr, "parse_ether_addr: improperly formed address '%s'\n",
+ *argv);
+ return -1;
+ }
+
+ argc--; argv++;
+ if (argc > 0 && strcmp(argv[0], "at") == 0) {
+ NEXT_ARG();
+ if (parse_at(&argc, &argv, &off, &offmask))
+ return -1;
+ }
+
+ for (i = 0; i < 6; i += 2) {
+ key = *(__u16 *) (addr + i);
+
+ res = pack_key16(sel, key, 0xFFFF, off + i, offmask);
+ if (res < 0)
+ return -1;
+ }
+
+ *argc_p = argc;
+ *argv_p = argv;
+ return res;
+}
+
static int parse_ip(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
{
int res = -1;
@@ -509,6 +551,31 @@ static int parse_ip6(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
return res;
}
+static int parse_ether(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
+{
+ int res = -1;
+ int argc = *argc_p;
+ char **argv = *argv_p;
+
+ if (argc < 2)
+ return -1;
+
+ if (strcmp(*argv, "src") == 0) {
+ NEXT_ARG();
+ res = parse_ether_addr(&argc, &argv, sel, -8);
+ } else if (strcmp(*argv, "dst") == 0) {
+ NEXT_ARG();
+ res = parse_ether_addr(&argc, &argv, sel, -14);
+ } else {
+ fprintf(stderr, "Unknown match: ether %s\n", *argv);
+ return -1;
+ }
+
+ *argc_p = argc;
+ *argv_p = argv;
+ return res;
+}
+
#define parse_tcp parse_udp
static int parse_udp(int *argc_p, char ***argv_p, struct tc_u32_sel *sel)
{
@@ -629,6 +696,9 @@ static int parse_selector(int *argc_p, char ***argv_p,
} else if (matches(*argv, "mark") == 0) {
NEXT_ARG();
res = parse_mark(&argc, &argv, n);
+ } else if (matches(*argv, "ether") == 0) {
+ NEXT_ARG();
+ res = parse_ether(&argc, &argv, sel);
} else
return -1;