|
4 | 4 |
|
5 | 5 | use anyhow::{Result, anyhow}; |
6 | 6 | use ddm_admin_client::Client; |
7 | | -use ddm_admin_client::types::TunnelOrigin; |
| 7 | +use ddm_admin_client::types::{MulticastOrigin, TunnelOrigin, Vni}; |
8 | 8 | use slog::{Drain, Logger}; |
9 | 9 | use std::env; |
10 | 10 | use std::net::Ipv6Addr; |
@@ -642,6 +642,49 @@ async fn run_trio_tests( |
642 | 642 |
|
643 | 643 | println!("tunnel endpoint withdraw passed"); |
644 | 644 |
|
| 645 | + // Multicast group advertise/withdraw across the trio. Mirrors how |
| 646 | + // mg-lower in the switch zone publishes overlay→underlay multicast |
| 647 | + // bindings: the transit router originates an advertisement, and the |
| 648 | + // server routers learn it via DDM exchange. |
| 649 | + wait_for_eq!(multicast_originated_count(&t1).await?, 0); |
| 650 | + |
| 651 | + let mcast_origin = MulticastOrigin { |
| 652 | + overlay_group: "233.252.0.1".parse().unwrap(), |
| 653 | + underlay_group: "ff04::100".parse().unwrap(), |
| 654 | + vni: Vni(77), |
| 655 | + source: None, |
| 656 | + metric: 0, |
| 657 | + }; |
| 658 | + |
| 659 | + t1.advertise_multicast_groups(&vec![mcast_origin.clone()]) |
| 660 | + .await?; |
| 661 | + |
| 662 | + wait_for_eq!(multicast_originated_count(&t1).await?, 1); |
| 663 | + wait_for_eq!(multicast_group_count(&t1).await?, 0); |
| 664 | + wait_for_eq!(multicast_group_count(&s1).await?, 1); |
| 665 | + wait_for_eq!(multicast_group_count(&s2).await?, 1); |
| 666 | + |
| 667 | + println!("multicast group advertise passed"); |
| 668 | + |
| 669 | + // Server router restart: s1's view of the multicast group must |
| 670 | + // converge again after ddmd restarts. wait_for_eq tolerates the |
| 671 | + // restart window via unwrap_or sentinel. |
| 672 | + zs1.stop_router()?; |
| 673 | + zs1.start_router(false)?; |
| 674 | + let s1 = Client::new("http://10.0.0.1:8000", log.clone()); |
| 675 | + wait_for_eq!(multicast_group_count(&s1).await.unwrap_or(99), 1); |
| 676 | + |
| 677 | + println!("multicast router restart passed"); |
| 678 | + |
| 679 | + t1.withdraw_multicast_groups(&vec![mcast_origin]).await?; |
| 680 | + |
| 681 | + wait_for_eq!(multicast_originated_count(&t1).await?, 0); |
| 682 | + wait_for_eq!(multicast_group_count(&t1).await?, 0); |
| 683 | + wait_for_eq!(multicast_group_count(&s1).await?, 0); |
| 684 | + wait_for_eq!(multicast_group_count(&s2).await?, 0); |
| 685 | + |
| 686 | + println!("multicast group withdraw passed"); |
| 687 | + |
645 | 688 | Ok(()) |
646 | 689 | } |
647 | 690 |
|
@@ -812,6 +855,14 @@ async fn tunnel_originated_endpoint_count(c: &Client) -> Result<usize> { |
812 | 855 | Ok(c.get_originated_tunnel_endpoints().await?.len()) |
813 | 856 | } |
814 | 857 |
|
| 858 | +async fn multicast_group_count(c: &Client) -> Result<usize> { |
| 859 | + Ok(c.get_multicast_groups().await?.len()) |
| 860 | +} |
| 861 | + |
| 862 | +async fn multicast_originated_count(c: &Client) -> Result<usize> { |
| 863 | + Ok(c.get_originated_multicast_groups().await?.len()) |
| 864 | +} |
| 865 | + |
815 | 866 | fn init_logger() -> Logger { |
816 | 867 | let decorator = slog_term::TermDecorator::new().build(); |
817 | 868 | let drain = slog_term::FullFormat::new(decorator).build().fuse(); |
|
0 commit comments