rotonda 0.5.2-alpha.0

composable, programmable BGP engine
Documentation
@use "Template"
@use "components/Tooltip"

<Template title="Peers overview">

<table>
    <tr>
        <th>asn</th>
        <th>bmp source</th>
        <th>peer addr</th>
        <th>ext next hop
            <Tooltip item="(?)" title="RFC8950 / Extended Next Hop exchanged in BGP OPENs">
            <ul class="legend">
                <li class="green">sent by both sides</li>
                <li class="yellow">sent by only one side</li>
                <li class="local">only configured locally</li>
                <li class="remote">only configured remotely</li>
            </ul>
            </Tooltip>
        </th>
        <th>bgp role
            <Tooltip item="(?)" title="RFC9234 Roles exchanged in BGP OPENs.">
            Locally configured role is on the left of the arrows, remote role
            on the right.<br/>
            </Tooltip>
        </th>
        <th>rib view</th>
        @if self.ext {
        <th># of routes</th>
        <th>ROV invalids</th>
        <th>OTC</th>
        <th>comm</th>
        <th>ext comm</th>
        <th>large comm</th>
        }
    </tr>
    @{
        let mut last_asn = Asn::from_u32(0);
        let mut last_bmp_id = None;
        let mut last_ip = "0.0.0.0".parse().unwrap();
    }
    @for peer in &self.peers { 
        @{ let Peer {ingress_info, bmp_router, ingress_id, num_routes, ext_next_hops, bgp_roles, observed_attributes: attrs} = peer;
            let Some(remote_asn) = ingress_info.remote_asn else { continue };
            let Some(remote_addr) = ingress_info.remote_addr else { continue };
            let Some(ribview) = ingress_info.peer_rib_type else { continue };
        }
    <tr>
        <td>@if last_asn != remote_asn { @{last_bmp_id = None; } <a href="/routes/peer_asn/@remote_asn">@remote_asn</a> }</td>
        <td>@if last_bmp_id != bmp_router.as_ref().map(|b| b.id) { @#bmp_router.as_ref().map(|r| bmp_details(r)).alt("") }</td>
        <td>@if last_ip != remote_addr { <a href="/routes/peer_ip/@remote_addr">@remote_addr</a> }</td>
        <td>
        @if ext_next_hops.only_local().count() > 0 {
            <span class="yellow">L:
                @for enh in ext_next_hops.only_local() { @enh }
            </span>
        } 
        
        @for enh in ext_next_hops.both() { <span class="green">@enh</span> }

        @if ext_next_hops.only_remote().count() > 0 {
            <span class="yellow">R:
                @for enh in ext_next_hops.only_remote() { @enh }
            </span>
        } 


        </td>
        <td class=@(
            if bgp_roles.incomplete() { "yellow"}
            else if bgp_roles.correct() == Some(true) { "green" }
            else if bgp_roles.correct() == Some(false) { "red" }
            else { "" }
        )
        >
            @bgp_roles
        </td>
        <td><a href="/routes/@ingress_id">@ribview</a></td>
        @if self.ext {
        <td>@num_routes.alt("")</td>
        <td>@if *attrs & ObservedAttributes::ROV_INVALID  { x } </td>
        <td>@if *attrs & ObservedAttributes::OTC  { x } </td>
        <td>@if *attrs & ObservedAttributes::COMMUNITIES  { x } </td>
        <td>@if *attrs & ObservedAttributes::EXT_COMMUNITIES  { x } </td>
        <td>@if *attrs & ObservedAttributes::LARGE_COMMUNITIES  { x } </td>
        }
    </tr>
    @{
        last_asn = remote_asn;
        last_bmp_id = bmp_router.as_ref().map(|b| b.id);
        last_ip = remote_addr;

    }

    }
</table>

</Template>