blob: 3e3460defea9414c21ea4386673df2294233c5ff [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
20namespace patchpanel {
21
22// This class manages the iptables rules for traffic counters, and queries
23// iptables to get the counters when a request comes. This class will set up
24// several iptable rules to track the counters for each possible combination of
25// {bytes, packets} x (Traffic source) x (shill device) x {rx, tx} x {IPv4,
26// IPv6}. These counters will never be removed after they are set up, and thus
27// they represent the traffic usage from boot time.
28//
Jie Jiang31a0b4e2020-07-09 15:06:16 +090029// Implementation details
30//
31// Rules: All the rules/chains for accounting are in (INPUT, FORWARD or
32// POSTROUTING) chain in the mangle table. These rules take effect after routing
33// and will not change the fate of a packet. When a new interface comes up, we
34// will create the following new rules/chains (using both iptables and
35// ip6tables):
36// - Four accounting chains:
37// - For rx packets, `ingress_input_{ifname}` and `ingress_forward_{ifname}`
38// for INPUT and FORWARD chain, respectively;
39// - For tx packets, `egress_postrouting_{ifname}` and
40// `egress_forward_{ifname}` for POSTROUTING and FORWARD chain,
41// respectively. Note that we use `--socket-exists` in POSTROUTING chain to
42// avoid packets from FORWARD being matched again here.
43// - One accounting rule in each accounting chain, which provides the actual
44// counter for accounting. We will extend this to several rules when source
45// marking is ready.
46// - One jumping rule for each accounting chain in the corresponding prebuilt
47// chain, which matches packets with this new interface.
48// The above rules and chains will never be removed once created, so we will
49// check if one rule exists before creating it.
50//
51// Query: Two commands (iptables and ip6tables) will be executed in the mangle
52// table to get all the chains and rules. And then we perform a text parsing on
53// the output to get the counters. Counters for the same entry will be merged
54// before return.
55class CountersService {
56 public:
Jie Jianged0b1cc2020-07-10 15:55:33 +090057 using SourceDevice = std::pair<TrafficCounter::Source, std::string>;
58 struct Counter {
59 Counter() = default;
60 Counter(uint64_t rx_bytes,
61 uint64_t rx_packets,
62 uint64_t tx_bytes,
63 uint64_t tx_packets);
64
65 uint64_t rx_bytes = 0;
66 uint64_t rx_packets = 0;
67 uint64_t tx_bytes = 0;
68 uint64_t tx_packets = 0;
69 };
70
Hugo Benichi058a26a2020-11-26 10:10:39 +090071 CountersService(Datapath* datapath, MinijailedProcessRunner* runner);
Jie Jiang31a0b4e2020-07-09 15:06:16 +090072 ~CountersService() = default;
73
Hugo Benichi058a26a2020-11-26 10:10:39 +090074 // Installs the initial iptables setup for vpn accounting and for the given
75 // set of devices.
76 void Init(const std::set<std::string>& devices);
77 // Adds accounting rules and jump rules for a new physical device if this is
78 // the first time this device is seen.
79 void OnPhysicalDeviceAdded(const std::string& ifname);
80 // Removes jump rules for a physical device.
81 void OnPhysicalDeviceRemoved(const std::string& ifname);
82 // Adds accounting rules and jump rules for a new VPN device.
83 void OnVpnDeviceAdded(const std::string& ifname);
84 // Removes jump rules for a VPN device.
85 void OnVpnDeviceRemoved(const std::string& ifname);
Jie Jianged0b1cc2020-07-10 15:55:33 +090086 // Collects and returns counters from all the existing iptables rules.
87 // |devices| is the set of interfaces for which counters should be returned,
88 // any unknown interfaces will be ignored. If |devices| is empty, counters for
89 // all known interfaces will be returned. An empty map will be returned on
90 // any failure. Note that currently all traffic to/from an interface will be
91 // counted by (UNKNOWN, ifname), i.e., no other sources except for UNKNOWN are
92 // used.
93 std::map<SourceDevice, Counter> GetCounters(
94 const std::set<std::string>& devices);
95
Jie Jiang31a0b4e2020-07-09 15:06:16 +090096 private:
Hugo Benichi058a26a2020-11-26 10:10:39 +090097 // Creates an iptables chain in the mangle table. Returns true if the chain
98 // was created, or false if the chain already existed.
Hugo Benichicd27f4e2020-11-19 18:32:23 +090099 bool MakeAccountingChain(const std::string& chain_name);
Hugo Benichiaf2021b2020-11-20 14:07:16 +0900100 bool AddAccountingRule(const std::string& chain_name, TrafficSource source);
Hugo Benichi058a26a2020-11-26 10:10:39 +0900101 // Installs the required accounting chains and rules for the target
102 // |chain_tag|. Returns false if these chains and rules already existed.
103 bool SetupAccountingRules(const std::string& chain_tag);
104 // Installs jump rules in POSTROUTING to count traffic ingressing and
105 // egressing |ifname| with the accounting target |chain_tag|.
106 void SetupJumpRules(const std::string& op,
107 const std::string& ifname,
108 const std::string& chain_tag);
Jie Jiang31a0b4e2020-07-09 15:06:16 +0900109
Hugo Benichicd27f4e2020-11-19 18:32:23 +0900110 Datapath* datapath_;
Jie Jiang31a0b4e2020-07-09 15:06:16 +0900111 MinijailedProcessRunner* runner_;
Jie Jiang31a0b4e2020-07-09 15:06:16 +0900112};
113
Hugo Benichi92fa2032020-11-20 17:47:32 +0900114TrafficCounter::Source TrafficSourceToProto(TrafficSource source);
115
Jie Jiang31a0b4e2020-07-09 15:06:16 +0900116} // namespace patchpanel
117
118#endif // PATCHPANEL_COUNTERS_SERVICE_H_