1use std::net::Ipv4Addr;
2
3use bitfield::bitfield;
4use bytes::{BufMut, BytesMut};
5use eyre::{Result, bail, eyre};
6use nom::{
7 Err::Failure,
8 IResult, Parser,
9 combinator::peek,
10 number::complete::{be_u8, be_u16, be_u24, be_u32},
11};
12use serde::{Deserialize, Serialize};
13use strum::EnumDiscriminants;
14
15use crate::{
16 constants::{AddressFamilyId, SubsequentAfi},
17 parser::{BgpParserError, ParserContext, ProtocolErrorValues},
18};
19
20macro_rules! fail {
21 ( $($arg:expr),* $(,)? ) => {
22 Failure(BgpParserError::Eyre(eyre!($($arg),*)))
23 };
24}
25
26#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]
29pub struct OpenMessage {
30 pub version: u8,
32 pub asn: u16,
34 pub hold_time: u16,
36 pub identifier: Ipv4Addr,
38 pub options: Vec<OpenOption>,
40}
41
42impl OpenMessage {
43 pub fn from_wire<'a>(
47 ctx: &ParserContext,
48 buf: &'a [u8],
49 ) -> IResult<&'a [u8], Self, BgpParserError<&'a [u8]>> {
50 let (buf, version) = be_u8(buf)?;
51 if version != 4 {
52 return Err(Failure(BgpParserError::ProtocolError(
53 ProtocolErrorValues::UnknownOpenOption(version),
54 )));
55 }
56
57 let (buf, asn) = be_u16(buf)?;
58 let (buf, hold_time) = be_u16(buf)?;
59 let (buf, identifier) = be_u32(buf)?;
60
61 let (buf, opt_len) = be_u8(buf)?;
66 let (_, inner) = peek(be_u8).parse(buf)?;
67
68 let (buf, opt_len) = if inner == 255 {
69 let (buf, _) = be_u8(buf)?; be_u16(buf)?
71 } else {
72 (buf, opt_len as u16)
73 };
74
75 let (buf, opt_buf) = nom::bytes::take(opt_len).parse(buf)?;
76 let (opt_buf, options) =
77 nom::multi::many0(|buf| OpenOption::from_wire(ctx, buf)).parse(opt_buf)?;
78
79 if !opt_buf.is_empty() {
80 return Err(fail!(
81 "Leftover bytes after parsing open options: {:x?}",
82 opt_buf
83 ));
84 }
85
86 Ok((
87 buf,
88 Self {
89 version,
90 asn,
91 hold_time,
92 identifier: Ipv4Addr::from(identifier),
93 options,
94 },
95 ))
96 }
97
98 pub fn to_wire(&self, ctx: &ParserContext, out: &mut BytesMut) -> Result<()> {
99 out.put_u8(self.version);
100 out.put_u16(self.asn);
101 out.put_u16(self.hold_time);
102 out.put_u32(self.identifier.into());
103
104 let opt_len = self
107 .options
108 .iter()
109 .map(|o| o.wire_len(ctx))
110 .sum::<Result<u16>>()?;
111 if opt_len > u8::MAX as u16 {
112 out.put_u8(0xff); out.put_u8(0xff); out.put_u16(opt_len);
115 } else {
116 out.put_u8(opt_len as u8);
117 }
118
119 for option in &self.options {
120 option.to_wire(ctx, out)?;
121 }
122
123 Ok(())
124 }
125
126 pub fn wire_len(&self, ctx: &ParserContext) -> Result<u16> {
127 let mut total = 10;
128 let opt_len = self
129 .options
130 .iter()
131 .map(|o| o.wire_len(ctx))
132 .sum::<Result<u16>>()?;
133 if opt_len > u8::MAX as u16 {
134 total += opt_len + 3; } else {
136 total += opt_len;
137 }
138 Ok(total)
139 }
140}
141
142#[derive(Debug, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
143#[repr(u8)]
144pub enum OpenOption {
145 Capabilities(Vec<Capability>) = 2,
146}
147
148impl OpenOption {
149 pub fn from_wire<'a>(
150 ctx: &ParserContext,
151 buf: &'a [u8],
152 ) -> IResult<&'a [u8], Self, BgpParserError<&'a [u8]>> {
153 let (buf, type_code) = be_u8(buf)?;
154 let (buf, length) = be_u8(buf)?;
155
156 let (buf, payload) = nom::bytes::take(length).parse(buf)?;
157
158 match type_code {
159 v if v == OpenOptionDiscriminants::Capabilities as u8 => {
160 let (payload_consumed, (capabilities, _eof)) = nom::multi::many_till(
161 |buf| Capability::from_wire(ctx, buf),
162 nom::combinator::eof,
163 )
164 .parse(payload)?;
165
166 if !payload_consumed.is_empty() {
167 return Err(fail!(
168 "Leftover bytes when parsing BGP capabilities: {:x?}",
169 payload_consumed
170 ));
171 }
172 Ok((buf, Self::Capabilities(capabilities)))
173 }
174 other => {
175 return Err(Failure(BgpParserError::ProtocolError(
176 ProtocolErrorValues::UnknownOpenOption(other),
177 )));
178 }
179 }
180 }
181
182 pub fn to_wire(&self, ctx: &ParserContext, out: &mut BytesMut) -> Result<()> {
183 match self {
184 OpenOption::Capabilities(items) => {
185 let cap_len = items.iter().map(|i| i.wire_len(ctx)).sum::<Result<u16>>()?;
186 if cap_len > u8::MAX as u16 {
187 bail!("Cannot write Capabilities with more than u8::MAX length");
188 }
189 out.put_u8(OpenOptionDiscriminants::Capabilities as u8);
190 out.put_u8(cap_len as u8);
191 for item in items {
192 item.to_wire(ctx, out)?;
193 }
194 }
195 }
196 Ok(())
197 }
198
199 pub fn wire_len(&self, ctx: &ParserContext) -> Result<u16> {
200 match self {
201 OpenOption::Capabilities(items) => items
202 .iter()
203 .map(|i| i.wire_len(ctx))
204 .sum::<Result<u16>>()
205 .map(|v| v + 2),
206 }
207 }
208}
209
210#[derive(Debug, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
211#[repr(u8)]
212pub enum Capability {
213 MultiProtocol {
215 afi: AddressFamilyId,
216 safi: SubsequentAfi,
217 } = 1,
218 RouteRefresh = 2,
220 OutboundRouteFilter {
223 afi: AddressFamilyId,
224 safi: SubsequentAfi,
225 orfs: Vec<OutboundRouteFilterEntry>,
226 } = 3,
227 ExtendedNextHop {
229 entries: Vec<ExtendedNextHop>,
230 } = 5,
231 ExtendedMessage = 6,
233 BgpSec {
235 header: BgpSecHeader,
236 afi: AddressFamilyId,
237 } = 7,
238 MultiLabelCompat {} = 8,
240 BgpRole {
241 role: BgpRole,
242 } = 9,
243 GracefulRestart {
245 restart_state: bool,
249 restart_time: u16,
254 entries: Vec<GracefulRestartEntry>,
261 } = 64,
262 FourByteAsn {
264 asn: u32,
265 } = 65,
266 AddPath {
268 afi: AddressFamilyId,
269 safi: SubsequentAfi,
270 send_recv: AddPathSendRecv,
271 } = 69,
272 EnhancedRouteRefresh = 70,
274 LongLivedGracefulRestart(Vec<LongLivedGracefulRestart>) = 71,
276 UnknownCapability {
278 type_code: u8,
279 length: u8,
280 value: Vec<u8>,
281 },
282}
283
284impl Capability {
285 fn discriminant(&self) -> u8 {
286 match self {
287 Capability::MultiProtocol { .. } => CapabilityDiscriminants::MultiProtocol as u8,
288 Capability::RouteRefresh => CapabilityDiscriminants::RouteRefresh as u8,
289 Capability::OutboundRouteFilter { .. } => {
290 CapabilityDiscriminants::OutboundRouteFilter as u8
291 }
292 Capability::ExtendedNextHop { .. } => CapabilityDiscriminants::ExtendedNextHop as u8,
293 Capability::ExtendedMessage => CapabilityDiscriminants::ExtendedMessage as u8,
294 Capability::BgpSec { .. } => CapabilityDiscriminants::BgpSec as u8,
295 Capability::MultiLabelCompat {} => CapabilityDiscriminants::MultiLabelCompat as u8,
296 Capability::BgpRole { .. } => CapabilityDiscriminants::BgpRole as u8,
297 Capability::GracefulRestart { .. } => CapabilityDiscriminants::GracefulRestart as u8,
298 Capability::FourByteAsn { .. } => CapabilityDiscriminants::FourByteAsn as u8,
299 Capability::AddPath { .. } => CapabilityDiscriminants::AddPath as u8,
300 Capability::EnhancedRouteRefresh => CapabilityDiscriminants::EnhancedRouteRefresh as u8,
301 Capability::LongLivedGracefulRestart(_) => {
302 CapabilityDiscriminants::LongLivedGracefulRestart as u8
303 }
304 Capability::UnknownCapability { type_code, .. } => *type_code,
305 }
306 }
307 pub fn from_wire<'a>(
309 _ctx: &ParserContext,
310 buf: &'a [u8],
311 ) -> IResult<&'a [u8], Self, BgpParserError<&'a [u8]>> {
312 let (buf, typ) = be_u8(buf)?;
313 let (buf, len) = be_u8(buf)?;
314 let (buf, cap_buf) = nom::bytes::take(len).parse(buf)?;
315 macro_rules! require_empty {
316 ($buf:expr, $cap_type:expr) => {
317 if !buf.is_empty() {
318 return Err(nom::Err::Failure(BgpParserError::Eyre(eyre!(
319 "Unexpected leftover bytes {:x?} while parsing {} capability",
320 $buf,
321 $cap_type
322 ))));
323 }
324 };
325 }
326 match typ {
327 v if v == CapabilityDiscriminants::MultiProtocol as u8 => {
328 let (cap_buf, afi) = be_u16(cap_buf)?;
330 let (cap_buf, _) = be_u8(cap_buf)?;
331 let (cap_buf, safi) = be_u8(cap_buf)?;
332 require_empty!(cap_buf, "MultiProtocol");
333 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
334 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
335 Ok((buf, Self::MultiProtocol { afi, safi }))
336 }
337 v if v == CapabilityDiscriminants::RouteRefresh as u8 => {
338 require_empty!(cap_buf, "RouteRefresh");
339 Ok((buf, Self::RouteRefresh))
340 }
341 v if v == CapabilityDiscriminants::OutboundRouteFilter as u8 => {
342 let (cap_buf, afi) = be_u16(cap_buf)?;
343 let (cap_buf, _) = be_u8(cap_buf)?; let (cap_buf, safi) = be_u8(cap_buf)?;
345 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
346 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
347
348 let (cap_buf, _num_orfs) = be_u8(cap_buf)?;
349
350 let parse_orf = |buf: &'a [u8]| -> IResult<
351 &'a [u8],
352 OutboundRouteFilterEntry,
353 BgpParserError<&'a [u8]>,
354 > {
355 let (buf, orf_type) = be_u8(buf)?;
356 let (buf, send_recv) = be_u8(buf)?;
357 let orf_type = OrfType::from(orf_type);
358 let send_recv = OrfSendRecv::try_from(send_recv)
359 .map_err(|e| fail!("Failed to parse ORF send/recv: {}", e))?;
360
361 Ok((
362 buf,
363 OutboundRouteFilterEntry {
364 r#type: orf_type,
365 send_recv,
366 },
367 ))
368 };
369
370 let (cap_buf, orfs) = nom::multi::many0(parse_orf).parse(cap_buf)?;
371 require_empty!(cap_buf, "OutboundRouteFilter");
372
373 Ok((buf, Self::OutboundRouteFilter { afi, safi, orfs }))
374 }
375 v if v == CapabilityDiscriminants::ExtendedNextHop as u8 => {
376 let parse_enh = |buf: &'a [u8]| -> IResult<
378 &'a [u8],
379 ExtendedNextHop,
380 BgpParserError<&'a [u8]>,
381 > {
382 let (buf, afi) = be_u16(buf)?;
383 let (buf, safi) = be_u16(buf)?;
384 let (buf, nh_afi) = be_u16(buf)?;
385 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
386 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
387 let nh_afi = AddressFamilyId::try_from(nh_afi).map_err(|e| fail!("{}", e))?;
388 Ok((buf, ExtendedNextHop { afi, safi, nh_afi }))
389 };
390 let (cap_buf, entries) = nom::multi::many1(parse_enh).parse(cap_buf)?;
391 require_empty!(cap_buf, "ExtendedNextHop");
392
393 Ok((cap_buf, Self::ExtendedNextHop { entries }))
394 }
395 v if v == CapabilityDiscriminants::ExtendedMessage as u8 => {
396 require_empty!(cap_buf, "ExtendedMessage");
397 Ok((cap_buf, Self::ExtendedMessage))
398 }
399 v if v == CapabilityDiscriminants::BgpSec as u8 => {
400 let (cap_buf, header) = be_u8(cap_buf)?;
401 let (cap_buf, afi) = be_u16(cap_buf)?;
402 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
403 require_empty!(cap_buf, "BgpSec");
404 Ok((
405 cap_buf,
406 Self::BgpSec {
407 header: BgpSecHeader(header),
408 afi,
409 },
410 ))
411 }
412 v if v == CapabilityDiscriminants::MultiLabelCompat as u8 => {
413 todo!()
414 }
415 v if v == CapabilityDiscriminants::BgpRole as u8 => {
416 let (cap_buf, role) = be_u8(cap_buf)?;
417 let role = BgpRole::try_from(role).map_err(|e| fail!("{}", e))?;
418 require_empty!(cap_buf, "BgpRole");
419 Ok((cap_buf, Self::BgpRole { role }))
420 }
421 v if v == CapabilityDiscriminants::GracefulRestart as u8 => {
422 let (cap_buf, flags_restart_time) = be_u16(cap_buf)?;
424 let restart_state = ((1 << 15) & flags_restart_time) != 0;
425 let restart_time = flags_restart_time & 0xfff;
426 let parse_entry = |buf: &'a [u8]| -> IResult<
427 &'a [u8],
428 GracefulRestartEntry,
429 BgpParserError<&'a [u8]>,
430 > {
431 let (buf, afi) = be_u16(buf)?;
432 let (buf, safi) = be_u8(buf)?;
433 let (buf, flags) = be_u8(buf)?;
434 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
435 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
436 Ok((
437 buf,
438 GracefulRestartEntry {
439 afi,
440 safi,
441 preserve_forwarding: (flags & (1 << 7)) != 0,
442 },
443 ))
444 };
445 let (cap_buf, entries) = nom::multi::many0(parse_entry).parse(cap_buf)?;
446 require_empty!(cap_buf, "GracefulRestart");
447 Ok((
448 cap_buf,
449 Self::GracefulRestart {
450 restart_state,
451 restart_time,
452 entries,
453 },
454 ))
455 }
456 v if v == CapabilityDiscriminants::FourByteAsn as u8 => {
457 let (cap_buf, asn) = be_u32(cap_buf)?;
458 require_empty!(cap_buf, "FourByteAsn");
459 Ok((cap_buf, Self::FourByteAsn { asn }))
460 }
461 v if v == CapabilityDiscriminants::AddPath as u8 => {
462 let (cap_buf, afi) = be_u16(cap_buf)?;
463 let (cap_buf, safi) = be_u8(cap_buf)?;
464 let (cap_buf, send_recv) = be_u8(cap_buf)?;
465 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
466 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
467 let send_recv = AddPathSendRecv::try_from(send_recv).map_err(|e| fail!("{}", e))?;
468 require_empty!(cap_buf, "AddPath");
469 Ok((
470 cap_buf,
471 Self::AddPath {
472 afi,
473 safi,
474 send_recv,
475 },
476 ))
477 }
478 v if v == CapabilityDiscriminants::EnhancedRouteRefresh as u8 => {
479 require_empty!(cap_buf, "EnhancedRouteRefresh");
480 Ok((cap_buf, Self::EnhancedRouteRefresh))
481 }
482 v if v == CapabilityDiscriminants::LongLivedGracefulRestart as u8 => {
483 let parse_llgr = |buf: &'a [u8]| -> IResult<
484 &'a [u8],
485 LongLivedGracefulRestart,
486 BgpParserError<&'a [u8]>,
487 > {
488 let (buf, afi) = be_u16(buf)?;
489 let (buf, safi) = be_u8(buf)?;
490 let (buf, flags) = be_u8(buf)?;
491 let (buf, stale_time) = be_u24(buf)?;
492 let afi = AddressFamilyId::try_from(afi).map_err(|e| fail!("{}", e))?;
493 let safi = SubsequentAfi::try_from(safi).map_err(|e| fail!("{}", e))?;
494 Ok((
495 buf,
496 LongLivedGracefulRestart {
497 afi,
498 safi,
499 flags,
500 stale_time,
501 },
502 ))
503 };
504 let (cap_buf, entries) = nom::multi::many0(parse_llgr).parse(cap_buf)?;
505 require_empty!(cap_buf, "LongLivedGracefulRestart");
506 Ok((cap_buf, Self::LongLivedGracefulRestart(entries)))
507 }
508 type_code => {
509 Ok((
512 &[],
513 Self::UnknownCapability {
514 type_code,
515 length: cap_buf.len() as u8,
516 value: cap_buf.to_vec(),
517 },
518 ))
519 }
520 }
521 }
522
523 pub fn to_wire(&self, _ctx: &ParserContext, out: &mut BytesMut) -> Result<()> {
524 out.put_u8(self.discriminant());
525 out.put_u8(self.payload_len());
526 match self {
527 Capability::MultiProtocol { afi, safi } => {
528 out.put_u16(*afi as u16);
529 out.put_u8(0); out.put_u8(*safi as u8);
531 }
532 Capability::RouteRefresh => {}
533 Capability::OutboundRouteFilter { afi, safi, orfs } => {
534 out.put_u16(*afi as u16);
535 out.put_u8(0); out.put_u8(*safi as u8);
537 for orf in orfs {
538 out.put_u8(orf.r#type.clone().into());
539 out.put_u8(orf.send_recv.clone() as u8);
540 }
541 }
542 Capability::ExtendedNextHop { entries } => {
543 for entry in entries {
544 out.put_u16(entry.afi as u16);
545 out.put_u16(entry.safi as u16);
546 out.put_u16(entry.nh_afi as u16);
547 }
548 }
549 Capability::ExtendedMessage => {}
550 Capability::BgpSec { header, afi } => {
551 out.put_u8(header.0);
552 out.put_u16(*afi as u16);
553 }
554 Capability::MultiLabelCompat {} => todo!(),
555 Capability::BgpRole { role } => {
556 out.put_u8(role.into());
557 }
558 Capability::GracefulRestart {
559 restart_state,
560 restart_time,
561 entries,
562 } => {
563 let mut flags_restart_time = 0;
564 if *restart_state {
565 flags_restart_time |= 1 << 15;
566 }
567 if *restart_time > 0xfff {
568 bail!("Restart time too large to be encoded: {}", restart_time);
569 }
570 flags_restart_time |= restart_time;
571 out.put_u16(flags_restart_time);
572 for entry in entries {
573 out.put_u16(entry.afi as u16);
574 out.put_u8(entry.safi as u8);
575 let mut flags = 0;
576 if entry.preserve_forwarding {
577 flags |= 1 << 7;
578 }
579 out.put_u8(flags);
580 }
581 }
582 Capability::FourByteAsn { asn } => {
583 out.put_u32(*asn);
584 }
585 Capability::AddPath {
586 afi,
587 safi,
588 send_recv,
589 } => {
590 out.put_u16(*afi as u16);
591 out.put_u8(*safi as u8);
592 out.put_u8(send_recv.into());
593 }
594 Capability::EnhancedRouteRefresh => {}
595 Capability::LongLivedGracefulRestart(llgrs) => {
596 for llgr in llgrs {
597 out.put_u16(llgr.afi as u16);
598 out.put_u8(llgr.safi as u8);
599 out.put_u8(llgr.flags as u8);
600 out.put(&llgr.stale_time.to_be_bytes()[1..]);
601 }
602 }
603 Capability::UnknownCapability { value, .. } => out.put(value.as_slice()),
604 }
605 Ok(())
606 }
607
608 pub fn wire_len(&self, _ctx: &ParserContext) -> Result<u16> {
609 Ok(2 + self.payload_len() as u16)
610 }
611
612 fn payload_len(&self) -> u8 {
613 match self {
614 Capability::MultiProtocol { .. } => 4,
615 Capability::RouteRefresh => 0,
616 Capability::OutboundRouteFilter { orfs, .. } => 4 + 2 * orfs.len() as u8,
617 Capability::ExtendedNextHop { entries } => 6 * entries.len() as u8,
618 Capability::ExtendedMessage => 0,
619 Capability::BgpSec { .. } => 3,
620 Capability::MultiLabelCompat {} => todo!(),
621 Capability::BgpRole { .. } => 1,
622 Capability::GracefulRestart { entries, .. } => 2 + 4 * entries.len() as u8,
623 Capability::FourByteAsn { .. } => 4,
624 Capability::AddPath { .. } => 4,
625 Capability::EnhancedRouteRefresh => 0,
626 Capability::LongLivedGracefulRestart(long_lived_graceful_restarts) => {
627 8 * long_lived_graceful_restarts.len() as u8
628 }
629 Capability::UnknownCapability { value, .. } => value.len() as u8,
630 }
631 }
632}
633
634#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
636pub struct OutboundRouteFilterEntry {
637 pub r#type: OrfType,
638 pub send_recv: OrfSendRecv,
639}
640
641#[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
642#[repr(u8)]
643pub enum OrfType {
644 Reserved = 0,
645 Unassigned(u8),
646 AddressPrefix = 64,
647 CoveringPrefix = 65,
648 VpnPrefix = 66,
649 VendorSpecific(u8),
650}
651
652impl From<u8> for OrfType {
653 fn from(value: u8) -> Self {
654 match value {
655 v if v == OrfTypeDiscriminants::Reserved as u8 => Self::Reserved,
656 v if (1..64).contains(&v) => Self::Unassigned(v),
657 v if v == OrfTypeDiscriminants::AddressPrefix as u8 => Self::AddressPrefix,
658 v if v == OrfTypeDiscriminants::CoveringPrefix as u8 => Self::CoveringPrefix,
659 v if v == OrfTypeDiscriminants::VpnPrefix as u8 => Self::VpnPrefix,
660 other => Self::VendorSpecific(other),
661 }
662 }
663}
664
665impl From<OrfType> for u8 {
666 fn from(value: OrfType) -> Self {
667 match value {
668 OrfType::Reserved => OrfTypeDiscriminants::Reserved as u8,
669 OrfType::Unassigned(inner) => inner,
670 OrfType::AddressPrefix => OrfTypeDiscriminants::AddressPrefix as u8,
671 OrfType::CoveringPrefix => OrfTypeDiscriminants::CoveringPrefix as u8,
672 OrfType::VpnPrefix => OrfTypeDiscriminants::VpnPrefix as u8,
673 OrfType::VendorSpecific(inner) => inner,
674 }
675 }
676}
677
678#[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
679#[repr(u8)]
680pub enum OrfSendRecv {
681 Receive = 1,
682 Send = 2,
683 Both = 3,
684}
685
686impl TryFrom<u8> for OrfSendRecv {
687 type Error = eyre::ErrReport;
688
689 fn try_from(value: u8) -> Result<Self> {
690 Ok(match value {
691 value if value == OrfSendRecv::Receive as u8 => OrfSendRecv::Receive,
692 value if value == OrfSendRecv::Send as u8 => OrfSendRecv::Send,
693 value if value == OrfSendRecv::Both as u8 => OrfSendRecv::Both,
694 other => bail!("Invalid ORF send/recv value: {}", other),
695 })
696 }
697}
698
699#[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
700#[repr(u8)]
701pub enum AddPathSendRecv {
702 Receive = 1,
703 Send = 2,
704 Both = 3,
705}
706
707impl TryFrom<u8> for AddPathSendRecv {
708 type Error = eyre::ErrReport;
709
710 fn try_from(value: u8) -> Result<Self> {
711 Ok(match value {
712 value if value == AddPathSendRecv::Receive as u8 => AddPathSendRecv::Receive,
713 value if value == AddPathSendRecv::Send as u8 => AddPathSendRecv::Send,
714 value if value == AddPathSendRecv::Both as u8 => AddPathSendRecv::Both,
715 other => bail!("Invalid AddPathSendRecv send/recv value: {}", other),
716 })
717 }
718}
719
720impl From<&AddPathSendRecv> for u8 {
721 fn from(value: &AddPathSendRecv) -> Self {
722 match value {
723 AddPathSendRecv::Receive => AddPathSendRecv::Receive as u8,
724 AddPathSendRecv::Send => AddPathSendRecv::Send as u8,
725 AddPathSendRecv::Both => AddPathSendRecv::Both as u8,
726 }
727 }
728}
729
730#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
734pub struct ExtendedNextHop {
735 pub afi: AddressFamilyId,
737 pub safi: SubsequentAfi,
739 pub nh_afi: AddressFamilyId,
741}
742
743#[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, PartialEq, Eq)]
744#[repr(u8)]
745pub enum BgpRole {
746 Provider = 0,
747 RouteServer = 1,
748 RouteServerClient = 2,
749 Customer = 3,
750 Peer = 4,
751 Unknown(u8),
752}
753
754impl From<u8> for BgpRole {
755 fn from(value: u8) -> Self {
756 match value {
757 v if v == BgpRoleDiscriminants::Provider as u8 => Self::Provider,
758 v if v == BgpRoleDiscriminants::RouteServer as u8 => Self::RouteServer,
759 v if v == BgpRoleDiscriminants::RouteServerClient as u8 => Self::RouteServerClient,
760 v if v == BgpRoleDiscriminants::Customer as u8 => Self::Customer,
761 v if v == BgpRoleDiscriminants::Peer as u8 => Self::Peer,
762 other => Self::Unknown(other),
763 }
764 }
765}
766
767impl From<&BgpRole> for u8 {
768 fn from(value: &BgpRole) -> Self {
769 match value {
770 BgpRole::Provider => BgpRoleDiscriminants::Provider as u8,
771 BgpRole::RouteServer => BgpRoleDiscriminants::RouteServer as u8,
772 BgpRole::RouteServerClient => BgpRoleDiscriminants::RouteServerClient as u8,
773 BgpRole::Customer => BgpRoleDiscriminants::Customer as u8,
774 BgpRole::Peer => BgpRoleDiscriminants::Peer as u8,
775 BgpRole::Unknown(other) => *other,
776 }
777 }
778}
779
780#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
781pub struct LongLivedGracefulRestart {
782 pub afi: AddressFamilyId,
783 pub safi: SubsequentAfi,
784 pub flags: u8,
785 pub stale_time: u32,
788}
789
790bitfield! {
791 #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
792 pub struct BgpSecHeader(u8);
793 impl new;
794 u8, version, set_version : 3, 0; bool, dir, set_dir : 4; u8, unassigned, set_unassigned : 7, 5; }
798
799#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
801pub struct GracefulRestartEntry {
802 afi: AddressFamilyId,
803 safi: SubsequentAfi,
804 preserve_forwarding: bool,
808}
809
810#[cfg(test)]
811mod tests {
812 use std::net::Ipv4Addr;
813
814 use bytes::BytesMut;
815 use eyre::Result;
816
817 use crate::{
818 constants::{AddressFamilyId, SubsequentAfi},
819 open::{Capability, ExtendedNextHop, GracefulRestartEntry, OpenMessage, OpenOption},
820 parser::ParserContext,
821 };
822
823 macro_rules! test_capability_roundtrip {
824 ($name:ident, $input_bytes: expr, $expected: expr) => {
825 #[test]
826 fn $name() -> Result<()> {
827 let ctx = &default_v6_context();
828 let (buf, parsed) = Capability::from_wire(ctx, $input_bytes)?;
829 assert_eq!(parsed, $expected);
830 assert!(buf.is_empty());
831 let mut out = BytesMut::with_capacity(u16::MAX as usize);
832 parsed.to_wire(ctx, &mut out)?;
833 assert_eq!(out.to_vec(), $input_bytes);
834 Ok(())
835 }
836 };
837 }
838 fn default_v6_context() -> ParserContext {
841 ParserContext {
842 four_octet_asn: Some(true),
843 address_family: Some(AddressFamilyId::Ipv6),
844 }
845 }
846
847 test_capability_roundtrip!(
848 test_multiptotocol,
849 &[0x01, 0x04, 0x00, 0x01, 0x00, 0x01],
850 Capability::MultiProtocol {
851 afi: AddressFamilyId::Ipv4,
852 safi: SubsequentAfi::Unicast
853 }
854 );
855
856 test_capability_roundtrip!(test_route_refresh, &[0x02, 0x00], Capability::RouteRefresh);
857
858 test_capability_roundtrip!(
859 test_route_refresh_cisco_unsupported,
860 &[0x80, 0x00],
861 Capability::UnknownCapability {
862 type_code: 0x80,
863 length: 0x00,
864 value: vec![]
865 }
866 );
867
868 test_capability_roundtrip!(
869 test_four_octet_asn,
870 &[0x41, 0x04, 0x00, 0x00, 0xfd, 0xe8],
871 Capability::FourByteAsn { asn: 65000 }
872 );
873
874 test_capability_roundtrip!(
875 test_graceful_restart,
876 &[0x40, 0x06, 0x01, 0x2c, 0x00, 0x01, 0x01, 0x00],
877 Capability::GracefulRestart {
878 restart_state: false,
879 restart_time: 300,
880 entries: vec![GracefulRestartEntry {
881 afi: AddressFamilyId::Ipv4,
882 safi: SubsequentAfi::Unicast,
883 preserve_forwarding: false,
884 }]
885 }
886 );
887
888 test_capability_roundtrip!(
889 test_extended_nexthop,
890 &[
891 0x05, 0x12, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02,
892 0x00, 0x01, 0x00, 0x80, 0x00, 0x02
893 ],
894 Capability::ExtendedNextHop {
895 entries: vec![
896 ExtendedNextHop {
897 afi: AddressFamilyId::Ipv4,
898 safi: SubsequentAfi::Unicast,
899 nh_afi: AddressFamilyId::Ipv6,
900 },
901 ExtendedNextHop {
902 afi: AddressFamilyId::Ipv4,
903 safi: SubsequentAfi::Multicast,
904 nh_afi: AddressFamilyId::Ipv6,
905 },
906 ExtendedNextHop {
907 afi: AddressFamilyId::Ipv4,
908 safi: SubsequentAfi::MplsLabelledVpn,
909 nh_afi: AddressFamilyId::Ipv6
910 }
911 ]
912 }
913 );
914
915 #[test]
916 fn test_open_roundtrip() -> Result<()> {
917 let buf = &[
918 0x04, 0xfd, 0xe8, 0x00, 0xb4, 0x0a, 0x00, 0x00, 0x01, 0x38, 0x02, 0x06, 0x01, 0x04,
919 0x00, 0x01, 0x00, 0x01, 0x02, 0x02, 0x80, 0x00, 0x02, 0x02, 0x02, 0x00, 0x02, 0x06,
920 0x41, 0x04, 0x00, 0x00, 0xfd, 0xe8, 0x02, 0x08, 0x40, 0x06, 0x01, 0x2c, 0x00, 0x01,
921 0x01, 0x00, 0x02, 0x14, 0x05, 0x12, 0x00, 0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01,
922 0x00, 0x02, 0x00, 0x02, 0x00, 0x01, 0x00, 0x80, 0x00, 0x02,
923 ];
924 let expected = OpenMessage {
925 version: 4,
926 asn: 65000,
927 hold_time: 180,
928 identifier: Ipv4Addr::new(10, 0, 0, 1),
929 options: vec![
930 OpenOption::Capabilities(vec![Capability::MultiProtocol {
931 afi: AddressFamilyId::Ipv4,
932 safi: SubsequentAfi::Unicast,
933 }]),
934 OpenOption::Capabilities(vec![Capability::UnknownCapability {
935 type_code: 0x80,
936 length: 0x00,
937 value: vec![],
938 }]),
939 OpenOption::Capabilities(vec![Capability::RouteRefresh]),
940 OpenOption::Capabilities(vec![Capability::FourByteAsn { asn: 65000 }]),
941 OpenOption::Capabilities(vec![Capability::GracefulRestart {
942 restart_state: false,
943 restart_time: 300,
944 entries: vec![GracefulRestartEntry {
945 afi: AddressFamilyId::Ipv4,
946 safi: SubsequentAfi::Unicast,
947 preserve_forwarding: false,
948 }],
949 }]),
950 OpenOption::Capabilities(vec![Capability::ExtendedNextHop {
951 entries: vec![
952 ExtendedNextHop {
953 afi: AddressFamilyId::Ipv4,
954 safi: SubsequentAfi::Unicast,
955 nh_afi: AddressFamilyId::Ipv6,
956 },
957 ExtendedNextHop {
958 afi: AddressFamilyId::Ipv4,
959 safi: SubsequentAfi::Multicast,
960 nh_afi: AddressFamilyId::Ipv6,
961 },
962 ExtendedNextHop {
963 afi: AddressFamilyId::Ipv4,
964 safi: SubsequentAfi::MplsLabelledVpn,
965 nh_afi: AddressFamilyId::Ipv6,
966 },
967 ],
968 }]),
969 ],
970 };
971
972 let ctx = default_v6_context();
973 let (_, parsed) = OpenMessage::from_wire(&ctx, buf)?;
974 assert_eq!(parsed, expected);
975 let mut out = BytesMut::with_capacity(u16::MAX as usize);
976 parsed.to_wire(&ctx, &mut out)?;
977 assert_eq!(buf.to_vec(), out.to_vec());
978 Ok(())
979 }
980}