]> sourceware.org Git - systemtap.git/commitdiff
PR13667: rework/simplify rough draft for netfilter.hook probes
authorFrank Ch. Eigler <fche@redhat.com>
Thu, 12 Apr 2012 20:19:36 +0000 (16:19 -0400)
committerFrank Ch. Eigler <fche@redhat.com>
Thu, 12 Apr 2012 20:19:36 +0000 (16:19 -0400)
tapset-nethook.cxx

index 8d1e5bcca95e47f17ecb3cc03f615f0a46f583f3..0f28fda1ce6cc1fd04db87db3bfb9bab53b43bcd 100644 (file)
@@ -1,7 +1,5 @@
-// tapset for nethooks
-// Copyright (C) 2005-2011 Red Hat Inc.
-// Copyright (C) 2005-2007 Intel Corporation.
-// Copyright (C) 2008
+// tapset for netfilter hooks
+// Copyright (C) 2012 Red Hat Inc.
 //
 // This file is part of systemtap, and is free software.  You can
 // redistribute it and/or modify it under the terms of the GNU General
 using namespace std;
 using namespace __gnu_cxx;
 
-static const string TOK_NETHOOK("nethook");
+static const string TOK_NETFILTER("netfilter");
+static const string TOK_HOOK("hook");
 
 
 // ------------------------------------------------------------------------
-// nethook derived probes
+// netfilter derived probes
 // ------------------------------------------------------------------------
 
 
-struct nethook_derived_probe: public derived_probe
+struct netfilter_derived_probe: public derived_probe
 {
-  int64_t hook, protocol;
-  nethook_derived_probe (probe* p, probe_point* l,
-                       int64_t hook, int64_t hooknum);
+  netfilter_derived_probe (probe* p, probe_point* l);
   virtual void join_group (systemtap_session& s);
-
-  // No assertion need be emitted, since this probe is allowed for unprivileged
-  // users.
-  void emit_privilege_assertion (translator_output*) {}
   void print_dupe_stamp(ostream& o) { print_dupe_stamp_unprivileged (o); }
 };
 
 
-struct nethook_derived_probe_group: public generic_dpg<nethook_derived_probe>
+struct netfilter_derived_probe_group: public generic_dpg<netfilter_derived_probe>
 {
-  void emit_netfunc (translator_output* o);
 public:
   void emit_module_decls (systemtap_session& s);
   void emit_module_init (systemtap_session& s);
@@ -53,93 +45,38 @@ public:
 };
 
 
-nethook_derived_probe::nethook_derived_probe (probe* p, probe_point* l,
-                                          int64_t h, int64_t proto, int64_t r):
-  derived_probe (p, l), hook (h), protocol (proto), resault(r)
+netfilter_derived_probe::netfilter_derived_probe (probe* p, probe_point* l):
+  derived_probe (p, l)
 {
-  if (hook < 0 || hook > 4) // h must be within hooks
-    //TRANSLATORS: 'nethook' is the name of a probe point
-    throw semantic_error (_("invalid hook for nethook"));
-
-  if (proto < 0 || proto > 255)
-    //TRANSLATORS: 'protocol' is a key word
-    throw semantic_error (_("invalid protocol for nethook"));
-
-  if (locations.size() != 1)
-    throw semantic_error (_("only expect one probe point"));
-  // so we don't have to loop over them in the other functions
 }
 
 
 void
-nethook_derived_probe::join_group (systemtap_session& s)
+netfilter_derived_probe::join_group (systemtap_session& s)
 {
-  if (! s.nethook_derived_probes)
-    s.nethook_derived_probes = new nethook_derived_probe_group ();
-  s.nethook_derived_probes->enroll (this);
+  if (! s.netfilter_derived_probes)
+    s.netfilter_derived_probes = new netfilter_derived_probe_group ();
+  s.netfilter_derived_probes->enroll (this);
 }
 
 
 void
