Skip to content

Commit

Permalink
Add nexthop message.
Browse files Browse the repository at this point in the history
  • Loading branch information
kishiguro committed Nov 3, 2024
1 parent a55ede9 commit d327d20
Show file tree
Hide file tree
Showing 9 changed files with 432 additions and 5 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pub mod address;
pub mod link;
pub mod neighbour;
pub mod neighbour_table;
pub mod nexthop;
pub mod nsid;
pub mod prefix;
pub mod route;
Expand Down
52 changes: 50 additions & 2 deletions src/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use netlink_packet_utils::{
DecodeError, Emitable, Parseable, ParseableParametrized,
};

use crate::nexthop::{NexthopMessage, NexthopMessageBuffer};
use crate::tc::{TcActionMessage, TcActionMessageBuffer};
use crate::{
address::{AddressHeader, AddressMessage, AddressMessageBuffer},
Expand Down Expand Up @@ -76,6 +77,9 @@ const RTM_GETNSID: u16 = 90;
const RTM_NEWCHAIN: u16 = 100;
const RTM_DELCHAIN: u16 = 101;
const RTM_GETCHAIN: u16 = 102;
const RTM_NEWNEXTHOP: u16 = 104;
const RTM_DELNEXTHOP: u16 = 105;
const RTM_GETNEXTHOP: u16 = 106;
const RTM_NEWLINKPROP: u16 = 108;
const RTM_DELLINKPROP: u16 = 109;

Expand Down Expand Up @@ -322,6 +326,22 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
}
}

// Nexthop Messages
RTM_NEWNEXTHOP | RTM_DELNEXTHOP | RTM_GETNEXTHOP => {
let err = "invalid nexthop message";
let msg = NexthopMessage::parse(
&NexthopMessageBuffer::new_checked(&buf.inner())
.context(err)?,
)
.context(err)?;
match message_type {
RTM_NEWNEXTHOP => RouteNetlinkMessage::NewNexthop(msg),
RTM_DELNEXTHOP => RouteNetlinkMessage::DelNexthop(msg),
RTM_GETNEXTHOP => RouteNetlinkMessage::GetNexthop(msg),
_ => unreachable!(),
}
}

_ => {
return Err(
format!("Unknown message type: {message_type}").into()
Expand Down Expand Up @@ -369,6 +389,9 @@ pub enum RouteNetlinkMessage {
NewTrafficChain(TcMessage),
DelTrafficChain(TcMessage),
GetTrafficChain(TcMessage),
NewNexthop(NexthopMessage),
DelNexthop(NexthopMessage),
GetNexthop(NexthopMessage),
NewNsId(NsidMessage),
DelNsId(NsidMessage),
GetNsId(NsidMessage),
Expand Down Expand Up @@ -526,6 +549,18 @@ impl RouteNetlinkMessage {
matches!(self, RouteNetlinkMessage::DelRule(_))
}

pub fn is_get_nexthop(&self) -> bool {
matches!(self, RouteNetlinkMessage::GetNexthop(_))
}

pub fn is_new_nexthop(&self) -> bool {
matches!(self, RouteNetlinkMessage::NewNexthop(_))
}

pub fn is_del_nexthop(&self) -> bool {
matches!(self, RouteNetlinkMessage::DelNexthop(_))
}

pub fn message_type(&self) -> u16 {
use self::RouteNetlinkMessage::*;

Expand Down Expand Up @@ -570,6 +605,9 @@ impl RouteNetlinkMessage {
GetRule(_) => RTM_GETRULE,
NewRule(_) => RTM_NEWRULE,
DelRule(_) => RTM_DELRULE,
NewNexthop(_) => RTM_NEWNEXTHOP,
DelNexthop(_) => RTM_DELNEXTHOP,
GetNexthop(_) => RTM_GETNEXTHOP,
}
}
}
Expand Down Expand Up @@ -637,7 +675,12 @@ impl Emitable for RouteNetlinkMessage {
| DelTrafficAction(ref msg)
| GetTrafficAction(ref msg)
=> msg.buffer_len(),
}

| NewNexthop(ref msg)
| DelNexthop(ref msg)
| GetNexthop(ref msg)
=> msg.buffer_len(),
}
}

