Microsoft Branch Cache Hash Offload
Problem this snippet solves:
BranchCache is a technology that Microsoft released with Windows 7 and Server 2008 R2 which can have a profound effect on where users actually source their content and the bandwidth consumed in retrieving that data. It’s fairly common in today’s work world to see global enterprises have multiple branch offices with users who regularly access data from a single centralized datacenter. If you take a look at the data that these users are commonly requesting, you’ll quickly realize that there is often a significant amount of data that is repetitive between the branch users. BranchCache is a technology designed to cut down on the unnecessary round trips from the branch office to the datacenter for data. By keeping an accessible copy of the content in the local branch, there will be a significant reduction in bandwidth used, and users will often be able to get the content faster than retrieving it from the distant datacenter.
This iRule will offload the hash calculation from the servers.
How to use this snippet:
Tested with oneconnect and tcp profiles applied, as well as this http profile:
profile http ms-pccrc-http {
compress enable
compress buffer size 131072
compress http 1.0 disable
compress gzip memory level 16k
compress gzip window size 64k
}
Code :
when HTTP_REQUEST {
set client "[IP::remote_addr]:[TCP::remote_port], URI: [HTTP::uri]"
set key "[HTTP::host][HTTP::uri]"
persist uie $key
if { [HTTP::header "Accept-Encoding"] contains "peerdist" } {
set will_peerdist 1
log local0. "$client - peerdist requested"
set pcc [session lookup uie $key]
if { [llength $pcc] != 0 } {
set pl [lrange [persist lookup uie $key] 0 2]
if { $pl ne [lindex $pcc 0] } {
log local0. "$client - cached peerdist hash does not match persistence: $pl != [lindex $pcc 0]"
} else {
log local0. "$client - responding with previously cached peerdist hash."
HTTP::respond 200 content [binary format a* [lindex $pcc 1]] \
"Content-Encoding" "peerdist" \
"X-P2P-PeerDist" "Version=1.0, ContentLength=[lindex $pcc 2]" \
"ETag" [lindex $pcc 3] \
"Content-Type" [lindex $pcc 4]
}
unset pl
}
unset pcc
} else {
set will_peerdist 0
log local0. "$client - peerdist not requested"
}
}
when HTTP_RESPONSE {
# Client can do peerdist, but server response is normal
if { $will_peerdist && \
[HTTP::status] == 200 && \
! [HTTP::header exists "Content-Encoding"] || \
[HTTP::header "Content-Encoding"] eq "identity" } {
set clen [HTTP::header "Content-Length"]
if { $clen > 0 } {
log local0. "[IP::remote_addr]:[TCP::remote_port]->$client - collecting content: $clen"
set h_len $clen
if { $h_len > 65536 } { set h_len 65536 }
HTTP::collect $h_len
} else {
log local0. "[IP::remote_addr]:[TCP::remote_port]->$client - no content found: $clen, headers: [HTTP::header names]"
}
}
}
when HTTP_RESPONSE_DATA {
if { ! [info exists offset] } {
set offset 0
set blkcnt 0
set blkhashes {}
set blkpci {}
set segoff 0
set segcnt 0
set seglen 0
set segpci {}
set secret [virtual name]
HTTP::header replace "Content-Encoding" "peerdist"
HTTP::header insert "X-P2P-PeerDist" "Version=1.0, ContentLength=$clen"
log local0. "$client - peerdist hashing started"
}
while { $offset < $clen } {
#log local0. "$client - currently collected: [HTTP::payload length], hashing offset: $offset (of $clen)"
set h_len [expr {$clen - $offset}]
if { $h_len > 65536 } { set h_len 65536 }
# if have more to do, but we haven't collected it yet
if { [HTTP::payload length] < $h_len } {
HTTP::collect $h_len
#log local0. "$client - waiting for [expr {$h_len-[HTTP::payload length]}] more, have: [HTTP::payload length]"
return
}
# Hash the current block
set blkhashes [binary format a*a* $blkhashes [sha256 [HTTP::payload $h_len]]]
# Delete the payload we just hashed since we don't need it anymore
HTTP::payload replace 0 $h_len {}
incr offset $h_len
incr blkcnt
# At the Segment boundary
if { $blkcnt >= 512 } {
# Add a segment hash of block hashes
set seglen [expr {$offset - $segoff}]
set seghash [sha256 $blkhashes]
set seghods [sha256 [binary format a*a* $seghash $secret]]
lappend segpci [binary format wiia*a* $segoff $seglen 65536 $seghash $seghods]
# Add a block hash
lappend blkpci [binary format ia* $blkcnt $blkhashes]
set blkhashes {}
set blkcnt 0
set segoff $offset
incr segcnt
log local0. "$client - segment, len: $seglen, cnt: $segcnt, off: $segoff"
}
}
# Didn't end on a block/segment boundary
if { $blkcnt > 0 } {
# Add a segment hash of block hashes for the last segment
set seglen [expr {$offset - $segoff}]
set seghash [sha256 $blkhashes]
set seghods [sha256 [binary format a*a* $seghash $secret]]
lappend segpci [binary format wiia*a* $segoff $seglen 65536 $seghash $seghods]
# Add a block hash
lappend blkpci [binary format ia* $blkcnt $blkhashes]
set blkcnt 0
incr segcnt
log local0. "$client - last segment, cnt: $segcnt, len: $seglen"
}
# Now build the new payload with the hashes
set pci [binary format siiii 0x0100 0x800C 0 0 $segcnt]
HTTP::payload replace 0 0 $pci
set offset [string length $pci]
foreach pci $segpci {
HTTP::payload replace $offset 0 $pci
incr offset [string length $pci]
}
foreach pci $blkpci {
HTTP::payload replace $offset 0 $pci
incr offset [string length $pci]
}
session add uie $key [list [LB::server] [HTTP::payload] $clen [HTTP::header ETag] [HTTP::header Content-Type]]
HTTP::release
log local0. "$client - content hash completed!"
unset -nocomplain pci offset blkcnt blkpci blkhashes secret key
unset -nocomplain segoff segcnt seglen segpci seghash seghods
}1 Comment
- Walter_Kacynski
Cirrostratus
What is the use case that this was applied for? Does it support HTTPS based applications?