-nethook_derived_probe_group::emit_netfunc (systemtap_session& s)
-{
-  s.op->newline() << "unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))";
-  s.op->newline() << "{";
-  s.op->newline(1) << "sock_buff = skb;"; 
-  s.op->newline() << "if(!sock_buff) { return NF_ACCEPT;}";
-  s.op->newline() << "ip_header = (struct iphdr *)skb_network_header(sock_buff);";
-  s.op->newline() << "if(!ip_header) { return NF_ACCEPT;}";
-  s.op->newline() << "if (ip_header->protocol==TCP) {";
-  s.op->newline(1) << "tcp_header = (struct tcphdr *)skb_transport_header(sock_buff);";
-  s.op->newline() << "printk(KERN_INFO \"[TCP, HTTP] Packet Recieved...\n   From: %d.%d.%d.%d:%d\n   To:%d.%d.%d.%d:%d\",";
-  s.op->newline(1) << "(ip_header->saddr & 0x000000FF),";
-  s.op->newline() << "(ip_header->saddr & 0x0000FF00) >> 8,";
-  s.op->newline() << "(ip_header->saddr & 0x00FF0000) >> 16,";
-  s.op->newline() << "(ip_header->saddr & 0xFF000000) >> 24,";
-  s.op->newline() << "ntohs(tcp_header->source),";
-  s.op->newline() << "(ip_header->daddr & 0x000000FF),";
-  s.op->newline() << "(ip_header->daddr & 0x0000FF00) >> 8,";
-  s.op->newline() << "(ip_header->daddr & 0x00FF0000) >> 16,";
-  s.op->newline() << "(ip_header->daddr & 0xFF000000) >> 24,";
-  s.op->newline() << "ntohs(tcp_header->dest));";
-  s.op->newline(-1) << "return NF_ACCEPT;";
-  s.op->newline(-1) << "}";
-  s.op->newline() << "return NF_ACCEPT;";
-  s.op->newline(-1) << "}";
-}
-
-
-void
-nethook_derived_probe_group::emit_module_decls (systemtap_session& s)
+netfilter_derived_probe_group::emit_module_decls (systemtap_session& s)
 {
   if (probes.empty()) return;
 
-  s.op->newline() << "/* ---- nethook probes ---- */";
-
-  s.op->newline() << "static struct stap_nethook_probe {";
-  s.op->newline(1) << "struct nethook_list nethook_list;";
-  s.op->newline() << "struct stap_probe * const probe;";
-  s.op->newline() << "unsigned hook, protocol;";
-  s.op->newline(-1) << "} stap_nethook_probes [" << probes.size() << "] = {";
-  s.op->indent(1);
-  for (unsigned i=0; i < probes.size(); i++)
-    {
-      s.op->newline () << "{";
-      s.op->line() << " .probe=" << common_probe_init (probes[i]) << ",";
-      s.op->line() << " .hook=" << probes[i]->hook << ",";
-      s.op->line() << " .protocol=" << probes[i]->protocol << ",";
-      s.op->line() << " },";
-    }
-  s.op->newline(-1) << "};";
-  s.op->newline();
-
-  s.op->newline() << "static void enter_nethook_probe (struct stap_be_probe *stp) {";
-  s.op->indent(1);
-  common_probe_entryfn_prologue (s.op, "stp->state", "stp->probe",
-                                "_STP_PROBE_HANDLER_NETHOOK", false);
-  s.op->newline() << "(*stp->probe->ph) (c);";
-  common_probe_entryfn_epilogue (s.op, false, s.suppress_handler_errors);
-  s.op->newline(-1) << "}";
+  // Here we emit any global data structures and functions, including callback functions
+  // to be invoked by netfilter.
+  // 
+  // For other kernel callbacks, a token is passed back to help identify a particular
+  // probe-point registration.  For netfilter, nope, so once we're in a notification callback,
+  // we can't find out exactly on whose (which probe point's) behalf we were called.
+  // 
+  // So, we just emit one netfilter callback function per systemtap probe, each with its
+  // own nf_hook_ops structure.  Note that the translator already emits a stp_probes[] array,
+  // pre-filled with probe names and handler functions and that sort of stuff.
+  s.op->newline() << "/* ---- netfilter probes ---- */";
 
   s.op->newline() << "#include <linux/netfilter.h>";
   s.op->newline() << "#include <linux/netfilter_ipv4.h>";
@@ -147,58 +84,90 @@ nethook_derived_probe_group::emit_module_decls (systemtap_session& s)
   s.op->newline() << "#include <linux/udp.h>";
   s.op->newline() << "#include <linux/tcp.h>";
   s.op->newline() << "#include <linux/ip.h>";
-  s.op->newline() << "#define TCP 6";
-  s.op->newline() << "#define UDP 17";
-  s.op->newline() << "static struct nf_hook_ops nfho;";
-  s.op->newline() << "struct sk_buff *sock_buff;";
-  s.op->newline() << "struct udphdr *udp_header;";
-  s.op->newline() << "struct tcphdr *tcp_header;";
-  s.op->newline() << "struct iphdr *ip_header;";
+
+  for (unsigned i=0; i < probes.size(); i++)
+    {
+      netfilter_derived_probe *np = probes[i];
+      s.op->newline() << "static void enter_netfilter_probe_" << np->name;
+      s.op->newline() << "(unsigned int hooknum, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *))";
+      s.op->newline() << "{";
+      s.op->newline(1) << "struct stap_probe * const stp = & stap_probes[", p->session_index << "];";
+      common_probe_entryfn_prologue (s.op, "STAP_SESSION_RUNNING", "stp",
+                                     "_STP_PROBE_HANDLER_NETFILTER", 
+                                     false);
+      // Pretend to touch each netfilter hook callback argument, so we
+      // don't get complaints about unused parameters.
+      s.op->newline() << "(void) hooknum;";
+      s.op->newline() << "(void) skb;";
+      s.op->newline() << "(void) in;";
+      s.op->newline() << "(void) out;";
+      s.op->newline() << "(void) okfn;";
+      // Finally, invoke the probe handler
+      s.op->newline() << "(*stp->ph) (c);";
+      common_probe_entryfn_epilogue (s.op, false, s.suppress_handler_errors);
+      s.op->newline() << "return NF_ACCEPT;"; // XXX: this could instead be an output from the handler
+      s.op->newline(-1) << "}";
+
+      // now emit the nf_hook_ops struct for this probe.
+      s.op->newline() << "static struct nf_hook_ops netfilter_opts_ = {" << np->name;
+      s.op->newline() << ".hook = & enter_netfilter_probe_" << np->name << ",";
+      s.op->newline() << ".owner = THIS_MODULE,";
+      s.op->newline() << ".hooknum = 0,"; // XXX: should be probe point argument
+      s.op->newline() << ".pf = PF_INET,"; // XXX: should be probe point argument
+      s.op->newline() << ".priority = PF_INET,"; // XXX: should be probe point argument
+      s.op->newline(-1) << "};";
+    }
+  s.op->newline();
 }
 
 
 void
