1use bytes::{Bytes, BytesMut};
13use ndn_packet::{Name, NameComponent};
14use ndn_tlv::{TlvReader, TlvWriter};
15
16mod tlv {
19 pub const FACE_ID: u64 = 0x69;
21 pub const COST: u64 = 0x6a;
22 pub const STRATEGY_WRAPPER: u64 = 0x6b;
23 pub const FLAGS: u64 = 0x6c;
24 pub const EXPIRATION_PERIOD: u64 = 0x6d;
25 pub const ORIGIN: u64 = 0x6f;
26 pub const URI: u64 = 0x72;
27
28 pub const FACE_STATUS: u64 = 0x80;
30 pub const LOCAL_URI: u64 = 0x81;
31 pub const FACE_SCOPE: u64 = 0x84;
32 pub const FACE_PERSISTENCY: u64 = 0x85;
33 pub const LINK_TYPE: u64 = 0x86;
34 pub const BASE_CONGESTION_MARKING_INTERVAL: u64 = 0x87;
35 pub const DEFAULT_CONGESTION_THRESHOLD: u64 = 0x88;
36 pub const MTU: u64 = 0x89;
37 pub const N_IN_INTERESTS: u64 = 0x90;
38 pub const N_IN_DATA: u64 = 0x91;
39 pub const N_OUT_INTERESTS: u64 = 0x92;
40 pub const N_OUT_DATA: u64 = 0x93;
41 pub const N_IN_BYTES: u64 = 0x94;
42 pub const N_OUT_BYTES: u64 = 0x95;
43 pub const N_IN_NACKS: u64 = 0x97;
44 pub const N_OUT_NACKS: u64 = 0x98;
45
46 pub const ENTRY: u64 = 0x80;
48 pub const NEXT_HOP_RECORD: u64 = 0x81;
50 pub const ROUTE: u64 = 0x81;
52
53 pub const NAME: u64 = 0x07;
55 #[allow(dead_code)]
56 pub const NAME_COMPONENT: u64 = 0x08;
57}
58
59fn encode_non_neg_int(value: u64) -> Vec<u8> {
63 if value <= 0xFF {
64 vec![value as u8]
65 } else if value <= 0xFFFF {
66 (value as u16).to_be_bytes().to_vec()
67 } else if value <= 0xFFFF_FFFF {
68 (value as u32).to_be_bytes().to_vec()
69 } else {
70 value.to_be_bytes().to_vec()
71 }
72}
73
74fn write_non_neg_int(w: &mut TlvWriter, typ: u64, value: u64) {
76 w.write_tlv(typ, &encode_non_neg_int(value));
77}
78
79fn read_non_neg_int(buf: &[u8]) -> Option<u64> {
81 match buf.len() {
82 1 => Some(buf[0] as u64),
83 2 => Some(u16::from_be_bytes([buf[0], buf[1]]) as u64),
84 4 => Some(u32::from_be_bytes([buf[0], buf[1], buf[2], buf[3]]) as u64),
85 8 => Some(u64::from_be_bytes([
86 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
87 ])),
88 _ => None,
89 }
90}
91
92fn encode_name(w: &mut TlvWriter, name: &Name) {
95 w.write_nested(tlv::NAME, |w| {
96 for comp in name.components() {
97 w.write_tlv(comp.typ, &comp.value);
98 }
99 });
100}
101
102fn decode_name(value: Bytes) -> Option<Name> {
103 let mut r = TlvReader::new(value);
104 let mut components = Vec::new();
105 while !r.is_empty() {
106 let (typ, val) = r.read_tlv().ok()?;
107 components.push(NameComponent { typ, value: val });
108 }
109 if components.is_empty() {
110 Some(Name::root())
111 } else {
112 Some(Name::from_components(components))
113 }
114}
115
116#[derive(Debug, Clone)]
122pub struct FaceStatus {
123 pub face_id: u64,
124 pub uri: String,
126 pub local_uri: String,
128 pub face_scope: u64,
130 pub face_persistency: u64,
132 pub link_type: u64,
134 pub mtu: Option<u64>,
135 pub base_congestion_marking_interval: Option<u64>,
136 pub default_congestion_threshold: Option<u64>,
137 pub n_in_interests: u64,
138 pub n_in_data: u64,
139 pub n_in_nacks: u64,
140 pub n_out_interests: u64,
141 pub n_out_data: u64,
142 pub n_out_nacks: u64,
143 pub n_in_bytes: u64,
144 pub n_out_bytes: u64,
145}
146
147impl FaceStatus {
148 pub fn encode(&self) -> Bytes {
150 let mut w = TlvWriter::new();
151 w.write_nested(tlv::FACE_STATUS, |w| {
152 write_non_neg_int(w, tlv::FACE_ID, self.face_id);
153 w.write_tlv(tlv::URI, self.uri.as_bytes());
154 w.write_tlv(tlv::LOCAL_URI, self.local_uri.as_bytes());
155 write_non_neg_int(w, tlv::FACE_SCOPE, self.face_scope);
156 write_non_neg_int(w, tlv::FACE_PERSISTENCY, self.face_persistency);
157 write_non_neg_int(w, tlv::LINK_TYPE, self.link_type);
158 if let Some(v) = self.base_congestion_marking_interval {
159 write_non_neg_int(w, tlv::BASE_CONGESTION_MARKING_INTERVAL, v);
160 }
161 if let Some(v) = self.default_congestion_threshold {
162 write_non_neg_int(w, tlv::DEFAULT_CONGESTION_THRESHOLD, v);
163 }
164 if let Some(v) = self.mtu {
165 write_non_neg_int(w, tlv::MTU, v);
166 }
167 write_non_neg_int(w, tlv::N_IN_INTERESTS, self.n_in_interests);
168 write_non_neg_int(w, tlv::N_IN_DATA, self.n_in_data);
169 write_non_neg_int(w, tlv::N_IN_NACKS, self.n_in_nacks);
170 write_non_neg_int(w, tlv::N_OUT_INTERESTS, self.n_out_interests);
171 write_non_neg_int(w, tlv::N_OUT_DATA, self.n_out_data);
172 write_non_neg_int(w, tlv::N_OUT_NACKS, self.n_out_nacks);
173 write_non_neg_int(w, tlv::N_IN_BYTES, self.n_in_bytes);
174 write_non_neg_int(w, tlv::N_OUT_BYTES, self.n_out_bytes);
175 });
176 w.finish()
177 }
178
179 pub fn decode(buf: &mut &[u8]) -> Option<Self> {
181 let mut r = TlvReader::new(Bytes::copy_from_slice(buf));
182 let (typ, value) = r.read_tlv().ok()?;
183 if typ != tlv::FACE_STATUS {
184 return None;
185 }
186 let consumed = buf.len() - r.remaining();
188 *buf = &buf[consumed..];
189
190 let mut inner = TlvReader::new(value);
191 let mut face_id = 0u64;
192 let mut uri = String::new();
193 let mut local_uri = String::new();
194 let mut face_scope = 0u64;
195 let mut face_persistency = 0u64;
196 let mut link_type = 0u64;
197 let mut mtu = None;
198 let mut base_congestion = None;
199 let mut def_congestion = None;
200 let mut n_in_interests = 0u64;
201 let mut n_in_data = 0u64;
202 let mut n_in_nacks = 0u64;
203 let mut n_out_interests = 0u64;
204 let mut n_out_data = 0u64;
205 let mut n_out_nacks = 0u64;
206 let mut n_in_bytes = 0u64;
207 let mut n_out_bytes = 0u64;
208
209 while !inner.is_empty() {
210 let (t, v) = inner.read_tlv().ok()?;
211 match t {
212 tlv::FACE_ID => face_id = read_non_neg_int(&v)?,
213 tlv::URI => uri = std::str::from_utf8(&v).ok()?.to_owned(),
214 tlv::LOCAL_URI => local_uri = std::str::from_utf8(&v).ok()?.to_owned(),
215 tlv::FACE_SCOPE => face_scope = read_non_neg_int(&v)?,
216 tlv::FACE_PERSISTENCY => face_persistency = read_non_neg_int(&v)?,
217 tlv::LINK_TYPE => link_type = read_non_neg_int(&v)?,
218 tlv::MTU => mtu = read_non_neg_int(&v),
219 tlv::BASE_CONGESTION_MARKING_INTERVAL => {
220 base_congestion = read_non_neg_int(&v);
221 }
222 tlv::DEFAULT_CONGESTION_THRESHOLD => {
223 def_congestion = read_non_neg_int(&v);
224 }
225 tlv::N_IN_INTERESTS => n_in_interests = read_non_neg_int(&v)?,
226 tlv::N_IN_DATA => n_in_data = read_non_neg_int(&v)?,
227 tlv::N_IN_NACKS => n_in_nacks = read_non_neg_int(&v)?,
228 tlv::N_OUT_INTERESTS => n_out_interests = read_non_neg_int(&v)?,
229 tlv::N_OUT_DATA => n_out_data = read_non_neg_int(&v)?,
230 tlv::N_OUT_NACKS => n_out_nacks = read_non_neg_int(&v)?,
231 tlv::N_IN_BYTES => n_in_bytes = read_non_neg_int(&v)?,
232 tlv::N_OUT_BYTES => n_out_bytes = read_non_neg_int(&v)?,
233 _ => {} }
235 }
236
237 Some(FaceStatus {
238 face_id,
239 uri,
240 local_uri,
241 face_scope,
242 face_persistency,
243 link_type,
244 mtu,
245 base_congestion_marking_interval: base_congestion,
246 default_congestion_threshold: def_congestion,
247 n_in_interests,
248 n_in_data,
249 n_in_nacks,
250 n_out_interests,
251 n_out_data,
252 n_out_nacks,
253 n_in_bytes,
254 n_out_bytes,
255 })
256 }
257
258 pub fn decode_all(bytes: &[u8]) -> Vec<Self> {
260 let mut buf = bytes;
261 let mut out = Vec::new();
262 while !buf.is_empty() {
263 match Self::decode(&mut buf) {
264 Some(entry) => out.push(entry),
265 None => break,
266 }
267 }
268 out
269 }
270
271 pub fn persistency_str(&self) -> &'static str {
273 match self.face_persistency {
274 0 => "persistent",
275 1 => "on-demand",
276 2 => "permanent",
277 _ => "unknown",
278 }
279 }
280
281 pub fn scope_str(&self) -> &'static str {
283 match self.face_scope {
284 1 => "local",
285 _ => "non-local",
286 }
287 }
288}
289
290#[derive(Debug, Clone)]
294pub struct NextHopRecord {
295 pub face_id: u64,
296 pub cost: u64,
297}
298
299#[derive(Debug, Clone)]
303pub struct FibEntry {
304 pub name: Name,
305 pub nexthops: Vec<NextHopRecord>,
306}
307
308impl FibEntry {
309 pub fn encode(&self) -> Bytes {
311 let mut w = TlvWriter::new();
312 w.write_nested(tlv::ENTRY, |w| {
313 encode_name(w, &self.name);
314 for nh in &self.nexthops {
315 w.write_nested(tlv::NEXT_HOP_RECORD, |w| {
316 write_non_neg_int(w, tlv::FACE_ID, nh.face_id);
317 write_non_neg_int(w, tlv::COST, nh.cost);
318 });
319 }
320 });
321 w.finish()
322 }
323
324 pub fn decode(buf: &mut &[u8]) -> Option<Self> {
326 let mut r = TlvReader::new(Bytes::copy_from_slice(buf));
327 let (typ, value) = r.read_tlv().ok()?;
328 if typ != tlv::ENTRY {
329 return None;
330 }
331 let consumed = buf.len() - r.remaining();
332 *buf = &buf[consumed..];
333
334 let mut inner = TlvReader::new(value);
335 let mut name = None;
336 let mut nexthops = Vec::new();
337
338 while !inner.is_empty() {
339 let (t, v) = inner.read_tlv().ok()?;
340 match t {
341 tlv::NAME => name = decode_name(v),
342 tlv::NEXT_HOP_RECORD => {
343 let mut nr = TlvReader::new(v);
344 let mut face_id = 0u64;
345 let mut cost = 0u64;
346 while !nr.is_empty() {
347 if let Ok((nt, nv)) = nr.read_tlv() {
348 match nt {
349 tlv::FACE_ID => face_id = read_non_neg_int(&nv).unwrap_or(0),
350 tlv::COST => cost = read_non_neg_int(&nv).unwrap_or(0),
351 _ => {}
352 }
353 }
354 }
355 nexthops.push(NextHopRecord { face_id, cost });
356 }
357 _ => {}
358 }
359 }
360
361 Some(FibEntry {
362 name: name.unwrap_or_else(Name::root),
363 nexthops,
364 })
365 }
366
367 pub fn decode_all(bytes: &[u8]) -> Vec<Self> {
369 let mut buf = bytes;
370 let mut out = Vec::new();
371 while !buf.is_empty() {
372 match Self::decode(&mut buf) {
373 Some(entry) => out.push(entry),
374 None => break,
375 }
376 }
377 out
378 }
379}
380
381#[derive(Debug, Clone)]
385pub struct Route {
386 pub face_id: u64,
387 pub origin: u64,
388 pub cost: u64,
389 pub flags: u64,
390 pub expiration_period: Option<u64>,
391}
392
393#[derive(Debug, Clone)]
397pub struct RibEntry {
398 pub name: Name,
399 pub routes: Vec<Route>,
400}
401
402impl RibEntry {
403 pub fn encode(&self) -> Bytes {
405 let mut w = TlvWriter::new();
406 w.write_nested(tlv::ENTRY, |w| {
407 encode_name(w, &self.name);
408 for route in &self.routes {
409 w.write_nested(tlv::ROUTE, |w| {
410 write_non_neg_int(w, tlv::FACE_ID, route.face_id);
411 write_non_neg_int(w, tlv::ORIGIN, route.origin);
412 write_non_neg_int(w, tlv::COST, route.cost);
413 write_non_neg_int(w, tlv::FLAGS, route.flags);
414 if let Some(ep) = route.expiration_period {
415 write_non_neg_int(w, tlv::EXPIRATION_PERIOD, ep);
416 }
417 });
418 }
419 });
420 w.finish()
421 }
422
423 pub fn decode(buf: &mut &[u8]) -> Option<Self> {
425 let mut r = TlvReader::new(Bytes::copy_from_slice(buf));
426 let (typ, value) = r.read_tlv().ok()?;
427 if typ != tlv::ENTRY {
428 return None;
429 }
430 let consumed = buf.len() - r.remaining();
431 *buf = &buf[consumed..];
432
433 let mut inner = TlvReader::new(value);
434 let mut name = None;
435 let mut routes = Vec::new();
436
437 while !inner.is_empty() {
438 let (t, v) = inner.read_tlv().ok()?;
439 match t {
440 tlv::NAME => name = decode_name(v),
441 tlv::ROUTE => {
442 let mut rr = TlvReader::new(v);
443 let mut face_id = 0u64;
444 let mut origin = 0u64;
445 let mut cost = 0u64;
446 let mut flags = 0u64;
447 let mut expiration_period = None;
448 while !rr.is_empty() {
449 if let Ok((rt, rv)) = rr.read_tlv() {
450 match rt {
451 tlv::FACE_ID => {
452 face_id = read_non_neg_int(&rv).unwrap_or(0);
453 }
454 tlv::ORIGIN => {
455 origin = read_non_neg_int(&rv).unwrap_or(0);
456 }
457 tlv::COST => {
458 cost = read_non_neg_int(&rv).unwrap_or(0);
459 }
460 tlv::FLAGS => {
461 flags = read_non_neg_int(&rv).unwrap_or(0);
462 }
463 tlv::EXPIRATION_PERIOD => {
464 expiration_period = read_non_neg_int(&rv);
465 }
466 _ => {}
467 }
468 }
469 }
470 routes.push(Route {
471 face_id,
472 origin,
473 cost,
474 flags,
475 expiration_period,
476 });
477 }
478 _ => {}
479 }
480 }
481
482 Some(RibEntry {
483 name: name.unwrap_or_else(Name::root),
484 routes,
485 })
486 }
487
488 pub fn decode_all(bytes: &[u8]) -> Vec<Self> {
490 let mut buf = bytes;
491 let mut out = Vec::new();
492 while !buf.is_empty() {
493 match Self::decode(&mut buf) {
494 Some(entry) => out.push(entry),
495 None => break,
496 }
497 }
498 out
499 }
500}
501
502#[derive(Debug, Clone)]
508pub struct StrategyChoice {
509 pub name: Name,
510 pub strategy: Name,
511}
512
513impl StrategyChoice {
514 pub fn encode(&self) -> Bytes {
516 let mut w = TlvWriter::new();
517 w.write_nested(tlv::ENTRY, |w| {
518 encode_name(w, &self.name);
519 w.write_nested(tlv::STRATEGY_WRAPPER, |w| {
520 encode_name(w, &self.strategy);
521 });
522 });
523 w.finish()
524 }
525
526 pub fn decode(buf: &mut &[u8]) -> Option<Self> {
528 let mut r = TlvReader::new(Bytes::copy_from_slice(buf));
529 let (typ, value) = r.read_tlv().ok()?;
530 if typ != tlv::ENTRY {
531 return None;
532 }
533 let consumed = buf.len() - r.remaining();
534 *buf = &buf[consumed..];
535
536 let mut inner = TlvReader::new(value);
537 let mut name = None;
538 let mut strategy = None;
539
540 while !inner.is_empty() {
541 let (t, v) = inner.read_tlv().ok()?;
542 match t {
543 tlv::NAME => name = decode_name(v),
544 tlv::STRATEGY_WRAPPER => {
545 let mut sr = TlvReader::new(v);
547 if let Ok((st, sv)) = sr.read_tlv()
548 && st == tlv::NAME
549 {
550 strategy = decode_name(sv);
551 }
552 }
553 _ => {}
554 }
555 }
556
557 Some(StrategyChoice {
558 name: name.unwrap_or_else(Name::root),
559 strategy: strategy.unwrap_or_else(Name::root),
560 })
561 }
562
563 pub fn decode_all(bytes: &[u8]) -> Vec<Self> {
565 let mut buf = bytes;
566 let mut out = Vec::new();
567 while !buf.is_empty() {
568 match Self::decode(&mut buf) {
569 Some(entry) => out.push(entry),
570 None => break,
571 }
572 }
573 out
574 }
575}
576
577pub fn encode_dataset<T, F>(items: &[T], encode_fn: F) -> Bytes
581where
582 F: Fn(&T) -> Bytes,
583{
584 let mut buf = BytesMut::new();
585 for item in items {
586 buf.extend_from_slice(&encode_fn(item));
587 }
588 buf.freeze()
589}
590
591#[cfg(test)]
592mod tests {
593 use super::*;
594 use bytes::Bytes;
595 use ndn_packet::NameComponent;
596
597 fn name(components: &[&[u8]]) -> Name {
598 Name::from_components(
599 components
600 .iter()
601 .map(|c| NameComponent::generic(Bytes::copy_from_slice(c))),
602 )
603 }
604
605 #[test]
606 fn face_status_roundtrip() {
607 let fs = FaceStatus {
608 face_id: 1,
609 uri: "udp4://192.168.1.1:6363".to_owned(),
610 local_uri: "udp4://0.0.0.0:6363".to_owned(),
611 face_scope: 0,
612 face_persistency: 0,
613 link_type: 0,
614 mtu: Some(8800),
615 base_congestion_marking_interval: None,
616 default_congestion_threshold: None,
617 n_in_interests: 100,
618 n_in_data: 50,
619 n_in_nacks: 2,
620 n_out_interests: 80,
621 n_out_data: 30,
622 n_out_nacks: 1,
623 n_in_bytes: 10000,
624 n_out_bytes: 5000,
625 };
626 let encoded = fs.encode();
627 let mut buf = encoded.as_ref();
628 let decoded = FaceStatus::decode(&mut buf).unwrap();
629 assert!(buf.is_empty());
630 assert_eq!(decoded.face_id, 1);
631 assert_eq!(decoded.uri, "udp4://192.168.1.1:6363");
632 assert_eq!(decoded.local_uri, "udp4://0.0.0.0:6363");
633 assert_eq!(decoded.mtu, Some(8800));
634 assert_eq!(decoded.n_in_interests, 100);
635 }
636
637 #[test]
638 fn face_status_decode_all() {
639 let faces = vec![
640 FaceStatus {
641 face_id: 1,
642 uri: "udp4://1.2.3.4:6363".to_owned(),
643 local_uri: "udp4://0.0.0.0:0".to_owned(),
644 face_scope: 0,
645 face_persistency: 0,
646 link_type: 0,
647 mtu: None,
648 base_congestion_marking_interval: None,
649 default_congestion_threshold: None,
650 n_in_interests: 0,
651 n_in_data: 0,
652 n_in_nacks: 0,
653 n_out_interests: 0,
654 n_out_data: 0,
655 n_out_nacks: 0,
656 n_in_bytes: 0,
657 n_out_bytes: 0,
658 },
659 FaceStatus {
660 face_id: 2,
661 uri: "tcp4://5.6.7.8:6363".to_owned(),
662 local_uri: "tcp4://0.0.0.0:0".to_owned(),
663 face_scope: 1,
664 face_persistency: 2,
665 link_type: 0,
666 mtu: None,
667 base_congestion_marking_interval: None,
668 default_congestion_threshold: None,
669 n_in_interests: 0,
670 n_in_data: 0,
671 n_in_nacks: 0,
672 n_out_interests: 0,
673 n_out_data: 0,
674 n_out_nacks: 0,
675 n_in_bytes: 0,
676 n_out_bytes: 0,
677 },
678 ];
679 let mut buf = BytesMut::new();
680 for f in &faces {
681 buf.extend_from_slice(&f.encode());
682 }
683 let decoded = FaceStatus::decode_all(&buf);
684 assert_eq!(decoded.len(), 2);
685 assert_eq!(decoded[0].face_id, 1);
686 assert_eq!(decoded[1].face_id, 2);
687 assert_eq!(decoded[1].face_persistency, 2);
688 }
689
690 #[test]
691 fn fib_entry_roundtrip() {
692 let entry = FibEntry {
693 name: name(&[b"ndn", b"test"]),
694 nexthops: vec![
695 NextHopRecord {
696 face_id: 1,
697 cost: 10,
698 },
699 NextHopRecord {
700 face_id: 2,
701 cost: 5,
702 },
703 ],
704 };
705 let encoded = entry.encode();
706 let mut buf = encoded.as_ref();
707 let decoded = FibEntry::decode(&mut buf).unwrap();
708 assert!(buf.is_empty());
709 assert_eq!(decoded.nexthops.len(), 2);
710 assert_eq!(decoded.nexthops[0].face_id, 1);
711 assert_eq!(decoded.nexthops[0].cost, 10);
712 assert_eq!(decoded.nexthops[1].face_id, 2);
713 assert_eq!(decoded.nexthops[1].cost, 5);
714 }
715
716 #[test]
717 fn rib_entry_roundtrip() {
718 let entry = RibEntry {
719 name: name(&[b"ndn"]),
720 routes: vec![Route {
721 face_id: 3,
722 origin: 0,
723 cost: 10,
724 flags: 1,
725 expiration_period: Some(30_000),
726 }],
727 };
728 let encoded = entry.encode();
729 let mut buf = encoded.as_ref();
730 let decoded = RibEntry::decode(&mut buf).unwrap();
731 assert!(buf.is_empty());
732 assert_eq!(decoded.routes.len(), 1);
733 assert_eq!(decoded.routes[0].face_id, 3);
734 assert_eq!(decoded.routes[0].expiration_period, Some(30_000));
735 }
736
737 #[test]
738 fn strategy_choice_roundtrip() {
739 let entry = StrategyChoice {
740 name: name(&[b"ndn"]),
741 strategy: name(&[b"localhost", b"nfd", b"strategy", b"best-route"]),
742 };
743 let encoded = entry.encode();
744 let mut buf = encoded.as_ref();
745 let decoded = StrategyChoice::decode(&mut buf).unwrap();
746 assert!(buf.is_empty());
747 assert_eq!(
748 decoded.strategy.to_string(),
749 "/localhost/nfd/strategy/best-route"
750 );
751 }
752}