blob: fb284abd6e9d40c5ccbcbfb459f0c58ba660cbae [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
Jie Jianged0b1cc2020-07-10 15:55:33 +09008#include <map>
Jie Jiang31a0b4e2020-07-09 15:06:16 +09009#include <set>
10#include <string>
Jie Jianged0b1cc2020-07-10 15:55:33 +090011#include <utility>
Jie Jiang31a0b4e2020-07-09 15:06:16 +090012#include <vector>
13
Jie Jianged0b1cc2020-07-10 15:55:33 +090014#include <patchpanel/proto_bindings/patchpanel_service.pb.h>
15
Hugo Benichicd27f4e2020-11-19 18:32:23 +090016#include "patchpanel/datapath.h"
Jie Jiang31a0b4e2020-07-09 15:06:16 +090017#include "patchpanel/minijailed_process_runner.h"
Hugo Benichiaf2021b2020-11-20 14:07:16 +090018#include "patchpanel/routing_service.h"
Jie Jiang31a0b4e2020-07-09 15:06:16 +090019#include "patchpanel/shill_client.h"
20
21namespace patchpanel {
22
23// This class manages the iptables rules for traffic counters, and queries
24// iptables to get the counters when a request comes. This class will set up
25// several iptable rules to track the counters for each possible combination of
26// {bytes, packets} x (Traffic source) x (shill device) x {rx, tx} x {IPv4,
27// IPv6}. These counters will never be removed after they are set up, and thus
28// they represent the traffic usage from boot time.
29//
Jie Jiang31a0b4e2020-07-09 15:06:16 +090030// Implementation details
31//
32// Rules: All the rules/chains for accounting are in (INPUT, FORWARD or
33// POSTROUTING) chain in the mangle table. These rules take effect after routing
34// and will not change the fate of a packet. When a new interface comes up, we
35// will create the following new rules/chains (using both iptables and
36// ip6tables):
37// - Four accounting chains:
38// - For rx packets, `ingress_input_{ifname}` and `ingress_forward_{ifname}`
39// for INPUT and FORWARD chain, respectively;
40// - For tx packets, `egress_postrouting_{ifname}` and
41// `egress_forward_{ifname}` for POSTROUTING and FORWARD chain,
42// respectively. Note that we use `--socket-exists` in POSTROUTING chain to
43// avoid packets from FORWARD being matched again here.
44// - One accounting rule in each accounting chain, which provides the actual
45// counter for accounting. We will extend this to several rules when source
46// marking is ready.
47// - One jumping rule for each accounting chain in the corresponding prebuilt
48// chain, which matches packets with this new interface.
49// The above rules and chains will never be removed once created, so we will
50// check if one rule exists before creating it.
51//
52// Query: Two commands (iptables and ip6tables) will be executed in the mangle
53// table to get all the chains and rules. And then we perform a text parsing on
54// the output to get the counters. Counters for the same entry will be merged
55// before return.
56class CountersService {
57 public:
Jie Jianged0b1cc2020-07-10 15:55:33 +090058 using SourceDevice = std::pair<TrafficCounter::Source, std::string>;
59 struct Counter {
60 Counter() = default;
61 Counter(uint64_t rx_bytes,
62 uint64_t rx_packets,
63 uint64_t tx_bytes,
64 uint64_t tx_packets);
65
66 uint64_t rx_bytes = 0;
67 uint64_t rx_packets = 0;
68 uint64_t tx_bytes = 0;
69 uint64_t tx_packets = 0;
70 };
71
Hugo Benichicd27f4e2020-11-19 18:32:23 +090072 CountersService(ShillClient* shill_client,
73 Datapath* datapath,
74 MinijailedProcessRunner* runner);
Jie Jiang31a0b4e2020-07-09 15:06:16 +090075 ~CountersService() = default;
76
Jie Jianged0b1cc2020-07-10 15:55:33 +090077 // Collects and returns counters from all the existing iptables rules.
78 // |devices| is the set of interfaces for which counters should be returned,
79 // any unknown interfaces will be ignored. If |devices| is empty, counters for
80 // all known interfaces will be returned. An empty map will be returned on
81 // any failure. Note that currently all traffic to/from an interface will be
82 // counted by (UNKNOWN, ifname), i.e., no other sources except for UNKNOWN are
83 // used.
84 std::map<SourceDevice, Counter> GetCounters(
85 const std::set<std::string>& devices);
86
Jie Jiang31a0b4e2020-07-09 15:06:16 +090087 private:
Hugo Benichicd27f4e2020-11-19 18:32:23 +090088 bool MakeAccountingChain(const std::string& chain_name);
Hugo Benichiaf2021b2020-11-20 14:07:16 +090089 bool AddAccountingRule(const std::string& chain_name, TrafficSource source);
Jie Jiang31a0b4e2020-07-09 15:06:16 +090090
Jie Jiangcf749152020-07-09 22:20:58 +090091 // Installs the required chains and rules for the given shill device.
92 void SetupChainsAndRules(const std::string& ifname);
Jie Jiangcf749152020-07-09 22:20:58 +090093
Jie Jiang31a0b4e2020-07-09 15:06:16 +090094 void OnDeviceChanged(const std::set<std::string>& added,
95 const std::set<std::string>& removed);
96
97 ShillClient* shill_client_;
Hugo Benichicd27f4e2020-11-19 18:32:23 +090098 Datapath* datapath_;
Jie Jiang31a0b4e2020-07-09 15:06:16 +090099 MinijailedProcessRunner* runner_;
100
101 base::WeakPtrFactory<CountersService> weak_factory_{this};
102};
103
Hugo Benichi92fa2032020-11-20 17:47:32 +0900104TrafficCounter::Source TrafficSourceToProto(TrafficSource source);
105
Jie Jiang31a0b4e2020-07-09 15:06:16 +0900106} // namespace patchpanel
107
108#endif // PATCHPANEL_COUNTERS_SERVICE_H_