/*
* fc_ipclassifier.cc -- click-fastclassifier functions for IPFilter and
* IPClassifier
* Eddie Kohler
*
* Copyright (c) 1999-2000 Massachusetts Institute of Technology
* Copyright (c) 2000 Mazu Networks, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, subject to the conditions
* listed in the Click LICENSE file. These conditions include: you must
* preserve this copyright notice, and you cannot mention the copyright
* holders in advertising related to the Software without their permission.
* The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This
* notice is a summary of the Click LICENSE file; the license in that file is
* legally binding. */
#include <click/config.h>
#include <click/straccum.hh>
#include "click-fastclassifier.hh"
// magic constants imported from Click itself
#define IPCLASSIFIER_TRANSP_FAKE_OFFSET 64
static void
write_checked_body(const Classifier_Program &c, StringAccum &source)
{
source << " const unsigned *ip_data = (const unsigned *)p->ip_header();\n\
const unsigned *transp_data = (const unsigned *)p->transport_header();\n\
int l = p->length() + " << IPCLASSIFIER_TRANSP_FAKE_OFFSET << " - p->transport_header_offset();\n";
source << " assert(l < " << c.safe_length << ");\n";
for (int i = 0; i < c.program.size(); i++) {
const Classifier_Insn &e = c.program[i];
int want_l = e.offset + 4;
if (!e.mask.c[3]) {
want_l--;
if (!e.mask.c[2]) {
want_l--;
if (!e.mask.c[1])
want_l--;
}
}
bool switched = (e.yes == i + 1);
int branch1 = (switched ? e.no : e.yes);
int branch2 = (switched ? e.yes : e.no);
source << " lstep_" << i << ":\n";
int offset;
String datavar;
String length_check;
if (e.offset >= IPCLASSIFIER_TRANSP_FAKE_OFFSET) {
offset = (e.offset - IPCLASSIFIER_TRANSP_FAKE_OFFSET)/4;
datavar = "transp_data";
length_check = "l < " + String(want_l);
} else {
offset = e.offset/4;
datavar = "ip_data";
length_check = "false";
}
if (want_l >= c.safe_length) {
branch2 = e.no;
goto output_branch2;
}
if (switched)
source << " if (" << length_check << " || ("
<< datavar << "[" << offset << "] & "
<< e.mask.u << "U) != " << e.value.u << "U)";
else
source << " if (!(" << length_check << ") && ("
<< datavar << "[" << offset << "] & "
<< e.mask.u << "U) == " << e.value.u << "U)";
if (branch1 <= -c.noutputs)
source << " {\n p->kill();\n return;\n }\n";
else if (branch1 <= 0)
source << " {\n output(" << -branch1 << ").push(p);\n return;\n }\n";
else
source << "\n goto lstep_" << branch1 << ";\n";
output_branch2:
if (branch2 <= -c.noutputs)
source << " p->kill();\n return;\n";
else if (branch2 <= 0)
source << " output(" << -branch2 << ").push(p);\n return;\n";
else if (branch2 != i + 1)
source << " goto lstep_" << branch2 << ";\n";
}
}
static void
write_unchecked_body(const Classifier_Program &c, StringAccum &source)
{
source << " const unsigned *ip_data = (const unsigned *)p->ip_header();\n\
const unsigned *transp_data = (const unsigned *)p->transport_header();\n";
for (int i = 0; i < c.program.size(); i++) {
const Classifier_Insn &e = c.program[i];
bool switched = (e.yes == i + 1);
int branch1 = (switched ? e.no : e.yes);
int branch2 = (switched ? e.yes : e.no);
source << " step_" << i << ":\n";
int offset;
String datavar;
if (e.offset >= IPCLASSIFIER_TRANSP_FAKE_OFFSET)
offset = (e.offset - IPCLASSIFIER_TRANSP_FAKE_OFFSET)/4, datavar = "transp_data";
else
offset = e.offset/4, datavar = "ip_data";
if (switched)
source << " if ((" << datavar << "[" << offset << "] & " << e.mask.u
<< "U) != " << e.value.u << "U)";
else
source << " if ((" << datavar << "[" << offset << "] & " << e.mask.u
<< "U) == " << e.value.u << "U)";
if (branch1 <= -c.noutputs)
source << " {\n p->kill();\n return;\n }\n";
else if (branch1 <= 0)
source << " {\n output(" << -branch1 << ").push(p);\n return;\n }\n";
else
source << "\n goto step_" << branch1 << ";\n";
if (branch2 <= -c.noutputs)
source << " p->kill();\n return;\n";
else if (branch2 <= 0)
source << " output(" << -branch2 << ").push(p);\n return;\n";
else if (branch2 != i + 1)
source << " goto step_" << branch2 << ";\n";
}
}
static void
write_push_body(const Classifier_Program &c, StringAccum &source)
{
if (c.safe_length >= IPCLASSIFIER_TRANSP_FAKE_OFFSET)
source << "\
if (p->length() + " << IPCLASSIFIER_TRANSP_FAKE_OFFSET << " - p->transport_header_offset() < " << c.safe_length << ")\n\
length_checked_push(p);\n\
else\n\
length_unchecked_push(p);\n";
else
source << " length_unchecked_push(p);\n";
}
extern "C" void
add_fast_classifiers_2()
{
add_classifier_type("IPClassifier", IPCLASSIFIER_TRANSP_FAKE_OFFSET,
0,
write_checked_body,
write_unchecked_body,
write_push_body);
add_classifier_type("IPFilter", IPCLASSIFIER_TRANSP_FAKE_OFFSET,
0,
write_checked_body,
write_unchecked_body,
write_push_body);
}
syntax highlighted by Code2HTML, v. 0.9.1