249 lines
6.2 KiB
Rust
249 lines
6.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use strum::FromRepr;
|
|
use thiserror::Error;
|
|
|
|
#[derive(Debug, Error)]
|
|
#[error("Unknown BGP error code {code} subcode {subcode}")]
|
|
pub struct UnknownErrorCode {
|
|
pub code: u8,
|
|
pub subcode: u8,
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)]
|
|
#[repr(u8)]
|
|
pub enum BgpError {
|
|
#[error("Message header error")]
|
|
MsgHeader(MsgHeaderSubcode) = 1,
|
|
|
|
#[error("Open message error")]
|
|
OpenMsg(OpenMsgSubcode) = 2,
|
|
|
|
#[error("Update message error")]
|
|
UpdateMsg(UpdateMsgSubcode) = 3,
|
|
|
|
#[error("Hold timer expired")]
|
|
HoldTimer = 4,
|
|
|
|
#[error("Finite state machine error")]
|
|
FsmError(FsmSubcode) = 5,
|
|
|
|
#[error("Cease")]
|
|
Cease(CeaseSubcode) = 6,
|
|
|
|
#[error("Route refresh message error")]
|
|
RouteRefresh(RouteRefreshSubcode) = 7,
|
|
|
|
#[error("Send hold timer expired")]
|
|
SendHoldTimer = 8,
|
|
}
|
|
|
|
impl BgpError {
|
|
pub fn from_code_subcode(code: u8, subcode: u8) -> Result<Self, UnknownErrorCode> {
|
|
let err = || UnknownErrorCode { code, subcode };
|
|
match code {
|
|
1 => Ok(Self::MsgHeader(
|
|
MsgHeaderSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
2 => Ok(Self::OpenMsg(
|
|
OpenMsgSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
3 => Ok(Self::UpdateMsg(
|
|
UpdateMsgSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
4 => Ok(Self::HoldTimer),
|
|
5 => Ok(Self::FsmError(
|
|
FsmSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
6 => Ok(Self::Cease(
|
|
CeaseSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
7 => Ok(Self::RouteRefresh(
|
|
RouteRefreshSubcode::try_from(subcode).map_err(|_| err())?,
|
|
)),
|
|
8 => Ok(Self::SendHoldTimer),
|
|
_ => Err(err()),
|
|
}
|
|
}
|
|
|
|
pub fn code_subcode(&self) -> (u8, u8) {
|
|
match self {
|
|
Self::MsgHeader(s) => (1, *s as u8),
|
|
Self::OpenMsg(s) => (2, *s as u8),
|
|
Self::UpdateMsg(s) => (3, *s as u8),
|
|
Self::HoldTimer => (4, 0),
|
|
Self::FsmError(s) => (5, *s as u8),
|
|
Self::Cease(s) => (6, *s as u8),
|
|
Self::RouteRefresh(s) => (7, *s as u8),
|
|
Self::SendHoldTimer => (8, 0),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum MsgHeaderSubcode {
|
|
#[error("Connection not synchronized")]
|
|
ConnNotSynchronized = 1,
|
|
|
|
#[error("Bad message length")]
|
|
BadMessageLength = 2,
|
|
|
|
#[error("Bad message type")]
|
|
BadMessageType = 3,
|
|
}
|
|
|
|
impl TryFrom<u8> for MsgHeaderSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum OpenMsgSubcode {
|
|
#[error("Unsupported BGP version number")]
|
|
UnsupportedVersion = 1,
|
|
|
|
#[error("Bad peer AS number")]
|
|
BadPeerAs = 2,
|
|
|
|
#[error("Bad BGP identifier")]
|
|
BadBgpId = 3,
|
|
|
|
#[error("Unsupported optional parameter")]
|
|
UnsupportedOptionalParam = 4,
|
|
|
|
#[error("Unacceptable hold time")]
|
|
UnacceptableHoldTime = 6,
|
|
|
|
#[error("Unsupported capability")]
|
|
UnsupportedCapability = 7,
|
|
|
|
#[error("Role mismatch")]
|
|
RoleMismatch = 8,
|
|
}
|
|
|
|
impl TryFrom<u8> for OpenMsgSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum UpdateMsgSubcode {
|
|
#[error("Malformed attribute list")]
|
|
MalformedAttrs = 1,
|
|
|
|
#[error("Unrecognized well known attribute")]
|
|
UnrecognizedWellKnownAttr = 2,
|
|
|
|
#[error("Missing well known attribute")]
|
|
MissingWellKnown = 3,
|
|
|
|
#[error("Attribute flags error")]
|
|
AttributeFlags = 4,
|
|
|
|
#[error("Attribute length error")]
|
|
AttributeLength = 5,
|
|
|
|
#[error("Invalid origin")]
|
|
InvalidOrigin = 6,
|
|
|
|
#[error("Invalid next hop")]
|
|
InvalidNextHop = 8,
|
|
|
|
#[error("Optional attribute error")]
|
|
OptionalAttribute = 9,
|
|
|
|
#[error("Invalid network field")]
|
|
InvalidNetworkField = 10,
|
|
|
|
#[error("Malformed AS path")]
|
|
MalformedAsPath = 11,
|
|
}
|
|
|
|
impl TryFrom<u8> for UpdateMsgSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum FsmSubcode {
|
|
#[error("Received an unexpected message in OpenSent state")]
|
|
UnexpectedOpenSent = 1,
|
|
|
|
#[error("Received an unexpected message in OpenConfirm state")]
|
|
UnexpectedOpenConfirm = 2,
|
|
|
|
#[error("Received an unexpected message in Established state")]
|
|
UnexpectedEstablished = 3,
|
|
}
|
|
|
|
impl TryFrom<u8> for FsmSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum CeaseSubcode {
|
|
#[error("Maximum number of prefixes reached")]
|
|
MaxPrefixes = 1,
|
|
|
|
#[error("Administrative shutdown")]
|
|
AdminShutdown = 2,
|
|
|
|
#[error("Peer deconfigured")]
|
|
PeerDeconf = 3,
|
|
|
|
#[error("Administrative reset")]
|
|
AdminReset = 4,
|
|
|
|
#[error("Connection rejected")]
|
|
ConnRejected = 5,
|
|
|
|
#[error("Configuration change")]
|
|
ConfChange = 6,
|
|
|
|
#[error("Connection collision resolution")]
|
|
ConnCollisionResolution = 7,
|
|
|
|
#[error("Out of resources")]
|
|
OutOfResources = 8,
|
|
|
|
#[error("Hard reset")]
|
|
HardReset = 9,
|
|
|
|
#[error("BFD down")]
|
|
BfdDown = 10,
|
|
}
|
|
|
|
impl TryFrom<u8> for CeaseSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Error, Serialize, Deserialize, FromRepr)]
|
|
#[repr(u8)]
|
|
pub enum RouteRefreshSubcode {
|
|
#[error("Invalid message length")]
|
|
InvalidLength = 1,
|
|
}
|
|
|
|
impl TryFrom<u8> for RouteRefreshSubcode {
|
|
type Error = ();
|
|
fn try_from(v: u8) -> Result<Self, ()> {
|
|
Self::from_repr(v).ok_or(())
|
|
}
|
|
}
|