IP_PROTO_UDP = 17
class ASTAction(Enum):
- OR = 1,
- AND = 2,
- NOT = 3,
- EXPR = 4
+ OR = 1
+ AND = 2
+ NOT = 3
+ FALSE = 4
+ TRUE = 5
+ EXPR = 6
class ASTNode:
def __init__(self, action, left, right=None):
self.action = action
+ if action == ASTAction.FALSE or action == ASTAction.TRUE:
+ assert left is None and right is None
+ return
self.left = left
if right is None:
assert action == ASTAction.EXPR or action == ASTAction.NOT
return "(" + self.left.write(expr_param, expr_param2) + ") && (" + self.right.write(expr_param, expr_param2) + ")"
if self.action == ASTAction.NOT:
return "!(" + self.left.write(expr_param, expr_param2) + ")"
+ if self.action == ASTAction.FALSE:
+ return "0"
+ if self.action == ASTAction.TRUE:
+ return "1"
if self.action == ASTAction.EXPR:
return self.left.write(expr_param, expr_param2)
def parse_ast(expr, parse_expr):
expr = expr.strip()
- and_split = expr.split("&&", 1)
+ comma_split = expr.split(",", 1)
or_split = expr.split("||", 1)
- if len(and_split) > 1 and not "||" in and_split[0]:
- return ASTNode(ASTAction.AND, parse_ast(and_split[0], parse_expr), parse_ast(and_split[1], parse_expr))
+ if len(comma_split) > 1 and not "||" in comma_split[0]:
+ return ASTNode(ASTAction.OR, parse_ast(comma_split[0], parse_expr), parse_ast(comma_split[1], parse_expr))
if len(or_split) > 1:
- assert not "&&" in or_split[0]
+ assert not "," in or_split[0]
return ASTNode(ASTAction.OR, parse_ast(or_split[0], parse_expr), parse_ast(or_split[1], parse_expr))
- comma_split = expr.split(",", 1)
- if len(comma_split) > 1:
- return ASTNode(ASTAction.OR, parse_ast(comma_split[0], parse_expr), parse_ast(comma_split[1], parse_expr))
+ and_split = expr.split("&&", 1)
+ if len(and_split) > 1:
+ return ASTNode(ASTAction.AND, parse_ast(and_split[0], parse_expr), parse_ast(and_split[1], parse_expr))
+
+ if expr.strip() == "true":
+ return ASTNode(ASTAction.TRUE, None)
+ if expr.strip() == "false":
+ return ASTNode(ASTAction.FALSE, None)
if expr.startswith("!"):
return ASTNode(ASTAction.NOT, parse_ast(expr[1:], parse_expr))
with open("rules.h", "w") as out:
parse = argparse.ArgumentParser()
parse.add_argument("--ihl", dest="ihl", required=True, choices=["drop-options","accept-options","parse-options"])
+ parse.add_argument("--v6frag", dest="v6frag", required=True, choices=["drop-frags","ignore","parse-frags","ignore-parse-if-rule"])
parse.add_argument("--8021q", dest="vlan", required=True, choices=["drop-vlan","accept-vlan","parse-vlan"])
parse.add_argument("--require-8021q", dest="vlan_tag")
args = parse.parse_args(sys.argv[1:])
elif args.ihl == "parse-options":
out.write("#define PARSE_IHL PARSE\n")
+ if args.v6frag == "drop-frags":
+ out.write("#define PARSE_V6_FRAG XDP_DROP\n")
+ elif args.v6frag == "ignore":
+ pass
+ elif args.v6frag == "parse-frags":
+ out.write("#define PARSE_V6_FRAG PARSE\n")
+
if args.vlan == "drop-vlan":
out.write("#define PARSE_8021Q XDP_DROP\n")
elif args.vlan == "accept-vlan":
assert False
out.write("#define REQ_8021Q " + args.vlan_tag + "\n")
+ use_v4 = False
+ use_v6 = False
+ use_v6_frags = False
+ rulecnt = 0
+
out.write("#define RULES \\\n")
def write_rule(r):
continue
if t[0].strip() == "flow4":
proto = 4
+ use_v4 = True
out.write("if (eth_proto == htons(ETH_P_IP)) { \\\n")
out.write("\tdo {\\\n")
elif t[0].strip() == "flow6":
proto = 6
+ use_v6 = True
out.write("if (eth_proto == htons(ETH_P_IPV6)) { \\\n")
out.write("\tdo {\\\n")
else:
elif step.strip().startswith("label"):
write_rule(flow_label_to_rule(step.strip()[6:]))
elif step.strip().startswith("fragment"):
+ if proto == 6:
+ use_v6_frags = True
write_rule(fragment_to_rule(proto, step.strip()[9:]))
elif step.strip() == "":
pass
else:
assert False
- out.write("\t\treturn XDP_DROP;\\\n")
+ out.write(f"\t\tconst uint32_t ruleidx = STATIC_RULE_CNT + {rulecnt};\\\n")
+ out.write("\t\tDO_RETURN(ruleidx, XDP_DROP);\\\n")
out.write("\t} while(0);\\\n}\\\n")
+ rulecnt += 1
out.write("\n")
+ out.write(f"#define RULECNT {rulecnt}\n")
+ if use_v4:
+ out.write("#define NEED_V4_PARSE\n")
+ if use_v6:
+ out.write("#define NEED_V6_PARSE\n")
+ if args.v6frag == "ignore-parse-if-rule":
+ if use_v6_frags:
+ out.write("#define PARSE_V6_FRAG PARSE\n")