#[rustfmt::skip]
Expand Down Expand Up @@ -702,7 +745,12 @@ impl Emitable for RouteNetlinkMessage {
| DelTrafficAction(ref msg)
| GetTrafficAction(ref msg)
=> msg.emit(buffer),
}

| NewNexthop(ref msg)
| DelNexthop(ref msg)
| GetNexthop(ref msg)
=> msg.emit(buffer),
}
}
}

Expand Down
154 changes: 154 additions & 0 deletions src/nexthop/attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// SPDX-License-Identifier: MIT

use anyhow::Context;
use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::{
nla::{DefaultNla, Nla, NlaBuffer},
parsers::{parse_u16, parse_u32},
DecodeError, Emitable, Parseable, ParseableParametrized,
};

use crate::{
route::{RouteAddress, RouteLwTunnelEncap},
AddressFamily,
};

use super::NexthopGroup;

const NHA_ID: u16 = 1;
const NHA_GROUP: u16 = 2;
const NHA_GROUP_TYPE: u16 = 3;
const NHA_BLACKHOLE: u16 = 4;
const NHA_OIF: u16 = 5;
const NHA_GATEWAY: u16 = 6;
const NHA_ENCAP_TYPE: u16 = 7;
const NHA_ENCAP: u16 = 8;
const NHA_GROUPS: u16 = 9;
const NHA_MASTER: u16 = 10;
const NHA_FDB: u16 = 11;
// const NHA_RES_GROUP: u16 = 12;
// const NHA_RES_BUCKET: u16 = 13;

#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum NexthopAttribute {
Id(u32),
Group(Vec<NexthopGroup>),
GroupType(u16),
Blackhole,
Oif(u32),
Gateway(RouteAddress),
EncapType(u16),
Encap(Vec<RouteLwTunnelEncap>),
Groups,
Master(u32),
Fdb,
Other(DefaultNla),
}

impl Nla for NexthopAttribute {
fn value_len(&self) -> usize {
match self {
Self::Id(_) | Self::Oif(_) | Self::Master(_) => 4,
Self::Group(groups) => {
groups.iter().map(|grp| grp.buffer_len()).sum()
}
Self::GroupType(_) | Self::EncapType(_) => 2,
Self::Blackhole | Self::Groups | Self::Fdb => 0,
Self::Encap(v) => v.as_slice().buffer_len(),
Self::Gateway(addr) => addr.buffer_len(),
Self::Other(attr) => attr.value_len(),
}
}

fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Id(value) | Self::Oif(value) | Self::Master(value) => {
NativeEndian::write_u32(buffer, *value)
}
Self::Group(groups) => {
let mut offset = 0;
for grp in groups {
let len = grp.buffer_len();
grp.emit(&mut buffer[offset..offset + len]);
offset += len
}
}
Self::GroupType(value) | Self::EncapType(value) => {
NativeEndian::write_u16(buffer, *value);
}
Self::Blackhole | Self::Groups | Self::Fdb => {}
Self::Encap(nlas) => nlas.as_slice().emit(buffer),
Self::Gateway(addr) => addr.emit(buffer),
Self::Other(attr) => attr.emit_value(buffer),
}
}

fn kind(&self) -> u16 {
match self {
Self::Id(_) => NHA_ID,
Self::Group(_) => NHA_GROUP,
Self::GroupType(_) => NHA_GROUP_TYPE,
Self::Blackhole => NHA_BLACKHOLE,
Self::Oif(_) => NHA_OIF,
Self::Gateway(_) => NHA_GATEWAY,
Self::EncapType(_) => NHA_ENCAP_TYPE,
Self::Encap(_) => NHA_ENCAP,
Self::Groups => NHA_GROUPS,
Self::Master(_) => NHA_MASTER,
Self::Fdb => NHA_FDB,
Self::Other(nla) => nla.kind(),
}
}
}