-nethook_derived_probe_group::emit_module_init (systemtap_session& s)
+netfilter_derived_probe_group::emit_module_init (systemtap_session& s)
 {
   if (probes.empty()) return;
 
-  s.op->newline() << "for (i=0; i<" << probes.size() << "; i++) {";
-  s.op->newline(1) << "struct stap_nethook_probe* stp = & stap_nethook_probes [i];";
-  s.op->newline(1) << "enter_nethook_probe (stp); /* rc = 0 */";
-  s.op->newline() << "stap_nethook_probes[i].hook = hook_func;";
-  s.op->newline() << "stap_nethook_probes[i].hooknum = 0;";
-  s.op->newline() << "stap_nethook_probes[i].pf = PF_INET;";
-  s.op->newline() << "stap_nethook_probes[i].priority = NF_IP_PRI_FIRST;";
-  s.op->newline() << "int rc = nf_register_hook(&stap_nethook_probes[i]);";
-  s.op->newline() << "if (rc < 0)";
-  s.op->newline() << "{";
-  s.op->newline(1) << "for (j=i-1; j>=0; j--)";
-  s.op->newline(1) << "nf_unregister_hook(&stap_nethook_probes[j]);";
-  s.op->newline(-2) << "}";
-  s.op->newline(-1) << "}";
-
-  emit_netfunc(s.op);
+  // We register (do not execute) the probes here.
+  // NB: since we anticipate only a few netfilter/hook type probes, there is no need to
+  // emit an initialization loop into the generated C code.  We can simply unroll it.
+  for (unsigned i=0; i < probes.size(); i++) 
+    {
+      netfilter_derived_probe *np = probes[i];
+      s.op->newline() << "rc = nf_register_hook (& netfilter_opts_" << np->name << ");";
+      if (i > 0) // unregister others upon failure
+        {
+          s.op->newline() << "if (rc < 0) {";
+          s.op->newline(1);
+          for (unsigned j=i-1; j>=0; j++) 
+            {
+              netfilter_derived_probe *np2 = probes[j];
+              s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np2->name << ");";
+            }
+          s.op->newline(-1) << "}";
+        }
+    }
 }
 
 
 void
