blob: 4df89805af92ef47d219183f840b02d53e6ee7e8 [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 PORTIER_INTERFACE_DISABLE_LABELS_H_
#define PORTIER_INTERFACE_DISABLE_LABELS_H_
#include <bitset>
namespace portier {
// The InterfaceDisableLabels is used to simplify the process of
// enabling and disabling interfaces. There are several reasons for
// disabling an interface, most of them are independant or each other,
// and the interface should not be reenabled until all reasons have
// been changed.
//
// To use this class, have the interface inherit from this class and
// implement the callbacks OnEnabled() and OnDisable().
//
// Reasons for being disabled can be classified as "hard" or "soft".
// - Soft - Soft reasons are ones that can occur from normal operation
// of the ND proxy, but should not prevent external processes from
// being able to reenabled them on command.
// - Hard - Hard reasons can occur from both normal operator and
// exceptional circumstances during the ND proxy's runtime. These
// circumstances must be cleared before allowing external processes
// from being able to reenable the interface.
//
// Reasons for disabling an interface:
// - Software Disabled (soft) - Another process or a system user has
// requested that an interface to be disabled.
// - ND Loop Detected (soft) - One of conditions for loop prevention
// have occured on an interface. The interface must be disabled
// temporarily before attempting to reuse it. This could have been
// due to a configuration issue or by a test packet, as such it is
// treated as non-external.
// - Link Down (hard) - The network interface has been set into a
// DOWN state by the OS or by another processes. Interface must be
// brought up before allowing the interface to be used again.
// - Not Group Member (hard) - If an interface is not a member of a
// proxy groupe, then it should not be allowed to be enabled.
//
// The interface are enabled and disabled using a callback. The
// callbacks are expected to take the name of the interface as its
// only parameter and return true if it successfully trigger a state
// change.
//
// When an interface receives its first reason for being disabled,
// the disable callback is called. Any subsequent reasons are
// tracked, but do not cause an other call to disable.
//
class InterfaceDisableLabels {
public:
// Currently allocated number of flags. This number is much larger
// then needed to allow for extensions.
static constexpr size_t kFlagCount = 32;
// Reason flags, used internally for tracking which reasons have
// been triggered on an interface.
using Flags = std::bitset<kFlagCount>;
InterfaceDisableLabels() = default;
virtual ~InterfaceDisableLabels() = default;
// Enables an interface only if the interface has no reasons to be
// disabled. Returns true if the OnEnable was called().
bool TryEnable();
// Clears all of the soft labels currently tracked. Optionally,
// |use_callback| can be set to true, in which the OnEnable()
// callback will be called if there are no hard reasons. Returns
// true only if OnEnabled() was called. If |use_callback| is
// false, then the function will always return false.
bool ClearSoftLabels(bool use_callback = false);
// Clears all labels currently tracked. Optionally, |use_callback|
// can be set to true, in which the OnEnable() callback will be
// called after clearing the labels.
void ClearAllLabels(bool use_callback = false);
// For all of the following methods:
// - The `Mark*' will label the interface as having reason *. The
// `OnDisabled()' callback will be called if there were no
// previous marked labels. They return true if the callback
// was called.
// - The `Clear*' will clear the label. The `OnEnabled()' callback
// will be called if clearing the label removed the last label.
// They return true if the callback was called.
// - The `IsMarked*' return true if the specified label is marked.
bool MarkSoftwareDisabled(bool use_callback = true);
bool ClearSoftwareDisabled(bool use_callback = true);
bool IsMarkedSoftwareDisabled() const;
bool MarkLoopDetected();
bool ClearLoopDetected();
bool IsMarkedLoopDetected() const;
bool MarkLinkDown();
bool ClearLinkDown();
bool IsMarkedLinkDown() const;
bool MarkGroupless(bool use_callback = true);
bool ClearGroupless();
bool IsMarkedGroupless();
protected:
// Callback for enabling a interface. Called when all labels are
// cleared.
virtual void OnEnabled() = 0;
// Callback for disabling a interface. Called when first label is
// marked.
virtual void OnDisabled() = 0;
private:
bool SetFlag(size_t flag_pos, bool use_callback);
bool ClearFlag(size_t flag_pos, bool use_callback);
Flags reason_flags_;
};
} // namespace portier
#endif // PORTIER_INTERFACE_DISABLE_LABELS_H_