patchpanel: Introduce CountersService for traffic accounting

This patch adds the framework code for CountersService and two helper
functions in it. The actual implementation will comes with the following
patches.

BUG=b:160112868
TEST=build

Change-Id: I9a6f67cc5759969da3685541e0313dffd982769d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform2/+/2289712
Reviewed-by: Garrick Evans <garrick@chromium.org>
Reviewed-by: Hugo Benichi <hugobenichi@google.com>
Tested-by: Jie Jiang <jiejiang@chromium.org>
Commit-Queue: Jie Jiang <jiejiang@chromium.org>
diff --git a/patchpanel/counters_service.cc b/patchpanel/counters_service.cc
new file mode 100644
index 0000000..aeb1ff4
--- /dev/null
+++ b/patchpanel/counters_service.cc
@@ -0,0 +1,58 @@
+// Copyright 2020 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "patchpanel/counters_service.h"
+
+#include <set>
+#include <string>
+#include <vector>
+
+namespace patchpanel {
+
+namespace {
+
+constexpr char kMangleTable[] = "mangle";
+
+}  // namespace
+
+CountersService::CountersService(ShillClient* shill_client,
+                                 MinijailedProcessRunner* runner)
+    : shill_client_(shill_client), runner_(runner) {
+  // Triggers the callback manually to make sure no device is missed.
+  OnDeviceChanged(shill_client_->get_devices(), {});
+  shill_client_->RegisterDevicesChangedHandler(base::BindRepeating(
+      &CountersService::OnDeviceChanged, weak_factory_.GetWeakPtr()));
+}
+
+void CountersService::OnDeviceChanged(const std::set<std::string>& added,
+                                      const std::set<std::string>& removed) {}
+
+void CountersService::IptablesNewChain(const std::string& chain_name) {
+  // There is no straightforward way to check if a chain exists or not.
+  runner_->iptables(kMangleTable, {"-N", chain_name, "-w"},
+                    false /*log_failures*/);
+  runner_->ip6tables(kMangleTable, {"-N", chain_name, "-w"},
+                     false /*log_failures*/);
+}
+
+void CountersService::IptablesNewRule(std::vector<std::string> params) {
+  DCHECK_GT(params.size(), 0);
+  const std::string action = params[0];
+  DCHECK(action == "-I" || action == "-A");
+  params.emplace_back("-w");
+
+  params[0] = "-C";
+  if (runner_->iptables(kMangleTable, params, false /*log_failures*/) != 0) {
+    params[0] = action;
+    runner_->iptables(kMangleTable, params);
+  }
+
+  params[0] = "-C";
+  if (runner_->ip6tables(kMangleTable, params, false /*log_failures*/) != 0) {
+    params[0] = action;
+    runner_->ip6tables(kMangleTable, params);
+  }
+}
+
+}  // namespace patchpanel