-nethook_derived_probe_group::emit_module_exit (systemtap_session& s)
+netfilter_derived_probe_group::emit_module_exit (systemtap_session& s)
 {
- if (probes.empty()) return;
-  s.op->newline() << "for (i=0; i<" << probes.size() << "; i++)";
- s.op->newline(1) << "nf_unregister_hook(&stap_nethook_probes[i]);";
-  s.op->indent(-1);
-
-
+  if (probes.empty()) return;
+  
+  // We register (do not execute) the probes here.
+  for (unsigned i=0; i < probes.size(); i++) 
+    {
+      netfilter_derived_probe *np = probes[i];
+      s.op->newline() << "nf_unregister_hook (& netfilter_opts_" << np->name << ");";
+    }
 }
 
 
 // ------------------------------------------------------------------------
-// unified probe builder for nethook probes
+// unified probe builder for netfilter probes
 // ------------------------------------------------------------------------
 
 
-struct nethook_builder: public derived_probe_builder
+struct netfilter_builder: public derived_probe_builder
 {
     virtual void build(systemtap_session & sess,
                        probe * base, probe_point * location,
@@ -208,35 +177,27 @@ struct nethook_builder: public derived_probe_builder
     static void register_patterns(systemtap_session& s);
 };
 
+
 void
-nethook_builder::build(systemtap_session & sess,
+netfilter_builder::build(systemtap_session & sess,
     probe * base,
     probe_point * location,
     literal_map_t const & parameters,
     vector<derived_probe *> & finished_results)
 {
-  int64_t hook, protocol;
-
-
-  if (get_param(parameters, "hook", hook) && get_param(parameters, "protocol", protocol));
-    {
-      finished_results.push_back
-        (new nethook_derived_probe(base, location, hook, protocol));
-    }
-  return;
+  // XXX: extract optional probe point arguments later
+  finished_results.push_back(new netfilter_derived_probe(base, location));
 }
 
+
 void
-register_tapset_nethooks(systemtap_session& s)
+register_tapset_netfilters(systemtap_session& s)
 {
   match_node* root = s.pattern_root;
-  derived_probe_builder *builder = new nethook_builder();
-
-  root = root->bind(TOK_NETHOOK);
+  derived_probe_builder *builder = new netfilter_builder();
 
-  root->bind_num(TOK_NETHOOK)
-    ->bind_privilege(pr_all)
-    ->bind(builder);
+  // netfilter.hook
+  root->bind(TOK_NETFILTER)->bind(TOK_HOOK)->bind(builder);
 }
 
 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.035518 seconds and 5 git commands to generate.