blob: d1ffdcd4508bc37733f96211b295c001a28cac80 [file] [log] [blame]
Jie Jiang31a0b4e2020-07-09 15:06:16 +09001// Copyright 2020 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef PATCHPANEL_COUNTERS_SERVICE_H_
6#define PATCHPANEL_COUNTERS_SERVICE_H_
7
8#include <set>
9#include <string>
10#include <vector>
11
12#include "patchpanel/minijailed_process_runner.h"
13#include "patchpanel/shill_client.h"
14
15namespace patchpanel {
16
17// This class manages the iptables rules for traffic counters, and queries
18// iptables to get the counters when a request comes. This class will set up
19// several iptable rules to track the counters for each possible combination of
20// {bytes, packets} x (Traffic source) x (shill device) x {rx, tx} x {IPv4,
21// IPv6}. These counters will never be removed after they are set up, and thus
22// they represent the traffic usage from boot time.
23//
24// TODO(jiejiang): The following will be implemented in the following patches.
25//
26// Implementation details
27//
28// Rules: All the rules/chains for accounting are in (INPUT, FORWARD or
29// POSTROUTING) chain in the mangle table. These rules take effect after routing
30// and will not change the fate of a packet. When a new interface comes up, we
31// will create the following new rules/chains (using both iptables and
32// ip6tables):
33// - Four accounting chains:
34// - For rx packets, `ingress_input_{ifname}` and `ingress_forward_{ifname}`
35// for INPUT and FORWARD chain, respectively;
36// - For tx packets, `egress_postrouting_{ifname}` and
37// `egress_forward_{ifname}` for POSTROUTING and FORWARD chain,
38// respectively. Note that we use `--socket-exists` in POSTROUTING chain to
39// avoid packets from FORWARD being matched again here.
40// - One accounting rule in each accounting chain, which provides the actual
41// counter for accounting. We will extend this to several rules when source
42// marking is ready.
43// - One jumping rule for each accounting chain in the corresponding prebuilt
44// chain, which matches packets with this new interface.
45// The above rules and chains will never be removed once created, so we will
46// check if one rule exists before creating it.
47//
48// Query: Two commands (iptables and ip6tables) will be executed in the mangle
49// table to get all the chains and rules. And then we perform a text parsing on
50// the output to get the counters. Counters for the same entry will be merged
51// before return.
52class CountersService {
53 public:
54 CountersService(ShillClient* shill_client, MinijailedProcessRunner* runner);
55 ~CountersService() = default;
56
57 private:
58 // TODO(b/161060333): Move the following two functions elsewhere.
59 // Creates a new chain using both iptables and ip6tables in the mangle table.
60 void IptablesNewChain(const std::string& chain_name);
61
62 // Creates a new rule using both iptables and ip6tables in the mangle table.
63 // The first element in |params| should be "-I" (insert) or "-A" (append), and
64 // this function will replace it with "-C" to do the check before executing
65 // the actual insert or append command. This function will also append "-w" to
66 // |params|. Note that |params| is passed by value because it will be modified
67 // inside the function, and the normal pattern to use this function is passing
68 // an rvalue (e.g., `IptablesNewRule({"-I", "INPUT", ...})`), so no extra copy
69 // should happen in such cases.
70 void IptablesNewRule(std::vector<std::string> params);
71
72 void OnDeviceChanged(const std::set<std::string>& added,
73 const std::set<std::string>& removed);
74
75 ShillClient* shill_client_;
76 MinijailedProcessRunner* runner_;
77
78 base::WeakPtrFactory<CountersService> weak_factory_{this};
79};
80
81} // namespace patchpanel
82
83#endif // PATCHPANEL_COUNTERS_SERVICE_H_