Private/OwnLsa.ps1

function Get-OspfNextSequence {
    param($Session, [string]$Key)
    $next = $script:OspfInitialSequence
    $e = $Session.Lsdb[$Key]
    if ($e) { $next = [math]::Max($next, (Read-OspfLsaHeader $e.Bytes 0).Sequence + 1) }
    if ($Session.SeqFloor.ContainsKey($Key)) { $next = [math]::Max($next, $Session.SeqFloor[$Key] + 1) }
    [long]$next
}

function Set-OspfOwnLsa {
    # Originates (or refreshes) one self-originated LSA; floods it when its content changed.
    param($Session, [datetime]$Now, [hashtable]$Parameters, [switch]$Force)
    $key = "$($script:LsaTypeNumbers[$Parameters.Type])|$($Parameters.LinkStateId)|$($Session.RouterId)"
    $seq = Get-OspfNextSequence $Session $Key
    $lsa = New-OspfLsa @Parameters -AdvertisingRouter $Session.RouterId -Sequence $seq
    $e = $Session.Lsdb[$key]
    if ($e -and -not $Force -and $e.Originated -and (Get-OspfLsaAge $e $Now) -lt $script:OspfMaxAge) {
        $old = [byte[]]$e.Bytes
        if ($old.Length -eq $lsa.Length -and [System.Convert]::ToHexString($old[20..($old.Length - 1)]) -eq [System.Convert]::ToHexString($lsa[20..($lsa.Length - 1)])) { return $key }
    }
    $null = Install-OspfLsa $Session $lsa $Now -Originated
    $Session.Originated[$key] = $true
    $Session.SeqFloor[$key] = $seq
    Add-OspfEvent -Session $Session -Direction 'Info' -Type 'Originate' -Message "LSA $key seq=0x$('{0:X8}' -f $seq)"
    Send-OspfFlood $Session @($key) $Now
    $key
}

function Update-OspfOwnLsas {
    param($Session, [datetime]$Now = [datetime]::UtcNow, [switch]$Force)
    $force = $Force -or [bool]$Session.ForceOriginate
    $Session.LsaDirty = $false
    $Session.ForceOriginate = $false
    if ($force) { $Session.LastRefresh = $Now }
    if ($Session.Status -ne 'Running') { return }
    $desired = [System.Collections.Generic.HashSet[string]]::new()
    $me = $Session.LocalAddress
    $full = @($Session.Neighbors.Values | Where-Object { $_.State -eq 'Full' })

    $links = [System.Collections.Generic.List[object]]::new()
    $netAddr = ConvertFrom-OspfLong $Session.NetworkLong
    if ($Session.NetworkType -eq 'PointToPoint') {
        foreach ($n in $full) { $links.Add((New-OspfRouterLink PointToPoint $n.RouterId $me -Metric $Session.Cost)) }
        $links.Add((New-OspfRouterLink Stub $netAddr $Session.Mask -Metric $Session.Cost))
    }
    else {
        $drFull = ($Session.Dr -eq $Session.LocalAddressLong -and $full.Count -gt 0) -or
        ($Session.Dr -ne 0 -and @($full | Where-Object { $_.Address -eq $Session.Dr }).Count -gt 0)
        if ($drFull) { $links.Add((New-OspfRouterLink Transit (ConvertFrom-OspfLong $Session.Dr) $me -Metric $Session.Cost)) }
        else { $links.Add((New-OspfRouterLink Stub $netAddr $Session.Mask -Metric $Session.Cost)) }
    }
    foreach ($p in $Session.Prefixes) { $links.Add((New-OspfRouterLink Stub $p.Network $p.Mask -Metric $p.Metric)) }
    $flags = 0
    if ($Session.Summaries.Count -gt 0) { $flags = $flags -bor 1 }
    if ($Session.Externals.Count -gt 0) { $flags = $flags -bor 2 }
    $null = $desired.Add((Set-OspfOwnLsa -Session $Session -Now $Now -Force:$force -Parameters @{ Type = 'Router'; LinkStateId = $Session.RouterId; Link = $links.ToArray(); Flags = $flags }))

    if ($Session.NetworkType -eq 'Broadcast' -and $Session.Dr -eq $Session.LocalAddressLong -and $full.Count -gt 0) {
        $att = @($Session.RouterId) + @($full | ForEach-Object { $_.RouterId })
        $null = $desired.Add((Set-OspfOwnLsa -Session $Session -Now $Now -Force:$force -Parameters @{ Type = 'Network'; LinkStateId = $me; Mask = $Session.Mask; AttachedRouter = $att }))
    }
    foreach ($x in $Session.Externals) {
        $null = $desired.Add((Set-OspfOwnLsa -Session $Session -Now $Now -Force:$force -Parameters @{
                    Type = 'External'; LinkStateId = $x.Network; Mask = $x.Mask; Metric = $x.Metric; ExternalType = $x.ExternalType; Tag = $x.Tag; ForwardingAddress = $x.ForwardingAddress }))
    }
    foreach ($x in $Session.Summaries) {
        $null = $desired.Add((Set-OspfOwnLsa -Session $Session -Now $Now -Force:$force -Parameters @{ Type = 'SummaryNetwork'; LinkStateId = $x.Network; Mask = $x.Mask; Metric = $x.Metric }))
    }
    foreach ($k in @($Session.Originated.Keys)) {
        if (-not $desired.Contains($k)) {
            Add-OspfEvent -Session $Session -Direction 'Info' -Type 'Flush' -Message "Flushing LSA $k"
            Stop-OspfLsaInstance $Session $k $Now
        }
    }
}