blob: 80ca196495e77e360482dc665e5283312f83650a [file] [log] [blame]
// Copyright 2018 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.
#ifndef ARC_NETWORK_DEVICE_H_
#define ARC_NETWORK_DEVICE_H_
#include <linux/in6.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <unistd.h>
#include <map>
#include <memory>
#include <string>
#include <base/bind.h>
#include <base/memory/weak_ptr.h>
#include <gtest/gtest_prod.h> // for FRIEND_TEST
#include "arc/network/ipc.pb.h"
#include "arc/network/mac_address_generator.h"
#include "arc/network/neighbor_finder.h"
#include "arc/network/router_finder.h"
#include "arc/network/subnet.h"
namespace arc_networkd {
// Reserved name for the Android device.
extern const char kAndroidDevice[];
// Reserved name for the Android device for legacy single network configs.
extern const char kAndroidLegacyDevice[];
// Reserved name for the Android device for ARCVM.
// TODO(garrick): This can be removed
extern const char kAndroidVmDevice[];
// Encapsulates a physical (e.g. eth0) or proxy (e.g. arc) network device and
// its configuration spec (interfaces, addresses) on the host and in the
// container. It manages additional services such as router detection, address
// assignment, and MDNS and SSDP forwarding. This class is the authoritative
// source for configuration events.
class Device {
public:
using DeviceHandler = base::Callback<void(Device*)>;
class Context {
public:
virtual ~Context() = default;
virtual bool IsLinkUp() const = 0;
protected:
Context() = default;
private:
DISALLOW_COPY_AND_ASSIGN(Context);
};
class Config {
public:
Config(const std::string& host_ifname,
const std::string& guest_ifname,
const MacAddress& guest_mac_addr,
std::unique_ptr<Subnet> ipv4_subnet,
std::unique_ptr<SubnetAddress> host_ipv4_addr,
std::unique_ptr<SubnetAddress> guest_ipv4_addr,
std::unique_ptr<Subnet> lxd_ipv4_subnet = nullptr);
~Config() = default;
std::string host_ifname() const { return host_ifname_; }
std::string guest_ifname() const { return guest_ifname_; }
MacAddress guest_mac_addr() const { return guest_mac_addr_; }
uint32_t host_ipv4_addr() const { return host_ipv4_addr_->Address(); }
uint32_t guest_ipv4_addr() const { return guest_ipv4_addr_->Address(); }
const SubnetAddress* const host_ipv4_subnet_addr() const {
return host_ipv4_addr_.get();
}
const SubnetAddress* const guest_ipv4_subnet_addr() const {
return guest_ipv4_addr_.get();
}
const Subnet* const ipv4_subnet() const { return ipv4_subnet_.get(); }
const Subnet* const lxd_ipv4_subnet() const {
return lxd_ipv4_subnet_.get();
}
friend std::ostream& operator<<(std::ostream& stream, const Device& device);
private:
// The name of the interface created on the CrOS side. This should always
// be defined.
std::string host_ifname_;
// If applicable, the name of the device interface exposed in the guest. For
// example, for ARC P, this name will match the physical device name.
std::string guest_ifname_;
// A random MAC address assigned to the device.
MacAddress guest_mac_addr_;
// The IPV4 subnet allocated for this device.
std::unique_ptr<Subnet> ipv4_subnet_;
// The address allocated from |ipv4_subnet| for use by the CrOS-side
// interface associated with this device.
std::unique_ptr<SubnetAddress> host_ipv4_addr_;
// The address allocated from |ipv4_subnet| for use by the guest-side
// interface associated with this device, if applicable.
std::unique_ptr<SubnetAddress> guest_ipv4_addr_;
// If applicable, an additional subnet allocated for this device for guests
// like Crostini to use for assigning addresses to containers running within
// the VM.
std::unique_ptr<Subnet> lxd_ipv4_subnet_;
DISALLOW_COPY_AND_ASSIGN(Config);
};
struct Options {
bool fwd_multicast;
bool ipv6_enabled;
bool find_ipv6_routes_legacy;
// Indicates this device must track shill's default interface.
// TODO(garrick): Further qualify if this interface is a physical interface
// or an ARC VPN to match the distinction shill is making; specifically, ARC
// N should not loop back into itself but for Termina this should flow over
// the VPN.
bool use_default_interface;
// Indicates this is a special device used for Android. In single-networked
// guests (like ARC N) it is the only bridge into the container; in
// multi-networked guests it is used (only) to support VPNs and ADB over
// TCP.
bool is_android;
// Indicates this device is managed directly by a guest service and should
// not be mutated in response to shill updates.
bool is_sticky;
};
struct IPv6Config {
IPv6Config() : prefix_len(0), addr_attempts(0) {}
void clear();
struct in6_addr addr;
struct in6_addr router;
int prefix_len;
std::string ifname;
int addr_attempts;
};
Device(const std::string& ifname,
std::unique_ptr<Config> config,
const Options& options,
GuestMessage::GuestType guest);
~Device() = default;
const std::string& ifname() const;
Config& config() const;
IPv6Config& ipv6_config();
const Options& options() const;
void set_context(std::unique_ptr<Context> ctx);
Context* context();
bool IsAndroid() const;
bool IsArc() const;
bool UsesDefaultInterface() const;
void RegisterIPv6Handlers(const DeviceHandler& up_handler,
const DeviceHandler& down_handler);
void UnregisterIPv6Handlers();
void StartIPv6RoutingLegacy(const std::string& ifname);
void StopIPv6RoutingLegacy();
void OnGuestStart(GuestMessage::GuestType guest);
void OnGuestStop(GuestMessage::GuestType guest);
friend std::ostream& operator<<(std::ostream& stream, const Device& device);
private:
// Callback from RouterFinder. May be triggered multiple times, e.g.
// if the route disappears or changes.
void OnRouteFound(const struct in6_addr& prefix,
int prefix_len,
const struct in6_addr& router);
// Callback from NeighborFinder to indicate whether an IPv6 address
// collision was found or not found.
void OnNeighborCheckResult(bool found);
const std::string ifname_;
std::unique_ptr<Config> config_;
const Options options_;
GuestMessage::GuestType guest_;
std::unique_ptr<Context> ctx_;
// Indicates if the host-side interface is up. Guest-size interfaces
// may be tracked in the guest-specific context.
bool host_link_up_;
IPv6Config ipv6_config_;
DeviceHandler ipv6_up_handler_;
DeviceHandler ipv6_down_handler_;
std::unique_ptr<RouterFinder> router_finder_;
std::unique_ptr<NeighborFinder> neighbor_finder_;
base::WeakPtrFactory<Device> weak_factory_{this};
FRIEND_TEST(DeviceTest, DisableLegacyAndroidDeviceSendsTwoMessages);
DISALLOW_COPY_AND_ASSIGN(Device);
};
} // namespace arc_networkd
#endif // ARC_NETWORK_DEVICE_H_