1 /*
2  * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $Id: fttag.c,v 1.19 2004/01/05 17:55:37 maf Exp $
27  */
28 
29 #include "ftconfig.h"
30 #include "ftlib.h"
31 
32 #include "radix.h"
33 
34 #include <sys/time.h>
35 #include <sys/types.h>
36 #include <sys/uio.h>
37 #include <sys/socket.h>
38 #include <sys/resource.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #include <sys/stat.h>
42 #include <syslog.h>
43 #include <dirent.h>
44 #include <limits.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <time.h>
49 #include <fcntl.h>
50 #include <zlib.h>
51 
52 #if HAVE_STRINGS_H
53  #include <strings.h>
54 #endif
55 #if HAVE_STRING_H
56   #include <string.h>
57 #endif
58 
59 #if !HAVE_STRSEP
60   char    *strsep (char **, const char *);
61 #endif
62 
63 extern int max_keylen;
64 extern uint32_t mask_lookup[];
65 
66 static struct radix_node_head *rhead;
67 
68 struct line_parser {
69   struct fttag_action *cur_action;
70   struct fttag_def *cur_def;
71   struct fttag_def_term *cur_def_term;
72   int state, type;
73   int lineno;
74   char *buf;
75   const char *fname;
76 };
77 
78 #define FT_TAG_OR_SRCDST (FT_TAG_OR_SRC_TAG|FT_TAG_OR_DST_TAG)
79 #define FT_TAG_SET_SRCDST (FT_TAG_SET_SRC_TAG|FT_TAG_SET_DST_TAG)
80 
81 static int parse_action(struct line_parser *lp, struct fttag *fttag);
82 static int parse_action_type(struct line_parser *lp, struct fttag *fttag);
83 static int parse_action_match(struct line_parser *lp, struct fttag *fttag);
84 static int parse_def(struct line_parser *lp, struct fttag *fttag);
85 static int parse_def_exporter(struct line_parser *lp, struct fttag *fttag);
86 static int parse_def_term(struct line_parser *lp, struct fttag *fttag);
87 static int parse_def_input_filter(struct line_parser *lp, struct fttag *fttag);
88 static int parse_def_output_filter(struct line_parser *lp, struct fttag *fttag);
89 static int parse_def_action(struct line_parser *lp, struct fttag *fttag);
90 static int resolve_actions(struct fttag *fttag);
91 
92 static int walk_free(struct radix_node *rn, struct walkarg *UNUSED);
93 
94 static void eval_match_src_as(struct fttag_action *fta,
95   struct fts3rec_v1005 *rec);
96 static void eval_match_dst_as(struct fttag_action *fta,
97   struct fts3rec_v1005 *rec);
98 static void eval_match_src_prefix(struct fttag_action *fta,
99   struct fts3rec_v1005 *rec);
100 static void eval_match_dst_prefix(struct fttag_action *fta,
101   struct fts3rec_v1005 *rec);
102 static void eval_match_nexthop(struct fttag_action *fta,
103   struct fts3rec_v1005 *rec);
104 static void eval_match_as(struct fttag_action *fta,
105   struct fts3rec_v1005 *rec);
106 static void eval_match_prefix(struct fttag_action *fta,
107   struct fts3rec_v1005 *rec);
108 static void eval_match_tcp_src_port(struct fttag_action *fta,
109   struct fts3rec_v1005 *rec);
110 static void eval_match_tcp_dst_port(struct fttag_action *fta,
111   struct fts3rec_v1005 *rec);
112 static void eval_match_tcp_port(struct fttag_action *fta,
113   struct fts3rec_v1005 *rec);
114 static void eval_match_udp_src_port(struct fttag_action *fta,
115   struct fts3rec_v1005 *rec);
116 static void eval_match_udp_dst_port(struct fttag_action *fta,
117   struct fts3rec_v1005 *rec);
118 static void eval_match_udp_port(struct fttag_action *fta,
119   struct fts3rec_v1005 *rec);
120 static void eval_match_tos(struct fttag_action *fta,
121   struct fts3rec_v1005 *rec);
122 static void eval_match_any(struct fttag_action *fta,
123   struct fts3rec_v1005 *rec);
124 static void eval_match_in_interface(struct fttag_action *fta,
125   struct fts3rec_v1005 *rec);
126 static void eval_match_out_interface(struct fttag_action *fta,
127   struct fts3rec_v1005 *rec);
128 static void eval_match_interface(struct fttag_action *fta,
129   struct fts3rec_v1005 *rec);
130 static void eval_match_exporter(struct fttag_action *fta,
131   struct fts3rec_v1005 *rec);
132 static void eval_match_src_ip(struct fttag_action *fta,
133   struct fts3rec_v1005 *rec);
134 static void eval_match_dst_ip(struct fttag_action *fta,
135   struct fts3rec_v1005 *rec);
136 static void eval_match_ip(struct fttag_action *fta,
137   struct fts3rec_v1005 *rec);
138 
139 #define PARSE_STATE_ACTION          0x1
140 #define PARSE_STATE_DEFINITION      0x2
141 
142 #define NEXT_WORD(A,B)\
143   for (;;) {\
144     B = strsep(A, " \t");\
145     if ((B && *B != 0) || (!B))\
146       break;\
147   }\
148 
149 struct jump {
150   char *name;
151   int state;
152   int (*func)(struct line_parser *lp, struct fttag *fttag);
153 };
154 
155 static struct jump pjump[] = {{"tag-action", 0, parse_action},
156           {"type", PARSE_STATE_ACTION, parse_action_type},
157           {"match", PARSE_STATE_ACTION, parse_action_match},
158           {"tag-definition", 0, parse_def},
159           {"exporter", PARSE_STATE_DEFINITION, parse_def_exporter},
160           {"term", PARSE_STATE_DEFINITION, parse_def_term},
161           {"input-filter", PARSE_STATE_DEFINITION, parse_def_input_filter},
162           {"output-filter", PARSE_STATE_DEFINITION, parse_def_output_filter},
163           {"action", PARSE_STATE_DEFINITION, parse_def_action},
164           {0, 0, 0},
165           };
166 /*
167  * data structures:
168  *
169  *
170  * fttag holds the head pointers to a list of actions, and definitions.
171  *
172  * Each definition holds a list of terms.  A term is a combination of
173  * an input filter, output filter and list of actions.
174  *
175  * struct fttag_def               : linked list of definitions
176  * struct fttag_action            : linked list of actions
177  * struct fttag_def_term          : each term in a definition
178  * struct fttag_def_term_actions  : each action in a term
179  *
180  * actions contain one of the following:
181  *
182  * struct fttag_prefix_look              : prefix radix trie lookup entry
183  * struct fttag_as_look                  : AS table lookup
184  * struct fttag_port_look                : port table lookup
185  * struct fttag_tos_look                 : tos table lookup
186  * struct fttag_next_hop_look            : next hop hash lookup entry
187  * struct fttag_interface_look           : interface table lookup entry
188  * struct fttag_exporter                 : exporter hash lookup entry
189  * struct fttag_ip_look                  : IP address hash lookup entry
190  *
191  * struct fftag_exp_hash                 : hash table mapping exporter_ip
192  *                                         to list of definitions.  Used
193  *                                         when processing flows.  ie, lookup
194  *                                         by exporter, test input/output
195  *                                         filter then use action to add
196  *                                         tags.
197  *
198  */
199 
200 struct fttag_prefix_look {
201   struct radix_node rt_nodes[2]; /* radix tree glue */
202   struct radix_sockaddr_in addr;
203   uint8_t masklen;
204   uint16_t set_flags;
205   uint32_t src_tag;
206   uint32_t dst_tag;
207 };
208 
209 struct fttag_as_look {
210   uint16_t set_flags_lookup[65536];
211   uint32_t src_tag_lookup[65536];
212   uint32_t dst_tag_lookup[65536];
213 };
214 
215 struct fttag_port_look {
216   uint16_t set_flags_lookup[65536];
217   uint32_t src_tag_lookup[65536];
218   uint32_t dst_tag_lookup[65536];
219 };
220 
221 struct fttag_tos_look {
222   uint16_t set_flags_lookup[256];
223   uint32_t src_tag_lookup[256];
224   uint32_t dst_tag_lookup[256];
225 };
226 
227 struct fttag_interface_look {
228   uint16_t set_flags_lookup[65536];
229   uint32_t src_tag_lookup[65536];
230   uint32_t dst_tag_lookup[65536];
231 };
232 
233 struct fttag_any_look {
234   uint16_t set_flags;
235   uint32_t src_tag;
236   uint32_t dst_tag;
237 };
238 
239 struct fttag_next_hop_look {
240   FT_SLIST_ENTRY(fttag_next_hop_look) chain;
241   uint32_t addr; /* key */
242   uint16_t set_flags;
243   uint32_t src_tag;
244   uint32_t dst_tag;
245 };
246 
247 struct fttag_exporter_look {
248   FT_SLIST_ENTRY(fttag_exporter_look) chain;
249   uint32_t addr; /* key */
250   uint16_t set_flags;
251   uint32_t src_tag;
252   uint32_t dst_tag;
253 };
254 
255 struct fttag_ip_look {
256   FT_SLIST_ENTRY(fttag_ip_look) chain;
257   uint32_t addr; /* key */
258   uint16_t set_flags;
259   uint32_t src_tag;
260   uint32_t dst_tag;
261 };
262 
263 /*
264  * function: fttag_load
265  *
266  * Process fname into fttag.
267  *
268  * returns: 0  ok
269  *          <0 fail
270  */
fttag_load(struct fttag * fttag,struct ftvar * ftvar,const char * fname)271 int fttag_load(struct fttag *fttag, struct ftvar *ftvar, const char *fname)
272 {
273   static int rn_init_called;
274   struct stat sb;
275   struct jump *jmp;
276   struct line_parser lp;
277   int fd, ret, found = 0;
278   char *buf, *buf2, *c;
279   char sbuf[FT_LP_MAXLINE];
280 
281   ret = -1;
282   buf = (char*)0L;
283   bzero(&lp, sizeof lp);
284   bzero(fttag, sizeof *fttag);
285 
286   if (!rn_init_called) {
287     max_keylen = sizeof(struct radix_sockaddr_in);
288     rn_init();
289     rn_init_called = 1;
290   }
291 
292   FT_SLIST_INIT(&fttag->defs);
293   FT_SLIST_INIT(&fttag->actions);
294 
295   lp.fname = fname;
296 
297   if ((fd = open(fname, O_RDONLY, 0)) < 0) {
298     fterr_warn("open(%s)", fname);
299     goto load_tags_out;
300   }
301 
302   if (fstat(fd, &sb) < 0) {
303     fterr_warn("stat(%s)", fname);
304     goto load_tags_out;
305   }
306 
307   /* allocate storage for file */
308   if (!(buf = malloc(sb.st_size+1))) {
309     fterr_warn("malloc()");
310     goto load_tags_out;
311   }
312 
313   /* read in file */
314   if (read(fd, buf, sb.st_size) != sb.st_size) {
315     fterr_warnx("read(%s): short", fname);
316     goto load_tags_out;
317   }
318 
319   /* null terminate file */
320   buf[sb.st_size] = 0;
321 
322   buf2 = buf;
323 
324   for (;;) {
325 
326     /* rip a line */
327     for (;;) {
328       c = strsep(&buf2, "\n");
329       ++lp.lineno;
330       if ((c && *c != 0) || (!c))
331         break;
332     }
333 
334     /* no more lines */
335     if (!c) {
336       goto load_tags_done;
337     }
338 
339     /* do variable substitutions first */
340     if (ftvar) {
341       if (ftvar_evalstr(ftvar, c, sbuf, sizeof(sbuf)) < 0) {
342         fterr_warnx("ftvar_evalstr(): failed");
343         goto load_tags_done;
344       }
345     } else {
346       strncpy(sbuf, c, sizeof(sbuf));
347       sbuf[sizeof(sbuf)-1] = 0;
348     }
349 
350     lp.buf = sbuf;
351 
352     /* first word */
353     NEXT_WORD(&lp.buf, c);
354 
355     /* whitespace only line */
356     if (!c) {
357       continue;
358     }
359 
360     /* comment line */
361     if (c && *c == '#')
362       continue;
363 
364     for (jmp = pjump; jmp->name; ++jmp) {
365 
366       found = 0;
367 
368       if (((!jmp->state) || (jmp->state & lp.state))
369         && (!strcasecmp(c, jmp->name))) {
370 
371         found = 1;
372 
373         if (jmp->func(&lp, fttag))
374           goto load_tags_out;
375 
376         NEXT_WORD(&lp.buf, c);
377 
378         if (c) {
379           fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c);
380           goto load_tags_out;
381         }
382 
383         break;
384 
385       }
386 
387     } /* test each word */
388 
389     if (!found) {
390       fterr_warnx("%s line %d: Unexpected \"%s\".", lp.fname, lp.lineno, c);
391       goto load_tags_out;
392     }
393 
394   } /* more lines */
395 
396 load_tags_done:
397 
398   if (resolve_actions(fttag))
399     goto load_tags_out;
400 
401   ret = 0;
402 
403 load_tags_out:
404 
405   if (fd != -1)
406     close(fd);
407 
408   if (buf)
409     free(buf);
410 
411   if (ret == -1)
412     fttag_free(fttag);
413 
414   return ret;
415 
416 } /* fttag_load */
417 
418 /*
419  * function: fttag_defintion_find
420  *
421  * Return a pointer to a fttag_def_lookup for use later with
422  * fttag_def_eval
423  *
424  * Note this allocates storage and precomputes a hash table
425  * to speed up the eval phase.  Storage is freed by fttag_free()
426  *
427  * returns : pointer to fttag_def_lookup or null if not found or error.
428  *
429  */
fttag_def_find(struct fttag * fttag,const char * name)430 struct fttag_def *fttag_def_find(struct fttag *fttag, const char *name)
431 {
432   struct fttag_def *ftd;
433 
434   /* foreach definition */
435   FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
436 
437     if (!(strcasecmp(ftd->name, name)))
438       return ftd;
439 
440   }
441 
442   return (struct fttag_def*)0L;
443 
444 } /* fttag_def_find */
445 
446 /*
447  * function: parse_action
448  *
449  * process the 'action' line.  Each action has a unique name which
450  * is added to the fttag->actions linked list.  The current action is
451  * updated in lp.  Actions by themself do nothing, they must be pointed
452  * to by a definition.
453  *
454  * returns: 0  ok
455  *          <0 fail
456  */
parse_action(struct line_parser * lp,struct fttag * fttag)457 int parse_action(struct line_parser *lp, struct fttag *fttag)
458 {
459   char *c;
460   struct fttag_action *fta;
461 
462   NEXT_WORD(&lp->buf, c);
463 
464   if (!c) {
465     fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno);
466     return -1;
467   }
468 
469   /* check if it exists */
470   FT_SLIST_FOREACH(fta, &fttag->actions, chain) {
471 
472     if (!strcasecmp(c, fta->name)) {
473       fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname,
474         lp->lineno, c);
475       return -1;
476     }
477 
478   }
479 
480   /* no, add a new entry to the list */
481   if (!(fta = (struct fttag_action*)malloc(sizeof (struct fttag_action)))) {
482     fterr_warn("malloc()");
483     return -1;
484   }
485 
486   bzero(fta, sizeof *fta);
487 
488   if (!(fta->name = (char*)malloc(strlen(c)+1))) {
489     fterr_warn("malloc()");
490     free(fta);
491     return -1;
492   }
493 
494   strcpy(fta->name, c);
495 
496   FT_SLIST_INSERT_HEAD(&fttag->actions, fta, chain);
497 
498   lp->state = PARSE_STATE_ACTION;
499   lp->cur_action = fta;
500 
501   return 0;
502 
503 } /* parse_action */
504 
505 /*
506  * function: parse_action_type
507  *
508  * process the 'type' line.  When the type is set the initial storage
509  * (table/hash/radix trie) is allocated.
510  *
511  * returns: 0  ok
512  *          <0 fail
513  */
parse_action_type(struct line_parser * lp,struct fttag * fttag)514 int parse_action_type(struct line_parser *lp, struct fttag *fttag)
515 {
516   char *c;
517 
518   if (!lp->cur_action) {
519     fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno);
520     return -1;
521   }
522 
523   NEXT_WORD(&lp->buf, c);
524 
525   if (!c) {
526     fterr_warnx("%s line %d: Expecting type.", lp->fname, lp->lineno);
527     return -1;
528   }
529 
530   if (lp->cur_action->type) {
531     fterr_warnx("%s line %d: Type previously defined.", lp->fname, lp->lineno);
532     return -1;
533   }
534 
535   if (!strcasecmp(c, "src-prefix")) {
536     lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_PREFIX;
537     lp->cur_action->eval = eval_match_src_prefix;
538   } else if (!strcasecmp(c, "source-prefix")) {
539       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_PREFIX;
540       lp->cur_action->eval = eval_match_src_prefix;
541   } else if (!strcasecmp(c, "dst-prefix")) {
542       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_PREFIX;
543       lp->cur_action->eval = eval_match_dst_prefix;
544   } else if (!strcasecmp(c, "destination-prefix")) {
545       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_PREFIX;
546       lp->cur_action->eval = eval_match_dst_prefix;
547   } else if (!strcasecmp(c, "prefix")) {
548       lp->cur_action->eval = eval_match_prefix;
549       lp->cur_action->type = FT_TAG_TYPE_MATCH_PREFIX;
550   } else if (!strcasecmp(c, "next-hop")) {
551       lp->cur_action->eval = eval_match_nexthop;
552       lp->cur_action->type = FT_TAG_TYPE_MATCH_NEXTHOP;
553   } else if (!strcasecmp(c, "src-as")) {
554       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_AS;
555       lp->cur_action->eval = eval_match_src_as;
556   } else if (!strcasecmp(c, "source-as")) {
557       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_AS;
558       lp->cur_action->eval = eval_match_src_as;
559   } else if (!strcasecmp(c, "dst-as")) {
560       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_AS;
561       lp->cur_action->eval = eval_match_dst_as;
562   } else if (!strcasecmp(c, "destination-as")) {
563       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_AS;
564       lp->cur_action->eval = eval_match_dst_as;
565   } else if (!strcasecmp(c, "as")) {
566       lp->cur_action->eval = eval_match_as;
567       lp->cur_action->type = FT_TAG_TYPE_MATCH_AS;
568   } else if (!strcasecmp(c, "tcp-src-port")) {
569       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_TCP_PORT;
570       lp->cur_action->eval = eval_match_tcp_src_port;
571   } else if (!strcasecmp(c, "tcp-source-port")) {
572       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_TCP_PORT;
573       lp->cur_action->eval = eval_match_tcp_src_port;
574   } else if (!strcasecmp(c, "tcp-dst-port")) {
575       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_TCP_PORT;
576       lp->cur_action->eval = eval_match_tcp_dst_port;
577   } else if (!strcasecmp(c, "tcp-destination-port")) {
578       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_TCP_PORT;
579       lp->cur_action->eval = eval_match_tcp_dst_port;
580   } else if (!strcasecmp(c, "tcp-port")) {
581       lp->cur_action->eval = eval_match_tcp_port;
582       lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT;
583   } else if (!strcasecmp(c, "udp-src-port")) {
584       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_UDP_PORT;
585       lp->cur_action->eval = eval_match_udp_src_port;
586   } else if (!strcasecmp(c, "udp-source-port")) {
587       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_UDP_PORT;
588       lp->cur_action->eval = eval_match_udp_src_port;
589   } else if (!strcasecmp(c, "udp-dst-port")) {
590       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_UDP_PORT;
591       lp->cur_action->eval = eval_match_udp_dst_port;
592   } else if (!strcasecmp(c, "udp-destination-port")) {
593       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_UDP_PORT;
594       lp->cur_action->eval = eval_match_udp_dst_port;
595   } else if (!strcasecmp(c, "udp-port")) {
596       lp->cur_action->eval = eval_match_udp_port;
597       lp->cur_action->type = FT_TAG_TYPE_MATCH_TCP_PORT;
598   } else if (!strcasecmp(c, "tos")) {
599       lp->cur_action->eval = eval_match_tos;
600       lp->cur_action->type = FT_TAG_TYPE_MATCH_TOS;
601   } else if (!strcasecmp(c, "any")) {
602       lp->cur_action->eval = eval_match_any;
603       lp->cur_action->type = FT_TAG_TYPE_MATCH_ANY;
604   } else if (!strcasecmp(c, "src-ip")) {
605       lp->cur_action->eval = eval_match_src_ip;
606       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_IP;
607   } else if (!strcasecmp(c, "source-ip-address")) {
608       lp->cur_action->eval = eval_match_src_ip;
609       lp->cur_action->type = FT_TAG_TYPE_MATCH_SRC_IP;
610   } else if (!strcasecmp(c, "dst-ip")) {
611       lp->cur_action->eval = eval_match_dst_ip;
612       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_IP;
613   } else if (!strcasecmp(c, "destination-ip-address")) {
614       lp->cur_action->eval = eval_match_dst_ip;
615       lp->cur_action->type = FT_TAG_TYPE_MATCH_DST_IP;
616   } else if (!strcasecmp(c, "ip")) {
617       lp->cur_action->eval = eval_match_ip;
618       lp->cur_action->type = FT_TAG_TYPE_MATCH_IP;
619   } else if (!strcasecmp(c, "exporter")) {
620       lp->cur_action->eval = eval_match_exporter;
621       lp->cur_action->type = FT_TAG_TYPE_MATCH_EXPORTER;
622   } else if (!strcasecmp(c, "input-interface")) {
623       lp->cur_action->eval = eval_match_in_interface;
624       lp->cur_action->type = FT_TAG_TYPE_MATCH_IN_INTERFACE;
625   } else if (!strcasecmp(c, "output-interface")) {
626       lp->cur_action->eval = eval_match_out_interface;
627       lp->cur_action->type = FT_TAG_TYPE_MATCH_OUT_INTERFACE;
628   } else if (!strcasecmp(c, "interface")) {
629       lp->cur_action->eval = eval_match_interface;
630       lp->cur_action->type = FT_TAG_TYPE_MATCH_INTERFACE;
631   } else {
632     fterr_warnx("%s line %d: Unrecognized type.", lp->fname, lp->lineno);
633     return -1;
634   }
635 
636   /* allocate storage for lookup */
637 
638   if ((lp->cur_action->type & FT_TAG_TYPE_MATCH_AS)) {
639 
640     if (!(lp->cur_action->look = malloc(sizeof (struct fttag_as_look)))) {
641       fterr_warn("malloc()");
642       return -1;
643     }
644 
645     bzero(lp->cur_action->look, sizeof (struct fttag_as_look));
646 
647   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_TOS) {
648 
649     if (!(lp->cur_action->look = malloc(sizeof (struct fttag_tos_look)))) {
650       fterr_warn("malloc()");
651       return -1;
652     }
653 
654     bzero(lp->cur_action->look, sizeof (struct fttag_tos_look));
655 
656   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_ANY) {
657 
658     if (!(lp->cur_action->look = malloc(sizeof (struct fttag_any_look)))) {
659       fterr_warn("malloc()");
660       return -1;
661     }
662 
663     bzero(lp->cur_action->look, sizeof (struct fttag_any_look));
664 
665   } else if (lp->cur_action->type &
666     (FT_TAG_TYPE_MATCH_TCP_PORT|FT_TAG_TYPE_MATCH_UDP_PORT)) {
667 
668     if (!(lp->cur_action->look = malloc(sizeof (struct fttag_port_look)))) {
669       fterr_warn("malloc()");
670       return -1;
671     }
672 
673     bzero(lp->cur_action->look, sizeof (struct fttag_port_look));
674 
675   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_PREFIX) {
676 
677     if (rn_inithead((void**)&lp->cur_action->look, 32) < 0) {
678       fterr_warnx("rn_inithead(): failed");
679       return -1;
680     }
681 
682   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_NEXTHOP) {
683 
684     if (!(lp->cur_action->look = ftchash_new(256, sizeof
685       (struct fttag_next_hop_look), 4, 16))) {
686       fterr_warnx("ftchash_new(): failed");
687       return -1;
688     }
689 
690   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_EXPORTER) {
691 
692     if (!(lp->cur_action->look = ftchash_new(256, sizeof
693       (struct fttag_exporter_look), 4, 16))) {
694       fterr_warnx("ftchash_new(): failed");
695       return -1;
696     }
697 
698   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_IP) {
699 
700     if (!(lp->cur_action->look = ftchash_new(256, sizeof
701       (struct fttag_ip_look), 4, 16))) {
702       fterr_warnx("ftchash_new(): failed");
703       return -1;
704     }
705 
706   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_INTERFACE) {
707 
708     if (!(lp->cur_action->look = malloc(sizeof (struct fttag_interface_look)))) {
709       fterr_warn("malloc()");
710       return -1;
711     }
712 
713     bzero(lp->cur_action->look, sizeof (struct fttag_interface_look));
714   }
715 
716   return 0;
717 
718 } /* parse_action_type */
719 
720 /*
721  * function: parse_action_match
722  *
723  * process the 'match/set' line.  The match action depends on the type which
724  * must be configured first.  An AS match is added to a table, a next-hop
725  * is added to a hash (chash_*) and a prefix is added to a radix trie, etc.
726  *
727  * returns: 0  ok
728  *          <0 fail
729  */
parse_action_match(struct line_parser * lp,struct fttag * fttag)730 int parse_action_match(struct line_parser *lp, struct fttag *fttag)
731 {
732   struct radix_sockaddr_in sock1, sock2;
733   struct fttag_as_look *as_look;
734   struct fttag_next_hop_look *nh_look, nh_look2;
735   struct fttag_prefix_look *prefix_look;
736   struct fttag_port_look *port_look;
737   struct fttag_tos_look *tos_look;
738   struct fttag_interface_look *interface_look;
739   struct fttag_exporter_look *exporter_look, exporter_look2;
740   struct fttag_ip_look *ip_look, ip_look2;
741   struct fttag_any_look *any_look;
742   struct ip_prefix ipp;
743   struct radix_node_head *rhead;
744   uint32_t tag, hash, ipaddr;
745   uint16_t as, port, interface;
746   uint8_t tos;
747   int sflag, new, tflag2, tmpflag, tflag;
748   char *c, *match;
749 
750   if (!lp->cur_action->type) {
751     fterr_warnx("%s line %d: Must set type first.", lp->fname, lp->lineno);
752     return -1;
753   }
754 
755   bzero(&sock1, sizeof sock1);
756   bzero(&sock2, sizeof sock2);
757 
758   sock1.sin_family = AF_INET;
759   sock1.sin_len = sizeof (struct radix_sockaddr_in);
760 
761   sock2.sin_family = AF_INET;
762   sock2.sin_len = sizeof (struct radix_sockaddr_in);
763 
764   as_look = lp->cur_action->look;
765   nh_look = lp->cur_action->look;
766   prefix_look = lp->cur_action->look;
767   port_look = lp->cur_action->look;
768   tos_look = lp->cur_action->look;
769   any_look = lp->cur_action->look;
770   interface_look = lp->cur_action->look;
771   ip_look = lp->cur_action->look;
772   exporter_look = lp->cur_action->look;
773 
774   NEXT_WORD(&lp->buf, c);
775 
776   if (!c) {
777     fterr_warnx("%s line %d: Expecting match data.", lp->fname, lp->lineno);
778     return -1;
779   }
780 
781   match = c;
782 
783   NEXT_WORD(&lp->buf, c);
784 
785   if (!c) {
786     fterr_warnx("%s line %d: Expecting [set|or]-[source|destination].",
787     lp->fname, lp->lineno);
788     return -1;
789   }
790 
791   if (!strcasecmp(c, "set-src")) {
792     sflag = FT_TAG_SET_SRC_TAG;
793     tflag = FT_TAG_SET_SRC_TAG;
794     tflag2 = FT_TAG_OR_SRC_TAG;
795   } else if (!strcasecmp(c, "set-source")) {
796     sflag = FT_TAG_SET_SRC_TAG;
797     tflag = FT_TAG_SET_SRC_TAG;
798     tflag2 = FT_TAG_OR_SRC_TAG;
799   } else if (!strcasecmp(c, "set-dst")) {
800     sflag = FT_TAG_SET_DST_TAG;
801     tflag = FT_TAG_SET_DST_TAG;
802     tflag2 = FT_TAG_OR_DST_TAG;
803   } else if (!strcasecmp(c, "set-destination")) {
804     sflag = FT_TAG_SET_DST_TAG;
805     tflag = FT_TAG_SET_DST_TAG;
806     tflag2 = FT_TAG_OR_DST_TAG;
807   } else if (!strcasecmp(c, "or-src")) {
808     sflag = FT_TAG_OR_SRC_TAG;
809     tflag = FT_TAG_SET_SRC_TAG;
810     tflag2 = 0;
811   } else if (!strcasecmp(c, "or-source")) {
812     sflag = FT_TAG_OR_SRC_TAG;
813     tflag = FT_TAG_SET_SRC_TAG;
814     tflag2 = 0;
815   } else if (!strcasecmp(c, "or-dst")) {
816     sflag = FT_TAG_OR_DST_TAG;
817     tflag = FT_TAG_SET_DST_TAG;
818     tflag2 = 0;
819   } else if (!strcasecmp(c, "or-destination")) {
820     sflag = FT_TAG_OR_DST_TAG;
821     tflag = FT_TAG_SET_DST_TAG;
822     tflag2 = 0;
823   } else {
824     fterr_warnx("%s line %d: Expecting [set|or]-[source|destination].",
825     lp->fname, lp->lineno);
826     return -1;
827   }
828 
829 
830 /*
831  * The data structure allows one SET or multiple OR's per
832  * source/destination tag.  Enforce this in the config parser
833  *
834  *         Error conditions
835  *        current     sflag
836  *      ------------------------
837  *       SET_SRC and SET_SRC
838  *       SET_DST and SET_DST
839  *            or
840  *       SET_SRC and OR_SRC
841  *       SET_DST and OR_DST
842  *            or
843  *       OR_SRC and  SET_SRC
844  *       OR_DST and  SET_DST
845 */
846 
847   NEXT_WORD(&lp->buf, c);
848 
849   if (!c) {
850     fterr_warnx("%s line %d: Expecting set data.", lp->fname, lp->lineno);
851     return -1;
852   }
853 
854   tag = strtoul(c, (char **)0L, 0);
855 
856   if (lp->cur_action->type & FT_TAG_TYPE_MATCH_AS) {
857 
858     as = atoi(match);
859 
860     tmpflag = as_look->set_flags_lookup[as];
861 
862     if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
863        ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
864       fterr_warnx(
865         "%s line %d: Only one set per source/destination per match.",
866         lp->fname, lp->lineno);
867       return -1;
868     }
869 
870     as_look->set_flags_lookup[as] |= sflag;
871 
872     if (sflag & FT_TAG_SET_SRC_TAG)
873       as_look->src_tag_lookup[as] = tag;
874 
875     if (sflag & FT_TAG_OR_SRC_TAG)
876       as_look->src_tag_lookup[as] |= tag;
877 
878     if (sflag & FT_TAG_SET_DST_TAG)
879       as_look->dst_tag_lookup[as] = tag;
880 
881     if (sflag & FT_TAG_OR_DST_TAG)
882       as_look->dst_tag_lookup[as] |= tag;
883 
884   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_INTERFACE) {
885 
886     interface = atoi(match);
887 
888     tmpflag = interface_look->set_flags_lookup[interface];
889 
890     if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
891        ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
892       fterr_warnx(
893         "%s line %d: Only one set per source/destination per match.",
894         lp->fname, lp->lineno);
895       return -1;
896     }
897 
898     interface_look->set_flags_lookup[interface] |= sflag;
899 
900     if (sflag & FT_TAG_SET_SRC_TAG)
901       interface_look->src_tag_lookup[interface] = tag;
902 
903     if (sflag & FT_TAG_OR_SRC_TAG)
904       interface_look->src_tag_lookup[interface] |= tag;
905 
906     if (sflag & FT_TAG_SET_DST_TAG)
907       interface_look->dst_tag_lookup[interface] = tag;
908 
909     if (sflag & FT_TAG_OR_DST_TAG)
910       interface_look->dst_tag_lookup[interface] |= tag;
911 
912 
913   } else if (lp->cur_action->type &
914     (FT_TAG_TYPE_MATCH_TCP_PORT|FT_TAG_TYPE_MATCH_UDP_PORT)) {
915 
916     port = atoi(match);
917 
918     tmpflag = port_look->set_flags_lookup[port];
919 
920     if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
921        ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
922       fterr_warnx(
923         "%s line %d: Only one set per source/destination per match.",
924         lp->fname, lp->lineno);
925       return -1;
926     }
927 
928     port_look->set_flags_lookup[port] |= sflag;
929 
930     if (sflag & FT_TAG_SET_SRC_TAG)
931       port_look->src_tag_lookup[port] = tag;
932 
933     if (sflag & FT_TAG_OR_SRC_TAG)
934       port_look->src_tag_lookup[port] |= tag;
935 
936     if (sflag & FT_TAG_SET_DST_TAG)
937       port_look->dst_tag_lookup[port] = tag;
938 
939     if (sflag & FT_TAG_OR_DST_TAG)
940       port_look->dst_tag_lookup[port] |= tag;
941 
942   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_TOS) {
943 
944     tos = atoi(match);
945 
946     tmpflag = tos_look->set_flags_lookup[tos];
947 
948     if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
949        ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
950       fterr_warnx(
951         "%s line %d: Only one set per source/destination per match.",
952         lp->fname, lp->lineno);
953       return -1;
954     }
955 
956     tos_look->set_flags_lookup[tos] |= sflag;
957 
958     if (sflag & FT_TAG_SET_SRC_TAG)
959       tos_look->src_tag_lookup[tos] = tag;
960 
961     if (sflag & FT_TAG_OR_SRC_TAG)
962       tos_look->src_tag_lookup[tos] |= tag;
963 
964     if (sflag & FT_TAG_SET_DST_TAG)
965       tos_look->dst_tag_lookup[tos] = tag;
966 
967     if (sflag & FT_TAG_OR_DST_TAG)
968       tos_look->dst_tag_lookup[tos] |= tag;
969 
970   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_ANY) {
971 
972     if (strcasecmp(match, "any")) {
973       fterr_warnx("%s line %d: Match must be any.", lp->fname, lp->lineno);
974       return -1;
975     }
976 
977     tmpflag = any_look->set_flags;
978 
979     if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
980        ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
981       fterr_warnx(
982         "%s line %d: Only one set per source/destination per match.",
983         lp->fname, lp->lineno);
984       return -1;
985     }
986 
987     any_look->set_flags |= sflag;
988 
989     if (sflag & FT_TAG_SET_SRC_TAG)
990       any_look->src_tag = tag;
991 
992     if (sflag & FT_TAG_OR_SRC_TAG)
993       any_look->src_tag |= tag;
994 
995     if (sflag & FT_TAG_SET_DST_TAG)
996       any_look->dst_tag = tag;
997 
998     if (sflag & FT_TAG_OR_DST_TAG)
999       any_look->dst_tag |= tag;
1000 
1001   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_PREFIX) {
1002 
1003     ipp = scan_ip_prefix(match);
1004     sock1.sin_addr.s_addr = ipp.addr;
1005     sock2.sin_addr.s_addr = (!ipp.len) ? 0 : mask_lookup[ipp.len];
1006 
1007     rhead = lp->cur_action->look;
1008 
1009     /* try to retrieve from trie */
1010     prefix_look = (struct fttag_prefix_look*)rhead->rnh_lookup(&sock1,
1011     &sock2, rhead);
1012 
1013     new = 1;
1014 
1015     /* if it exists, make sure not a duplicate set */
1016     if (prefix_look && (prefix_look->addr.sin_addr.s_addr == ipp.addr) &&
1017        (prefix_look->masklen == ipp.len)) {
1018 
1019       tmpflag = prefix_look->set_flags;
1020 
1021       if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1022          ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1023         fterr_warnx(
1024           "%s line %d: Only one set per source/destination per match.",
1025           lp->fname, lp->lineno);
1026         return -1;
1027       } else {
1028         new = 0;
1029       }
1030 
1031     }
1032 
1033     /* allocate a new prefix lookup */
1034     if (new) {
1035 
1036       if (!(prefix_look = (struct fttag_prefix_look*)malloc(sizeof
1037         (struct fttag_prefix_look)))) {
1038         fterr_warn("malloc(prefix_look)");
1039         return -1;
1040       }
1041 
1042       bzero(prefix_look, sizeof *prefix_look);
1043 
1044       prefix_look->rt_nodes->rn_key = (caddr_t)&prefix_look->addr;
1045 
1046       prefix_look->addr.sin_addr.s_addr = ipp.addr;
1047       prefix_look->addr.sin_len = sizeof (struct radix_sockaddr_in);
1048       prefix_look->addr.sin_family = AF_INET;
1049 
1050       sock1.sin_addr.s_addr = (!ipp.len) ? 0 : mask_lookup[ipp.len];
1051 
1052       prefix_look->masklen = ipp.len;
1053 
1054       /* add it to the trie */
1055       if (!rhead->rnh_addaddr(&prefix_look->addr, &sock1, rhead,
1056         prefix_look->rt_nodes)) {
1057         free(prefix_look);
1058         fterr_warnx("rnh_addaddr(): failed for %s",match);
1059         return -1;
1060       }
1061 
1062     } /* new */
1063 
1064     /* finish filling in */
1065 
1066     prefix_look->set_flags |= sflag;
1067 
1068     if (sflag & FT_TAG_SET_SRC_TAG)
1069       prefix_look->src_tag = tag;
1070 
1071     if (sflag & FT_TAG_OR_SRC_TAG)
1072       prefix_look->src_tag |= tag;
1073 
1074     if (sflag & FT_TAG_SET_DST_TAG)
1075       prefix_look->dst_tag = tag;
1076 
1077     if (sflag & FT_TAG_OR_DST_TAG)
1078       prefix_look->dst_tag |= tag;
1079 
1080 
1081   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_NEXTHOP) {
1082 
1083     ipaddr = scan_ip(match);
1084 
1085     hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1086     hash = (hash>>8) ^ (hash & 0xFF);
1087 
1088     nh_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1089 
1090     new = 1;
1091 
1092     /* if it exists, make sure not a duplicate set */
1093     if (nh_look) {
1094 
1095       tmpflag = nh_look->set_flags;
1096 
1097       if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1098          ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1099         fterr_warnx(
1100           "%s line %d: Only one set per source/destination per match.",
1101           lp->fname, lp->lineno);
1102         return -1;
1103       } else {
1104         new = 0;
1105       }
1106 
1107     }
1108 
1109     if (new) {
1110 
1111       bzero(&nh_look2, sizeof nh_look2);
1112 
1113       nh_look2.addr = ipaddr;
1114 
1115       if (!(nh_look = ftchash_update(lp->cur_action->look, &nh_look2, hash))) {
1116         fterr_warnx("ftch_update(): failed");
1117         return -1;
1118       }
1119 
1120     }
1121 
1122     /* finish filling in fields */
1123 
1124     nh_look->set_flags |= sflag;
1125 
1126     if (sflag & FT_TAG_SET_SRC_TAG)
1127       nh_look->src_tag = tag;
1128 
1129     if (sflag & FT_TAG_OR_SRC_TAG)
1130       nh_look->src_tag |= tag;
1131 
1132     if (sflag & FT_TAG_SET_DST_TAG)
1133       nh_look->dst_tag = tag;
1134 
1135     if (sflag & FT_TAG_OR_DST_TAG)
1136       nh_look->dst_tag |= tag;
1137 
1138   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_EXPORTER) {
1139 
1140     ipaddr = scan_ip(match);
1141 
1142     hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1143     hash = (hash>>8) ^ (hash & 0xFF);
1144 
1145     exporter_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1146 
1147     new = 1;
1148 
1149     /* if it exists, make sure not a duplicate set */
1150     if (exporter_look) {
1151 
1152       tmpflag = exporter_look->set_flags;
1153 
1154       if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1155          ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1156         fterr_warnx(
1157           "%s line %d: Only one set per source/destination per match.",
1158           lp->fname, lp->lineno);
1159         return -1;
1160       } else {
1161         new = 0;
1162       }
1163 
1164     }
1165 
1166     if (new) {
1167 
1168       bzero(&exporter_look2, sizeof exporter_look2);
1169 
1170       exporter_look2.addr = ipaddr;
1171 
1172       if (!(exporter_look = ftchash_update(lp->cur_action->look,
1173         &exporter_look2, hash))) {
1174         fterr_warnx("ftch_update(): failed");
1175         return -1;
1176       }
1177 
1178     }
1179 
1180     /* finish filling in fields */
1181 
1182     exporter_look->set_flags |= sflag;
1183 
1184     if (sflag & FT_TAG_SET_SRC_TAG)
1185       exporter_look->src_tag = tag;
1186 
1187     if (sflag & FT_TAG_OR_SRC_TAG)
1188       exporter_look->src_tag |= tag;
1189 
1190     if (sflag & FT_TAG_SET_DST_TAG)
1191       exporter_look->dst_tag = tag;
1192 
1193     if (sflag & FT_TAG_OR_DST_TAG)
1194       exporter_look->dst_tag |= tag;
1195 
1196   } else if (lp->cur_action->type & FT_TAG_TYPE_MATCH_IP) {
1197 
1198     ipaddr = scan_ip(match);
1199 
1200     hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1201     hash = (hash>>8) ^ (hash & 0xFF);
1202 
1203     ip_look = ftchash_lookup(lp->cur_action->look, &ipaddr, hash);
1204 
1205     new = 1;
1206 
1207     /* if it exists, make sure not a duplicate set */
1208     if (ip_look) {
1209 
1210       tmpflag = ip_look->set_flags;
1211 
1212       if (((tmpflag & FT_TAG_SET_SRCDST) & tflag) ||
1213          ((tmpflag & FT_TAG_OR_SRCDST) & tflag2)) {
1214         fterr_warnx(
1215           "%s line %d: Only one set per source/destination per match.",
1216           lp->fname, lp->lineno);
1217         return -1;
1218       } else {
1219         new = 0;
1220       }
1221 
1222     }
1223 
1224     if (new) {
1225 
1226       bzero(&ip_look2, sizeof ip_look2);
1227 
1228       ip_look2.addr = ipaddr;
1229 
1230       if (!(ip_look = ftchash_update(lp->cur_action->look,
1231         &ip_look2, hash))) {
1232         fterr_warnx("ftch_update(): failed");
1233         return -1;
1234       }
1235 
1236     }
1237 
1238     /* finish filling in fields */
1239 
1240     ip_look->set_flags |= sflag;
1241 
1242     if (sflag & FT_TAG_SET_SRC_TAG)
1243       ip_look->src_tag = tag;
1244 
1245     if (sflag & FT_TAG_OR_SRC_TAG)
1246       ip_look->src_tag |= tag;
1247 
1248     if (sflag & FT_TAG_SET_DST_TAG)
1249       ip_look->dst_tag = tag;
1250 
1251     if (sflag & FT_TAG_OR_DST_TAG)
1252       ip_look->dst_tag |= tag;
1253 
1254   }
1255 
1256   return 0;
1257 
1258 } /* parse_action_match */
1259 
1260 /*
1261  * function: parse_def
1262  *
1263  * process the 'definition' line.  Each definition has a unique name which
1264  * is added to the fttag->defs linked list.  The current definition is
1265  * updated in lp.
1266  *
1267  * returns: 0  ok
1268  *          <0 fail
1269  */
parse_def(struct line_parser * lp,struct fttag * fttag)1270 int parse_def(struct line_parser *lp, struct fttag *fttag)
1271 {
1272   char *c;
1273   struct fttag_def *ftd;
1274 
1275   NEXT_WORD(&lp->buf, c);
1276 
1277   if (!c) {
1278     fterr_warnx("%s line %d: Expecting name.", lp->fname, lp->lineno);
1279     return -1;
1280   }
1281 
1282   /* check if it exists */
1283   FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
1284 
1285     if (!strcasecmp(c, ftd->name)) {
1286       fterr_warnx("%s line %d: Name (%s) previously defined.", lp->fname,
1287         lp->lineno, c);
1288       return -1;
1289     }
1290 
1291   }
1292 
1293   /* no, add a new entry to the list */
1294   if (!(ftd = (struct fttag_def*)malloc(sizeof
1295     (struct fttag_def)))) {
1296     fterr_warn("malloc()");
1297     return -1;
1298   }
1299 
1300   bzero(ftd, sizeof *ftd);
1301 
1302   FT_STAILQ_INIT(&ftd->terms);
1303 
1304   if (!(ftd->name = (char*)malloc(strlen(c)+1))) {
1305     fterr_warn("malloc()");
1306     free(ftd);
1307     return -1;
1308   }
1309 
1310   strcpy(ftd->name, c);
1311 
1312   FT_SLIST_INSERT_HEAD(&fttag->defs, ftd, chain);
1313 
1314   lp->state = PARSE_STATE_DEFINITION;
1315   lp->cur_def = ftd;
1316 
1317   return 0;
1318 
1319 } /* parse_def */
1320 
1321 /*
1322  * function: parse_def_term
1323  *
1324  * process the term line.  Each definition has a list of terms, the
1325  * terms have a common input, output, and exporter IP filter and
1326  * may have one or more actions.  Without an action a term has
1327  * no purpose.
1328  *
1329  * returns: 0  ok
1330  *          <0 fail
1331  */
parse_def_term(struct line_parser * lp,struct fttag * fttag)1332 int parse_def_term(struct line_parser *lp, struct fttag *fttag)
1333 {
1334   struct fttag_def_term *ftdt;
1335 
1336   if (!lp->cur_def) {
1337     fterr_warnx("%s line %d: Must set name first.", lp->fname, lp->lineno);
1338     return -1;
1339   }
1340 
1341   /* no, add a new term entry to this definition */
1342   if (!(ftdt = (struct fttag_def_term*)malloc(sizeof *ftdt))) {
1343     fterr_warn("malloc()");
1344     return -1;
1345   }
1346 
1347   bzero(ftdt, sizeof *ftdt);
1348 
1349   FT_STAILQ_INIT(&ftdt->actions);
1350 
1351   FT_STAILQ_INSERT_TAIL(&lp->cur_def->terms, ftdt, chain);
1352 
1353   lp->cur_def_term = ftdt;
1354 
1355   return 0;
1356 
1357 } /* parse_def_term */
1358 
1359 /*
1360  * function: parse_def_exporter
1361  *
1362  * process the 'exporter' line.
1363  *
1364  * returns: 0  ok
1365  *          <0 fail
1366  */
parse_def_exporter(struct line_parser * lp,struct fttag * fttag)1367 int parse_def_exporter(struct line_parser *lp, struct fttag *fttag)
1368 {
1369   char *c;
1370 
1371   if (!lp->cur_def_term) {
1372     fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1373     return -1;
1374   }
1375 
1376   NEXT_WORD(&lp->buf, c);
1377 
1378   if (!c) {
1379     fterr_warnx("%s line %d: Expecting exporter.", lp->fname, lp->lineno);
1380     return -1;
1381   }
1382 
1383   if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_EXPORTER) {
1384     fterr_warnx("%s line %d: Exporter previously defined.", lp->fname,
1385     lp->lineno);
1386     return -1;
1387   }
1388 
1389   lp->cur_def_term->exporter_ip = scan_ip(c);
1390 
1391   lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_EXPORTER;
1392 
1393   return 0;
1394 
1395 } /* parse_def_exporter */
1396 
1397 /*
1398  * function: parse_def_input_filter
1399  *
1400  * process the 'input-filter' line.
1401  *
1402  * returns: 0  ok
1403  *          <0 fail
1404  */
parse_def_input_filter(struct line_parser * lp,struct fttag * fttag)1405 int parse_def_input_filter(struct line_parser *lp, struct fttag *fttag)
1406 {
1407   char *c;
1408 
1409   if (!lp->cur_def_term) {
1410     fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1411     return -1;
1412   }
1413 
1414   NEXT_WORD(&lp->buf, c);
1415 
1416   if (!c) {
1417     fterr_warnx("%s line %d: Expecting filter list.", lp->fname, lp->lineno);
1418     return -1;
1419   }
1420 
1421   if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_INPUT) {
1422     fterr_warnx("%s line %d: Input filter previously defined.", lp->fname,
1423     lp->lineno);
1424     return -1;
1425   }
1426 
1427   if (load_lookup(c, 65536, lp->cur_def_term->in_tbl)) {
1428     fterr_warnx("load_lookup(): failed");
1429     return -1;
1430   }
1431 
1432   lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_INPUT;
1433 
1434   return 0;
1435 
1436 } /* parse_def_input_filter */
1437 
1438 /*
1439  * function: parse_def_output_filter
1440  *
1441  * process the 'output-filter' line.
1442  *
1443  * returns: 0  ok
1444  *          <0 fail
1445  */
parse_def_output_filter(struct line_parser * lp,struct fttag * fttag)1446 int parse_def_output_filter(struct line_parser *lp, struct fttag *fttag)
1447 {
1448   char *c;
1449 
1450   if (!lp->cur_def_term) {
1451     fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1452     return -1;
1453   }
1454 
1455   NEXT_WORD(&lp->buf, c);
1456 
1457   if (!c) {
1458     fterr_warnx("%s line %d: Expecting filter list.", lp->fname, lp->lineno);
1459     return -1;
1460   }
1461 
1462   if (lp->cur_def_term->flags & FT_TAG_DEF_FILTER_OUTPUT) {
1463     fterr_warnx("%s line %d: Output filter previously defined.", lp->fname,
1464     lp->lineno);
1465     return -1;
1466   }
1467 
1468   if (load_lookup(c, 65536, lp->cur_def_term->out_tbl)) {
1469     fterr_warnx("load_lookup(): failed");
1470     return -1;
1471   }
1472 
1473   lp->cur_def_term->flags |= FT_TAG_DEF_FILTER_OUTPUT;
1474 
1475   return 0;
1476 
1477 } /* parse_def_output_filter */
1478 
1479 /*
1480  * function: parse_def_action
1481  *
1482  * foreach action listed, add it to a linked list of actions for the
1483  * definition.  Note resolve_actions() must be called before the actions
1484  * are valid.
1485  *
1486  * returns: 0  ok
1487  *          <0 fail
1488  */
parse_def_action(struct line_parser * lp,struct fttag * fttag)1489 int parse_def_action(struct line_parser *lp, struct fttag *fttag)
1490 {
1491   struct fttag_def_term_actions *ftdta;
1492   char *c;
1493 
1494   if (!lp->cur_def_term) {
1495     fterr_warnx("%s line %d: Must start term.", lp->fname, lp->lineno);
1496     return -1;
1497   }
1498 
1499   NEXT_WORD(&lp->buf, c);
1500 
1501   if (!c) {
1502     fterr_warnx("%s line %d: Expecting action.", lp->fname, lp->lineno);
1503     return -1;
1504   }
1505 
1506   /* add a new entry to the list */
1507   if (!(ftdta = (struct fttag_def_term_actions*)malloc(sizeof *ftdta))) {
1508     fterr_warn("malloc()");
1509     return -1;
1510   }
1511 
1512   bzero(ftdta, sizeof *ftdta);
1513 
1514   if (!(ftdta->name = (char*)malloc(strlen(c)+1))) {
1515     fterr_warn("malloc()");
1516     free(ftdta);
1517     return -1;
1518   }
1519   strcpy(ftdta->name, c);
1520 
1521   FT_STAILQ_INSERT_TAIL(&lp->cur_def_term->actions, ftdta, chain);
1522 
1523   /* resolve the ftdta->action later in resolve_actions */
1524 
1525   return 0;
1526 
1527 } /* parse_def_action */
1528 
1529 /*
1530  * function: resolve_actions
1531  *
1532  * The parser points to the name of the action in the definition to allow
1533  * for definitions to be defined before actions in the config file.  This
1534  * fixes the pointers so the definitions point to the actions
1535  *
1536  * returns: 0  ok
1537  *          <0 fail (an action could not be resolved)
1538  */
resolve_actions(struct fttag * fttag)1539 int resolve_actions(struct fttag *fttag)
1540 {
1541   struct fttag_def *ftd;
1542   struct fttag_def_term *ftdt;
1543   struct fttag_def_term_actions *ftdta;
1544   struct fttag_action *fta;
1545   int i, found = 0;
1546 
1547   /* foreach definition */
1548   FT_SLIST_FOREACH(ftd, &fttag->defs, chain) {
1549 
1550     /* foreach term in the definition */
1551     FT_STAILQ_FOREACH(ftdt, &ftd->terms, chain) {
1552 
1553       /*
1554        * pre-init filter to all 1's to minimize test in eval later
1555        */
1556 
1557       if (!(ftdt->flags & FT_TAG_DEF_FILTER_INPUT))
1558         for (i = 0; i < 65536; ++i)
1559           ftdt->in_tbl[i] = 1;
1560 
1561       if (!(ftdt->flags & FT_TAG_DEF_FILTER_OUTPUT))
1562         for (i = 0; i < 65536; ++i)
1563           ftdt->out_tbl[i] = 1;
1564 
1565       /* foreach action in the term */
1566       FT_STAILQ_FOREACH(ftdta, &ftdt->actions, chain) {
1567 
1568         found = 0;
1569 
1570         /* foreach action */
1571         FT_SLIST_FOREACH(fta, &fttag->actions, chain) {
1572 
1573           if (!(strcasecmp(fta->name, ftdta->name))) {
1574 
1575             ftdta->action = fta;
1576             found = 1;
1577             break;
1578 
1579           }
1580 
1581         }
1582 
1583       }
1584 
1585       if (!found) {
1586 
1587         fterr_warnx("Unable to resolve action \"%s\" in tag-definition \"%s\".", ftdta->name, ftd->name);
1588         return -1;
1589 
1590       }
1591 
1592     }
1593 
1594   }
1595 
1596   return 0;
1597 
1598 } /* resolve actions */
1599 
1600 /*
1601  * function: fttag_free
1602  *
1603  * free resources allocated by fttag_load()
1604  *
1605  */
fttag_free(struct fttag * fttag)1606 void fttag_free(struct fttag *fttag)
1607 {
1608   struct fttag_action *fta;
1609   struct fttag_def *ftd;
1610   struct fttag_def_term *ftdt;
1611   struct fttag_def_term_actions *ftdta;
1612 
1613   /* foreach action, remove the action and associated storge */
1614   while (!FT_SLIST_EMPTY(&fttag->actions)) {
1615 
1616     fta = FT_SLIST_FIRST(&fttag->actions);
1617 
1618     FT_SLIST_REMOVE_HEAD(&fttag->actions, chain);
1619 
1620     if (fta->type & FT_TAG_TYPE_MATCH_AS)
1621       free(fta->look);
1622     else if (fta->type & FT_TAG_TYPE_MATCH_NEXTHOP)
1623       ftchash_free(fta->look);
1624     else if (fta->type & FT_TAG_TYPE_MATCH_EXPORTER)
1625       ftchash_free(fta->look);
1626     else if (fta->type & FT_TAG_TYPE_MATCH_IP)
1627       ftchash_free(fta->look);
1628     else if (fta->type & FT_TAG_TYPE_MATCH_PREFIX) {
1629       rhead = fta->look;
1630       rhead->rnh_walktree(rhead, walk_free, 0);
1631     }
1632 
1633     free(fta->name);
1634     free(fta);
1635 
1636   } /* while */
1637 
1638   /* foreach definition, remove the definition and associated storage */
1639   while (!FT_SLIST_EMPTY(&fttag->defs)) {
1640 
1641     ftd = FT_SLIST_FIRST(&fttag->defs);
1642 
1643     FT_SLIST_REMOVE_HEAD(&fttag->defs, chain);
1644 
1645     /* foreach term in the definition */
1646     while (!FT_STAILQ_EMPTY(&ftd->terms)) {
1647 
1648       ftdt = FT_STAILQ_FIRST(&ftd->terms);
1649 
1650       while (!FT_STAILQ_EMPTY(&ftdt->actions)) {
1651 
1652         ftdta = FT_STAILQ_FIRST(&ftdt->actions);
1653 
1654         if (ftdta->name)
1655           free(ftdta->name);
1656 
1657         FT_STAILQ_REMOVE_HEAD(&ftdt->actions, chain);
1658 
1659         free(ftdta);
1660 
1661       }
1662 
1663       FT_STAILQ_REMOVE_HEAD(&ftd->terms, chain);
1664 
1665       free (ftdt);
1666 
1667     }
1668 
1669     free(ftd->name);
1670     free(ftd);
1671 
1672   } /* while */
1673 
1674 } /* fttag_free */
1675 
1676 /*
1677  * function: fttag_def_eval
1678  *
1679  * perform tag actions on a flow
1680  *
1681  * run down each term in the definition
1682  *  evaluate the filter, if okay
1683  *    run every action
1684  *
1685  * the filter is activated by
1686  *  FT_TAG_DEF_FILTER_INPUT - check input
1687  *  FT_TAG_DEF_FILTER_OUTPUT check output
1688  *  FT_TAG_DEF_FILTER_EXPORTER check exporter
1689  *
1690  *
1691  * returns 0
1692  */
fttag_def_eval(struct fttag_def * ftd,struct fts3rec_v1005 * rec)1693 int fttag_def_eval(struct fttag_def *ftd,
1694   struct fts3rec_v1005 *rec)
1695 {
1696   struct fttag_def_term *ftdt;
1697   struct fttag_def_term_actions *ftdta;
1698   struct fttag_action *fta;
1699 
1700   /* foreach term in the definition */
1701   FT_STAILQ_FOREACH(ftdt, &ftd->terms, chain) {
1702 
1703     /* in_tbl is preloaded with "permit any" so don't check the flags bit */
1704     if (!ftdt->in_tbl[rec->input])
1705       continue;
1706 
1707     /* out_tbl is preloaded with "permit any" so don't check the flags bit */
1708     if (!ftdt->out_tbl[rec->output])
1709       continue;
1710 
1711     if (ftdt->flags & FT_TAG_DEF_FILTER_EXPORTER)
1712       if (ftdt->exporter_ip != rec->exaddr)
1713         continue;
1714 
1715     /* for every action chained to this term */
1716     FT_STAILQ_FOREACH(ftdta, &ftdt->actions, chain) {
1717 
1718       /* the action */
1719       fta = ftdta->action;
1720 
1721       /* based on the type do the action if a match is made */
1722       fta->eval(fta, rec);
1723 
1724     } /* foreach action references by the term */
1725 
1726   } /* foreach term */
1727 
1728   return 0;
1729 
1730 } /* fttag_def_eval */
1731 
eval_match_src_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1732 static void eval_match_src_as(struct fttag_action *fta,
1733   struct fts3rec_v1005 *rec)
1734 {
1735   struct fttag_as_look *as_look;
1736   uint16_t set_tmp;
1737 
1738   as_look = fta->look;
1739 
1740   set_tmp = as_look->set_flags_lookup[rec->src_as];
1741 
1742   if (set_tmp & FT_TAG_SET_DST_TAG)
1743     rec->dst_tag = as_look->dst_tag_lookup[rec->src_as];
1744   else if (set_tmp & FT_TAG_OR_DST_TAG)
1745     rec->dst_tag |= as_look->dst_tag_lookup[rec->src_as];
1746 
1747   if (set_tmp & FT_TAG_SET_SRC_TAG)
1748     rec->src_tag = as_look->src_tag_lookup[rec->src_as];
1749   if (set_tmp & FT_TAG_OR_SRC_TAG)
1750     rec->src_tag |= as_look->src_tag_lookup[rec->src_as];
1751 
1752 } /* eval_match_src_as */
1753 
eval_match_dst_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1754 static void eval_match_dst_as(struct fttag_action *fta,
1755   struct fts3rec_v1005 *rec)
1756 {
1757   struct fttag_as_look *as_look;
1758   uint16_t set_tmp;
1759 
1760   as_look = fta->look;
1761 
1762   set_tmp = as_look->set_flags_lookup[rec->dst_as];
1763 
1764   if (set_tmp & FT_TAG_SET_DST_TAG)
1765     rec->dst_tag = as_look->dst_tag_lookup[rec->dst_as];
1766   else if (set_tmp & FT_TAG_OR_DST_TAG)
1767     rec->dst_tag |= as_look->dst_tag_lookup[rec->dst_as];
1768 
1769   if (set_tmp & FT_TAG_SET_SRC_TAG)
1770     rec->src_tag = as_look->src_tag_lookup[rec->dst_as];
1771   if (set_tmp & FT_TAG_OR_SRC_TAG)
1772     rec->src_tag |= as_look->src_tag_lookup[rec->dst_as];
1773 
1774 } /* eval_match_dst_as */
1775 
eval_match_src_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1776 static void eval_match_src_prefix(struct fttag_action *fta,
1777   struct fts3rec_v1005 *rec)
1778 {
1779   struct radix_sockaddr_in dst_sock;
1780   struct fttag_prefix_look *prefix_look;
1781   struct radix_node_head *rhead;
1782   uint16_t set_tmp;
1783 
1784   rhead = fta->look;
1785 
1786   dst_sock.sin_addr.s_addr = rec->srcaddr;
1787   dst_sock.sin_len = sizeof (struct radix_sockaddr_in);
1788   dst_sock.sin_family = AF_INET;
1789 
1790   prefix_look = (struct fttag_prefix_look *)
1791     rhead->rnh_matchaddr(&dst_sock, rhead);
1792 
1793   if (prefix_look) {
1794 
1795     set_tmp = prefix_look->set_flags;
1796 
1797     if (set_tmp & FT_TAG_SET_DST_TAG)
1798       rec->dst_tag = prefix_look->dst_tag;
1799     else if (set_tmp & FT_TAG_OR_DST_TAG)
1800       rec->dst_tag |= prefix_look->dst_tag;
1801 
1802     if (set_tmp & FT_TAG_SET_SRC_TAG)
1803       rec->src_tag = prefix_look->src_tag;
1804     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1805      rec->src_tag |= prefix_look->src_tag;
1806 
1807   }
1808 
1809 } /* eval_match_src_prefix */
1810 
eval_match_dst_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1811 static void eval_match_dst_prefix(struct fttag_action *fta,
1812   struct fts3rec_v1005 *rec)
1813 {
1814   struct radix_sockaddr_in dst_sock;
1815   struct fttag_prefix_look *prefix_look;
1816   struct radix_node_head *rhead;
1817   uint16_t set_tmp;
1818 
1819   rhead = fta->look;
1820 
1821   dst_sock.sin_addr.s_addr = rec->dstaddr;
1822   dst_sock.sin_len = sizeof (struct radix_sockaddr_in);
1823   dst_sock.sin_family = AF_INET;
1824 
1825   prefix_look = (struct fttag_prefix_look *)
1826     rhead->rnh_matchaddr(&dst_sock, rhead);
1827 
1828   if (prefix_look) {
1829 
1830     set_tmp = prefix_look->set_flags;
1831 
1832     if (set_tmp & FT_TAG_SET_DST_TAG)
1833       rec->dst_tag = prefix_look->dst_tag;
1834     else if (set_tmp & FT_TAG_OR_DST_TAG)
1835       rec->dst_tag |= prefix_look->dst_tag;
1836 
1837     if (set_tmp & FT_TAG_SET_SRC_TAG)
1838       rec->src_tag = prefix_look->src_tag;
1839     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1840      rec->src_tag |= prefix_look->src_tag;
1841 
1842   }
1843 
1844 } /* eval_match_dst_prefix */
1845 
eval_match_nexthop(struct fttag_action * fta,struct fts3rec_v1005 * rec)1846 static void eval_match_nexthop(struct fttag_action *fta,
1847   struct fts3rec_v1005 *rec)
1848 {
1849   struct ftchash *ftch;
1850   uint32_t hash, ipaddr;
1851   struct fttag_next_hop_look *nh_look;
1852   uint16_t set_tmp;
1853 
1854   ftch = fta->look;
1855   ipaddr = rec->nexthop;
1856 
1857   hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1858   hash = (hash>>8) ^ (hash & 0xFF);
1859 
1860   /* lookup next hop */
1861   nh_look = ftchash_lookup(ftch, &ipaddr, hash);
1862 
1863   if (nh_look) {
1864 
1865     set_tmp = nh_look->set_flags;
1866 
1867     if (set_tmp & FT_TAG_SET_DST_TAG)
1868       rec->dst_tag = nh_look->dst_tag;
1869     else if (set_tmp & FT_TAG_OR_DST_TAG)
1870       rec->dst_tag |= nh_look->dst_tag;
1871 
1872     if (set_tmp & FT_TAG_SET_SRC_TAG)
1873       rec->src_tag = nh_look->src_tag;
1874     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1875       rec->src_tag |= nh_look->src_tag;
1876 
1877   }
1878 
1879 } /* eval_match_nexthop */
1880 
eval_match_exporter(struct fttag_action * fta,struct fts3rec_v1005 * rec)1881 static void eval_match_exporter(struct fttag_action *fta,
1882   struct fts3rec_v1005 *rec)
1883 {
1884   struct ftchash *ftch;
1885   uint32_t hash, ipaddr;
1886   struct fttag_exporter_look *exporter_look;
1887   uint16_t set_tmp;
1888 
1889   ftch = fta->look;
1890   ipaddr = rec->exaddr;
1891 
1892   hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1893   hash = (hash>>8) ^ (hash & 0xFF);
1894 
1895   /* lookup next hop */
1896   exporter_look = ftchash_lookup(ftch, &ipaddr, hash);
1897 
1898   if (exporter_look) {
1899 
1900     set_tmp = exporter_look->set_flags;
1901 
1902 
1903     if (set_tmp & FT_TAG_SET_DST_TAG)
1904       rec->dst_tag = exporter_look->dst_tag;
1905     else if (set_tmp & FT_TAG_OR_DST_TAG)
1906       rec->dst_tag |= exporter_look->dst_tag;
1907 
1908     if (set_tmp & FT_TAG_SET_SRC_TAG)
1909       rec->src_tag = exporter_look->src_tag;
1910     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1911       rec->src_tag |= exporter_look->src_tag;
1912 
1913   }
1914 
1915 } /* eval_match_exporter */
1916 
eval_match_src_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)1917 static void eval_match_src_ip(struct fttag_action *fta,
1918   struct fts3rec_v1005 *rec)
1919 {
1920   struct ftchash *ftch;
1921   uint32_t hash, ipaddr;
1922   struct fttag_ip_look *ip_look;
1923   uint16_t set_tmp;
1924 
1925   ftch = fta->look;
1926   ipaddr = rec->srcaddr;
1927 
1928   hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1929   hash = (hash>>8) ^ (hash & 0xFF);
1930 
1931   /* lookup next hop */
1932   ip_look = ftchash_lookup(ftch, &ipaddr, hash);
1933 
1934   if (ip_look) {
1935 
1936     set_tmp = ip_look->set_flags;
1937 
1938 
1939     if (set_tmp & FT_TAG_SET_DST_TAG)
1940       rec->dst_tag = ip_look->dst_tag;
1941     else if (set_tmp & FT_TAG_OR_DST_TAG)
1942       rec->dst_tag |= ip_look->dst_tag;
1943 
1944     if (set_tmp & FT_TAG_SET_SRC_TAG)
1945       rec->src_tag = ip_look->src_tag;
1946     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1947       rec->src_tag |= ip_look->src_tag;
1948 
1949   }
1950 
1951 } /* eval_match_src_ip */
1952 
eval_match_dst_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)1953 static void eval_match_dst_ip(struct fttag_action *fta,
1954   struct fts3rec_v1005 *rec)
1955 {
1956   struct ftchash *ftch;
1957   uint32_t hash, ipaddr;
1958   struct fttag_ip_look *ip_look;
1959   uint16_t set_tmp;
1960 
1961   ftch = fta->look;
1962   ipaddr = rec->dstaddr;
1963 
1964   hash = (ipaddr>>16) ^ (ipaddr & 0xFFFF);
1965   hash = (hash>>8) ^ (hash & 0xFF);
1966 
1967   /* lookup next hop */
1968   ip_look = ftchash_lookup(ftch, &ipaddr, hash);
1969 
1970   if (ip_look) {
1971 
1972     set_tmp = ip_look->set_flags;
1973 
1974 
1975     if (set_tmp & FT_TAG_SET_DST_TAG)
1976       rec->dst_tag = ip_look->dst_tag;
1977     else if (set_tmp & FT_TAG_OR_DST_TAG)
1978       rec->dst_tag |= ip_look->dst_tag;
1979 
1980     if (set_tmp & FT_TAG_SET_SRC_TAG)
1981       rec->src_tag = ip_look->src_tag;
1982     else if (set_tmp & FT_TAG_OR_SRC_TAG)
1983       rec->src_tag |= ip_look->src_tag;
1984 
1985   }
1986 
1987 } /* eval_match_dst_ip */
1988 
eval_match_prefix(struct fttag_action * fta,struct fts3rec_v1005 * rec)1989 static void eval_match_prefix(struct fttag_action *fta,
1990   struct fts3rec_v1005 *rec)
1991 {
1992   eval_match_src_prefix(fta, rec);
1993   eval_match_dst_prefix(fta, rec);
1994 } /* eval_match_prefix */
1995 
eval_match_as(struct fttag_action * fta,struct fts3rec_v1005 * rec)1996 static void eval_match_as(struct fttag_action *fta,
1997   struct fts3rec_v1005 *rec)
1998 {
1999   eval_match_src_as(fta, rec);
2000   eval_match_dst_as(fta, rec);
2001 } /* eval_match_as */
2002 
eval_match_tcp_src_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2003 static void eval_match_tcp_src_port(struct fttag_action *fta,
2004   struct fts3rec_v1005 *rec)
2005 {
2006   struct fttag_port_look *port_look;
2007   uint16_t set_tmp;
2008 
2009   port_look = fta->look;
2010 
2011   /* only TCP here */
2012   if (rec->prot != 6)
2013     return;
2014 
2015   set_tmp = port_look->set_flags_lookup[rec->srcport];
2016 
2017   if (set_tmp & FT_TAG_SET_DST_TAG)
2018     rec->dst_tag = port_look->dst_tag_lookup[rec->srcport];
2019   else if (set_tmp & FT_TAG_OR_DST_TAG)
2020     rec->dst_tag |= port_look->dst_tag_lookup[rec->srcport];
2021 
2022   if (set_tmp & FT_TAG_SET_SRC_TAG)
2023     rec->src_tag = port_look->src_tag_lookup[rec->srcport];
2024   if (set_tmp & FT_TAG_OR_SRC_TAG)
2025     rec->src_tag |= port_look->src_tag_lookup[rec->srcport];
2026 
2027 } /* eval_match_tcp_src_port */
2028 
eval_match_tcp_dst_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2029 static void eval_match_tcp_dst_port(struct fttag_action *fta,
2030   struct fts3rec_v1005 *rec)
2031 {
2032   struct fttag_port_look *port_look;
2033   uint16_t set_tmp;
2034 
2035   port_look = fta->look;
2036 
2037   /* only TCP here */
2038   if (rec->prot != 6)
2039     return;
2040 
2041   set_tmp = port_look->set_flags_lookup[rec->dstport];
2042 
2043   if (set_tmp & FT_TAG_SET_DST_TAG)
2044     rec->dst_tag = port_look->dst_tag_lookup[rec->dstport];
2045   else if (set_tmp & FT_TAG_OR_DST_TAG)
2046     rec->dst_tag |= port_look->dst_tag_lookup[rec->dstport];
2047 
2048   if (set_tmp & FT_TAG_SET_SRC_TAG)
2049     rec->src_tag = port_look->src_tag_lookup[rec->dstport];
2050   if (set_tmp & FT_TAG_OR_SRC_TAG)
2051     rec->src_tag |= port_look->src_tag_lookup[rec->dstport];
2052 
2053 } /* eval_match_tcp_dst_port */
2054 
eval_match_udp_src_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2055 static void eval_match_udp_src_port(struct fttag_action *fta,
2056   struct fts3rec_v1005 *rec)
2057 {
2058   struct fttag_port_look *port_look;
2059   uint16_t set_tmp;
2060 
2061   port_look = fta->look;
2062 
2063   /* only UDP here */
2064   if (rec->prot != 17)
2065     return;
2066 
2067   set_tmp = port_look->set_flags_lookup[rec->srcport];
2068 
2069   if (set_tmp & FT_TAG_SET_DST_TAG)
2070     rec->dst_tag = port_look->dst_tag_lookup[rec->srcport];
2071   else if (set_tmp & FT_TAG_OR_DST_TAG)
2072     rec->dst_tag |= port_look->dst_tag_lookup[rec->srcport];
2073 
2074   if (set_tmp & FT_TAG_SET_SRC_TAG)
2075     rec->src_tag = port_look->src_tag_lookup[rec->srcport];
2076   if (set_tmp & FT_TAG_OR_SRC_TAG)
2077     rec->src_tag |= port_look->src_tag_lookup[rec->srcport];
2078 
2079 } /* eval_match_udp_src_port */
2080 
eval_match_udp_dst_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2081 static void eval_match_udp_dst_port(struct fttag_action *fta,
2082   struct fts3rec_v1005 *rec)
2083 {
2084   struct fttag_port_look *port_look;
2085   uint16_t set_tmp;
2086 
2087   port_look = fta->look;
2088 
2089   /* only UDP here */
2090   if (rec->prot != 17)
2091     return;
2092 
2093   set_tmp = port_look->set_flags_lookup[rec->dstport];
2094 
2095   if (set_tmp & FT_TAG_SET_DST_TAG)
2096     rec->dst_tag = port_look->dst_tag_lookup[rec->dstport];
2097   else if (set_tmp & FT_TAG_OR_DST_TAG)
2098     rec->dst_tag |= port_look->dst_tag_lookup[rec->dstport];
2099 
2100   if (set_tmp & FT_TAG_SET_SRC_TAG)
2101     rec->src_tag = port_look->src_tag_lookup[rec->dstport];
2102   if (set_tmp & FT_TAG_OR_SRC_TAG)
2103     rec->src_tag |= port_look->src_tag_lookup[rec->dstport];
2104 
2105 } /* eval_match_udp_dst_port */
2106 
eval_match_tcp_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2107 static void eval_match_tcp_port(struct fttag_action *fta,
2108   struct fts3rec_v1005 *rec)
2109 {
2110   eval_match_tcp_src_port(fta, rec);
2111   eval_match_tcp_dst_port(fta, rec);
2112 } /* eval_match_tcp_port */
2113 
eval_match_udp_port(struct fttag_action * fta,struct fts3rec_v1005 * rec)2114 static void eval_match_udp_port(struct fttag_action *fta,
2115   struct fts3rec_v1005 *rec)
2116 {
2117   eval_match_udp_src_port(fta, rec);
2118   eval_match_udp_dst_port(fta, rec);
2119 } /* eval_match_udp_port */
2120 
eval_match_in_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2121 static void eval_match_in_interface(struct fttag_action *fta,
2122   struct fts3rec_v1005 *rec)
2123 {
2124   struct fttag_interface_look *interface_look;
2125   uint16_t set_tmp;
2126 
2127   interface_look = fta->look;
2128 
2129   set_tmp = interface_look->set_flags_lookup[rec->input];
2130 
2131   if (set_tmp & FT_TAG_SET_DST_TAG)
2132     rec->dst_tag = interface_look->dst_tag_lookup[rec->input];
2133   else if (set_tmp & FT_TAG_OR_DST_TAG)
2134     rec->dst_tag |= interface_look->dst_tag_lookup[rec->input];
2135 
2136   if (set_tmp & FT_TAG_SET_SRC_TAG)
2137     rec->src_tag = interface_look->src_tag_lookup[rec->input];
2138   if (set_tmp & FT_TAG_OR_SRC_TAG)
2139     rec->src_tag |= interface_look->src_tag_lookup[rec->input];
2140 
2141 } /* eval_match_in_interface */
2142 
eval_match_out_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2143 static void eval_match_out_interface(struct fttag_action *fta,
2144   struct fts3rec_v1005 *rec)
2145 {
2146   struct fttag_interface_look *interface_look;
2147   uint16_t set_tmp;
2148 
2149   interface_look = fta->look;
2150 
2151   set_tmp = interface_look->set_flags_lookup[rec->output];
2152 
2153   if (set_tmp & FT_TAG_SET_DST_TAG)
2154     rec->dst_tag = interface_look->dst_tag_lookup[rec->output];
2155   else if (set_tmp & FT_TAG_OR_DST_TAG)
2156     rec->dst_tag |= interface_look->dst_tag_lookup[rec->output];
2157 
2158   if (set_tmp & FT_TAG_SET_SRC_TAG)
2159     rec->src_tag = interface_look->src_tag_lookup[rec->output];
2160   if (set_tmp & FT_TAG_OR_SRC_TAG)
2161     rec->src_tag |= interface_look->src_tag_lookup[rec->output];
2162 
2163 } /* eval_match_out_interface */
2164 
eval_match_interface(struct fttag_action * fta,struct fts3rec_v1005 * rec)2165 static void eval_match_interface(struct fttag_action *fta,
2166   struct fts3rec_v1005 *rec)
2167 {
2168   eval_match_in_interface(fta, rec);
2169   eval_match_out_interface(fta, rec);
2170 } /* eval_match_interface */
2171 
eval_match_ip(struct fttag_action * fta,struct fts3rec_v1005 * rec)2172 static void eval_match_ip(struct fttag_action *fta,
2173   struct fts3rec_v1005 *rec)
2174 {
2175   eval_match_src_ip(fta, rec);
2176   eval_match_dst_ip(fta, rec);
2177 } /* eval_match_ip */
2178 
eval_match_tos(struct fttag_action * fta,struct fts3rec_v1005 * rec)2179 static void eval_match_tos(struct fttag_action *fta,
2180   struct fts3rec_v1005 *rec)
2181 {
2182   struct fttag_tos_look *tos_look;
2183   uint16_t set_tmp;
2184 
2185   tos_look = fta->look;
2186 
2187   set_tmp = tos_look->set_flags_lookup[rec->tos];
2188 
2189   if (set_tmp & FT_TAG_SET_DST_TAG)
2190     rec->dst_tag = tos_look->dst_tag_lookup[rec->tos];
2191   else if (set_tmp & FT_TAG_OR_DST_TAG)
2192     rec->dst_tag |= tos_look->dst_tag_lookup[rec->tos];
2193 
2194   if (set_tmp & FT_TAG_SET_SRC_TAG)
2195     rec->src_tag = tos_look->src_tag_lookup[rec->tos];
2196   if (set_tmp & FT_TAG_OR_SRC_TAG)
2197     rec->src_tag |= tos_look->src_tag_lookup[rec->tos];
2198 
2199 } /* eval_match_tos */
2200 
eval_match_any(struct fttag_action * fta,struct fts3rec_v1005 * rec)2201 static void eval_match_any(struct fttag_action *fta,
2202   struct fts3rec_v1005 *rec)
2203 {
2204   struct fttag_any_look *any_look;
2205   uint16_t set_tmp;
2206 
2207   any_look = fta->look;
2208 
2209   set_tmp = any_look->set_flags;
2210 
2211   if (set_tmp & FT_TAG_SET_DST_TAG)
2212     rec->dst_tag = any_look->dst_tag;
2213   else if (set_tmp & FT_TAG_OR_DST_TAG)
2214     rec->dst_tag |= any_look->dst_tag;
2215 
2216   if (set_tmp & FT_TAG_SET_SRC_TAG)
2217     rec->src_tag = any_look->src_tag;
2218   if (set_tmp & FT_TAG_OR_SRC_TAG)
2219     rec->src_tag |= any_look->src_tag;
2220 
2221 } /* eval_match_any */
2222 
2223 
walk_free(struct radix_node * rn,struct walkarg * UNUSED)2224 static int walk_free(struct radix_node *rn, struct walkarg *UNUSED)
2225 {
2226   struct fttag_prefix_look *r;
2227   struct radix_sockaddr_in sock1, sock2;
2228 
2229   r = (struct  fttag_prefix_look*)rn;
2230   bzero(&sock1, sizeof sock1);
2231   bzero(&sock2, sizeof sock2);
2232 
2233   sock1.sin_addr.s_addr = r->addr.sin_addr.s_addr;
2234   sock1.sin_len = sizeof sock1;
2235   sock1.sin_family = AF_INET;
2236 
2237   sock2.sin_addr.s_addr = (!r->masklen) ? 0: mask_lookup[r->masklen];
2238   sock2.sin_len = sizeof sock2;
2239   sock2.sin_family = AF_INET;
2240 
2241   if (r != (struct fttag_prefix_look*)rhead->rnh_deladdr(&sock1,
2242     &sock2, rhead))
2243     fterr_errx(1, "rn_deladdr(): failed.");
2244   else
2245     free(r);
2246 
2247   return 0;
2248 } /* walk_free */
2249 
2250