impl<'a, T: AsRef<[u8]> + ?Sized>
ParseableParametrized<NlaBuffer<&'a T>, AddressFamily>
for NexthopAttribute
{
fn parse_with_param(
buf: &NlaBuffer<&'a T>,
address_family: AddressFamily,
) -> Result<Self, DecodeError> {
let payload = buf.value();
Ok(match buf.kind() {
NHA_ID => Self::Id(
parse_u32(payload).context(format!("invalid NHA_ID value"))?,
),
NHA_GROUP => {
let mut groups = vec![];
let mut i: usize = 0;
while i + 8 <= payload.len() {
groups.push(NexthopGroup::parse(&payload[i..i + 8])?);
i += 8;
}
Self::Group(groups)
}
NHA_GROUP_TYPE => Self::GroupType(
parse_u16(payload)
.context(format!("invalid NHA_GROUP_TYPE value"))?,
),
NHA_BLACKHOLE => Self::Blackhole,
NHA_OIF => Self::Oif(
parse_u32(payload).context(format!("invalid NHA_OIF value"))?,
),
NHA_GATEWAY => {
Self::Gateway(RouteAddress::parse(address_family, payload)?)
}
NHA_ENCAP_TYPE => Self::EncapType(
parse_u16(payload)
.context(format!("invalid NHA_ENCAP_TYPE value"))?,
),
NHA_GROUPS => Self::Groups,
NHA_MASTER => Self::Master(
parse_u32(payload)
.context(format!("invalid NHA_MASTER value"))?,
),
NHA_FDB => Self::Fdb,
_ => Self::Other(
DefaultNla::parse(buf)
.context("invalid link NLA value (unknown type)")?,
),
})
}
}
26 changes: 26 additions & 0 deletions src/nexthop/flags.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT

const RTNH_F_DEAD: u32 = 1 << 0;
const RTNH_F_PERVASIVE: u32 = 1 << 1;
const RTNH_F_ONLINK: u32 = 1 << 2;
const RTNH_F_OFFLOAD: u32 = 1 << 3;
const RTNH_F_LINKDOWN: u32 = 1 << 4;
const RTNH_F_UNRESOLVED: u32 = 1 << 5;
const RTNH_F_TRAP: u32 = 1 << 6;
// const RTNH_COMPARE_MASK: u32 =
// RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD | RTNH_F_TRAP;

bitflags! {
#[derive(Clone, Eq, PartialEq, Debug, Copy, Default)]
#[non_exhaustive]
pub struct NexthopFlags: u32 {
const Dead = RTNH_F_DEAD;
const Pervasive = RTNH_F_PERVASIVE;
const Onlink =RTNH_F_ONLINK;
const Offload = RTNH_F_OFFLOAD;
const Linkdown = RTNH_F_LINKDOWN;
const Unresolved = RTNH_F_UNRESOLVED;
const Trap= RTNH_F_TRAP;
const _ = !0;
}
}
43 changes: 43 additions & 0 deletions src/nexthop/group.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use byteorder::{ByteOrder, NativeEndian};
use netlink_packet_utils::{
parsers::{parse_u16, parse_u32},
DecodeError, Emitable,
};

#[derive(Debug, PartialEq, Eq, Clone, Copy)]
/// Nexthop Group
pub struct NexthopGroup {
/// Nexthop id
pub id: u32,
/// Weight of this nexthop
pub weight: u8,
/// Reserved
pub resvd1: u8,
/// Reserved
pub resvd2: u16,
}

impl Emitable for NexthopGroup {
fn buffer_len(&self) -> usize {
8
}

fn emit(&self, buffer: &mut [u8]) {
NativeEndian::write_u32(buffer, self.id);
buffer[4] = self.weight;
buffer[5] = self.resvd1;
NativeEndian::write_u16(&mut buffer[6..8], self.resvd2);
}
}

impl NexthopGroup {
pub fn parse(payload: &[u8]) -> Result<Self, DecodeError> {
let grp = Self {
id: parse_u32(payload)?,
weight: payload[4],
resvd1: payload[5],
resvd2: parse_u16(&payload[6..8])?,
};
Ok(grp)
}
}
Loading

0 comments on commit d327d20

Please sign in to comment.