mirror of
https://github.com/xtaci/kcptun.git
synced 2024-04-21 12:32:32 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5232c2953 | ||
|
|
0a9243f27c | ||
|
|
b7167b5859 | ||
|
|
b63eeb6301 | ||
|
|
5b5c094e4b | ||
|
|
c4bd77cf28 | ||
|
|
94c9cacf4f | ||
|
|
9a5b31b470 | ||
|
|
07ad03fecf | ||
|
|
2225d258cb | ||
|
|
e9316f7be4 | ||
|
|
9ac04cd24d | ||
|
|
76c4d231f2 | ||
|
|
160b68cbc5 | ||
|
|
212504f6c2 | ||
|
|
114cd97025 | ||
|
|
b2be91cdb5 |
@@ -106,7 +106,7 @@ All precompiled releases are genereated from `build-release.sh` script.
|
||||
|
||||
> eg: `-mode fast3`
|
||||
|
||||
> Aggresiveness/Responsiveness on retransmission for embeded modes are:
|
||||
> Aggresiveness/Responsiveness on retransmission for embedded modes are:
|
||||
|
||||
> *fast3 > fast2 > fast > normal > default*
|
||||
|
||||
@@ -152,7 +152,7 @@ GLOBAL OPTIONS:
|
||||
--mode value profiles: fast3, fast2, fast, normal, manual (default: "fast")
|
||||
--conn value set num of UDP connections to server (default: 1)
|
||||
--autoexpire value set auto expiration time(in seconds) for a single UDP connection, 0 to disable (default: 0)
|
||||
--scavengettl value set how long an expired connection can live(in sec), -1 to disable (default: 600)
|
||||
--scavengettl value set how long an expired connection can live (in seconds) (default: 600)
|
||||
--mtu value set maximum transmission unit for UDP packets (default: 1350)
|
||||
--sndwnd value set send window size(num of packets) (default: 128)
|
||||
--rcvwnd value set receive window size(num of packets) (default: 512)
|
||||
@@ -224,8 +224,6 @@ It is able to detect and correct multiple symbol errors. By adding t check symbo
|
||||
|
||||

|
||||
|
||||
Setting parameters of RS-Code with ```-datashard m -parityshard n``` on **BOTH** KCP Client & KCP Server **MUST** be **IDENTICAL**.
|
||||
|
||||
#### DSCP
|
||||
|
||||
Differentiated services or DiffServ is a computer networking architecture that specifies a simple, scalable and coarse-grained mechanism for classifying and managing network traffic and providing quality of service (QoS) on modern IP networks. DiffServ can, for example, be used to provide low-latency to critical network traffic such as voice or streaming media while providing simple best-effort service to non-critical services such as web traffic or file transfers.
|
||||
@@ -293,7 +291,7 @@ Reference: https://blog.golang.org/go15gc
|
||||
Primary memory allocation are done from a global buffer pool *xmit.Buf*, in kcp-go, when we need to allocate some bytes, we can get from that pool, and a *fixed-capacity* 1500 bytes(mtuLimit) will be returned, the *rx queue*, *tx queue* and *fec queue* all receive bytes from there, and they will return the bytes to the pool after using to prevent *unnecessary zer0ing* of bytes.
|
||||
The pool mechanism maintained a *high watermark* for slice objects, these *in-flight* objects from the pool will survive from the perodical garbage collection, meanwhile the pool kept the ability to return the memory to runtime if in idle, `-sndwnd`,`-rcvwnd`,`-ds`, `-ps`, these parameters affect this *high watermark*, the larger the value, the bigger the memory consumption will be.
|
||||
|
||||
`-smuxbuf` also affects the maximum memory consumption, this parameter maintains a subtle balance between *concurrency* and *resource*, you can increase this value(default 4MB) to boost concurrency if you have many clients to serve and you get a powerful server at the same time, and also you can decrease this value to serve only 1 or 2 clients and hope this program can run under some embeded SoC system with limited memory and only you can access. (Notice that the `-smuxbuf` value is not proprotional to concurrency, you need to test.)
|
||||
`-smuxbuf` also affects the maximum memory consumption, this parameter maintains a subtle balance between *concurrency* and *resource*, you can increase this value(default 4MB) to boost concurrency if you have many clients to serve and you get a powerful server at the same time, and also you can decrease this value to serve only 1 or 2 clients and hope this program can run under some embedded SoC system with limited memory and only you can access. (Notice that the `-smuxbuf` value is not proprotional to concurrency, you need to test.)
|
||||
|
||||
|
||||
#### Compression
|
||||
@@ -357,13 +355,11 @@ Low-level KCP configuration can be altered by using manual mode like above, make
|
||||
|
||||
### Identical Parmeters
|
||||
|
||||
The parameters below **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
These parameters **MUST** be **IDENTICAL** on **BOTH** side:
|
||||
|
||||
1. -key
|
||||
1. -crypt
|
||||
1. -nocomp
|
||||
1. -datashard
|
||||
1. -parityshard
|
||||
1. -smuxver
|
||||
|
||||
### References
|
||||
|
||||
@@ -57,6 +57,12 @@ for os in ${OSES[@]}; do
|
||||
$sum kcptun-${os}-386-$VERSION.tar.gz
|
||||
done
|
||||
|
||||
#Apple M1 device
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o server_darwin_arm64 github.com/xtaci/kcptun/server
|
||||
env CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 go build -mod=vendor -ldflags "$LDFLAGS" -gcflags "$GCFLAGS" -o client_darwin_arm64 github.com/xtaci/kcptun/client
|
||||
tar -zcf kcptun-darwin-arm64-$VERSION.tar.gz client_darwin_arm64 server_darwin_arm64
|
||||
$sum kcptun-darwin-arm64-$VERSION.tar.gz
|
||||
|
||||
# ARM
|
||||
ARMS=(5 6 7)
|
||||
for v in ${ARMS[@]}; do
|
||||
|
||||
+44
-33
@@ -73,6 +73,11 @@ func checkError(err error) {
|
||||
}
|
||||
}
|
||||
|
||||
type timedSession struct {
|
||||
session *smux.Session
|
||||
expiryDate time.Time
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(int64(time.Now().Nanosecond()))
|
||||
if VERSION == "SELFBUILD" {
|
||||
@@ -104,7 +109,7 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none, null",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
@@ -124,7 +129,7 @@ func main() {
|
||||
cli.IntFlag{
|
||||
Name: "scavengettl",
|
||||
Value: 600,
|
||||
Usage: "set how long an expired connection can live(in sec), -1 to disable",
|
||||
Usage: "set how long an expired connection can live (in seconds)",
|
||||
},
|
||||
cli.IntFlag{
|
||||
Name: "mtu",
|
||||
@@ -335,6 +340,8 @@ func main() {
|
||||
log.Println("key derivation done")
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "null":
|
||||
block = nil
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
@@ -421,20 +428,16 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
numconn := uint16(config.Conn)
|
||||
muxes := make([]struct {
|
||||
session *smux.Session
|
||||
ttl time.Time
|
||||
}, numconn)
|
||||
|
||||
for k := range muxes {
|
||||
muxes[k].session = waitConn()
|
||||
muxes[k].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
}
|
||||
|
||||
chScavenger := make(chan *smux.Session, 128)
|
||||
go scavenger(chScavenger, config.ScavengeTTL)
|
||||
// start snmp logger
|
||||
go generic.SnmpLogger(config.SnmpLog, config.SnmpPeriod)
|
||||
|
||||
// start scavenger
|
||||
chScavenger := make(chan timedSession, 128)
|
||||
go scavenger(chScavenger, &config)
|
||||
|
||||
// start listener
|
||||
numconn := uint16(config.Conn)
|
||||
muxes := make([]timedSession, numconn)
|
||||
rr := uint16(0)
|
||||
for {
|
||||
p1, err := listener.AcceptTCP()
|
||||
@@ -444,10 +447,13 @@ func main() {
|
||||
idx := rr % numconn
|
||||
|
||||
// do auto expiration && reconnection
|
||||
if muxes[idx].session.IsClosed() || (config.AutoExpire > 0 && time.Now().After(muxes[idx].ttl)) {
|
||||
chScavenger <- muxes[idx].session
|
||||
if muxes[idx].session == nil || muxes[idx].session.IsClosed() ||
|
||||
(config.AutoExpire > 0 && time.Now().After(muxes[idx].expiryDate)) {
|
||||
muxes[idx].session = waitConn()
|
||||
muxes[idx].ttl = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
muxes[idx].expiryDate = time.Now().Add(time.Duration(config.AutoExpire) * time.Second)
|
||||
if config.AutoExpire > 0 { // only when autoexpire set
|
||||
chScavenger <- muxes[idx]
|
||||
}
|
||||
}
|
||||
|
||||
go handleClient(muxes[idx].session, p1, config.Quiet)
|
||||
@@ -457,30 +463,35 @@ func main() {
|
||||
myApp.Run(os.Args)
|
||||
}
|
||||
|
||||
type scavengeSession struct {
|
||||
session *smux.Session
|
||||
ts time.Time
|
||||
}
|
||||
func scavenger(ch chan timedSession, config *Config) {
|
||||
// When AutoExpire is set to 0 (default), sessionList will keep empty.
|
||||
// Then this routine won't need to do anything; thus just terminate it.
|
||||
if config.AutoExpire <= 0 {
|
||||
return
|
||||
}
|
||||
|
||||
func scavenger(ch chan *smux.Session, ttl int) {
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
var sessionList []scavengeSession
|
||||
var sessionList []timedSession
|
||||
for {
|
||||
select {
|
||||
case sess := <-ch:
|
||||
sessionList = append(sessionList, scavengeSession{sess, time.Now()})
|
||||
log.Println("session marked as expired", sess.RemoteAddr())
|
||||
case item := <-ch:
|
||||
sessionList = append(sessionList, timedSession{
|
||||
item.session,
|
||||
item.expiryDate.Add(time.Duration(config.ScavengeTTL) * time.Second)})
|
||||
case <-ticker.C:
|
||||
var newList []scavengeSession
|
||||
if len(sessionList) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
var newList []timedSession
|
||||
for k := range sessionList {
|
||||
s := sessionList[k]
|
||||
if s.session.NumStreams() == 0 || s.session.IsClosed() {
|
||||
log.Println("session normally closed", s.session.RemoteAddr())
|
||||
s.session.Close()
|
||||
} else if ttl >= 0 && time.Since(s.ts) >= time.Duration(ttl)*time.Second {
|
||||
log.Println("session reached scavenge ttl", s.session.RemoteAddr())
|
||||
if s.session.IsClosed() {
|
||||
log.Println("scavenger: session normally closed:", s.session.LocalAddr())
|
||||
} else if time.Now().After(s.expiryDate) {
|
||||
s.session.Close()
|
||||
log.Println("scavenger: session closed due to ttl:", s.session.LocalAddr())
|
||||
} else {
|
||||
newList = append(newList, sessionList[k])
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
[unit]
|
||||
Description=kcptun
|
||||
|
||||
Wants=network.target
|
||||
|
||||
@@ -4,12 +4,16 @@ require (
|
||||
github.com/coreos/go-iptables v0.4.2 // indirect
|
||||
github.com/golang/snappy v0.0.1
|
||||
github.com/google/gopacket v1.1.17 // indirect
|
||||
github.com/klauspost/reedsolomon v1.10.0 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/urfave/cli v1.21.0
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17
|
||||
github.com/xtaci/smux v1.5.14
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||
github.com/xtaci/smux v1.5.16
|
||||
github.com/xtaci/tcpraw v1.2.25
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 // indirect
|
||||
)
|
||||
|
||||
go 1.14
|
||||
|
||||
@@ -1,35 +1,67 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/coreos/go-iptables v0.4.2 h1:KH0EwId05JwWIfb96gWvkiT2cbuOu8ygqUaB+yPAwIg=
|
||||
github.com/coreos/go-iptables v0.4.2/go.mod h1:/mVI274lEDI2ns62jHCDnCyBF9Iwsmekav8Dbxlm1MU=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gopacket v1.1.17 h1:rMrlX2ZY2UbvT+sdz3+6J+pp2z+msCq9MxTU6ymxbBY=
|
||||
github.com/google/gopacket v1.1.17/go.mod h1:UdDNZ1OO62aGYVnPhxT1U6aI7ukYtA/kB8vaU0diBUM=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
github.com/klauspost/reedsolomon v1.9.9 h1:qCL7LZlv17xMixl55nq2/Oa1Y86nfO8EqDfv2GHND54=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
github.com/klauspost/reedsolomon v1.9.9/go.mod h1:O7yFFHiQwDR6b2t63KPUpccPtNdp5ADgh1gg4fd12wo=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLUjSSJMU+fW+RDMstRdmnDWj9Q+AsA=
|
||||
github.com/klauspost/reedsolomon v1.10.0 h1:MonMtg979rxSHjwtsla5dZLhreS0Lu42AyQ20bhjIGg=
|
||||
github.com/klauspost/reedsolomon v1.10.0/go.mod h1:qHMIzMkuZUWqIh8mS/GruPdo3u0qwX2jk/LH440ON7Y=
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo=
|
||||
github.com/templexxx/cpu v0.0.7/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/xorsimd v0.4.1 h1:iUZcywbOYDRAZUasAs2eSCUW8eobuZDy0I9FJiORkVg=
|
||||
github.com/templexxx/xorsimd v0.4.1/go.mod h1:W+ffZz8jJMH2SXwuKu9WhygqBMbFnp14G2fqEr8qaNo=
|
||||
github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
|
||||
github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
|
||||
github.com/tjfoc/gmsm v1.4.1 h1:aMe1GlZb+0bLjn+cKTPEvvn9oUEBlJitaZiiBwsbgho=
|
||||
github.com/tjfoc/gmsm v1.4.1/go.mod h1:j4INPkHWMrhJb38G+J6W4Tw0AbuN8Thu3PbdVYhVcTE=
|
||||
github.com/urfave/cli v1.21.0 h1:wYSSj06510qPIzGSua9ZqsncMmWE3Zr55KBERygyrxE=
|
||||
github.com/urfave/cli v1.21.0/go.mod h1:lxDj6qX9Q6lWQxIrbrT0nwecwUtRnhVZAJjJZrVUZZQ=
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17 h1:bkdaqtER0PMlP05BBHfu6W+71kt/NwbAk93KH7F78Ck=
|
||||
github.com/xtaci/kcp-go/v5 v5.5.17/go.mod h1:pVx3jb4LT5edTmPayc77tIU9nRsjGck8wep5ZV/RBO0=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI=
|
||||
github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
|
||||
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
|
||||
github.com/xtaci/smux v1.5.14 h1:1j+zJYDZRv9FHaWqCJfH5RPizIm0fSzJIFbfVn8zsfg=
|
||||
github.com/xtaci/smux v1.5.14/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/xtaci/smux v1.5.16 h1:FBPYOkW8ZTjLKUM4LI4xnnuuDC8CQ/dB04HD519WoEk=
|
||||
github.com/xtaci/smux v1.5.16/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
|
||||
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=
|
||||
github.com/xtaci/tcpraw v1.2.25/go.mod h1:dKyZ2V75s0cZ7cbgJYdxPvms7af0joIeOyx1GgJQbLk=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
@@ -39,36 +71,85 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de h1:ikNHVSjEfnvz6sxdSPCaPt572qowuyMDMJLLm3Db3ig=
|
||||
golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e h1:TsQ7F31D3bUCLeqPT0u+yjp1guoArKaNKmCr22PYgTQ=
|
||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190405154228-4b34438f7a67/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9 h1:yi1hN8dcqI9l8klZfy4B8mJvFmmAxJEePIQQFNSd7Cs=
|
||||
golang.org/x/sys v0.0.0-20200808120158-1030fc2bf1d9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810 h1:rHZQSjJdAI4Xf5Qzeh2bBc5YJIkPFVM6oDtMFYmgws0=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123 h1:4JSJPND/+4555t1HfXYF4UEqDqiSKCgeV0+hbA8hMs4=
|
||||
golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
+131
@@ -0,0 +1,131 @@
|
||||
%global debug_package %{nil}
|
||||
%global _dwz_low_mem_die_limit 0
|
||||
%global __os_install_post /usr/lib/rpm/brp-compress %{nil}
|
||||
|
||||
Name: kcptun
|
||||
Version: 20210922
|
||||
Release: 1
|
||||
Summary: A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
License: MIT
|
||||
URL: https://github.com/xtaci/kcptun
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: golang
|
||||
BuildRequires: glibc-static
|
||||
|
||||
%description
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%package server
|
||||
Summary: kcptun-server
|
||||
Requires: systemd
|
||||
|
||||
%description server
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%package client
|
||||
Summary: kcptun-client
|
||||
Requires: systemd
|
||||
|
||||
%description client
|
||||
A Stable & Secure Tunnel based on KCP with N:M multiplexing and FEC
|
||||
|
||||
%prep
|
||||
%autosetup
|
||||
|
||||
%build
|
||||
LDFLAGS='-s -w -linkmode=external -extldflags -static -X main.VERSION=%{version}'
|
||||
go build -ldflags "$LDFLAGS" -o %{name}-server github.com/xtaci/kcptun/server
|
||||
go build -ldflags "$LDFLAGS" -o %{name}-client github.com/xtaci/kcptun/client
|
||||
|
||||
%install
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_bindir}
|
||||
%{__install} -p -m 755 kcptun-server $RPM_BUILD_ROOT%{_bindir}/kcptun-server
|
||||
%{__install} -p -m 755 kcptun-client $RPM_BUILD_ROOT%{_bindir}/kcptun-client
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_sysconfdir}/%{name}
|
||||
%{__install} -p -m 644 examples/server.json $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/server.json
|
||||
%{__install} -p -m 644 examples/local.json $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/client.json
|
||||
|
||||
%{__mkdir} -p $RPM_BUILD_ROOT%{_unitdir}
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/kcptun-server.service <<EOF
|
||||
[Unit]
|
||||
Description=kcptun-server
|
||||
Wants=network.target
|
||||
After=syslog.target network-online.target
|
||||
ConditionFileIsExecutable=/usr/bin/kcptun-server
|
||||
ConditionPathExists=/etc/kcptun/server.json
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=GOGC=20
|
||||
ExecStart=/usr/bin/kcptun-server -c /etc/kcptun/server.json
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
KillMode=process
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
cat > $RPM_BUILD_ROOT%{_unitdir}/kcptun-client.service <<EOF
|
||||
[Unit]
|
||||
Description=kcptun-client
|
||||
After=syslog.target network-online.target
|
||||
ConditionFileIsExecutable=/usr/bin/kcptun-client
|
||||
ConditionPathExists=/etc/kcptun/client.json
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
Environment=GOGC=20
|
||||
ExecStart=/usr/bin/kcptun-client -c /etc/kcptun/client.json
|
||||
Restart=on-failure
|
||||
RestartSec=10
|
||||
KillMode=process
|
||||
LimitNOFILE=65536
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
|
||||
%post server
|
||||
%systemd_post %{name}-server.service
|
||||
|
||||
%preun server
|
||||
%systemd_preun %{name}-server.service
|
||||
|
||||
%postun server
|
||||
%systemd_postun_with_restart %{name}-server.service
|
||||
|
||||
%post client
|
||||
%systemd_post %{name}-client.service
|
||||
|
||||
%preun client
|
||||
%systemd_preun %{name}-client.service
|
||||
|
||||
%postun client
|
||||
%systemd_postun_with_restart %{name}-client.service
|
||||
|
||||
%files server
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/kcptun-server
|
||||
%config(noreplace) %{_sysconfdir}/%{name}/server.json
|
||||
%{_unitdir}/kcptun-server.service
|
||||
%license LICENSE.md
|
||||
%doc README.md Dockerfile
|
||||
|
||||
%files client
|
||||
%defattr(-,root,root,-)
|
||||
%{_bindir}/kcptun-client
|
||||
%config(noreplace) %{_sysconfdir}/%{name}/client.json
|
||||
%{_unitdir}/kcptun-client.service
|
||||
%license LICENSE.md
|
||||
%doc README.md Dockerfile
|
||||
|
||||
%changelog
|
||||
* Thu Dec 30 2021 Purple Grape <purplegrape4@gmail.com>
|
||||
- First package for kcptun
|
||||
+3
-1
@@ -149,7 +149,7 @@ func main() {
|
||||
cli.StringFlag{
|
||||
Name: "crypt",
|
||||
Value: "aes",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none",
|
||||
Usage: "aes, aes-128, aes-192, salsa20, blowfish, twofish, cast5, 3des, tea, xtea, xor, sm4, none, null",
|
||||
},
|
||||
cli.StringFlag{
|
||||
Name: "mode",
|
||||
@@ -361,6 +361,8 @@ func main() {
|
||||
log.Println("key derivation done")
|
||||
var block kcp.BlockCrypt
|
||||
switch config.Crypt {
|
||||
case "null":
|
||||
block = nil
|
||||
case "sm4":
|
||||
block, _ = kcp.NewSM4BlockCrypt(pass[:16])
|
||||
case "tea":
|
||||
|
||||
-46
@@ -1,46 +0,0 @@
|
||||
language: go
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- master
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -race ./...
|
||||
- go test -tags=noasm ./...
|
||||
|
||||
stages:
|
||||
- gofmt
|
||||
- test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: 'master'
|
||||
fast_finish: true
|
||||
include:
|
||||
- stage: gofmt
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- diff <(gofmt -d .) <(printf "")
|
||||
- diff <(gofmt -d ./private) <(printf "")
|
||||
- go install github.com/klauspost/asmfmt/cmd/asmfmt
|
||||
- diff <(asmfmt -d .) <(printf "")
|
||||
- stage: i386
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- GOOS=linux GOARCH=386 go test .
|
||||
-191
@@ -1,191 +0,0 @@
|
||||
# cpuid
|
||||
Package cpuid provides information about the CPU running the current program.
|
||||
|
||||
CPU features are detected on startup, and kept for fast access through the life of the application.
|
||||
Currently x86 / x64 (AMD64/i386) and ARM (ARM64) is supported, and no external C (cgo) code is used, which should make the library very easy to use.
|
||||
|
||||
You can access the CPU information by accessing the shared CPU variable of the cpuid library.
|
||||
|
||||
Package home: https://github.com/klauspost/cpuid
|
||||
|
||||
[![GoDoc][1]][2] [![Build Status][3]][4]
|
||||
|
||||
[1]: https://godoc.org/github.com/klauspost/cpuid?status.svg
|
||||
[2]: https://godoc.org/github.com/klauspost/cpuid
|
||||
[3]: https://travis-ci.org/klauspost/cpuid.svg?branch=master
|
||||
[4]: https://travis-ci.org/klauspost/cpuid
|
||||
|
||||
# features
|
||||
|
||||
## x86 CPU Instructions
|
||||
* **CMOV** (i686 CMOV)
|
||||
* **NX** (NX (No-Execute) bit)
|
||||
* **AMD3DNOW** (AMD 3DNOW)
|
||||
* **AMD3DNOWEXT** (AMD 3DNowExt)
|
||||
* **MMX** (standard MMX)
|
||||
* **MMXEXT** (SSE integer functions or AMD MMX ext)
|
||||
* **SSE** (SSE functions)
|
||||
* **SSE2** (P4 SSE functions)
|
||||
* **SSE3** (Prescott SSE3 functions)
|
||||
* **SSSE3** (Conroe SSSE3 functions)
|
||||
* **SSE4** (Penryn SSE4.1 functions)
|
||||
* **SSE4A** (AMD Barcelona microarchitecture SSE4a instructions)
|
||||
* **SSE42** (Nehalem SSE4.2 functions)
|
||||
* **AVX** (AVX functions)
|
||||
* **AVX2** (AVX2 functions)
|
||||
* **FMA3** (Intel FMA 3)
|
||||
* **FMA4** (Bulldozer FMA4 functions)
|
||||
* **XOP** (Bulldozer XOP functions)
|
||||
* **F16C** (Half-precision floating-point conversion)
|
||||
* **BMI1** (Bit Manipulation Instruction Set 1)
|
||||
* **BMI2** (Bit Manipulation Instruction Set 2)
|
||||
* **TBM** (AMD Trailing Bit Manipulation)
|
||||
* **LZCNT** (LZCNT instruction)
|
||||
* **POPCNT** (POPCNT instruction)
|
||||
* **AESNI** (Advanced Encryption Standard New Instructions)
|
||||
* **CLMUL** (Carry-less Multiplication)
|
||||
* **HTT** (Hyperthreading (enabled))
|
||||
* **HLE** (Hardware Lock Elision)
|
||||
* **RTM** (Restricted Transactional Memory)
|
||||
* **RDRAND** (RDRAND instruction is available)
|
||||
* **RDSEED** (RDSEED instruction is available)
|
||||
* **ADX** (Intel ADX (Multi-Precision Add-Carry Instruction Extensions))
|
||||
* **SHA** (Intel SHA Extensions)
|
||||
* **AVX512F** (AVX-512 Foundation)
|
||||
* **AVX512DQ** (AVX-512 Doubleword and Quadword Instructions)
|
||||
* **AVX512IFMA** (AVX-512 Integer Fused Multiply-Add Instructions)
|
||||
* **AVX512PF** (AVX-512 Prefetch Instructions)
|
||||
* **AVX512ER** (AVX-512 Exponential and Reciprocal Instructions)
|
||||
* **AVX512CD** (AVX-512 Conflict Detection Instructions)
|
||||
* **AVX512BW** (AVX-512 Byte and Word Instructions)
|
||||
* **AVX512VL** (AVX-512 Vector Length Extensions)
|
||||
* **AVX512VBMI** (AVX-512 Vector Bit Manipulation Instructions)
|
||||
* **AVX512VBMI2** (AVX-512 Vector Bit Manipulation Instructions, Version 2)
|
||||
* **AVX512VNNI** (AVX-512 Vector Neural Network Instructions)
|
||||
* **AVX512VPOPCNTDQ** (AVX-512 Vector Population Count Doubleword and Quadword)
|
||||
* **GFNI** (Galois Field New Instructions)
|
||||
* **VAES** (Vector AES)
|
||||
* **AVX512BITALG** (AVX-512 Bit Algorithms)
|
||||
* **VPCLMULQDQ** (Carry-Less Multiplication Quadword)
|
||||
* **AVX512BF16** (AVX-512 BFLOAT16 Instructions)
|
||||
* **AVX512VP2INTERSECT** (AVX-512 Intersect for D/Q)
|
||||
* **MPX** (Intel MPX (Memory Protection Extensions))
|
||||
* **ERMS** (Enhanced REP MOVSB/STOSB)
|
||||
* **RDTSCP** (RDTSCP Instruction)
|
||||
* **CX16** (CMPXCHG16B Instruction)
|
||||
* **SGX** (Software Guard Extensions, with activation details)
|
||||
* **VMX** (Virtual Machine Extensions)
|
||||
|
||||
## Performance
|
||||
* **RDTSCP()** Returns current cycle count. Can be used for benchmarking.
|
||||
* **SSE2SLOW** (SSE2 is supported, but usually not faster)
|
||||
* **SSE3SLOW** (SSE3 is supported, but usually not faster)
|
||||
* **ATOM** (Atom processor, some SSSE3 instructions are slower)
|
||||
* **Cache line** (Probable size of a cache line).
|
||||
* **L1, L2, L3 Cache size** on newer Intel/AMD CPUs.
|
||||
|
||||
## ARM CPU features
|
||||
|
||||
# ARM FEATURE DETECTION DISABLED!
|
||||
|
||||
See [#52](https://github.com/klauspost/cpuid/issues/52).
|
||||
|
||||
Currently only `arm64` platforms are implemented.
|
||||
|
||||
* **FP** Single-precision and double-precision floating point
|
||||
* **ASIMD** Advanced SIMD
|
||||
* **EVTSTRM** Generic timer
|
||||
* **AES** AES instructions
|
||||
* **PMULL** Polynomial Multiply instructions (PMULL/PMULL2)
|
||||
* **SHA1** SHA-1 instructions (SHA1C, etc)
|
||||
* **SHA2** SHA-2 instructions (SHA256H, etc)
|
||||
* **CRC32** CRC32/CRC32C instructions
|
||||
* **ATOMICS** Large System Extensions (LSE)
|
||||
* **FPHP** Half-precision floating point
|
||||
* **ASIMDHP** Advanced SIMD half-precision floating point
|
||||
* **ARMCPUID** Some CPU ID registers readable at user-level
|
||||
* **ASIMDRDM** Rounding Double Multiply Accumulate/Subtract (SQRDMLAH/SQRDMLSH)
|
||||
* **JSCVT** Javascript-style double->int convert (FJCVTZS)
|
||||
* **FCMA** Floating point complex number addition and multiplication
|
||||
* **LRCPC** Weaker release consistency (LDAPR, etc)
|
||||
* **DCPOP** Data cache clean to Point of Persistence (DC CVAP)
|
||||
* **SHA3** SHA-3 instructions (EOR3, RAXI, XAR, BCAX)
|
||||
* **SM3** SM3 instructions
|
||||
* **SM4** SM4 instructions
|
||||
* **ASIMDDP** SIMD Dot Product
|
||||
* **SHA512** SHA512 instructions
|
||||
* **SVE** Scalable Vector Extension
|
||||
* **GPA** Generic Pointer Authentication
|
||||
|
||||
## Cpu Vendor/VM
|
||||
* **Intel**
|
||||
* **AMD**
|
||||
* **VIA**
|
||||
* **Transmeta**
|
||||
* **NSC**
|
||||
* **KVM** (Kernel-based Virtual Machine)
|
||||
* **MSVM** (Microsoft Hyper-V or Windows Virtual PC)
|
||||
* **VMware**
|
||||
* **XenHVM**
|
||||
* **Bhyve**
|
||||
* **Hygon**
|
||||
|
||||
# installing
|
||||
|
||||
```go get github.com/klauspost/cpuid```
|
||||
|
||||
# example
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/klauspost/cpuid"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print basic CPU information:
|
||||
fmt.Println("Name:", cpuid.CPU.BrandName)
|
||||
fmt.Println("PhysicalCores:", cpuid.CPU.PhysicalCores)
|
||||
fmt.Println("ThreadsPerCore:", cpuid.CPU.ThreadsPerCore)
|
||||
fmt.Println("LogicalCores:", cpuid.CPU.LogicalCores)
|
||||
fmt.Println("Family", cpuid.CPU.Family, "Model:", cpuid.CPU.Model)
|
||||
fmt.Println("Features:", cpuid.CPU.Features)
|
||||
fmt.Println("Cacheline bytes:", cpuid.CPU.CacheLine)
|
||||
fmt.Println("L1 Data Cache:", cpuid.CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L1 Instruction Cache:", cpuid.CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L2 Cache:", cpuid.CPU.Cache.L2, "bytes")
|
||||
fmt.Println("L3 Cache:", cpuid.CPU.Cache.L3, "bytes")
|
||||
|
||||
// Test if we have a specific feature:
|
||||
if cpuid.CPU.SSE() {
|
||||
fmt.Println("We have Streaming SIMD Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
>go run main.go
|
||||
Name: Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz
|
||||
PhysicalCores: 2
|
||||
ThreadsPerCore: 2
|
||||
LogicalCores: 4
|
||||
Family 6 Model: 42
|
||||
Features: CMOV,MMX,MMXEXT,SSE,SSE2,SSE3,SSSE3,SSE4.1,SSE4.2,AVX,AESNI,CLMUL
|
||||
Cacheline bytes: 64
|
||||
We have Streaming SIMD Extensions
|
||||
```
|
||||
|
||||
# private package
|
||||
|
||||
In the "private" folder you can find an autogenerated version of the library you can include in your own packages.
|
||||
|
||||
For this purpose all exports are removed, and functions and constants are lowercased.
|
||||
|
||||
This is not a recommended way of using the library, but provided for convenience, if it is difficult for you to use external packages.
|
||||
|
||||
# license
|
||||
|
||||
This code is published under an MIT license. See LICENSE file for more information.
|
||||
-1504
File diff suppressed because it is too large
Load Diff
Generated
+74
@@ -0,0 +1,74 @@
|
||||
# This is an example goreleaser.yaml file with some sane defaults.
|
||||
# Make sure to check the documentation at http://goreleaser.com
|
||||
|
||||
builds:
|
||||
-
|
||||
id: "cpuid"
|
||||
binary: cpuid
|
||||
main: ./cmd/cpuid/main.go
|
||||
env:
|
||||
- CGO_ENABLED=0
|
||||
flags:
|
||||
- -ldflags=-s -w
|
||||
goos:
|
||||
- aix
|
||||
- linux
|
||||
- freebsd
|
||||
- netbsd
|
||||
- windows
|
||||
- darwin
|
||||
goarch:
|
||||
- 386
|
||||
- amd64
|
||||
- arm64
|
||||
goarm:
|
||||
- 7
|
||||
|
||||
archives:
|
||||
-
|
||||
id: cpuid
|
||||
name_template: "cpuid-{{ .Os }}_{{ .Arch }}_{{ .Version }}"
|
||||
replacements:
|
||||
aix: AIX
|
||||
darwin: OSX
|
||||
linux: Linux
|
||||
windows: Windows
|
||||
386: i386
|
||||
amd64: x86_64
|
||||
freebsd: FreeBSD
|
||||
netbsd: NetBSD
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
format: zip
|
||||
files:
|
||||
- LICENSE
|
||||
checksum:
|
||||
name_template: 'checksums.txt'
|
||||
snapshot:
|
||||
name_template: "{{ .Tag }}-next"
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- '^doc:'
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
- '^tests:'
|
||||
- '^Update\sREADME.md'
|
||||
|
||||
nfpms:
|
||||
-
|
||||
file_name_template: "cpuid_package_{{ .Version }}_{{ .Os }}_{{ .Arch }}"
|
||||
vendor: Klaus Post
|
||||
homepage: https://github.com/klauspost/cpuid
|
||||
maintainer: Klaus Post <klauspost@gmail.com>
|
||||
description: CPUID Tool
|
||||
license: BSD 3-Clause
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
replacements:
|
||||
darwin: Darwin
|
||||
linux: Linux
|
||||
freebsd: FreeBSD
|
||||
amd64: x86_64
|
||||
Generated
Vendored
Generated
Vendored
+258
@@ -0,0 +1,258 @@
|
||||
# cpuid
|
||||
Package cpuid provides information about the CPU running the current program.
|
||||
|
||||
CPU features are detected on startup, and kept for fast access through the life of the application.
|
||||
Currently x86 / x64 (AMD64/i386) and ARM (ARM64) is supported, and no external C (cgo) code is used, which should make the library very easy to use.
|
||||
|
||||
You can access the CPU information by accessing the shared CPU variable of the cpuid library.
|
||||
|
||||
Package home: https://github.com/klauspost/cpuid
|
||||
|
||||
[](https://pkg.go.dev/github.com/klauspost/cpuid/v2)
|
||||
[![Build Status][3]][4]
|
||||
|
||||
[3]: https://travis-ci.org/klauspost/cpuid.svg?branch=master
|
||||
[4]: https://travis-ci.org/klauspost/cpuid
|
||||
|
||||
## installing
|
||||
|
||||
`go get -u github.com/klauspost/cpuid/v2` using modules.
|
||||
|
||||
Drop `v2` for others.
|
||||
|
||||
## example
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
. "github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Print basic CPU information:
|
||||
fmt.Println("Name:", CPU.BrandName)
|
||||
fmt.Println("PhysicalCores:", CPU.PhysicalCores)
|
||||
fmt.Println("ThreadsPerCore:", CPU.ThreadsPerCore)
|
||||
fmt.Println("LogicalCores:", CPU.LogicalCores)
|
||||
fmt.Println("Family", CPU.Family, "Model:", CPU.Model, "Vendor ID:", CPU.VendorID)
|
||||
fmt.Println("Features:", strings.Join(CPU.FeatureSet(), ","))
|
||||
fmt.Println("Cacheline bytes:", CPU.CacheLine)
|
||||
fmt.Println("L1 Data Cache:", CPU.Cache.L1D, "bytes")
|
||||
fmt.Println("L1 Instruction Cache:", CPU.Cache.L1I, "bytes")
|
||||
fmt.Println("L2 Cache:", CPU.Cache.L2, "bytes")
|
||||
fmt.Println("L3 Cache:", CPU.Cache.L3, "bytes")
|
||||
fmt.Println("Frequency", CPU.Hz, "hz")
|
||||
|
||||
// Test if we have these specific features:
|
||||
if CPU.Supports(SSE, SSE2) {
|
||||
fmt.Println("We have Streaming SIMD 2 Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Sample output:
|
||||
```
|
||||
>go run main.go
|
||||
Name: AMD Ryzen 9 3950X 16-Core Processor
|
||||
PhysicalCores: 16
|
||||
ThreadsPerCore: 2
|
||||
LogicalCores: 32
|
||||
Family 23 Model: 113 Vendor ID: AMD
|
||||
Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CMOV,CX16,F16C,FMA3,HTT,HYPERVISOR,LZCNT,MMX,MMXEXT,NX,POPCNT,RDRAND,RDSEED,RDTSCP,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3
|
||||
Cacheline bytes: 64
|
||||
L1 Data Cache: 32768 bytes
|
||||
L1 Instruction Cache: 32768 bytes
|
||||
L2 Cache: 524288 bytes
|
||||
L3 Cache: 16777216 bytes
|
||||
Frequency 0 hz
|
||||
We have Streaming SIMD 2 Extensions
|
||||
```
|
||||
|
||||
# usage
|
||||
|
||||
The `cpuid.CPU` provides access to CPU features. Use `cpuid.CPU.Supports()` to check for CPU features.
|
||||
A faster `cpuid.CPU.Has()` is provided which will usually be inlined by the gc compiler.
|
||||
|
||||
Note that for some cpu/os combinations some features will not be detected.
|
||||
`amd64` has rather good support and should work reliably on all platforms.
|
||||
|
||||
Note that hypervisors may not pass through all CPU features.
|
||||
|
||||
## arm64 feature detection
|
||||
|
||||
Not all operating systems provide ARM features directly
|
||||
and there is no safe way to do so for the rest.
|
||||
|
||||
Currently `arm64/linux` and `arm64/freebsd` should be quite reliable.
|
||||
`arm64/darwin` adds features expected from the M1 processor, but a lot remains undetected.
|
||||
|
||||
A `DetectARM()` can be used if you are able to control your deployment,
|
||||
it will detect CPU features, but may crash if the OS doesn't intercept the calls.
|
||||
A `-cpu.arm` flag for detecting unsafe ARM features can be added. See below.
|
||||
|
||||
Note that currently only features are detected on ARM,
|
||||
no additional information is currently available.
|
||||
|
||||
## flags
|
||||
|
||||
It is possible to add flags that affects cpu detection.
|
||||
|
||||
For this the `Flags()` command is provided.
|
||||
|
||||
This must be called *before* `flag.Parse()` AND after the flags have been parsed `Detect()` must be called.
|
||||
|
||||
This means that any detection used in `init()` functions will not contain these flags.
|
||||
|
||||
Example:
|
||||
|
||||
```Go
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cpuid.Flags()
|
||||
flag.Parse()
|
||||
cpuid.Detect()
|
||||
|
||||
// Test if we have these specific features:
|
||||
if cpuid.CPU.Supports(cpuid.SSE, cpuid.SSE2) {
|
||||
fmt.Println("We have Streaming SIMD 2 Extensions")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## commandline
|
||||
|
||||
Download as binary from: https://github.com/klauspost/cpuid/releases
|
||||
|
||||
Install from source:
|
||||
|
||||
`go install github.com/klauspost/cpuid/v2/cmd/cpuid@latest`
|
||||
|
||||
### Example
|
||||
|
||||
```
|
||||
λ cpuid
|
||||
Name: AMD Ryzen 9 3950X 16-Core Processor
|
||||
Vendor String: AuthenticAMD
|
||||
Vendor ID: AMD
|
||||
PhysicalCores: 16
|
||||
Threads Per Core: 2
|
||||
Logical Cores: 32
|
||||
CPU Family 23 Model: 113
|
||||
Features: ADX,AESNI,AVX,AVX2,BMI1,BMI2,CLMUL,CLZERO,CMOV,CMPXCHG8,CPBOOST,CX16,F16C,FMA3,FXSR,FXSROPT,HTT,HYPERVISOR,LAHF,LZCNT,MCAOVERFLOW,MMX,MMXEXT,MOVBE,NX,OSXSAVE,POPCNT,RDRAND,RDSEED,RDTSCP,SCE,SHA,SSE,SSE2,SSE3,SSE4,SSE42,SSE4A,SSSE3,SUCCOR,X87,XSAVE
|
||||
Microarchitecture level: 3
|
||||
Cacheline bytes: 64
|
||||
L1 Instruction Cache: 32768 bytes
|
||||
L1 Data Cache: 32768 bytes
|
||||
L2 Cache: 524288 bytes
|
||||
L3 Cache: 16777216 bytes
|
||||
|
||||
```
|
||||
### JSON Output:
|
||||
|
||||
```
|
||||
λ cpuid --json
|
||||
{
|
||||
"BrandName": "AMD Ryzen 9 3950X 16-Core Processor",
|
||||
"VendorID": 2,
|
||||
"VendorString": "AuthenticAMD",
|
||||
"PhysicalCores": 16,
|
||||
"ThreadsPerCore": 2,
|
||||
"LogicalCores": 32,
|
||||
"Family": 23,
|
||||
"Model": 113,
|
||||
"CacheLine": 64,
|
||||
"Hz": 0,
|
||||
"BoostFreq": 0,
|
||||
"Cache": {
|
||||
"L1I": 32768,
|
||||
"L1D": 32768,
|
||||
"L2": 524288,
|
||||
"L3": 16777216
|
||||
},
|
||||
"SGX": {
|
||||
"Available": false,
|
||||
"LaunchControl": false,
|
||||
"SGX1Supported": false,
|
||||
"SGX2Supported": false,
|
||||
"MaxEnclaveSizeNot64": 0,
|
||||
"MaxEnclaveSize64": 0,
|
||||
"EPCSections": null
|
||||
},
|
||||
"Features": [
|
||||
"ADX",
|
||||
"AESNI",
|
||||
"AVX",
|
||||
"AVX2",
|
||||
"BMI1",
|
||||
"BMI2",
|
||||
"CLMUL",
|
||||
"CLZERO",
|
||||
"CMOV",
|
||||
"CMPXCHG8",
|
||||
"CPBOOST",
|
||||
"CX16",
|
||||
"F16C",
|
||||
"FMA3",
|
||||
"FXSR",
|
||||
"FXSROPT",
|
||||
"HTT",
|
||||
"HYPERVISOR",
|
||||
"LAHF",
|
||||
"LZCNT",
|
||||
"MCAOVERFLOW",
|
||||
"MMX",
|
||||
"MMXEXT",
|
||||
"MOVBE",
|
||||
"NX",
|
||||
"OSXSAVE",
|
||||
"POPCNT",
|
||||
"RDRAND",
|
||||
"RDSEED",
|
||||
"RDTSCP",
|
||||
"SCE",
|
||||
"SHA",
|
||||
"SSE",
|
||||
"SSE2",
|
||||
"SSE3",
|
||||
"SSE4",
|
||||
"SSE42",
|
||||
"SSE4A",
|
||||
"SSSE3",
|
||||
"SUCCOR",
|
||||
"X87",
|
||||
"XSAVE"
|
||||
],
|
||||
"X64Level": 3
|
||||
}
|
||||
```
|
||||
|
||||
### Check CPU microarch level
|
||||
|
||||
```
|
||||
λ cpuid --check-level=3
|
||||
2022/03/18 17:04:40 AMD Ryzen 9 3950X 16-Core Processor
|
||||
2022/03/18 17:04:40 Microarchitecture level 3 is supported. Max level is 3.
|
||||
Exit Code 0
|
||||
|
||||
λ cpuid --check-level=4
|
||||
2022/03/18 17:06:18 AMD Ryzen 9 3950X 16-Core Processor
|
||||
2022/03/18 17:06:18 Microarchitecture level 4 not supported. Max level is 3.
|
||||
Exit Code 1
|
||||
```
|
||||
|
||||
# license
|
||||
|
||||
This code is published under an MIT license. See LICENSE file for more information.
|
||||
+1218
File diff suppressed because it is too large
Load Diff
Generated
Vendored
+5
@@ -40,3 +40,8 @@ TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// func asmDarwinHasAVX512() bool
|
||||
TEXT ·asmDarwinHasAVX512(SB), 7, $0
|
||||
MOVL $0, eax+0(FP)
|
||||
RET
|
||||
vendor/github.com/klauspost/cpuid/cpuid_amd64.s → vendor/github.com/klauspost/cpuid/v2/cpuid_amd64.s
Generated
Vendored
+30
@@ -40,3 +40,33 @@ TEXT ·asmRdtscpAsm(SB), 7, $0
|
||||
MOVL CX, ecx+8(FP)
|
||||
MOVL DX, edx+12(FP)
|
||||
RET
|
||||
|
||||
// From https://go-review.googlesource.com/c/sys/+/285572/
|
||||
// func asmDarwinHasAVX512() bool
|
||||
TEXT ·asmDarwinHasAVX512(SB), 7, $0-1
|
||||
MOVB $0, ret+0(FP) // default to false
|
||||
|
||||
#ifdef GOOS_darwin // return if not darwin
|
||||
#ifdef GOARCH_amd64 // return if not amd64
|
||||
// These values from:
|
||||
// https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h
|
||||
#define commpage64_base_address 0x00007fffffe00000
|
||||
#define commpage64_cpu_capabilities64 (commpage64_base_address+0x010)
|
||||
#define commpage64_version (commpage64_base_address+0x01E)
|
||||
#define hasAVX512F 0x0000004000000000
|
||||
MOVQ $commpage64_version, BX
|
||||
MOVW (BX), AX
|
||||
CMPW AX, $13 // versions < 13 do not support AVX512
|
||||
JL no_avx512
|
||||
MOVQ $commpage64_cpu_capabilities64, BX
|
||||
MOVQ (BX), AX
|
||||
MOVQ $hasAVX512F, CX
|
||||
ANDQ CX, AX
|
||||
JZ no_avx512
|
||||
MOVB $1, ret+0(FP)
|
||||
|
||||
no_avx512:
|
||||
#endif
|
||||
#endif
|
||||
RET
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build arm64,!gccgo,!noasm,!appengine
|
||||
|
||||
// See https://www.kernel.org/doc/Documentation/arm64/cpu-feature-registers.txt
|
||||
|
||||
// func getMidr
|
||||
TEXT ·getMidr(SB), 7, $0
|
||||
WORD $0xd5380000 // mrs x0, midr_el1 /* Main ID Register */
|
||||
MOVD R0, midr+0(FP)
|
||||
RET
|
||||
|
||||
// func getProcFeatures
|
||||
TEXT ·getProcFeatures(SB), 7, $0
|
||||
WORD $0xd5380400 // mrs x0, id_aa64pfr0_el1 /* Processor Feature Register 0 */
|
||||
MOVD R0, procFeatures+0(FP)
|
||||
RET
|
||||
|
||||
// func getInstAttributes
|
||||
TEXT ·getInstAttributes(SB), 7, $0
|
||||
WORD $0xd5380600 // mrs x0, id_aa64isar0_el1 /* Instruction Set Attribute Register 0 */
|
||||
WORD $0xd5380621 // mrs x1, id_aa64isar1_el1 /* Instruction Set Attribute Register 1 */
|
||||
MOVD R0, instAttrReg0+0(FP)
|
||||
MOVD R1, instAttrReg1+8(FP)
|
||||
RET
|
||||
|
||||
+247
@@ -0,0 +1,247 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build arm64 && !gccgo && !noasm && !appengine
|
||||
// +build arm64,!gccgo,!noasm,!appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
import "runtime"
|
||||
|
||||
func getMidr() (midr uint64)
|
||||
func getProcFeatures() (procFeatures uint64)
|
||||
func getInstAttributes() (instAttrReg0, instAttrReg1 uint64)
|
||||
|
||||
func initCPU() {
|
||||
cpuid = func(uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
cpuidex = func(x, y uint32) (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
xgetbv = func(uint32) (a, b uint32) { return 0, 0 }
|
||||
rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
}
|
||||
|
||||
func addInfo(c *CPUInfo, safe bool) {
|
||||
// Seems to be safe to assume on ARM64
|
||||
c.CacheLine = 64
|
||||
detectOS(c)
|
||||
|
||||
// ARM64 disabled since it may crash if interrupt is not intercepted by OS.
|
||||
if safe && !c.Supports(ARMCPUID) && runtime.GOOS != "freebsd" {
|
||||
return
|
||||
}
|
||||
midr := getMidr()
|
||||
|
||||
// MIDR_EL1 - Main ID Register
|
||||
// https://developer.arm.com/docs/ddi0595/h/aarch64-system-registers/midr_el1
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | Implementer | [31-24] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Variant | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Architecture | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | PartNum | [15-4] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | Revision | [3-0] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
switch (midr >> 24) & 0xff {
|
||||
case 0xC0:
|
||||
c.VendorString = "Ampere Computing"
|
||||
c.VendorID = Ampere
|
||||
case 0x41:
|
||||
c.VendorString = "Arm Limited"
|
||||
c.VendorID = ARM
|
||||
case 0x42:
|
||||
c.VendorString = "Broadcom Corporation"
|
||||
c.VendorID = Broadcom
|
||||
case 0x43:
|
||||
c.VendorString = "Cavium Inc"
|
||||
c.VendorID = Cavium
|
||||
case 0x44:
|
||||
c.VendorString = "Digital Equipment Corporation"
|
||||
c.VendorID = DEC
|
||||
case 0x46:
|
||||
c.VendorString = "Fujitsu Ltd"
|
||||
c.VendorID = Fujitsu
|
||||
case 0x49:
|
||||
c.VendorString = "Infineon Technologies AG"
|
||||
c.VendorID = Infineon
|
||||
case 0x4D:
|
||||
c.VendorString = "Motorola or Freescale Semiconductor Inc"
|
||||
c.VendorID = Motorola
|
||||
case 0x4E:
|
||||
c.VendorString = "NVIDIA Corporation"
|
||||
c.VendorID = NVIDIA
|
||||
case 0x50:
|
||||
c.VendorString = "Applied Micro Circuits Corporation"
|
||||
c.VendorID = AMCC
|
||||
case 0x51:
|
||||
c.VendorString = "Qualcomm Inc"
|
||||
c.VendorID = Qualcomm
|
||||
case 0x56:
|
||||
c.VendorString = "Marvell International Ltd"
|
||||
c.VendorID = Marvell
|
||||
case 0x69:
|
||||
c.VendorString = "Intel Corporation"
|
||||
c.VendorID = Intel
|
||||
}
|
||||
|
||||
// Lower 4 bits: Architecture
|
||||
// Architecture Meaning
|
||||
// 0b0001 Armv4.
|
||||
// 0b0010 Armv4T.
|
||||
// 0b0011 Armv5 (obsolete).
|
||||
// 0b0100 Armv5T.
|
||||
// 0b0101 Armv5TE.
|
||||
// 0b0110 Armv5TEJ.
|
||||
// 0b0111 Armv6.
|
||||
// 0b1111 Architectural features are individually identified in the ID_* registers, see 'ID registers'.
|
||||
// Upper 4 bit: Variant
|
||||
// An IMPLEMENTATION DEFINED variant number.
|
||||
// Typically, this field is used to distinguish between different product variants, or major revisions of a product.
|
||||
c.Family = int(midr>>16) & 0xff
|
||||
|
||||
// PartNum, bits [15:4]
|
||||
// An IMPLEMENTATION DEFINED primary part number for the device.
|
||||
// On processors implemented by Arm, if the top four bits of the primary
|
||||
// part number are 0x0 or 0x7, the variant and architecture are encoded differently.
|
||||
// Revision, bits [3:0]
|
||||
// An IMPLEMENTATION DEFINED revision number for the device.
|
||||
c.Model = int(midr) & 0xffff
|
||||
|
||||
procFeatures := getProcFeatures()
|
||||
|
||||
// ID_AA64PFR0_EL1 - Processor Feature Register 0
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | DIT | [51-48] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SVE | [35-32] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | GIC | [27-24] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | AdvSIMD | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FP | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | EL3 | [15-12] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL2 | [11-8] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL1 | [7-4] | n |
|
||||
// |--------------------------------------------------|
|
||||
// | EL0 | [3-0] | n |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
var f flagSet
|
||||
// if procFeatures&(0xf<<48) != 0 {
|
||||
// fmt.Println("DIT")
|
||||
// }
|
||||
f.setIf(procFeatures&(0xf<<32) != 0, SVE)
|
||||
if procFeatures&(0xf<<20) != 15<<20 {
|
||||
f.set(ASIMD)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64pfr0_el1
|
||||
// 0b0001 --> As for 0b0000, and also includes support for half-precision floating-point arithmetic.
|
||||
f.setIf(procFeatures&(0xf<<20) == 1<<20, FPHP, ASIMDHP)
|
||||
}
|
||||
f.setIf(procFeatures&(0xf<<16) != 0, FP)
|
||||
|
||||
instAttrReg0, instAttrReg1 := getInstAttributes()
|
||||
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
//
|
||||
// ID_AA64ISAR0_EL1 - Instruction Set Attribute Register 0
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | TS | [55-52] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FHM | [51-48] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | DP | [47-44] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SM4 | [43-40] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SM3 | [39-36] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA3 | [35-32] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | RDM | [31-28] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | ATOMICS | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | CRC32 | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA2 | [15-12] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | SHA1 | [11-8] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | AES | [7-4] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
// if instAttrReg0&(0xf<<52) != 0 {
|
||||
// fmt.Println("TS")
|
||||
// }
|
||||
// if instAttrReg0&(0xf<<48) != 0 {
|
||||
// fmt.Println("FHM")
|
||||
// }
|
||||
f.setIf(instAttrReg0&(0xf<<44) != 0, ASIMDDP)
|
||||
f.setIf(instAttrReg0&(0xf<<40) != 0, SM4)
|
||||
f.setIf(instAttrReg0&(0xf<<36) != 0, SM3)
|
||||
f.setIf(instAttrReg0&(0xf<<32) != 0, SHA3)
|
||||
f.setIf(instAttrReg0&(0xf<<28) != 0, ASIMDRDM)
|
||||
f.setIf(instAttrReg0&(0xf<<20) != 0, ATOMICS)
|
||||
f.setIf(instAttrReg0&(0xf<<16) != 0, CRC32)
|
||||
f.setIf(instAttrReg0&(0xf<<12) != 0, SHA2)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
// 0b0010 --> As 0b0001, plus SHA512H, SHA512H2, SHA512SU0, and SHA512SU1 instructions implemented.
|
||||
f.setIf(instAttrReg0&(0xf<<12) == 2<<12, SHA512)
|
||||
f.setIf(instAttrReg0&(0xf<<8) != 0, SHA1)
|
||||
f.setIf(instAttrReg0&(0xf<<4) != 0, AESARM)
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar0_el1
|
||||
// 0b0010 --> As for 0b0001, plus PMULL/PMULL2 instructions operating on 64-bit data quantities.
|
||||
f.setIf(instAttrReg0&(0xf<<4) == 2<<4, PMULL)
|
||||
|
||||
// https://developer.arm.com/docs/ddi0595/b/aarch64-system-registers/id_aa64isar1_el1
|
||||
//
|
||||
// ID_AA64ISAR1_EL1 - Instruction set attribute register 1
|
||||
// x--------------------------------------------------x
|
||||
// | Name | bits | visible |
|
||||
// |--------------------------------------------------|
|
||||
// | GPI | [31-28] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | GPA | [27-24] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | LRCPC | [23-20] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | FCMA | [19-16] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | JSCVT | [15-12] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | API | [11-8] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | APA | [7-4] | y |
|
||||
// |--------------------------------------------------|
|
||||
// | DPB | [3-0] | y |
|
||||
// x--------------------------------------------------x
|
||||
|
||||
// if instAttrReg1&(0xf<<28) != 0 {
|
||||
// fmt.Println("GPI")
|
||||
// }
|
||||
f.setIf(instAttrReg1&(0xf<<28) != 24, GPA)
|
||||
f.setIf(instAttrReg1&(0xf<<20) != 0, LRCPC)
|
||||
f.setIf(instAttrReg1&(0xf<<16) != 0, FCMA)
|
||||
f.setIf(instAttrReg1&(0xf<<12) != 0, JSCVT)
|
||||
// if instAttrReg1&(0xf<<8) != 0 {
|
||||
// fmt.Println("API")
|
||||
// }
|
||||
// if instAttrReg1&(0xf<<4) != 0 {
|
||||
// fmt.Println("APA")
|
||||
// }
|
||||
f.setIf(instAttrReg1&(0xf<<0) != 0, DCPOP)
|
||||
|
||||
// Store
|
||||
c.featureSet.or(f)
|
||||
}
|
||||
vendor/github.com/klauspost/cpuid/detect_ref.go → vendor/github.com/klauspost/cpuid/v2/detect_ref.go
Generated
Vendored
+3
-2
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build !amd64,!386,!arm64 gccgo noasm appengine
|
||||
//go:build (!amd64 && !386 && !arm64) || gccgo || noasm || appengine
|
||||
// +build !amd64,!386,!arm64 gccgo noasm appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
@@ -11,4 +12,4 @@ func initCPU() {
|
||||
rdtscpAsm = func() (a, b, c, d uint32) { return 0, 0, 0, 0 }
|
||||
}
|
||||
|
||||
func addInfo(info *CPUInfo) {}
|
||||
func addInfo(info *CPUInfo, safe bool) {}
|
||||
Generated
Vendored
+8
-5
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//+build 386,!gccgo,!noasm amd64,!gccgo,!noasm,!appengine
|
||||
//go:build (386 && !gccgo && !noasm && !appengine) || (amd64 && !gccgo && !noasm && !appengine)
|
||||
// +build 386,!gccgo,!noasm,!appengine amd64,!gccgo,!noasm,!appengine
|
||||
|
||||
package cpuid
|
||||
|
||||
@@ -8,26 +9,28 @@ func asmCpuid(op uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmCpuidex(op, op2 uint32) (eax, ebx, ecx, edx uint32)
|
||||
func asmXgetbv(index uint32) (eax, edx uint32)
|
||||
func asmRdtscpAsm() (eax, ebx, ecx, edx uint32)
|
||||
func asmDarwinHasAVX512() bool
|
||||
|
||||
func initCPU() {
|
||||
cpuid = asmCpuid
|
||||
cpuidex = asmCpuidex
|
||||
xgetbv = asmXgetbv
|
||||
rdtscpAsm = asmRdtscpAsm
|
||||
darwinHasAVX512 = asmDarwinHasAVX512
|
||||
}
|
||||
|
||||
func addInfo(c *CPUInfo) {
|
||||
func addInfo(c *CPUInfo, safe bool) {
|
||||
c.maxFunc = maxFunctionID()
|
||||
c.maxExFunc = maxExtendedFunction()
|
||||
c.BrandName = brandName()
|
||||
c.CacheLine = cacheLine()
|
||||
c.Family, c.Model = familyModel()
|
||||
c.Features = support()
|
||||
c.SGX = hasSGX(c.Features&SGX != 0, c.Features&SGXLC != 0)
|
||||
c.featureSet = support()
|
||||
c.SGX = hasSGX(c.featureSet.inSet(SGX), c.featureSet.inSet(SGXLC))
|
||||
c.ThreadsPerCore = threadsPerCore()
|
||||
c.LogicalCores = logicalCores()
|
||||
c.PhysicalCores = physicalCores()
|
||||
c.VendorID, c.VendorString = vendorID()
|
||||
c.Hz = hertz(c.BrandName)
|
||||
c.cacheSize()
|
||||
c.frequencies()
|
||||
}
|
||||
+216
@@ -0,0 +1,216 @@
|
||||
// Code generated by "stringer -type=FeatureID,Vendor"; DO NOT EDIT.
|
||||
|
||||
package cpuid
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[ADX-1]
|
||||
_ = x[AESNI-2]
|
||||
_ = x[AMD3DNOW-3]
|
||||
_ = x[AMD3DNOWEXT-4]
|
||||
_ = x[AMXBF16-5]
|
||||
_ = x[AMXINT8-6]
|
||||
_ = x[AMXTILE-7]
|
||||
_ = x[AVX-8]
|
||||
_ = x[AVX2-9]
|
||||
_ = x[AVX512BF16-10]
|
||||
_ = x[AVX512BITALG-11]
|
||||
_ = x[AVX512BW-12]
|
||||
_ = x[AVX512CD-13]
|
||||
_ = x[AVX512DQ-14]
|
||||
_ = x[AVX512ER-15]
|
||||
_ = x[AVX512F-16]
|
||||
_ = x[AVX512FP16-17]
|
||||
_ = x[AVX512IFMA-18]
|
||||
_ = x[AVX512PF-19]
|
||||
_ = x[AVX512VBMI-20]
|
||||
_ = x[AVX512VBMI2-21]
|
||||
_ = x[AVX512VL-22]
|
||||
_ = x[AVX512VNNI-23]
|
||||
_ = x[AVX512VP2INTERSECT-24]
|
||||
_ = x[AVX512VPOPCNTDQ-25]
|
||||
_ = x[AVXSLOW-26]
|
||||
_ = x[BMI1-27]
|
||||
_ = x[BMI2-28]
|
||||
_ = x[CETIBT-29]
|
||||
_ = x[CETSS-30]
|
||||
_ = x[CLDEMOTE-31]
|
||||
_ = x[CLMUL-32]
|
||||
_ = x[CLZERO-33]
|
||||
_ = x[CMOV-34]
|
||||
_ = x[CMPXCHG8-35]
|
||||
_ = x[CPBOOST-36]
|
||||
_ = x[CX16-37]
|
||||
_ = x[ENQCMD-38]
|
||||
_ = x[ERMS-39]
|
||||
_ = x[F16C-40]
|
||||
_ = x[FMA3-41]
|
||||
_ = x[FMA4-42]
|
||||
_ = x[FXSR-43]
|
||||
_ = x[FXSROPT-44]
|
||||
_ = x[GFNI-45]
|
||||
_ = x[HLE-46]
|
||||
_ = x[HTT-47]
|
||||
_ = x[HWA-48]
|
||||
_ = x[HYPERVISOR-49]
|
||||
_ = x[IBPB-50]
|
||||
_ = x[IBS-51]
|
||||
_ = x[IBSBRNTRGT-52]
|
||||
_ = x[IBSFETCHSAM-53]
|
||||
_ = x[IBSFFV-54]
|
||||
_ = x[IBSOPCNT-55]
|
||||
_ = x[IBSOPCNTEXT-56]
|
||||
_ = x[IBSOPSAM-57]
|
||||
_ = x[IBSRDWROPCNT-58]
|
||||
_ = x[IBSRIPINVALIDCHK-59]
|
||||
_ = x[IBS_PREVENTHOST-60]
|
||||
_ = x[INT_WBINVD-61]
|
||||
_ = x[INVLPGB-62]
|
||||
_ = x[LAHF-63]
|
||||
_ = x[LZCNT-64]
|
||||
_ = x[MCAOVERFLOW-65]
|
||||
_ = x[MCOMMIT-66]
|
||||
_ = x[MMX-67]
|
||||
_ = x[MMXEXT-68]
|
||||
_ = x[MOVBE-69]
|
||||
_ = x[MOVDIR64B-70]
|
||||
_ = x[MOVDIRI-71]
|
||||
_ = x[MPX-72]
|
||||
_ = x[MSR_PAGEFLUSH-73]
|
||||
_ = x[MSRIRC-74]
|
||||
_ = x[NX-75]
|
||||
_ = x[OSXSAVE-76]
|
||||
_ = x[PCONFIG-77]
|
||||
_ = x[POPCNT-78]
|
||||
_ = x[RDPRU-79]
|
||||
_ = x[RDRAND-80]
|
||||
_ = x[RDSEED-81]
|
||||
_ = x[RDTSCP-82]
|
||||
_ = x[RTM-83]
|
||||
_ = x[RTM_ALWAYS_ABORT-84]
|
||||
_ = x[SCE-85]
|
||||
_ = x[SERIALIZE-86]
|
||||
_ = x[SEV-87]
|
||||
_ = x[SEV_64BIT-88]
|
||||
_ = x[SEV_ALTERNATIVE-89]
|
||||
_ = x[SEV_DEBUGSWAP-90]
|
||||
_ = x[SEV_ES-91]
|
||||
_ = x[SEV_RESTRICTED-92]
|
||||
_ = x[SEV_SNP-93]
|
||||
_ = x[SGX-94]
|
||||
_ = x[SGXLC-95]
|
||||
_ = x[SHA-96]
|
||||
_ = x[SME-97]
|
||||
_ = x[SME_COHERENT-98]
|
||||
_ = x[SSE-99]
|
||||
_ = x[SSE2-100]
|
||||
_ = x[SSE3-101]
|
||||
_ = x[SSE4-102]
|
||||
_ = x[SSE42-103]
|
||||
_ = x[SSE4A-104]
|
||||
_ = x[SSSE3-105]
|
||||
_ = x[STIBP-106]
|
||||
_ = x[SUCCOR-107]
|
||||
_ = x[TBM-108]
|
||||
_ = x[TME-109]
|
||||
_ = x[TSXLDTRK-110]
|
||||
_ = x[VAES-111]
|
||||
_ = x[VMPL-112]
|
||||
_ = x[VMSA_REGPROT-113]
|
||||
_ = x[VMX-114]
|
||||
_ = x[VPCLMULQDQ-115]
|
||||
_ = x[VTE-116]
|
||||
_ = x[WAITPKG-117]
|
||||
_ = x[WBNOINVD-118]
|
||||
_ = x[X87-119]
|
||||
_ = x[XGETBV1-120]
|
||||
_ = x[XOP-121]
|
||||
_ = x[XSAVE-122]
|
||||
_ = x[XSAVEC-123]
|
||||
_ = x[XSAVEOPT-124]
|
||||
_ = x[XSAVES-125]
|
||||
_ = x[AESARM-126]
|
||||
_ = x[ARMCPUID-127]
|
||||
_ = x[ASIMD-128]
|
||||
_ = x[ASIMDDP-129]
|
||||
_ = x[ASIMDHP-130]
|
||||
_ = x[ASIMDRDM-131]
|
||||
_ = x[ATOMICS-132]
|
||||
_ = x[CRC32-133]
|
||||
_ = x[DCPOP-134]
|
||||
_ = x[EVTSTRM-135]
|
||||
_ = x[FCMA-136]
|
||||
_ = x[FP-137]
|
||||
_ = x[FPHP-138]
|
||||
_ = x[GPA-139]
|
||||
_ = x[JSCVT-140]
|
||||
_ = x[LRCPC-141]
|
||||
_ = x[PMULL-142]
|
||||
_ = x[SHA1-143]
|
||||
_ = x[SHA2-144]
|
||||
_ = x[SHA3-145]
|
||||
_ = x[SHA512-146]
|
||||
_ = x[SM3-147]
|
||||
_ = x[SM4-148]
|
||||
_ = x[SVE-149]
|
||||
_ = x[lastID-150]
|
||||
_ = x[firstID-0]
|
||||
}
|
||||
|
||||
const _FeatureID_name = "firstIDADXAESNIAMD3DNOWAMD3DNOWEXTAMXBF16AMXINT8AMXTILEAVXAVX2AVX512BF16AVX512BITALGAVX512BWAVX512CDAVX512DQAVX512ERAVX512FAVX512FP16AVX512IFMAAVX512PFAVX512VBMIAVX512VBMI2AVX512VLAVX512VNNIAVX512VP2INTERSECTAVX512VPOPCNTDQAVXSLOWBMI1BMI2CETIBTCETSSCLDEMOTECLMULCLZEROCMOVCMPXCHG8CPBOOSTCX16ENQCMDERMSF16CFMA3FMA4FXSRFXSROPTGFNIHLEHTTHWAHYPERVISORIBPBIBSIBSBRNTRGTIBSFETCHSAMIBSFFVIBSOPCNTIBSOPCNTEXTIBSOPSAMIBSRDWROPCNTIBSRIPINVALIDCHKIBS_PREVENTHOSTINT_WBINVDINVLPGBLAHFLZCNTMCAOVERFLOWMCOMMITMMXMMXEXTMOVBEMOVDIR64BMOVDIRIMPXMSR_PAGEFLUSHMSRIRCNXOSXSAVEPCONFIGPOPCNTRDPRURDRANDRDSEEDRDTSCPRTMRTM_ALWAYS_ABORTSCESERIALIZESEVSEV_64BITSEV_ALTERNATIVESEV_DEBUGSWAPSEV_ESSEV_RESTRICTEDSEV_SNPSGXSGXLCSHASMESME_COHERENTSSESSE2SSE3SSE4SSE42SSE4ASSSE3STIBPSUCCORTBMTMETSXLDTRKVAESVMPLVMSA_REGPROTVMXVPCLMULQDQVTEWAITPKGWBNOINVDX87XGETBV1XOPXSAVEXSAVECXSAVEOPTXSAVESAESARMARMCPUIDASIMDASIMDDPASIMDHPASIMDRDMATOMICSCRC32DCPOPEVTSTRMFCMAFPFPHPGPAJSCVTLRCPCPMULLSHA1SHA2SHA3SHA512SM3SM4SVElastID"
|
||||
|
||||
var _FeatureID_index = [...]uint16{0, 7, 10, 15, 23, 34, 41, 48, 55, 58, 62, 72, 84, 92, 100, 108, 116, 123, 133, 143, 151, 161, 172, 180, 190, 208, 223, 230, 234, 238, 244, 249, 257, 262, 268, 272, 280, 287, 291, 297, 301, 305, 309, 313, 317, 324, 328, 331, 334, 337, 347, 351, 354, 364, 375, 381, 389, 400, 408, 420, 436, 451, 461, 468, 472, 477, 488, 495, 498, 504, 509, 518, 525, 528, 541, 547, 549, 556, 563, 569, 574, 580, 586, 592, 595, 611, 614, 623, 626, 635, 650, 663, 669, 683, 690, 693, 698, 701, 704, 716, 719, 723, 727, 731, 736, 741, 746, 751, 757, 760, 763, 771, 775, 779, 791, 794, 804, 807, 814, 822, 825, 832, 835, 840, 846, 854, 860, 866, 874, 879, 886, 893, 901, 908, 913, 918, 925, 929, 931, 935, 938, 943, 948, 953, 957, 961, 965, 971, 974, 977, 980, 986}
|
||||
|
||||
func (i FeatureID) String() string {
|
||||
if i < 0 || i >= FeatureID(len(_FeatureID_index)-1) {
|
||||
return "FeatureID(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _FeatureID_name[_FeatureID_index[i]:_FeatureID_index[i+1]]
|
||||
}
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[VendorUnknown-0]
|
||||
_ = x[Intel-1]
|
||||
_ = x[AMD-2]
|
||||
_ = x[VIA-3]
|
||||
_ = x[Transmeta-4]
|
||||
_ = x[NSC-5]
|
||||
_ = x[KVM-6]
|
||||
_ = x[MSVM-7]
|
||||
_ = x[VMware-8]
|
||||
_ = x[XenHVM-9]
|
||||
_ = x[Bhyve-10]
|
||||
_ = x[Hygon-11]
|
||||
_ = x[SiS-12]
|
||||
_ = x[RDC-13]
|
||||
_ = x[Ampere-14]
|
||||
_ = x[ARM-15]
|
||||
_ = x[Broadcom-16]
|
||||
_ = x[Cavium-17]
|
||||
_ = x[DEC-18]
|
||||
_ = x[Fujitsu-19]
|
||||
_ = x[Infineon-20]
|
||||
_ = x[Motorola-21]
|
||||
_ = x[NVIDIA-22]
|
||||
_ = x[AMCC-23]
|
||||
_ = x[Qualcomm-24]
|
||||
_ = x[Marvell-25]
|
||||
_ = x[lastVendor-26]
|
||||
}
|
||||
|
||||
const _Vendor_name = "VendorUnknownIntelAMDVIATransmetaNSCKVMMSVMVMwareXenHVMBhyveHygonSiSRDCAmpereARMBroadcomCaviumDECFujitsuInfineonMotorolaNVIDIAAMCCQualcommMarvelllastVendor"
|
||||
|
||||
var _Vendor_index = [...]uint8{0, 13, 18, 21, 24, 33, 36, 39, 43, 49, 55, 60, 65, 68, 71, 77, 80, 88, 94, 97, 104, 112, 120, 126, 130, 138, 145, 155}
|
||||
|
||||
func (i Vendor) String() string {
|
||||
if i < 0 || i >= Vendor(len(_Vendor_index)-1) {
|
||||
return "Vendor(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _Vendor_name[_Vendor_index[i]:_Vendor_index[i+1]]
|
||||
}
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
module github.com/klauspost/cpuid/v2
|
||||
|
||||
go 1.15
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
package cpuid
|
||||
|
||||
import "runtime"
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
// There are no hw.optional sysctl values for the below features on Mac OS 11.0
|
||||
// to detect their supported state dynamically. Assume the CPU features that
|
||||
// Apple Silicon M1 supports to be available as a minimal set of features
|
||||
// to all Go programs running on darwin/arm64.
|
||||
// TODO: Add more if we know them.
|
||||
c.featureSet.setIf(runtime.GOOS != "ios", AESARM, PMULL, SHA1, SHA2)
|
||||
c.PhysicalCores = runtime.NumCPU()
|
||||
// For now assuming 1 thread per core...
|
||||
c.ThreadsPerCore = 1
|
||||
c.LogicalCores = c.PhysicalCores
|
||||
return true
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
// Copyright 2018 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file located
|
||||
// here https://github.com/golang/sys/blob/master/LICENSE
|
||||
|
||||
package cpuid
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io/ioutil"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// HWCAP bits.
|
||||
const (
|
||||
hwcap_FP = 1 << 0
|
||||
hwcap_ASIMD = 1 << 1
|
||||
hwcap_EVTSTRM = 1 << 2
|
||||
hwcap_AES = 1 << 3
|
||||
hwcap_PMULL = 1 << 4
|
||||
hwcap_SHA1 = 1 << 5
|
||||
hwcap_SHA2 = 1 << 6
|
||||
hwcap_CRC32 = 1 << 7
|
||||
hwcap_ATOMICS = 1 << 8
|
||||
hwcap_FPHP = 1 << 9
|
||||
hwcap_ASIMDHP = 1 << 10
|
||||
hwcap_CPUID = 1 << 11
|
||||
hwcap_ASIMDRDM = 1 << 12
|
||||
hwcap_JSCVT = 1 << 13
|
||||
hwcap_FCMA = 1 << 14
|
||||
hwcap_LRCPC = 1 << 15
|
||||
hwcap_DCPOP = 1 << 16
|
||||
hwcap_SHA3 = 1 << 17
|
||||
hwcap_SM3 = 1 << 18
|
||||
hwcap_SM4 = 1 << 19
|
||||
hwcap_ASIMDDP = 1 << 20
|
||||
hwcap_SHA512 = 1 << 21
|
||||
hwcap_SVE = 1 << 22
|
||||
hwcap_ASIMDFHM = 1 << 23
|
||||
)
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
// For now assuming no hyperthreading is reasonable.
|
||||
c.LogicalCores = runtime.NumCPU()
|
||||
c.PhysicalCores = c.LogicalCores
|
||||
c.ThreadsPerCore = 1
|
||||
if hwcap == 0 {
|
||||
// We did not get values from the runtime.
|
||||
// Try reading /proc/self/auxv
|
||||
|
||||
// From https://github.com/golang/sys
|
||||
const (
|
||||
_AT_HWCAP = 16
|
||||
_AT_HWCAP2 = 26
|
||||
|
||||
uintSize = int(32 << (^uint(0) >> 63))
|
||||
)
|
||||
|
||||
buf, err := ioutil.ReadFile("/proc/self/auxv")
|
||||
if err != nil {
|
||||
// e.g. on android /proc/self/auxv is not accessible, so silently
|
||||
// ignore the error and leave Initialized = false. On some
|
||||
// architectures (e.g. arm64) doinit() implements a fallback
|
||||
// readout and will set Initialized = true again.
|
||||
return false
|
||||
}
|
||||
bo := binary.LittleEndian
|
||||
for len(buf) >= 2*(uintSize/8) {
|
||||
var tag, val uint
|
||||
switch uintSize {
|
||||
case 32:
|
||||
tag = uint(bo.Uint32(buf[0:]))
|
||||
val = uint(bo.Uint32(buf[4:]))
|
||||
buf = buf[8:]
|
||||
case 64:
|
||||
tag = uint(bo.Uint64(buf[0:]))
|
||||
val = uint(bo.Uint64(buf[8:]))
|
||||
buf = buf[16:]
|
||||
}
|
||||
switch tag {
|
||||
case _AT_HWCAP:
|
||||
hwcap = val
|
||||
case _AT_HWCAP2:
|
||||
// Not used
|
||||
}
|
||||
}
|
||||
if hwcap == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// HWCap was populated by the runtime from the auxiliary vector.
|
||||
// Use HWCap information since reading aarch64 system registers
|
||||
// is not supported in user space on older linux kernels.
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_AES), AESARM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMD), ASIMD)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDDP), ASIMDDP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDHP), ASIMDHP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ASIMDRDM), ASIMDRDM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_CPUID), ARMCPUID)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_CRC32), CRC32)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_DCPOP), DCPOP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_EVTSTRM), EVTSTRM)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FCMA), FCMA)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FP), FP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_FPHP), FPHP)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_JSCVT), JSCVT)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_LRCPC), LRCPC)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_PMULL), PMULL)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA1), SHA1)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA2), SHA2)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA3), SHA3)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SHA512), SHA512)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SM3), SM3)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SM4), SM4)
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_SVE), SVE)
|
||||
|
||||
// The Samsung S9+ kernel reports support for atomics, but not all cores
|
||||
// actually support them, resulting in SIGILL. See issue #28431.
|
||||
// TODO(elias.naur): Only disable the optimization on bad chipsets on android.
|
||||
c.featureSet.setIf(isSet(hwcap, hwcap_ATOMICS) && runtime.GOOS != "android", ATOMICS)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func isSet(hwc uint, value uint) bool {
|
||||
return hwc&value != 0
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
// Copyright (c) 2020 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build arm64 && !linux && !darwin
|
||||
// +build arm64,!linux,!darwin
|
||||
|
||||
package cpuid
|
||||
|
||||
import "runtime"
|
||||
|
||||
func detectOS(c *CPUInfo) bool {
|
||||
c.PhysicalCores = runtime.NumCPU()
|
||||
// For now assuming 1 thread per core...
|
||||
c.ThreadsPerCore = 1
|
||||
c.LogicalCores = c.PhysicalCores
|
||||
return false
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build nounsafe
|
||||
// +build nounsafe
|
||||
|
||||
package cpuid
|
||||
|
||||
var hwcap uint
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2021 Klaus Post, released under MIT License. See LICENSE file.
|
||||
|
||||
//go:build !nounsafe
|
||||
// +build !nounsafe
|
||||
|
||||
package cpuid
|
||||
|
||||
import _ "unsafe" // needed for go:linkname
|
||||
|
||||
//go:linkname hwcap internal/cpu.HWCap
|
||||
var hwcap uint
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
go tool dist list | while IFS=/ read os arch; do
|
||||
echo "Checking $os/$arch..."
|
||||
echo " normal"
|
||||
GOARCH=$arch GOOS=$os go build -o /dev/null .
|
||||
echo " noasm"
|
||||
GOARCH=$arch GOOS=$os go build -tags noasm -o /dev/null .
|
||||
echo " appengine"
|
||||
GOARCH=$arch GOOS=$os go build -tags appengine -o /dev/null .
|
||||
echo " noasm,appengine"
|
||||
GOARCH=$arch GOOS=$os go build -tags 'appengine noasm' -o /dev/null .
|
||||
done
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
language: go
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
- windows
|
||||
|
||||
arch:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- master
|
||||
|
||||
install:
|
||||
- go get ./...
|
||||
|
||||
script:
|
||||
- go vet ./...
|
||||
- go test -cpu=1,2 .
|
||||
- go test -tags=noasm -cpu=1,2 .
|
||||
- go build examples/simple-decoder.go
|
||||
- go build examples/simple-encoder.go
|
||||
- go build examples/stream-decoder.go
|
||||
- go build examples/stream-encoder.go
|
||||
|
||||
stages:
|
||||
- gofmt
|
||||
- test
|
||||
- deploy
|
||||
|
||||
jobs:
|
||||
allow_failures:
|
||||
- go: 'master'
|
||||
- arch: s390x
|
||||
fast_finish: true
|
||||
include:
|
||||
- stage: gofmt
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- diff <(gofmt -d .) <(printf "")
|
||||
- diff <(gofmt -d ./examples) <(printf "")
|
||||
- go install github.com/klauspost/asmfmt/cmd/asmfmt
|
||||
- diff <(asmfmt -d .) <(printf "")
|
||||
- stage: race
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- go test -cpu=1 -short -race .
|
||||
- go test -cpu=2 -short -race .
|
||||
- go test -tags=noasm -cpu=1 -short -race .
|
||||
- go test -tags=noasm -cpu=4 -short -race .
|
||||
- go test -no-avx512 -short -race .
|
||||
- go test -no-avx512 -no-avx2 -short -race .
|
||||
- go test -no-avx512 -no-avx2 -no-ssse3 -short -race .
|
||||
- stage: amd64-noasm
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- go test -no-avx512
|
||||
- go test -no-avx512 -no-avx2
|
||||
- go test -no-avx512 -no-avx2 -no-ssse3
|
||||
- stage: i386
|
||||
go: 1.14.x
|
||||
os: linux
|
||||
arch: amd64
|
||||
script:
|
||||
- GOOS=linux GOARCH=386 go test -short .
|
||||
+76
-10
@@ -1,8 +1,6 @@
|
||||
# Reed-Solomon
|
||||
[![GoDoc][1]][2] [![Build Status][3]][4]
|
||||
[](https://pkg.go.dev/github.com/klauspost/reedsolomon) [![Build Status][3]][4]
|
||||
|
||||
[1]: https://godoc.org/github.com/klauspost/reedsolomon?status.svg
|
||||
[2]: https://pkg.go.dev/github.com/klauspost/reedsolomon?tab=doc
|
||||
[3]: https://travis-ci.org/klauspost/reedsolomon.svg?branch=master
|
||||
[4]: https://travis-ci.org/klauspost/reedsolomon
|
||||
|
||||
@@ -23,7 +21,19 @@ To get the package use the standard:
|
||||
go get -u github.com/klauspost/reedsolomon
|
||||
```
|
||||
|
||||
Using Go modules recommended.
|
||||
|
||||
# Changes
|
||||
## 2021
|
||||
|
||||
* Use `GOAMD64=v4` to enable faster AVX2.
|
||||
* Add progressive shard encoding.
|
||||
* Wider AVX2 loops
|
||||
* Limit concurrency on AVX2, since we are likely memory bound.
|
||||
* Allow 0 parity shards.
|
||||
* Allow disabling inversion cache.
|
||||
* Faster AVX2 encoding.
|
||||
|
||||
|
||||
## May 2020
|
||||
|
||||
@@ -178,6 +188,17 @@ If you are only interested in the data shards (for reading purposes) you can cal
|
||||
err := enc.ReconstructData(data)
|
||||
```
|
||||
|
||||
If you don't need all data shards you can use `ReconstructSome()`:
|
||||
|
||||
```Go
|
||||
// Delete two data shards
|
||||
data[3] = nil
|
||||
data[7] = nil
|
||||
|
||||
// Reconstruct just the shard 3
|
||||
err := enc.ReconstructSome(data, []bool{false, false, false, true, false, false, false, false})
|
||||
```
|
||||
|
||||
So to sum up reconstruction:
|
||||
* The number of data/parity shards must match the numbers used for encoding.
|
||||
* The order of shards must be the same as used when encoding.
|
||||
@@ -209,6 +230,49 @@ To join a data set, use the `Join()` function, which will join the shards and wr
|
||||
err = enc.Join(io.Discard, data, len(bigfile))
|
||||
```
|
||||
|
||||
# Progressive encoding
|
||||
|
||||
It is possible to encode individual shards using EncodeIdx:
|
||||
|
||||
```Go
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out as 0. The caller must zero them.
|
||||
// Data shards must be delivered exactly once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the same.
|
||||
EncodeIdx(dataShard []byte, idx int, parity [][]byte) error
|
||||
```
|
||||
|
||||
This allows progressively encoding the parity by sending individual data shards.
|
||||
There is no requirement on shards being delivered in order,
|
||||
but when sent in order it allows encoding shards one at the time,
|
||||
effectively allowing the operation to be streaming.
|
||||
|
||||
The result will be the same as encoding all shards at once.
|
||||
There is a minor speed penalty using this method, so send
|
||||
shards at once if they are available.
|
||||
|
||||
## Example
|
||||
|
||||
```Go
|
||||
func test() {
|
||||
// Create an encoder with 7 data and 3 parity slices.
|
||||
enc, _ := reedsolomon.New(7, 3)
|
||||
|
||||
// This will be our output parity.
|
||||
parity := make([][]byte, 3)
|
||||
for i := range parity {
|
||||
parity[i] = make([]byte, 10000)
|
||||
}
|
||||
|
||||
for i := 0; i < 7; i++ {
|
||||
// Send data shards one at the time.
|
||||
_ = enc.EncodeIdx(make([]byte, 10000), i, parity)
|
||||
}
|
||||
|
||||
// parity now contains parity, as if all data was sent in one call.
|
||||
}
|
||||
```
|
||||
|
||||
# Streaming/Merging
|
||||
|
||||
It might seem like a limitation that all data should be in memory,
|
||||
@@ -300,14 +364,16 @@ Performance depends mainly on the number of parity shards.
|
||||
In rough terms, doubling the number of parity shards will double the encoding time.
|
||||
|
||||
Here are the throughput numbers with some different selections of data and parity shards.
|
||||
For reference each shard is 1MB random data, and 2 CPU cores are used for encoding.
|
||||
For reference each shard is 1MB random data, and 16 CPU cores are used for encoding.
|
||||
|
||||
| Data | Parity | Parity | MB/s | SSSE3 MB/s | SSSE3 Speed | Rel. Speed |
|
||||
|------|--------|--------|--------|-------------|-------------|------------|
|
||||
| 5 | 2 | 40% | 576,11 | 2599,2 | 451% | 100,00% |
|
||||
| 10 | 2 | 20% | 587,73 | 3100,28 | 528% | 102,02% |
|
||||
| 10 | 4 | 40% | 298,38 | 2470,97 | 828% | 51,79% |
|
||||
| 50 | 20 | 40% | 59,81 | 713,28 | 1193% | 10,38% |
|
||||
| Data | Parity | Go MB/s | SSSE3 MB/s | AVX2 MB/s |
|
||||
|------|--------|---------|------------|-----------|
|
||||
| 5 | 2 | 14287 | 66355 | 108755 |
|
||||
| 8 | 8 | 5569 | 34298 | 70516 |
|
||||
| 10 | 4 | 6766 | 48237 | 93875 |
|
||||
| 50 | 20 | 1540 | 12130 | 22090 |
|
||||
|
||||
The throughput numbers here is the size of the encoded data and parity shards.
|
||||
|
||||
If `runtime.GOMAXPROCS()` is set to a value higher than 1,
|
||||
the encoder will use multiple goroutines to perform the calculations in `Verify`, `Encode` and `Reconstruct`.
|
||||
|
||||
-20
@@ -1,20 +0,0 @@
|
||||
os: Visual Studio 2015
|
||||
|
||||
platform: x64
|
||||
|
||||
clone_folder: c:\gopath\src\github.com\klauspost\reedsolomon
|
||||
|
||||
# environment variables
|
||||
environment:
|
||||
GOPATH: c:\gopath
|
||||
|
||||
install:
|
||||
- echo %PATH%
|
||||
- echo %GOPATH%
|
||||
- go version
|
||||
- go env
|
||||
- go get -d ./...
|
||||
|
||||
build_script:
|
||||
- go test -v -cpu=2 ./...
|
||||
- go test -cpu=1,2,4 -short -race ./...
|
||||
+9
-7
@@ -76,7 +76,7 @@ func galSub(a, b byte) byte {
|
||||
// Table from https://github.com/templexxx/reedsolomon
|
||||
var invTable = [256]byte{0x0, 0x1, 0x8e, 0xf4, 0x47, 0xa7, 0x7a, 0xba, 0xad, 0x9d, 0xdd, 0x98, 0x3d, 0xaa, 0x5d, 0x96, 0xd8, 0x72, 0xc0, 0x58, 0xe0, 0x3e, 0x4c, 0x66, 0x90, 0xde, 0x55, 0x80, 0xa0, 0x83, 0x4b, 0x2a, 0x6c, 0xed, 0x39, 0x51, 0x60, 0x56, 0x2c, 0x8a, 0x70, 0xd0, 0x1f, 0x4a, 0x26, 0x8b, 0x33, 0x6e, 0x48, 0x89, 0x6f, 0x2e, 0xa4, 0xc3, 0x40, 0x5e, 0x50, 0x22, 0xcf, 0xa9, 0xab, 0xc, 0x15, 0xe1, 0x36, 0x5f, 0xf8, 0xd5, 0x92, 0x4e, 0xa6, 0x4, 0x30, 0x88, 0x2b, 0x1e, 0x16, 0x67, 0x45, 0x93, 0x38, 0x23, 0x68, 0x8c, 0x81, 0x1a, 0x25, 0x61, 0x13, 0xc1, 0xcb, 0x63, 0x97, 0xe, 0x37, 0x41, 0x24, 0x57, 0xca, 0x5b, 0xb9, 0xc4, 0x17, 0x4d, 0x52, 0x8d, 0xef, 0xb3, 0x20, 0xec, 0x2f, 0x32, 0x28, 0xd1, 0x11, 0xd9, 0xe9, 0xfb, 0xda, 0x79, 0xdb, 0x77, 0x6, 0xbb, 0x84, 0xcd, 0xfe, 0xfc, 0x1b, 0x54, 0xa1, 0x1d, 0x7c, 0xcc, 0xe4, 0xb0, 0x49, 0x31, 0x27, 0x2d, 0x53, 0x69, 0x2, 0xf5, 0x18, 0xdf, 0x44, 0x4f, 0x9b, 0xbc, 0xf, 0x5c, 0xb, 0xdc, 0xbd, 0x94, 0xac, 0x9, 0xc7, 0xa2, 0x1c, 0x82, 0x9f, 0xc6, 0x34, 0xc2, 0x46, 0x5, 0xce, 0x3b, 0xd, 0x3c, 0x9c, 0x8, 0xbe, 0xb7, 0x87, 0xe5, 0xee, 0x6b, 0xeb, 0xf2, 0xbf, 0xaf, 0xc5, 0x64, 0x7, 0x7b, 0x95, 0x9a, 0xae, 0xb6, 0x12, 0x59, 0xa5, 0x35, 0x65, 0xb8, 0xa3, 0x9e, 0xd2, 0xf7, 0x62, 0x5a, 0x85, 0x7d, 0xa8, 0x3a, 0x29, 0x71, 0xc8, 0xf6, 0xf9, 0x43, 0xd7, 0xd6, 0x10, 0x73, 0x76, 0x78, 0x99, 0xa, 0x19, 0x91, 0x14, 0x3f, 0xe6, 0xf0, 0x86, 0xb1, 0xe2, 0xf1, 0xfa, 0x74, 0xf3, 0xb4, 0x6d, 0x21, 0xb2, 0x6a, 0xe3, 0xe7, 0xb5, 0xea, 0x3, 0x8f, 0xd3, 0xc9, 0x42, 0xd4, 0xe8, 0x75, 0x7f, 0xff, 0x7e, 0xfd}
|
||||
|
||||
var mulTable = [256][256]uint8{[256]uint8{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
var mulTable = [256][256]uint8{{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
|
||||
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff},
|
||||
{0x0, 0x2, 0x4, 0x6, 0x8, 0xa, 0xc, 0xe, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1d, 0x1f, 0x19, 0x1b, 0x15, 0x17, 0x11, 0x13, 0xd, 0xf, 0x9, 0xb, 0x5, 0x7, 0x1, 0x3, 0x3d, 0x3f, 0x39, 0x3b, 0x35, 0x37, 0x31, 0x33, 0x2d, 0x2f, 0x29, 0x2b, 0x25, 0x27, 0x21, 0x23, 0x5d, 0x5f, 0x59, 0x5b, 0x55, 0x57, 0x51, 0x53, 0x4d, 0x4f, 0x49, 0x4b, 0x45, 0x47, 0x41, 0x43, 0x7d, 0x7f, 0x79, 0x7b, 0x75, 0x77, 0x71, 0x73, 0x6d, 0x6f, 0x69, 0x6b, 0x65, 0x67, 0x61, 0x63, 0x9d, 0x9f, 0x99, 0x9b, 0x95, 0x97, 0x91, 0x93, 0x8d, 0x8f, 0x89, 0x8b, 0x85, 0x87, 0x81, 0x83, 0xbd, 0xbf, 0xb9, 0xbb, 0xb5, 0xb7, 0xb1, 0xb3, 0xad, 0xaf, 0xa9, 0xab, 0xa5, 0xa7, 0xa1, 0xa3, 0xdd, 0xdf, 0xd9, 0xdb, 0xd5, 0xd7, 0xd1, 0xd3, 0xcd, 0xcf, 0xc9, 0xcb, 0xc5, 0xc7, 0xc1, 0xc3, 0xfd, 0xff, 0xf9, 0xfb, 0xf5, 0xf7, 0xf1, 0xf3, 0xed, 0xef, 0xe9, 0xeb, 0xe5, 0xe7, 0xe1, 0xe3},
|
||||
{0x0, 0x3, 0x6, 0x5, 0xc, 0xf, 0xa, 0x9, 0x18, 0x1b, 0x1e, 0x1d, 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9d, 0x9e, 0x9b, 0x98, 0x91, 0x92, 0x97, 0x94, 0x85, 0x86, 0x83, 0x80, 0x89, 0x8a, 0x8f, 0x8c, 0xad, 0xae, 0xab, 0xa8, 0xa1, 0xa2, 0xa7, 0xa4, 0xb5, 0xb6, 0xb3, 0xb0, 0xb9, 0xba, 0xbf, 0xbc, 0xfd, 0xfe, 0xfb, 0xf8, 0xf1, 0xf2, 0xf7, 0xf4, 0xe5, 0xe6, 0xe3, 0xe0, 0xe9, 0xea, 0xef, 0xec, 0xcd, 0xce, 0xcb, 0xc8, 0xc1, 0xc2, 0xc7, 0xc4, 0xd5, 0xd6, 0xd3, 0xd0, 0xd9, 0xda, 0xdf, 0xdc, 0x5d, 0x5e, 0x5b, 0x58, 0x51, 0x52, 0x57, 0x54, 0x45, 0x46, 0x43, 0x40, 0x49, 0x4a, 0x4f, 0x4c, 0x6d, 0x6e, 0x6b, 0x68, 0x61, 0x62, 0x67, 0x64, 0x75, 0x76, 0x73, 0x70, 0x79, 0x7a, 0x7f, 0x7c, 0x3d, 0x3e, 0x3b, 0x38, 0x31, 0x32, 0x37, 0x34, 0x25, 0x26, 0x23, 0x20, 0x29, 0x2a, 0x2f, 0x2c, 0xd, 0xe, 0xb, 0x8, 0x1, 0x2, 0x7, 0x4, 0x15, 0x16, 0x13, 0x10, 0x19, 0x1a, 0x1f, 0x1c},
|
||||
@@ -901,7 +901,7 @@ func galExp(a byte, n int) byte {
|
||||
return expTable[logResult]
|
||||
}
|
||||
|
||||
func genAvx2Matrix(matrixRows [][]byte, inputs, outputs int, dst []byte) []byte {
|
||||
func genAvx2Matrix(matrixRows [][]byte, inputs, inIdx, outputs int, dst []byte) []byte {
|
||||
if !avx2CodeGen {
|
||||
panic("codegen not enabled")
|
||||
}
|
||||
@@ -915,14 +915,16 @@ func genAvx2Matrix(matrixRows [][]byte, inputs, outputs int, dst []byte) []byte
|
||||
dst = dst[:wantBytes]
|
||||
}
|
||||
for i, row := range matrixRows[:outputs] {
|
||||
for j, idx := range row[:inputs] {
|
||||
for j, idx := range row[inIdx : inIdx+inputs] {
|
||||
dstIdx := (j*outputs + i) * 64
|
||||
dstPart := dst[dstIdx:]
|
||||
dstPart = dstPart[:64]
|
||||
lo := mulTableLow[idx][:]
|
||||
hi := mulTableHigh[idx][:]
|
||||
copy(dst[dstIdx:], lo)
|
||||
copy(dst[dstIdx+16:], lo)
|
||||
copy(dst[dstIdx+32:], hi)
|
||||
copy(dst[dstIdx+48:], hi)
|
||||
copy(dstPart[:16], lo)
|
||||
copy(dstPart[16:32], lo)
|
||||
copy(dstPart[32:48], hi)
|
||||
copy(dstPart[48:64], hi)
|
||||
}
|
||||
}
|
||||
return dst
|
||||
|
||||
+9
-8
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2019, Minio, Inc.
|
||||
@@ -105,7 +104,7 @@ func setupMatrix84(matrixRows [][]byte, inputOffset, outputOffset int, matrix *[
|
||||
// Invoke AVX512 routine for single output row in parallel
|
||||
func galMulAVX512Parallel81(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix81 *[matrixSize81]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -140,7 +139,7 @@ func galMulAVX512Parallel81(in, out [][]byte, matrixRows [][]byte, inputOffset,
|
||||
// Invoke AVX512 routine for 2 output rows in parallel
|
||||
func galMulAVX512Parallel82(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix82 *[matrixSize82]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -175,7 +174,7 @@ func galMulAVX512Parallel82(in, out [][]byte, matrixRows [][]byte, inputOffset,
|
||||
// Invoke AVX512 routine for 4 output rows in parallel
|
||||
func galMulAVX512Parallel84(in, out [][]byte, matrixRows [][]byte, inputOffset, outputOffset, start, stop int, matrix84 *[matrixSize84]byte) {
|
||||
done := stop - start
|
||||
if done <= 0 {
|
||||
if done <= 0 || len(in) == 0 || len(out) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -226,8 +225,9 @@ func galMulAVX512LastInput(inputOffset int, inputEnd int, outputOffset int, outp
|
||||
|
||||
// Perform the same as codeSomeShards, but taking advantage of
|
||||
// AVX512 parallelism for up to 4x faster execution as compared to AVX2
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
// Process using no goroutines
|
||||
outputCount := len(outputs)
|
||||
start, end := 0, r.o.perRound
|
||||
if end > byteCount {
|
||||
end = byteCount
|
||||
@@ -273,7 +273,8 @@ func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte,
|
||||
|
||||
// Perform the same as codeSomeShards, but taking advantage of
|
||||
// AVX512 parallelism for up to 4x faster execution as compared to AVX2
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
outputCount := len(outputs)
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
if do < r.o.minSplitSize {
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2019, Minio, Inc.
|
||||
|
||||
+6
-4
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
@@ -108,6 +107,9 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
in = in[done:]
|
||||
out = out[done:]
|
||||
}
|
||||
if len(in) == 0 {
|
||||
return
|
||||
}
|
||||
out = out[:len(in)]
|
||||
mt := mulTable[c][:256]
|
||||
for i := range in {
|
||||
@@ -115,7 +117,7 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
if o.useSSE2 {
|
||||
if len(in) >= bigSwitchover {
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
|
||||
+3
-4
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2017, Minio, Inc.
|
||||
@@ -52,7 +51,7 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
|
||||
galXorNEON(in, out)
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2017, Minio, Inc.
|
||||
|
||||
+1178
File diff suppressed because it is too large
Load Diff
+63422
File diff suppressed because it is too large
Load Diff
+18
@@ -0,0 +1,18 @@
|
||||
//go:build !amd64 || noasm || appengine || gccgo || nogen
|
||||
// +build !amd64 noasm appengine gccgo nogen
|
||||
|
||||
package reedsolomon
|
||||
|
||||
const maxAvx2Inputs = 1
|
||||
const maxAvx2Outputs = 1
|
||||
const minAvx2Size = 1
|
||||
const avxSizeMask = 0
|
||||
const avx2CodeGen = false
|
||||
|
||||
func galMulSlicesAvx2(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
panic("avx2 codegen not available")
|
||||
}
|
||||
|
||||
func galMulSlicesAvx2Xor(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
panic("avx2 codegen not available")
|
||||
}
|
||||
+694
@@ -0,0 +1,694 @@
|
||||
// Code generated by command: go generate gen.go. DO NOT EDIT.
|
||||
|
||||
//go:build !appengine && !noasm && gc && !nogen
|
||||
// +build !appengine,!noasm,gc,!nogen
|
||||
|
||||
package reedsolomon
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
const (
|
||||
avx2CodeGen = true
|
||||
maxAvx2Inputs = 10
|
||||
maxAvx2Outputs = 10
|
||||
minAvx2Size = 64
|
||||
avxSizeMask = maxInt - (minAvx2Size - 1)
|
||||
)
|
||||
|
||||
func galMulSlicesAvx2(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
n := (stop - start) & avxSizeMask
|
||||
|
||||
switch len(in) {
|
||||
case 1:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_1x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_1x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_1x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_1x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_1x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_1x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_1x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_1x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_1x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_1x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 2:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_2x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_2x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_2x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_2x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_2x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_2x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_2x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_2x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_2x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_2x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 3:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_3x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_3x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_3x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_3x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_3x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_3x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_3x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_3x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_3x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_3x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 4:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_4x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_4x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_4x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_4x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_4x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_4x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_4x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_4x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_4x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_4x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 5:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_5x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_5x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_5x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_5x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_5x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_5x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_5x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_5x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_5x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_5x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 6:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_6x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_6x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_6x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_6x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_6x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_6x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_6x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_6x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_6x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_6x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 7:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_7x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_7x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_7x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_7x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_7x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_7x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_7x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_7x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_7x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_7x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 8:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_8x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_8x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_8x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_8x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_8x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_8x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_8x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_8x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_8x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_8x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 9:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_9x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_9x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_9x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_9x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_9x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_9x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_9x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_9x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_9x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_9x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 10:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_10x1_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_10x2_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_10x3_64(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_10x4(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_10x5(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_10x6(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_10x7(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_10x8(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_10x9(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_10x10(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unhandled size: %dx%d", len(in), len(out)))
|
||||
}
|
||||
|
||||
func galMulSlicesAvx2Xor(matrix []byte, in, out [][]byte, start, stop int) int {
|
||||
n := (stop - start) & avxSizeMask
|
||||
|
||||
switch len(in) {
|
||||
case 1:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_1x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_1x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_1x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_1x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_1x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_1x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_1x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_1x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_1x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_1x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 2:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_2x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_2x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_2x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_2x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_2x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_2x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_2x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_2x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_2x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_2x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 3:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_3x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_3x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_3x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_3x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_3x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_3x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_3x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_3x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_3x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_3x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 4:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_4x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_4x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_4x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_4x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_4x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_4x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_4x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_4x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_4x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_4x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 5:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_5x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_5x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_5x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_5x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_5x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_5x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_5x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_5x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_5x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_5x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 6:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_6x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_6x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_6x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_6x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_6x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_6x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_6x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_6x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_6x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_6x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 7:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_7x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_7x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_7x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_7x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_7x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_7x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_7x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_7x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_7x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_7x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 8:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_8x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_8x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_8x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_8x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_8x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_8x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_8x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_8x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_8x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_8x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 9:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_9x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_9x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_9x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_9x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_9x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_9x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_9x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_9x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_9x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_9x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
case 10:
|
||||
switch len(out) {
|
||||
case 1:
|
||||
mulAvxTwo_10x1_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 2:
|
||||
mulAvxTwo_10x2_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 3:
|
||||
mulAvxTwo_10x3_64Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 4:
|
||||
mulAvxTwo_10x4Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 5:
|
||||
mulAvxTwo_10x5Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 6:
|
||||
mulAvxTwo_10x6Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 7:
|
||||
mulAvxTwo_10x7Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 8:
|
||||
mulAvxTwo_10x8Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 9:
|
||||
mulAvxTwo_10x9Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
case 10:
|
||||
mulAvxTwo_10x10Xor(matrix, in, out, start, n)
|
||||
return n
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("unhandled size: %dx%d", len(in), len(out)))
|
||||
}
|
||||
+22
-8
@@ -1,11 +1,14 @@
|
||||
//+build !amd64 noasm appengine gccgo
|
||||
//+build !arm64 noasm appengine gccgo
|
||||
//+build !ppc64le noasm appengine gccgo
|
||||
//go:build (!amd64 || noasm || appengine || gccgo) && (!arm64 || noasm || appengine || gccgo) && (!ppc64le || noasm || appengine || gccgo)
|
||||
// +build !amd64 noasm appengine gccgo
|
||||
// +build !arm64 noasm appengine gccgo
|
||||
// +build !ppc64le noasm appengine gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
|
||||
package reedsolomon
|
||||
|
||||
import "encoding/binary"
|
||||
|
||||
func galMulSlice(c byte, in, out []byte, o *options) {
|
||||
out = out[:len(in)]
|
||||
if c == 1 {
|
||||
@@ -21,9 +24,7 @@ func galMulSlice(c byte, in, out []byte, o *options) {
|
||||
func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
out = out[:len(in)]
|
||||
if c == 1 {
|
||||
for n, input := range in {
|
||||
out[n] ^= input
|
||||
}
|
||||
sliceXor(in, out, o)
|
||||
return
|
||||
}
|
||||
mt := mulTable[c][:256]
|
||||
@@ -32,8 +33,21 @@ func galMulSliceXor(c byte, in, out []byte, o *options) {
|
||||
}
|
||||
}
|
||||
|
||||
// slice galois add
|
||||
func sliceXor(in, out []byte, o *options) {
|
||||
// simple slice xor
|
||||
func sliceXor(in, out []byte, _ *options) {
|
||||
for len(out) >= 32 {
|
||||
inS := in[:32]
|
||||
v0 := binary.LittleEndian.Uint64(out[:]) ^ binary.LittleEndian.Uint64(inS[:])
|
||||
v1 := binary.LittleEndian.Uint64(out[8:]) ^ binary.LittleEndian.Uint64(inS[8:])
|
||||
v2 := binary.LittleEndian.Uint64(out[16:]) ^ binary.LittleEndian.Uint64(inS[16:])
|
||||
v3 := binary.LittleEndian.Uint64(out[24:]) ^ binary.LittleEndian.Uint64(inS[24:])
|
||||
binary.LittleEndian.PutUint64(out[:], v0)
|
||||
binary.LittleEndian.PutUint64(out[8:], v1)
|
||||
binary.LittleEndian.PutUint64(out[16:], v2)
|
||||
binary.LittleEndian.PutUint64(out[24:], v3)
|
||||
out = out[32:]
|
||||
in = in[32:]
|
||||
}
|
||||
for n, input := range in {
|
||||
out[n] ^= input
|
||||
}
|
||||
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//go:build !amd64 || noasm || appengine || gccgo
|
||||
// +build !amd64 noasm appengine gccgo
|
||||
|
||||
// Copyright 2020, Klaus Post, see LICENSE for details.
|
||||
|
||||
package reedsolomon
|
||||
|
||||
func (r *reedSolomon) codeSomeShardsAvx512(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
panic("codeSomeShardsAvx512 should not be called if built without asm")
|
||||
}
|
||||
|
||||
func (r *reedSolomon) codeSomeShardsAvx512P(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
panic("codeSomeShardsAvx512P should not be called if built without asm")
|
||||
}
|
||||
+2
-3
@@ -1,6 +1,5 @@
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
//go:build !noasm && !appengine && !gccgo
|
||||
// +build !noasm,!appengine,!gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2018, Minio, Inc.
|
||||
|
||||
+3
-1
@@ -1,4 +1,6 @@
|
||||
//+build !noasm !appengine !gccgo
|
||||
//+build !noasm
|
||||
//+build !appengine
|
||||
//+build !gccgo
|
||||
|
||||
// Copyright 2015, Klaus Post, see LICENSE for details.
|
||||
// Copyright 2018, Minio, Inc.
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
module github.com/klauspost/reedsolomon
|
||||
|
||||
go 1.15
|
||||
|
||||
require github.com/klauspost/cpuid/v2 v2.0.14
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
github.com/klauspost/cpuid/v2 v2.0.14 h1:QRqdp6bb9M9S5yyKeYteXKuoKE4p0tGlra81fKOpWH8=
|
||||
github.com/klauspost/cpuid/v2 v2.0.14/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c=
|
||||
+17
-13
@@ -14,7 +14,7 @@ import (
|
||||
// The tree uses a Reader-Writer mutex to make it thread-safe
|
||||
// when accessing cached matrices and inserting new ones.
|
||||
type inversionTree struct {
|
||||
mutex *sync.RWMutex
|
||||
mutex sync.RWMutex
|
||||
root inversionNode
|
||||
}
|
||||
|
||||
@@ -26,21 +26,22 @@ type inversionNode struct {
|
||||
// newInversionTree initializes a tree for storing inverted matrices.
|
||||
// Note that the root node is the identity matrix as it implies
|
||||
// there were no errors with the original data.
|
||||
func newInversionTree(dataShards, parityShards int) inversionTree {
|
||||
func newInversionTree(dataShards, parityShards int) *inversionTree {
|
||||
identity, _ := identityMatrix(dataShards)
|
||||
root := inversionNode{
|
||||
matrix: identity,
|
||||
children: make([]*inversionNode, dataShards+parityShards),
|
||||
}
|
||||
return inversionTree{
|
||||
mutex: &sync.RWMutex{},
|
||||
root: root,
|
||||
return &inversionTree{
|
||||
root: inversionNode{
|
||||
matrix: identity,
|
||||
children: make([]*inversionNode, dataShards+parityShards),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetInvertedMatrix returns the cached inverted matrix or nil if it
|
||||
// is not found in the tree keyed on the indices of invalid rows.
|
||||
func (t inversionTree) GetInvertedMatrix(invalidIndices []int) matrix {
|
||||
func (t *inversionTree) GetInvertedMatrix(invalidIndices []int) matrix {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
// Lock the tree for reading before accessing the tree.
|
||||
t.mutex.RLock()
|
||||
defer t.mutex.RUnlock()
|
||||
@@ -63,7 +64,10 @@ var errAlreadySet = errors.New("the root node identity matrix is already set")
|
||||
// keyed by the indices of invalid rows. The total number of shards
|
||||
// is required for creating the proper length lists of child nodes for
|
||||
// each node.
|
||||
func (t inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix, shards int) error {
|
||||
func (t *inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix, shards int) error {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
// If no invalid indices were given then we are done because the
|
||||
// root node is already set with the identity matrix.
|
||||
if len(invalidIndices) == 0 {
|
||||
@@ -86,7 +90,7 @@ func (t inversionTree) InsertInvertedMatrix(invalidIndices []int, matrix matrix,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matrix {
|
||||
func (n *inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matrix {
|
||||
// Get the child node to search next from the list of children. The
|
||||
// list of children starts relative to the parent index passed in
|
||||
// because the indices of invalid rows is sorted (by default). As we
|
||||
@@ -117,7 +121,7 @@ func (n inversionNode) getInvertedMatrix(invalidIndices []int, parent int) matri
|
||||
return node.matrix
|
||||
}
|
||||
|
||||
func (n inversionNode) insertInvertedMatrix(invalidIndices []int, matrix matrix, shards, parent int) {
|
||||
func (n *inversionNode) insertInvertedMatrix(invalidIndices []int, matrix matrix, shards, parent int) {
|
||||
// As above, get the child node to search next from the list of children.
|
||||
// The list of children starts relative to the parent index passed in
|
||||
// because the indices of invalid rows is sorted (by default). As we
|
||||
|
||||
+4
-1
@@ -218,7 +218,10 @@ func (m matrix) gaussianElimination() error {
|
||||
if m[r][r] == 0 {
|
||||
for rowBelow := r + 1; rowBelow < rows; rowBelow++ {
|
||||
if m[rowBelow][r] != 0 {
|
||||
m.SwapRows(r, rowBelow)
|
||||
err := m.SwapRows(r, rowBelow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
+44
-12
@@ -3,7 +3,7 @@ package reedsolomon
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/klauspost/cpuid"
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
// Option allows to override processing parameters.
|
||||
@@ -19,6 +19,8 @@ type options struct {
|
||||
usePAR1Matrix bool
|
||||
useCauchy bool
|
||||
fastOneParity bool
|
||||
inversionCache bool
|
||||
customMatrix [][]byte
|
||||
|
||||
// stream options
|
||||
concReads bool
|
||||
@@ -27,15 +29,16 @@ type options struct {
|
||||
}
|
||||
|
||||
var defaultOptions = options{
|
||||
maxGoroutines: 384,
|
||||
minSplitSize: -1,
|
||||
fastOneParity: false,
|
||||
maxGoroutines: 384,
|
||||
minSplitSize: -1,
|
||||
fastOneParity: false,
|
||||
inversionCache: true,
|
||||
|
||||
// Detect CPU capabilities.
|
||||
useSSSE3: cpuid.CPU.SSSE3(),
|
||||
useSSE2: cpuid.CPU.SSE2(),
|
||||
useAVX2: cpuid.CPU.AVX2(),
|
||||
useAVX512: cpuid.CPU.AVX512F() && cpuid.CPU.AVX512BW(),
|
||||
useSSSE3: cpuid.CPU.Supports(cpuid.SSSE3),
|
||||
useSSE2: cpuid.CPU.Supports(cpuid.SSE2),
|
||||
useAVX2: cpuid.CPU.Supports(cpuid.AVX2),
|
||||
useAVX512: cpuid.CPU.Supports(cpuid.AVX512F, cpuid.AVX512BW),
|
||||
}
|
||||
|
||||
func init() {
|
||||
@@ -109,6 +112,15 @@ func WithConcurrentStreamWrites(enabled bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithInversionCache allows to control the inversion cache.
|
||||
// This will cache reconstruction matrices so they can be reused.
|
||||
// Enabled by default.
|
||||
func WithInversionCache(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.inversionCache = enabled
|
||||
}
|
||||
}
|
||||
|
||||
// WithStreamBlockSize allows to set a custom block size per round of reads/writes.
|
||||
// If not set, any shard size set with WithAutoGoroutines will be used.
|
||||
// If WithAutoGoroutines is also unset, 4MB will be used.
|
||||
@@ -119,25 +131,33 @@ func WithStreamBlockSize(n int) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func withSSSE3(enabled bool) Option {
|
||||
// WithSSSE3 allows to enable/disable SSSE3 instructions.
|
||||
// If not set, SSSE3 will be turned on or off automatically based on CPU ID information.
|
||||
func WithSSSE3(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useSSSE3 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withAVX2(enabled bool) Option {
|
||||
// WithAVX2 allows to enable/disable AVX2 instructions.
|
||||
// If not set, AVX2 will be turned on or off automatically based on CPU ID information.
|
||||
func WithAVX2(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useAVX2 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withSSE2(enabled bool) Option {
|
||||
// WithSSE2 allows to enable/disable SSE2 instructions.
|
||||
// If not set, SSE2 will be turned on or off automatically based on CPU ID information.
|
||||
func WithSSE2(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useSSE2 = enabled
|
||||
}
|
||||
}
|
||||
|
||||
func withAVX512(enabled bool) Option {
|
||||
// WithAVX512 allows to enable/disable AVX512 instructions.
|
||||
// If not set, AVX512 will be turned on or off automatically based on CPU ID information.
|
||||
func WithAVX512(enabled bool) Option {
|
||||
return func(o *options) {
|
||||
o.useAVX512 = enabled
|
||||
}
|
||||
@@ -173,3 +193,15 @@ func WithFastOneParityMatrix() Option {
|
||||
o.fastOneParity = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomMatrix causes the encoder to use the manually specified matrix.
|
||||
// customMatrix represents only the parity chunks.
|
||||
// customMatrix must have at least ParityShards rows and DataShards columns.
|
||||
// It can be used for interoperability with libraries which generate
|
||||
// the matrix differently or to implement more complex coding schemes like LRC
|
||||
// (locally reconstructible codes).
|
||||
func WithCustomMatrix(customMatrix [][]byte) Option {
|
||||
return func(o *options) {
|
||||
o.customMatrix = customMatrix
|
||||
}
|
||||
}
|
||||
|
||||
+436
-126
@@ -18,7 +18,7 @@ import (
|
||||
"runtime"
|
||||
"sync"
|
||||
|
||||
"github.com/klauspost/cpuid"
|
||||
"github.com/klauspost/cpuid/v2"
|
||||
)
|
||||
|
||||
// Encoder is an interface to encode Reed-Salomon parity sets for your data.
|
||||
@@ -32,6 +32,12 @@ type Encoder interface {
|
||||
// data shards while this is running.
|
||||
Encode(shards [][]byte) error
|
||||
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out as 0. The caller must zero them.
|
||||
// Data shards must be delivered exactly once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the same.
|
||||
EncodeIdx(dataShard []byte, idx int, parity [][]byte) error
|
||||
|
||||
// Verify returns true if the parity shards contain correct data.
|
||||
// The data is the same format as Encode. No data is modified, so
|
||||
// you are allowed to read from data while this is running.
|
||||
@@ -71,6 +77,24 @@ type Encoder interface {
|
||||
// calling the Verify function is likely to fail.
|
||||
ReconstructData(shards [][]byte) error
|
||||
|
||||
// ReconstructSome will recreate only requested data shards, if possible.
|
||||
//
|
||||
// Given a list of shards, some of which contain data, fills in the
|
||||
// data shards indicated by true values in the "required" parameter.
|
||||
// The length of "required" array must be equal to DataShards.
|
||||
//
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil or zero-length.
|
||||
// If a shard is zero-length but has sufficient capacity, that memory will
|
||||
// be used, otherwise a new []byte will be allocated.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
//
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
ReconstructSome(shards [][]byte, required []bool) error
|
||||
|
||||
// Update parity is use for change a few data shards and update it's parity.
|
||||
// Input 'newDatashards' containing data shards changed.
|
||||
// Input 'shards' containing old data shards (if data shard not changed, it can be nil) and old parity shards.
|
||||
@@ -102,6 +126,15 @@ type Encoder interface {
|
||||
Join(dst io.Writer, shards [][]byte, outSize int) error
|
||||
}
|
||||
|
||||
const (
|
||||
avx2CodeGenMinSize = 64
|
||||
avx2CodeGenMinShards = 3
|
||||
avx2CodeGenMaxGoroutines = 8
|
||||
|
||||
intSize = 32 << (^uint(0) >> 63) // 32 or 64
|
||||
maxInt = 1<<(intSize-1) - 1
|
||||
)
|
||||
|
||||
// reedSolomon contains a matrix for a specific
|
||||
// distribution of datashards and parity shards.
|
||||
// Construct if using New()
|
||||
@@ -110,15 +143,16 @@ type reedSolomon struct {
|
||||
ParityShards int // Number of parity shards, should not be modified.
|
||||
Shards int // Total number of shards. Calculated, and should not be modified.
|
||||
m matrix
|
||||
tree inversionTree
|
||||
tree *inversionTree
|
||||
parity [][]byte
|
||||
o options
|
||||
mPool sync.Pool
|
||||
}
|
||||
|
||||
// ErrInvShardNum will be returned by New, if you attempt to create
|
||||
// an Encoder where either data or parity shards is zero or less.
|
||||
var ErrInvShardNum = errors.New("cannot create Encoder with zero or less data/parity shards")
|
||||
// an Encoder with less than one data shard or less than zero parity
|
||||
// shards.
|
||||
var ErrInvShardNum = errors.New("cannot create Encoder with less than one data shard or less than zero parity shards")
|
||||
|
||||
// ErrMaxShardNum will be returned by New, if you attempt to create an
|
||||
// Encoder where data and parity shards are bigger than the order of
|
||||
@@ -249,7 +283,7 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
for _, opt := range opts {
|
||||
opt(&r.o)
|
||||
}
|
||||
if dataShards <= 0 || parityShards <= 0 {
|
||||
if dataShards <= 0 || parityShards < 0 {
|
||||
return nil, ErrInvShardNum
|
||||
}
|
||||
|
||||
@@ -257,8 +291,28 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
return nil, ErrMaxShardNum
|
||||
}
|
||||
|
||||
if parityShards == 0 {
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
var err error
|
||||
switch {
|
||||
case r.o.customMatrix != nil:
|
||||
if len(r.o.customMatrix) < parityShards {
|
||||
return nil, errors.New("coding matrix must contain at least parityShards rows")
|
||||
}
|
||||
r.m = make([][]byte, r.Shards)
|
||||
for i := 0; i < dataShards; i++ {
|
||||
r.m[i] = make([]byte, dataShards)
|
||||
r.m[i][i] = 1
|
||||
}
|
||||
for k, row := range r.o.customMatrix {
|
||||
if len(row) < dataShards {
|
||||
return nil, errors.New("coding matrix must contain at least dataShards columns")
|
||||
}
|
||||
r.m[dataShards+k] = make([]byte, dataShards)
|
||||
copy(r.m[dataShards+k], row)
|
||||
}
|
||||
case r.o.fastOneParity && parityShards == 1:
|
||||
r.m, err = buildXorMatrix(dataShards, r.Shards)
|
||||
case r.o.useCauchy:
|
||||
@@ -274,6 +328,24 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
|
||||
// Calculate what we want per round
|
||||
r.o.perRound = cpuid.CPU.Cache.L2
|
||||
|
||||
divide := parityShards + 1
|
||||
if avx2CodeGen && r.o.useAVX2 && (dataShards > maxAvx2Inputs || parityShards > maxAvx2Outputs) {
|
||||
// Base on L1 cache if we have many inputs.
|
||||
r.o.perRound = cpuid.CPU.Cache.L1D
|
||||
divide = 0
|
||||
if dataShards > maxAvx2Inputs {
|
||||
divide += maxAvx2Inputs
|
||||
} else {
|
||||
divide += dataShards
|
||||
}
|
||||
if parityShards > maxAvx2Inputs {
|
||||
divide += maxAvx2Outputs
|
||||
} else {
|
||||
divide += parityShards
|
||||
}
|
||||
}
|
||||
|
||||
if r.o.perRound <= 0 {
|
||||
// Set to 128K if undetectable.
|
||||
r.o.perRound = 128 << 10
|
||||
@@ -283,8 +355,9 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
// If multiple threads per core, make sure they don't contend for cache.
|
||||
r.o.perRound /= cpuid.CPU.ThreadsPerCore
|
||||
}
|
||||
|
||||
// 1 input + parity must fit in cache, and we add one more to be safer.
|
||||
r.o.perRound = r.o.perRound / (1 + parityShards)
|
||||
r.o.perRound = r.o.perRound / divide
|
||||
// Align to 64 bytes.
|
||||
r.o.perRound = ((r.o.perRound + 63) / 64) * 64
|
||||
|
||||
@@ -302,10 +375,6 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
}
|
||||
|
||||
if r.o.perRound < r.o.minSplitSize {
|
||||
r.o.perRound = r.o.minSplitSize
|
||||
}
|
||||
|
||||
if r.o.shardSize > 0 {
|
||||
p := runtime.GOMAXPROCS(0)
|
||||
if p == 1 || r.o.shardSize <= r.o.minSplitSize*2 {
|
||||
@@ -328,12 +397,20 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Generated AVX2 does not need data to stay in L1 cache between runs.
|
||||
// We will be purely limited by RAM speed.
|
||||
if r.canAVX2C(avx2CodeGenMinSize, maxAvx2Inputs, maxAvx2Outputs) && r.o.maxGoroutines > avx2CodeGenMaxGoroutines {
|
||||
r.o.maxGoroutines = avx2CodeGenMaxGoroutines
|
||||
}
|
||||
|
||||
// Inverted matrices are cached in a tree keyed by the indices
|
||||
// of the invalid rows of the data to reconstruct.
|
||||
// The inversion root node will have the identity matrix as
|
||||
// its inversion matrix because it implies there are no errors
|
||||
// with the original data.
|
||||
r.tree = newInversionTree(dataShards, parityShards)
|
||||
if r.o.inversionCache {
|
||||
r.tree = newInversionTree(dataShards, parityShards)
|
||||
}
|
||||
|
||||
r.parity = make([][]byte, parityShards)
|
||||
for i := range r.parity {
|
||||
@@ -341,8 +418,9 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
}
|
||||
|
||||
if avx2CodeGen && r.o.useAVX2 {
|
||||
sz := r.DataShards * r.ParityShards * 2 * 32
|
||||
r.mPool.New = func() interface{} {
|
||||
return make([]byte, r.Shards*2*32)
|
||||
return make([]byte, sz)
|
||||
}
|
||||
}
|
||||
return &r, err
|
||||
@@ -353,7 +431,7 @@ func New(dataShards, parityShards int, opts ...Option) (Encoder, error) {
|
||||
// if there were too few shards to reconstruct the missing data.
|
||||
var ErrTooFewShards = errors.New("too few shards given")
|
||||
|
||||
// Encodes parity for a set of data shards.
|
||||
// Encode parity for a set of data shards.
|
||||
// An array 'shards' containing data shards followed by parity shards.
|
||||
// The number of shards must match the number given to New.
|
||||
// Each shard is a byte array, and they must all be the same size.
|
||||
@@ -373,7 +451,49 @@ func (r *reedSolomon) Encode(shards [][]byte) error {
|
||||
output := shards[r.DataShards:]
|
||||
|
||||
// Do the coding.
|
||||
r.codeSomeShards(r.parity, shards[0:r.DataShards], output, r.ParityShards, len(shards[0]))
|
||||
r.codeSomeShards(r.parity, shards[0:r.DataShards], output[:r.ParityShards], len(shards[0]))
|
||||
return nil
|
||||
}
|
||||
|
||||
// EncodeIdx will add parity for a single data shard.
|
||||
// Parity shards should start out zeroed. The caller must zero them before first call.
|
||||
// Data shards should only be delivered once. There is no check for this.
|
||||
// The parity shards will always be updated and the data shards will remain the unchanged.
|
||||
func (r *reedSolomon) EncodeIdx(dataShard []byte, idx int, parity [][]byte) error {
|
||||
if len(parity) != r.ParityShards {
|
||||
return ErrTooFewShards
|
||||
}
|
||||
if len(parity) == 0 {
|
||||
return nil
|
||||
}
|
||||
if idx < 0 || idx >= r.DataShards {
|
||||
return ErrInvShardNum
|
||||
}
|
||||
err := checkShards(parity, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(parity[0]) != len(dataShard) {
|
||||
return ErrShardSize
|
||||
}
|
||||
|
||||
// Process using no goroutines for now.
|
||||
start, end := 0, r.o.perRound
|
||||
if end > len(dataShard) {
|
||||
end = len(dataShard)
|
||||
}
|
||||
|
||||
for start < len(dataShard) {
|
||||
in := dataShard[start:end]
|
||||
for iRow := 0; iRow < r.ParityShards; iRow++ {
|
||||
galMulSliceXor(r.parity[iRow][idx], in, parity[iRow][start:end], &r.o)
|
||||
}
|
||||
start = end
|
||||
end += r.o.perRound
|
||||
if end > len(dataShard) {
|
||||
end = len(dataShard)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -421,6 +541,10 @@ func (r *reedSolomon) Update(shards [][]byte, newDatashards [][]byte) error {
|
||||
}
|
||||
|
||||
func (r *reedSolomon) updateParityShards(matrixRows, oldinputs, newinputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
if len(outputs) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
if r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize {
|
||||
r.updateParityShardsP(matrixRows, oldinputs, newinputs, outputs, outputCount, byteCount)
|
||||
return
|
||||
@@ -432,7 +556,7 @@ func (r *reedSolomon) updateParityShards(matrixRows, oldinputs, newinputs, outpu
|
||||
continue
|
||||
}
|
||||
oldin := oldinputs[c]
|
||||
// oldinputs data will be change
|
||||
// oldinputs data will be changed
|
||||
sliceXor(in, oldin, &r.o)
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], oldin, outputs[iRow], &r.o)
|
||||
@@ -487,7 +611,13 @@ func (r *reedSolomon) Verify(shards [][]byte) (bool, error) {
|
||||
toCheck := shards[r.DataShards:]
|
||||
|
||||
// Do the checking.
|
||||
return r.checkSomeShards(r.parity, shards[0:r.DataShards], toCheck, r.ParityShards, len(shards[0])), nil
|
||||
return r.checkSomeShards(r.parity, shards[:r.DataShards], toCheck[:r.ParityShards], len(shards[0])), nil
|
||||
}
|
||||
|
||||
func (r *reedSolomon) canAVX2C(byteCount int, inputs, outputs int) bool {
|
||||
return avx2CodeGen && r.o.useAVX2 &&
|
||||
byteCount >= avx2CodeGenMinSize && inputs+outputs >= avx2CodeGenMinShards &&
|
||||
inputs <= maxAvx2Inputs && outputs <= maxAvx2Outputs
|
||||
}
|
||||
|
||||
// Multiplies a subset of rows from a coding matrix by a full set of
|
||||
@@ -499,19 +629,19 @@ func (r *reedSolomon) Verify(shards [][]byte) (bool, error) {
|
||||
// The number of outputs computed, and the
|
||||
// number of matrix rows used, is determined by
|
||||
// outputCount, which is the number of outputs to compute.
|
||||
func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
if len(outputs) == 0 {
|
||||
return
|
||||
}
|
||||
switch {
|
||||
case r.o.useAVX512 && r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize && len(inputs) >= 4 && len(outputs) >= 2:
|
||||
r.codeSomeShardsAvx512P(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
r.codeSomeShardsAvx512P(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
case r.o.useAVX512 && len(inputs) >= 4 && len(outputs) >= 2:
|
||||
r.codeSomeShardsAvx512(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
r.codeSomeShardsAvx512(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
case r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize:
|
||||
r.codeSomeShardsP(matrixRows, inputs, outputs, outputCount, byteCount)
|
||||
case byteCount > r.o.minSplitSize:
|
||||
r.codeSomeShardsP(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -520,17 +650,50 @@ func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outpu
|
||||
if end > len(inputs[0]) {
|
||||
end = len(inputs[0])
|
||||
}
|
||||
if avx2CodeGen && r.o.useAVX2 && byteCount >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
m := genAvx2Matrix(matrixRows, len(inputs), len(outputs), r.mPool.Get().([]byte))
|
||||
if r.canAVX2C(byteCount, len(inputs), len(outputs)) {
|
||||
m := genAvx2Matrix(matrixRows, len(inputs), 0, len(outputs), r.mPool.Get().([]byte))
|
||||
start += galMulSlicesAvx2(m, inputs, outputs, 0, byteCount)
|
||||
r.mPool.Put(m)
|
||||
end = len(inputs[0])
|
||||
} else if len(inputs)+len(outputs) > avx2CodeGenMinShards && r.canAVX2C(byteCount, maxAvx2Inputs, maxAvx2Outputs) {
|
||||
end = len(inputs[0])
|
||||
inIdx := 0
|
||||
m := r.mPool.Get().([]byte)
|
||||
defer r.mPool.Put(m)
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
m = genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), m)
|
||||
if inIdx == 0 {
|
||||
galMulSlicesAvx2(m, inPer, outPer, 0, byteCount)
|
||||
} else {
|
||||
galMulSlicesAvx2Xor(m, inPer, outPer, 0, byteCount)
|
||||
}
|
||||
start = byteCount & avxSizeMask
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
if start >= end {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for start < len(inputs[0]) {
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
for c := 0; c < len(inputs); c++ {
|
||||
in := inputs[c][start:end]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][start:end], &r.o)
|
||||
} else {
|
||||
@@ -548,54 +711,227 @@ func (r *reedSolomon) codeSomeShards(matrixRows, inputs, outputs [][]byte, outpu
|
||||
|
||||
// Perform the same as codeSomeShards, but split the workload into
|
||||
// several goroutines.
|
||||
func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, outputCount, byteCount int) {
|
||||
func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
gor := r.o.maxGoroutines
|
||||
|
||||
var avx2Matrix []byte
|
||||
useAvx2 := r.canAVX2C(byteCount, len(inputs), len(outputs))
|
||||
if useAvx2 {
|
||||
avx2Matrix = genAvx2Matrix(matrixRows, len(inputs), 0, len(outputs), r.mPool.Get().([]byte))
|
||||
defer r.mPool.Put(avx2Matrix)
|
||||
} else if byteCount < 10<<20 && len(inputs)+len(outputs) > avx2CodeGenMinShards &&
|
||||
r.canAVX2C(byteCount/4, maxAvx2Inputs, maxAvx2Outputs) {
|
||||
// It appears there is a switchover point at around 10MB where
|
||||
// Regular processing is faster...
|
||||
r.codeSomeShardsAVXP(matrixRows, inputs, outputs, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
do := byteCount / gor
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
|
||||
exec := func(start, stop int) {
|
||||
if useAvx2 && stop-start >= 64 {
|
||||
start += galMulSlicesAvx2(avx2Matrix, inputs, outputs, start, stop)
|
||||
}
|
||||
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
for c := 0; c < len(inputs); c++ {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
if gor <= 1 {
|
||||
wg.Add(1)
|
||||
exec(0, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
var avx2Matrix []byte
|
||||
if avx2CodeGen && r.o.useAVX2 && byteCount >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
avx2Matrix = genAvx2Matrix(matrixRows, len(inputs), len(outputs), r.mPool.Get().([]byte))
|
||||
defer r.mPool.Put(avx2Matrix)
|
||||
}
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(start, stop int) {
|
||||
if avx2CodeGen && r.o.useAVX2 && stop-start >= 32 && len(inputs) > 1 && len(outputs) > 1 && len(inputs) <= maxAvx2Inputs && len(outputs) <= maxAvx2Outputs {
|
||||
start += galMulSlicesAvx2(avx2Matrix, inputs, outputs, start, stop)
|
||||
go exec(start, start+do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// Perform the same as codeSomeShards, but split the workload into
|
||||
// several goroutines.
|
||||
func (r *reedSolomon) codeSomeShardsAVXP(matrixRows, inputs, outputs [][]byte, byteCount int) {
|
||||
var wg sync.WaitGroup
|
||||
gor := r.o.maxGoroutines
|
||||
|
||||
type state struct {
|
||||
input [][]byte
|
||||
output [][]byte
|
||||
m []byte
|
||||
first bool
|
||||
}
|
||||
// Make a plan...
|
||||
plan := make([]state, 0, ((len(inputs)+maxAvx2Inputs-1)/maxAvx2Inputs)*((len(outputs)+maxAvx2Outputs-1)/maxAvx2Outputs))
|
||||
|
||||
tmp := r.mPool.Get().([]byte)
|
||||
defer func(b []byte) {
|
||||
r.mPool.Put(b)
|
||||
}(tmp)
|
||||
|
||||
// Flips between input first to output first.
|
||||
// We put the smallest data load in the inner loop.
|
||||
if len(inputs) > len(outputs) {
|
||||
inIdx := 0
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
// Generate local matrix
|
||||
m := genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), tmp)
|
||||
tmp = tmp[len(m):]
|
||||
plan = append(plan, state{
|
||||
input: inPer,
|
||||
output: outPer,
|
||||
m: m,
|
||||
first: inIdx == 0,
|
||||
})
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
} else {
|
||||
outs := outputs
|
||||
outIdx := 0
|
||||
for len(outs) > 0 {
|
||||
outPer := outs
|
||||
if len(outPer) > maxAvx2Outputs {
|
||||
outPer = outPer[:maxAvx2Outputs]
|
||||
}
|
||||
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
inIdx := 0
|
||||
ins := inputs
|
||||
for len(ins) > 0 {
|
||||
inPer := ins
|
||||
if len(inPer) > maxAvx2Inputs {
|
||||
inPer = inPer[:maxAvx2Inputs]
|
||||
}
|
||||
// Generate local matrix
|
||||
m := genAvx2Matrix(matrixRows[outIdx:], len(inPer), inIdx, len(outPer), tmp)
|
||||
tmp = tmp[len(m):]
|
||||
//fmt.Println("bytes:", len(inPer)*r.o.perRound, "out:", len(outPer)*r.o.perRound)
|
||||
plan = append(plan, state{
|
||||
input: inPer,
|
||||
output: outPer,
|
||||
m: m,
|
||||
first: inIdx == 0,
|
||||
})
|
||||
inIdx += len(inPer)
|
||||
ins = ins[len(inPer):]
|
||||
}
|
||||
outIdx += len(outPer)
|
||||
outs = outs[len(outPer):]
|
||||
}
|
||||
}
|
||||
|
||||
do := byteCount / gor
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
|
||||
exec := func(start, stop int) {
|
||||
lstart, lstop := start, start+r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
if lstop-lstart >= minAvx2Size {
|
||||
// Execute plan...
|
||||
for _, p := range plan {
|
||||
if p.first {
|
||||
galMulSlicesAvx2(p.m, p.input, p.output, lstart, lstop)
|
||||
} else {
|
||||
galMulSlicesAvx2Xor(p.m, p.input, p.output, lstart, lstop)
|
||||
}
|
||||
}
|
||||
lstart += (lstop - lstart) & avxSizeMask
|
||||
if lstart == lstop {
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for c := range inputs {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < len(outputs); iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
for lstart < stop {
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
in := inputs[c][lstart:lstop]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
if c == 0 {
|
||||
galMulSlice(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
} else {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow][lstart:lstop], &r.o)
|
||||
}
|
||||
}
|
||||
}
|
||||
lstart = lstop
|
||||
lstop += r.o.perRound
|
||||
if lstop > stop {
|
||||
lstop = stop
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}(start, start+do)
|
||||
}
|
||||
wg.Done()
|
||||
}
|
||||
if gor == 1 {
|
||||
wg.Add(1)
|
||||
exec(0, byteCount)
|
||||
return
|
||||
}
|
||||
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go exec(start, start+do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
@@ -604,20 +940,16 @@ func (r *reedSolomon) codeSomeShardsP(matrixRows, inputs, outputs [][]byte, outp
|
||||
// checkSomeShards is mostly the same as codeSomeShards,
|
||||
// except this will check values and return
|
||||
// as soon as a difference is found.
|
||||
func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, outputCount, byteCount int) bool {
|
||||
if r.o.maxGoroutines > 1 && byteCount > r.o.minSplitSize {
|
||||
return r.checkSomeShardsP(matrixRows, inputs, toCheck, outputCount, byteCount)
|
||||
func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, byteCount int) bool {
|
||||
if len(toCheck) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
outputs := make([][]byte, len(toCheck))
|
||||
for i := range outputs {
|
||||
outputs[i] = make([]byte, byteCount)
|
||||
}
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
in := inputs[c]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow], &r.o)
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, inputs, outputs, byteCount)
|
||||
|
||||
for i, calc := range outputs {
|
||||
if !bytes.Equal(calc, toCheck[i]) {
|
||||
@@ -627,57 +959,6 @@ func (r *reedSolomon) checkSomeShards(matrixRows, inputs, toCheck [][]byte, outp
|
||||
return true
|
||||
}
|
||||
|
||||
func (r *reedSolomon) checkSomeShardsP(matrixRows, inputs, toCheck [][]byte, outputCount, byteCount int) bool {
|
||||
same := true
|
||||
var mu sync.RWMutex // For above
|
||||
|
||||
var wg sync.WaitGroup
|
||||
do := byteCount / r.o.maxGoroutines
|
||||
if do < r.o.minSplitSize {
|
||||
do = r.o.minSplitSize
|
||||
}
|
||||
// Make sizes divisible by 64
|
||||
do = (do + 63) & (^63)
|
||||
start := 0
|
||||
for start < byteCount {
|
||||
if start+do > byteCount {
|
||||
do = byteCount - start
|
||||
}
|
||||
wg.Add(1)
|
||||
go func(start, do int) {
|
||||
defer wg.Done()
|
||||
outputs := make([][]byte, len(toCheck))
|
||||
for i := range outputs {
|
||||
outputs[i] = make([]byte, do)
|
||||
}
|
||||
for c := 0; c < r.DataShards; c++ {
|
||||
mu.RLock()
|
||||
if !same {
|
||||
mu.RUnlock()
|
||||
return
|
||||
}
|
||||
mu.RUnlock()
|
||||
in := inputs[c][start : start+do]
|
||||
for iRow := 0; iRow < outputCount; iRow++ {
|
||||
galMulSliceXor(matrixRows[iRow][c], in, outputs[iRow], &r.o)
|
||||
}
|
||||
}
|
||||
|
||||
for i, calc := range outputs {
|
||||
if !bytes.Equal(calc, toCheck[i][start:start+do]) {
|
||||
mu.Lock()
|
||||
same = false
|
||||
mu.Unlock()
|
||||
return
|
||||
}
|
||||
}
|
||||
}(start, do)
|
||||
start += do
|
||||
}
|
||||
wg.Wait()
|
||||
return same
|
||||
}
|
||||
|
||||
// ErrShardNoData will be returned if there are no shards,
|
||||
// or if the length of all shards is zero.
|
||||
var ErrShardNoData = errors.New("no shard data")
|
||||
@@ -732,7 +1013,7 @@ func shardSize(shards [][]byte) int {
|
||||
// The reconstructed shard set is complete, but integrity is not verified.
|
||||
// Use the Verify function to check if data set is ok.
|
||||
func (r *reedSolomon) Reconstruct(shards [][]byte) error {
|
||||
return r.reconstruct(shards, false)
|
||||
return r.reconstruct(shards, false, nil)
|
||||
}
|
||||
|
||||
// ReconstructData will recreate any missing data shards, if possible.
|
||||
@@ -751,19 +1032,39 @@ func (r *reedSolomon) Reconstruct(shards [][]byte) error {
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
func (r *reedSolomon) ReconstructData(shards [][]byte) error {
|
||||
return r.reconstruct(shards, true)
|
||||
return r.reconstruct(shards, true, nil)
|
||||
}
|
||||
|
||||
// ReconstructSome will recreate only requested data shards, if possible.
|
||||
//
|
||||
// Given a list of shards, some of which contain data, fills in the
|
||||
// data shards indicated by true values in the "required" parameter.
|
||||
// The length of "required" array must be equal to DataShards.
|
||||
//
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil or zero-length.
|
||||
// If a shard is zero-length but has sufficient capacity, that memory will
|
||||
// be used, otherwise a new []byte will be allocated.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
//
|
||||
// As the reconstructed shard set may contain missing parity shards,
|
||||
// calling the Verify function is likely to fail.
|
||||
func (r *reedSolomon) ReconstructSome(shards [][]byte, required []bool) error {
|
||||
return r.reconstruct(shards, true, required)
|
||||
}
|
||||
|
||||
// reconstruct will recreate the missing data shards, and unless
|
||||
// dataOnly is true, also the missing parity shards
|
||||
//
|
||||
// The length of the array must be equal to Shards.
|
||||
// The length of "shards" array must be equal to Shards.
|
||||
// You indicate that a shard is missing by setting it to nil.
|
||||
//
|
||||
// If there are too few shards to reconstruct the missing
|
||||
// ones, ErrTooFewShards will be returned.
|
||||
func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
if len(shards) != r.Shards {
|
||||
func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool, required []bool) error {
|
||||
if len(shards) != r.Shards || required != nil && len(required) < r.DataShards {
|
||||
return ErrTooFewShards
|
||||
}
|
||||
// Check arguments.
|
||||
@@ -778,15 +1079,19 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
// nothing to do.
|
||||
numberPresent := 0
|
||||
dataPresent := 0
|
||||
missingRequired := 0
|
||||
for i := 0; i < r.Shards; i++ {
|
||||
if len(shards[i]) != 0 {
|
||||
numberPresent++
|
||||
if i < r.DataShards {
|
||||
dataPresent++
|
||||
}
|
||||
} else if required != nil && required[i] {
|
||||
missingRequired++
|
||||
}
|
||||
}
|
||||
if numberPresent == r.Shards || dataOnly && dataPresent == r.DataShards {
|
||||
if numberPresent == r.Shards || dataOnly && dataPresent == r.DataShards ||
|
||||
required != nil && missingRequired == 0 {
|
||||
// Cool. All of the shards data data. We don't
|
||||
// need to do anything.
|
||||
return nil
|
||||
@@ -864,7 +1169,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount := 0
|
||||
|
||||
for iShard := 0; iShard < r.DataShards; iShard++ {
|
||||
if len(shards[iShard]) == 0 {
|
||||
if len(shards[iShard]) == 0 && (required == nil || required[iShard]) {
|
||||
if cap(shards[iShard]) >= shardSize {
|
||||
shards[iShard] = shards[iShard][0:shardSize]
|
||||
} else {
|
||||
@@ -875,7 +1180,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount++
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, subShards, outputs[:outputCount], outputCount, shardSize)
|
||||
r.codeSomeShards(matrixRows, subShards, outputs[:outputCount], shardSize)
|
||||
|
||||
if dataOnly {
|
||||
// Exit out early if we are only interested in the data shards
|
||||
@@ -890,7 +1195,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
// data shards were missing.
|
||||
outputCount = 0
|
||||
for iShard := r.DataShards; iShard < r.Shards; iShard++ {
|
||||
if len(shards[iShard]) == 0 {
|
||||
if len(shards[iShard]) == 0 && (required == nil || required[iShard]) {
|
||||
if cap(shards[iShard]) >= shardSize {
|
||||
shards[iShard] = shards[iShard][0:shardSize]
|
||||
} else {
|
||||
@@ -901,7 +1206,7 @@ func (r *reedSolomon) reconstruct(shards [][]byte, dataOnly bool) error {
|
||||
outputCount++
|
||||
}
|
||||
}
|
||||
r.codeSomeShards(matrixRows, shards[:r.DataShards], outputs[:outputCount], outputCount, shardSize)
|
||||
r.codeSomeShards(matrixRows, shards[:r.DataShards], outputs[:outputCount], shardSize)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -925,6 +1230,7 @@ func (r *reedSolomon) Split(data []byte) ([][]byte, error) {
|
||||
if len(data) == 0 {
|
||||
return nil, ErrShortData
|
||||
}
|
||||
dataLen := len(data)
|
||||
// Calculate number of bytes per data shard.
|
||||
perShard := (len(data) + r.DataShards - 1) / r.DataShards
|
||||
|
||||
@@ -940,6 +1246,10 @@ func (r *reedSolomon) Split(data []byte) ([][]byte, error) {
|
||||
padding = make([]byte, r.Shards*perShard-perShard*fullShards)
|
||||
copy(padding, data[perShard*fullShards:])
|
||||
data = data[0 : perShard*fullShards]
|
||||
} else {
|
||||
for i := dataLen; i < dataLen+r.DataShards; i++ {
|
||||
data[i] = 0
|
||||
}
|
||||
}
|
||||
|
||||
// Split into equal-length shards.
|
||||
|
||||
+242
-101
@@ -12,29 +12,23 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
sm4 acceration
|
||||
sm4 acceleration
|
||||
modified by Jack, 2017 Oct
|
||||
*/
|
||||
|
||||
package sm4
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const BlockSize = 16
|
||||
|
||||
var IV=make([]byte,BlockSize)
|
||||
type SM4Key []byte
|
||||
|
||||
type KeySizeError int
|
||||
|
||||
// Cipher is an instance of SM4 encryption.
|
||||
type Sm4Cipher struct {
|
||||
subkeys []uint32
|
||||
@@ -234,101 +228,10 @@ func generateSubKeys(key []byte) []uint32 {
|
||||
return subkeys
|
||||
}
|
||||
|
||||
func EncryptBlock(key SM4Key, dst, src []byte) {
|
||||
subkeys := generateSubKeys(key)
|
||||
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, false)
|
||||
}
|
||||
|
||||
func DecryptBlock(key SM4Key, dst, src []byte) {
|
||||
subkeys := generateSubKeys(key)
|
||||
cryptBlock(subkeys, make([]uint32, 4), make([]byte, 16), dst, src, true)
|
||||
}
|
||||
|
||||
func ReadKeyFromMem(data []byte, pwd []byte) (SM4Key, error) {
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, errors.New("SM4: pem decode failed")
|
||||
}
|
||||
if x509.IsEncryptedPEMBlock(block) {
|
||||
if block.Type != "SM4 ENCRYPTED KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
if pwd == nil {
|
||||
return nil, errors.New("SM4: need passwd")
|
||||
}
|
||||
data, err := x509.DecryptPEMBlock(block, pwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
if block.Type != "SM4 KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
return block.Bytes, nil
|
||||
}
|
||||
|
||||
func ReadKeyFromPem(FileName string, pwd []byte) (SM4Key, error) {
|
||||
data, err := ioutil.ReadFile(FileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadKeyFromMem(data, pwd)
|
||||
}
|
||||
|
||||
func WriteKeytoMem(key SM4Key, pwd []byte) ([]byte, error) {
|
||||
if pwd != nil {
|
||||
block, err := x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
} else {
|
||||
block := &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
}
|
||||
|
||||
func WriteKeyToPem(FileName string, key SM4Key, pwd []byte) (bool, error) {
|
||||
var block *pem.Block
|
||||
|
||||
if pwd != nil {
|
||||
var err error
|
||||
block, err = x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
}
|
||||
file, err := os.Create(FileName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
defer file.Close()
|
||||
err = pem.Encode(file, block)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (k KeySizeError) Error() string {
|
||||
return "SM4: invalid key size " + strconv.Itoa(int(k))
|
||||
}
|
||||
|
||||
// NewCipher creates and returns a new cipher.Block.
|
||||
func NewCipher(key []byte) (cipher.Block, error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, KeySizeError(len(key))
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
c := new(Sm4Cipher)
|
||||
c.subkeys = generateSubKeys(key)
|
||||
@@ -345,6 +248,244 @@ func (c *Sm4Cipher) Encrypt(dst, src []byte) {
|
||||
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, false)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func (c *Sm4Cipher) Decrypt(dst, src []byte) {
|
||||
cryptBlock(c.subkeys, c.block1, c.block2, dst, src, true)
|
||||
}
|
||||
|
||||
|
||||
|
||||
func xor(in, iv []byte) (out []byte) {
|
||||
if len(in) != len(iv) {
|
||||
return nil
|
||||
}
|
||||
|
||||
out = make([]byte, len(in))
|
||||
for i := 0; i < len(in); i++ {
|
||||
out[i] = in[i] ^ iv[i]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func pkcs7Padding(src []byte) []byte {
|
||||
padding := BlockSize - len(src)%BlockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padtext...)
|
||||
}
|
||||
|
||||
func pkcs7UnPadding(src []byte) ([]byte, error) {
|
||||
length := len(src)
|
||||
unpadding := int(src[length-1])
|
||||
if unpadding > BlockSize || unpadding == 0 {
|
||||
return nil, errors.New("Invalid pkcs7 padding (unpadding > BlockSize || unpadding == 0)")
|
||||
}
|
||||
|
||||
pad := src[len(src)-unpadding:]
|
||||
for i := 0; i < unpadding; i++ {
|
||||
if pad[i] != byte(unpadding) {
|
||||
return nil, errors.New("Invalid pkcs7 padding (pad[i] != unpadding)")
|
||||
}
|
||||
}
|
||||
|
||||
return src[:(length - unpadding)], nil
|
||||
}
|
||||
func SetIV(iv []byte)error{
|
||||
if len(iv)!=BlockSize{
|
||||
return errors.New("SM4: invalid iv size")
|
||||
}
|
||||
IV=iv
|
||||
return nil
|
||||
}
|
||||
|
||||
func Sm4Cbc(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
iv:=make([]byte,BlockSize)
|
||||
copy(iv,IV)
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mode {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := xor(inData[i*16:i*16+16], iv)
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Encrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
iv = out_tmp
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Decrypt(out_tmp, in_tmp)
|
||||
out_tmp = xor(out_tmp, iv)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
iv = in_tmp
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
func Sm4Ecb(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if mode {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Encrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
in_tmp := inData[i*16 : i*16+16]
|
||||
out_tmp := make([]byte, 16)
|
||||
c.Decrypt(out_tmp, in_tmp)
|
||||
copy(out[i*16:i*16+16], out_tmp)
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
//密码反馈模式(Cipher FeedBack (CFB))
|
||||
//https://blog.csdn.net/zy_strive_2012/article/details/102520356
|
||||
//https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func Sm4CFB(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
K := make([]byte, BlockSize)
|
||||
cipherBlock := make([]byte, BlockSize)
|
||||
plainBlock := make([]byte, BlockSize)
|
||||
if mode { //加密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
//copy(cipherBlock,out_tmp)
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, cipherBlock)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
//copy(cipherBlock,out_tmp)
|
||||
}
|
||||
|
||||
} else { //解密
|
||||
var i int = 0
|
||||
for ; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV) //这里是加密,而不是调用解密方法Decrypt
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, inData[(i-1)*16:(i-1)*16+16])
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
|
||||
}
|
||||
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
//输出反馈模式(Output feedback, OFB)
|
||||
//https://blog.csdn.net/chengqiuming/article/details/82390910
|
||||
//https://blog.csdn.net/sinat_23338865/article/details/72869841
|
||||
func Sm4OFB(key []byte, in []byte, mode bool) (out []byte, err error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
var inData []byte
|
||||
if mode {
|
||||
inData = pkcs7Padding(in)
|
||||
} else {
|
||||
inData = in
|
||||
}
|
||||
|
||||
out = make([]byte, len(inData))
|
||||
c, err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
K := make([]byte, BlockSize)
|
||||
cipherBlock := make([]byte, BlockSize)
|
||||
plainBlock := make([]byte, BlockSize)
|
||||
shiftIV := make([]byte, BlockSize)
|
||||
if mode { //加密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, shiftIV)
|
||||
cipherBlock = xor(K[:BlockSize], inData[i*16:i*16+16])
|
||||
copy(out[i*16:i*16+16], cipherBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
}
|
||||
|
||||
} else { //解密
|
||||
for i := 0; i < len(inData)/16; i++ {
|
||||
if i == 0 {
|
||||
c.Encrypt(K, IV) //这里是加密,而不是调用解密方法Decrypt
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
continue
|
||||
}
|
||||
c.Encrypt(K, shiftIV)
|
||||
plainBlock = xor(K[:BlockSize], inData[i*16:i*16+16]) //获取明文分组
|
||||
copy(out[i*16:i*16+16], plainBlock)
|
||||
copy(shiftIV, K[:BlockSize])
|
||||
}
|
||||
out, _ = pkcs7UnPadding(out)
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
Copyright Hyperledger-TWGC All Rights Reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
writed by Zhiwei Yan, 2020 Oct
|
||||
*/
|
||||
package sm4
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
//Paper: The Galois/Counter Mode of Operation (GCM) David A. Mcgrew,John Viega .2004.
|
||||
func Sm4GCM(key []byte, IV ,in, A []byte, mode bool) ([]byte, []byte, error) {
|
||||
if len(key) != BlockSize {
|
||||
return nil,nil, errors.New("SM4: invalid key size " + strconv.Itoa(len(key)))
|
||||
}
|
||||
if mode {
|
||||
C,T:=GCMEncrypt(key,IV,in,A)
|
||||
return C,T,nil
|
||||
}else{
|
||||
P,_T:=GCMDecrypt(key,IV,in,A)
|
||||
return P,_T,nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetH(key []byte) (H []byte){
|
||||
c,err := NewCipher(key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
zores:=make([]byte, BlockSize)
|
||||
H =make([]byte, BlockSize)
|
||||
c.Encrypt(H,zores)
|
||||
return H
|
||||
}
|
||||
|
||||
//ut = a + b
|
||||
func addition(a ,b []byte) (out []byte){
|
||||
Len:=len(a)
|
||||
if Len != len(b) {
|
||||
return nil
|
||||
}
|
||||
out = make([]byte, Len)
|
||||
for i := 0; i < Len; i++ {
|
||||
out[i] = a[i] ^ b[i]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func Rightshift(V []byte){
|
||||
n:=len(V)
|
||||
for i:=n-1;i>=0;i-- {
|
||||
V[i]=V[i]>>1
|
||||
if i!=0{
|
||||
V[i]=((V[i-1]&0x01)<<7)|V[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func findYi( Y []byte,index int) int{
|
||||
var temp byte
|
||||
i := uint(index)
|
||||
temp=Y[i/8]
|
||||
temp=temp>>(7-i%8)
|
||||
if temp & 0x01 == 1{
|
||||
return 1
|
||||
}else{
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func multiplication(X,Y []byte) (Z []byte){
|
||||
|
||||
R:=make([]byte,BlockSize)
|
||||
R[0]=0xe1
|
||||
Z=make([]byte,BlockSize)
|
||||
V:=make([]byte,BlockSize)
|
||||
copy(V,X)
|
||||
for i:=0;i<=127;i++{
|
||||
if findYi(Y,i)==1{
|
||||
Z=addition(Z,V)
|
||||
}
|
||||
if V[BlockSize-1]&0x01==0{
|
||||
Rightshift(V)
|
||||
}else{
|
||||
Rightshift(V)
|
||||
V=addition(V,R)
|
||||
}
|
||||
}
|
||||
return Z
|
||||
}
|
||||
|
||||
func GHASH(H []byte,A []byte,C []byte) (X[]byte){
|
||||
|
||||
calculm_v:=func(m ,v int) (int,int) {
|
||||
if(m==0 && v!=0){
|
||||
m=1
|
||||
v=v*8
|
||||
}else if(m!=0 && v==0) {
|
||||
v=BlockSize*8
|
||||
}else if(m!=0 && v!=0){
|
||||
m=m+1
|
||||
v=v*8
|
||||
}else { //m==0 && v==0
|
||||
m=1
|
||||
v=0
|
||||
}
|
||||
return m,v
|
||||
}
|
||||
m:=len(A)/BlockSize
|
||||
v:=len(A)%BlockSize
|
||||
m,v=calculm_v(m,v)
|
||||
|
||||
n:=len(C)/BlockSize
|
||||
u:=(len(C)%BlockSize)
|
||||
n,u=calculm_v(n,u)
|
||||
|
||||
//i=0
|
||||
X=make([]byte,BlockSize*(m+n+2)) //X0 = 0
|
||||
for i:=0;i<BlockSize;i++{
|
||||
X[i]=0x00
|
||||
}
|
||||
|
||||
//i=1...m-1
|
||||
for i:=1;i<=m-1;i++{
|
||||
copy(X[i*BlockSize:i*BlockSize+BlockSize],multiplication(addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],A[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize]),H)) //A 1-->m-1 对于数组来说是 0-->m-2
|
||||
}
|
||||
|
||||
//i=m
|
||||
zeros:=make([]byte,(128-v)/8)
|
||||
Am:=make([]byte,v/8)
|
||||
copy(Am[:],A[(m-1)*BlockSize:])
|
||||
Am=append(Am,zeros...)
|
||||
copy(X[m*BlockSize:m*BlockSize+BlockSize],multiplication( addition(X[(m-1)*BlockSize:(m-1)*BlockSize+BlockSize],Am),H))
|
||||
|
||||
//i=m+1...m+n-1
|
||||
for i:=m+1;i<=(m+n-1);i++{
|
||||
copy(X[i*BlockSize:i*BlockSize+BlockSize],multiplication( addition(X[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],C[(i-m-1)*BlockSize:(i-m-1)*BlockSize+BlockSize]),H))
|
||||
}
|
||||
|
||||
//i=m+n
|
||||
zeros =make([]byte,(128-u)/8)
|
||||
Cn:=make([]byte,u/8)
|
||||
copy(Cn[:],C[(n-1)*BlockSize:])
|
||||
Cn=append(Cn,zeros...)
|
||||
copy(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize],multiplication( addition(X[(m+n-1)*BlockSize:(m+n-1)*BlockSize+BlockSize],Cn),H))
|
||||
|
||||
//i=m+n+1
|
||||
var lenAB []byte
|
||||
calculateLenToBytes :=func(len int) []byte{
|
||||
data:=make([]byte,8)
|
||||
data[0]=byte((len>>56)&0xff)
|
||||
data[1]=byte((len>>48)&0xff)
|
||||
data[2]=byte((len>>40)&0xff)
|
||||
data[3]=byte((len>>32)&0xff)
|
||||
data[4]=byte((len>>24)&0xff)
|
||||
data[5]=byte((len>>16)&0xff)
|
||||
data[6]=byte((len>>8)&0xff)
|
||||
data[7]=byte((len>>0)&0xff)
|
||||
return data
|
||||
}
|
||||
lenAB=append(lenAB,calculateLenToBytes(len(A))...)
|
||||
lenAB=append(lenAB,calculateLenToBytes(len(C))...)
|
||||
copy(X[(m+n+1)*BlockSize:(m+n+1)*BlockSize+BlockSize],multiplication(addition(X[(m+n)*BlockSize:(m+n)*BlockSize+BlockSize],lenAB),H))
|
||||
return X[(m+n+1)*BlockSize:(m+n+1)*BlockSize+BlockSize]
|
||||
}
|
||||
|
||||
|
||||
func GetY0(H,IV []byte) []byte{
|
||||
if len(IV)*8 == 96 {
|
||||
zero31one1:=[]byte{0x00,0x00,0x00,0x01}
|
||||
IV=append(IV,zero31one1...)
|
||||
return IV
|
||||
}else{
|
||||
return GHASH(H,[]byte{},IV)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func incr(n int ,Y_i []byte) (Y_ii []byte) {
|
||||
|
||||
Y_ii=make([]byte,BlockSize*n)
|
||||
copy(Y_ii,Y_i)
|
||||
|
||||
addYone:=func(yi,yii []byte){
|
||||
copy(yii[:],yi[:])
|
||||
|
||||
Len:=len(yi)
|
||||
var rc byte=0x00
|
||||
for i:=Len-1;i>=0;i--{
|
||||
if(i==Len-1){
|
||||
if(yii[i]<0xff){
|
||||
yii[i]=yii[i]+0x01
|
||||
rc=0x00
|
||||
}else{
|
||||
yii[i]=0x00
|
||||
rc=0x01
|
||||
}
|
||||
}else{
|
||||
if yii[i]+rc<0xff {
|
||||
yii[i]=yii[i]+rc
|
||||
rc=0x00
|
||||
}else{
|
||||
yii[i]=0x00
|
||||
rc=0x01
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i:=1;i<n;i++{ //2^32
|
||||
addYone(Y_ii[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],Y_ii[i*BlockSize:i*BlockSize+BlockSize])
|
||||
}
|
||||
return Y_ii
|
||||
}
|
||||
|
||||
func MSB(len int, S []byte) (out []byte){
|
||||
return S[:len/8]
|
||||
}
|
||||
func GCMEncrypt(K,IV,P,A []byte) (C,T []byte){
|
||||
calculm_v:=func(m ,v int) (int,int) {
|
||||
if(m==0 && v!=0){
|
||||
m=1
|
||||
v=v*8
|
||||
}else if(m!=0 && v==0) {
|
||||
v=BlockSize*8
|
||||
}else if(m!=0 && v!=0){
|
||||
m=m+1
|
||||
v=v*8
|
||||
}else { //m==0 && v==0
|
||||
m=1
|
||||
v=0
|
||||
}
|
||||
return m,v
|
||||
}
|
||||
n:=len(P)/BlockSize
|
||||
u:=len(P)%BlockSize
|
||||
n,u=calculm_v(n,u)
|
||||
|
||||
H:=GetH(K)
|
||||
|
||||
Y0:=GetY0(H,IV)
|
||||
|
||||
Y:=make([]byte,BlockSize*(n+1))
|
||||
Y=incr(n+1,Y0)
|
||||
c,err := NewCipher(K)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
Enc:=make([]byte,BlockSize)
|
||||
C =make([]byte,len(P))
|
||||
|
||||
//i=1...n-1
|
||||
for i:=1;i<=n-1;i++{
|
||||
c.Encrypt(Enc,Y[i*BlockSize:i*BlockSize+BlockSize])
|
||||
|
||||
copy(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],addition(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],Enc))
|
||||
}
|
||||
|
||||
//i=n
|
||||
c.Encrypt(Enc,Y[n*BlockSize:n*BlockSize+BlockSize])
|
||||
out:=MSB(u,Enc)
|
||||
copy(C[(n-1)*BlockSize:],addition(P[(n-1)*BlockSize:],out))
|
||||
|
||||
c.Encrypt(Enc,Y0)
|
||||
|
||||
t:=128
|
||||
T =MSB(t,addition(Enc,GHASH(H,A,C)))
|
||||
return C,T
|
||||
}
|
||||
|
||||
func GCMDecrypt(K,IV,C,A []byte)(P,_T []byte){
|
||||
calculm_v:=func(m ,v int) (int,int) {
|
||||
if(m==0 && v!=0){
|
||||
m=1
|
||||
v=v*8
|
||||
}else if(m!=0 && v==0) {
|
||||
v=BlockSize*8
|
||||
}else if(m!=0 && v!=0){
|
||||
m=m+1
|
||||
v=v*8
|
||||
}else { //m==0 && v==0
|
||||
m=1
|
||||
v=0
|
||||
}
|
||||
return m,v
|
||||
}
|
||||
|
||||
H:=GetH(K)
|
||||
|
||||
Y0:=GetY0(H,IV)
|
||||
|
||||
Enc:=make([]byte,BlockSize)
|
||||
c,err := NewCipher(K)
|
||||
if err != nil{
|
||||
panic(err)
|
||||
}
|
||||
c.Encrypt(Enc,Y0)
|
||||
t:=128
|
||||
_T=MSB(t,addition(Enc,GHASH(H,A,C)))
|
||||
|
||||
n:=len(C)/BlockSize
|
||||
u:=len(C)%BlockSize
|
||||
n,u=calculm_v(n,u)
|
||||
Y:=make([]byte,BlockSize*(n+1))
|
||||
Y=incr(n+1,Y0)
|
||||
|
||||
P = make([]byte, BlockSize*n)
|
||||
for i:=1;i<=n;i++{
|
||||
c.Encrypt(Enc,Y[i*BlockSize:i*BlockSize+BlockSize])
|
||||
copy(P[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],addition(C[(i-1)*BlockSize:(i-1)*BlockSize+BlockSize],Enc))
|
||||
}
|
||||
|
||||
c.Encrypt(Enc,Y[n*BlockSize:n*BlockSize+BlockSize])
|
||||
out:=MSB(u,Enc)
|
||||
copy(P[(n-1)*BlockSize:],addition(C[(n-1)*BlockSize:],out))
|
||||
|
||||
return P,_T
|
||||
}
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
package sm4
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
)
|
||||
|
||||
// ReadKeyFromPem will return SM4Key from PEM format data.
|
||||
func ReadKeyFromPem(data []byte, pwd []byte) (SM4Key, error) {
|
||||
block, _ := pem.Decode(data)
|
||||
if block == nil {
|
||||
return nil, errors.New("SM4: pem decode failed")
|
||||
}
|
||||
if x509.IsEncryptedPEMBlock(block) {
|
||||
if block.Type != "SM4 ENCRYPTED KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
if pwd == nil {
|
||||
return nil, errors.New("SM4: need passwd")
|
||||
}
|
||||
data, err := x509.DecryptPEMBlock(block, pwd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
if block.Type != "SM4 KEY" {
|
||||
return nil, errors.New("SM4: unknown type")
|
||||
}
|
||||
return block.Bytes, nil
|
||||
}
|
||||
|
||||
// ReadKeyFromPemFile will return SM4Key from filename that saved PEM format data.
|
||||
func ReadKeyFromPemFile(FileName string, pwd []byte) (SM4Key, error) {
|
||||
data, err := ioutil.ReadFile(FileName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ReadKeyFromPem(data, pwd)
|
||||
}
|
||||
|
||||
// WriteKeyToPem will convert SM4Key to PEM format data and return it.
|
||||
func WriteKeyToPem(key SM4Key, pwd []byte) ([]byte, error) {
|
||||
if pwd != nil {
|
||||
block, err := x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256) //Use AES256 algorithms to encrypt SM4KEY
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
} else {
|
||||
block := &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
return pem.EncodeToMemory(block), nil
|
||||
}
|
||||
}
|
||||
|
||||
// WriteKeyToPemFile will convert SM4Key to PEM format data, then write it
|
||||
// into the input filename.
|
||||
func WriteKeyToPemFile(FileName string, key SM4Key, pwd []byte) error {
|
||||
var block *pem.Block
|
||||
var err error
|
||||
if pwd != nil {
|
||||
block, err = x509.EncryptPEMBlock(rand.Reader,
|
||||
"SM4 ENCRYPTED KEY", key, pwd, x509.PEMCipherAES256)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
block = &pem.Block{
|
||||
Type: "SM4 KEY",
|
||||
Bytes: key,
|
||||
}
|
||||
}
|
||||
pemBytes := pem.EncodeToMemory(block)
|
||||
err = ioutil.WriteFile(FileName, pemBytes, 0666)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ install:
|
||||
- go get github.com/xtaci/kcp-go
|
||||
|
||||
script:
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic -bench .
|
||||
- go test -coverprofile=coverage.txt -covermode=atomic -bench . -timeout 10m
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
package kcp
|
||||
|
||||
const maxAutoTuneSamples = 258
|
||||
|
||||
// pulse represents a 0/1 signal with time sequence
|
||||
type pulse struct {
|
||||
bit bool // 0 or 1
|
||||
seq uint32 // sequence of the signal
|
||||
}
|
||||
|
||||
// autoTune object
|
||||
type autoTune struct {
|
||||
pulses [maxAutoTuneSamples]pulse
|
||||
}
|
||||
|
||||
// Sample adds a signal sample to the pulse buffer
|
||||
func (tune *autoTune) Sample(bit bool, seq uint32) {
|
||||
tune.pulses[seq%maxAutoTuneSamples] = pulse{bit, seq}
|
||||
}
|
||||
|
||||
// Find a period for a given signal
|
||||
// returns -1 if not found
|
||||
//
|
||||
// --- ------
|
||||
// | |
|
||||
// |______________|
|
||||
// Period
|
||||
// Falling Edge Rising Edge
|
||||
func (tune *autoTune) FindPeriod(bit bool) int {
|
||||
// last pulse and initial index setup
|
||||
lastPulse := tune.pulses[0]
|
||||
idx := 1
|
||||
|
||||
// left edge
|
||||
var leftEdge int
|
||||
for ; idx < len(tune.pulses); idx++ {
|
||||
if lastPulse.bit != bit && tune.pulses[idx].bit == bit { // edge found
|
||||
if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure edge continuity
|
||||
leftEdge = idx
|
||||
break
|
||||
}
|
||||
}
|
||||
lastPulse = tune.pulses[idx]
|
||||
}
|
||||
|
||||
// right edge
|
||||
var rightEdge int
|
||||
lastPulse = tune.pulses[leftEdge]
|
||||
idx = leftEdge + 1
|
||||
|
||||
for ; idx < len(tune.pulses); idx++ {
|
||||
if lastPulse.seq+1 == tune.pulses[idx].seq { // ensure pulses in this level monotonic
|
||||
if lastPulse.bit == bit && tune.pulses[idx].bit != bit { // edge found
|
||||
rightEdge = idx
|
||||
break
|
||||
}
|
||||
} else {
|
||||
return -1
|
||||
}
|
||||
lastPulse = tune.pulses[idx]
|
||||
}
|
||||
|
||||
return rightEdge - leftEdge
|
||||
}
|
||||
+49
-5
@@ -13,6 +13,7 @@ const (
|
||||
typeData = 0xf1
|
||||
typeParity = 0xf2
|
||||
fecExpire = 60000
|
||||
rxFECMulti = 3 // FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
|
||||
)
|
||||
|
||||
// fecPacket is a decoded FEC packet
|
||||
@@ -45,21 +46,21 @@ type fecDecoder struct {
|
||||
|
||||
// RS decoder
|
||||
codec reedsolomon.Encoder
|
||||
|
||||
// auto tune fec parameter
|
||||
autoTune autoTune
|
||||
}
|
||||
|
||||
func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder {
|
||||
func newFECDecoder(dataShards, parityShards int) *fecDecoder {
|
||||
if dataShards <= 0 || parityShards <= 0 {
|
||||
return nil
|
||||
}
|
||||
if rxlimit < dataShards+parityShards {
|
||||
return nil
|
||||
}
|
||||
|
||||
dec := new(fecDecoder)
|
||||
dec.rxlimit = rxlimit
|
||||
dec.dataShards = dataShards
|
||||
dec.parityShards = parityShards
|
||||
dec.shardSize = dataShards + parityShards
|
||||
dec.rxlimit = rxFECMulti * dec.shardSize
|
||||
codec, err := reedsolomon.New(dataShards, parityShards)
|
||||
if err != nil {
|
||||
return nil
|
||||
@@ -73,6 +74,49 @@ func newFECDecoder(rxlimit, dataShards, parityShards int) *fecDecoder {
|
||||
|
||||
// decode a fec packet
|
||||
func (dec *fecDecoder) decode(in fecPacket) (recovered [][]byte) {
|
||||
// sample to auto FEC tuner
|
||||
if in.flag() == typeData {
|
||||
dec.autoTune.Sample(true, in.seqid())
|
||||
} else {
|
||||
dec.autoTune.Sample(false, in.seqid())
|
||||
}
|
||||
|
||||
// check if FEC parameters is out of sync
|
||||
var shouldTune bool
|
||||
if int(in.seqid())%dec.shardSize < dec.dataShards {
|
||||
if in.flag() != typeData { // expect typeData
|
||||
shouldTune = true
|
||||
}
|
||||
} else {
|
||||
if in.flag() != typeParity {
|
||||
shouldTune = true
|
||||
}
|
||||
}
|
||||
|
||||
if shouldTune {
|
||||
autoDS := dec.autoTune.FindPeriod(true)
|
||||
autoPS := dec.autoTune.FindPeriod(false)
|
||||
|
||||
// edges found, we can tune parameters now
|
||||
if autoDS > 0 && autoPS > 0 && autoDS < 256 && autoPS < 256 {
|
||||
// and make sure it's different
|
||||
if autoDS != dec.dataShards || autoPS != dec.parityShards {
|
||||
dec.dataShards = autoDS
|
||||
dec.parityShards = autoPS
|
||||
dec.shardSize = autoDS + autoPS
|
||||
dec.rxlimit = rxFECMulti * dec.shardSize
|
||||
codec, err := reedsolomon.New(autoDS, autoPS)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
dec.codec = codec
|
||||
dec.decodeCache = make([][]byte, dec.shardSize)
|
||||
dec.flagCache = make([]bool, dec.shardSize)
|
||||
//log.Println("autotune to :", dec.dataShards, dec.parityShards)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// insertion
|
||||
n := len(dec.rx) - 1
|
||||
insertIdx := 0
|
||||
|
||||
+1
@@ -5,6 +5,7 @@ require (
|
||||
github.com/klauspost/reedsolomon v1.9.9
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 // indirect
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/stretchr/testify v1.6.1
|
||||
github.com/templexxx/cpu v0.0.7 // indirect
|
||||
github.com/templexxx/xorsimd v0.4.1
|
||||
github.com/tjfoc/gmsm v1.3.2
|
||||
|
||||
+11
@@ -1,3 +1,5 @@
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s=
|
||||
github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4=
|
||||
@@ -7,6 +9,11 @@ github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104 h1:ULR/QWMgcgRiZLU
|
||||
github.com/mmcloughlin/avo v0.0.0-20200803215136-443f81d77104/go.mod h1:wqKykBG2QzQDJEzvRkcS8x6MiSJkF52hXZsXcjaB3ls=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/templexxx/cpu v0.0.1 h1:hY4WdLOgKdc8y13EYklu9OUTXik80BkxHoWvTO6MQQY=
|
||||
github.com/templexxx/cpu v0.0.1/go.mod h1:w7Tb+7qgcAlIyX4NhLuDKt78AHA5SzPmq0Wj6HiEnnk=
|
||||
github.com/templexxx/cpu v0.0.7 h1:pUEZn8JBy/w5yzdYWgx+0m0xL9uk6j4K91C5kOViAzo=
|
||||
@@ -55,4 +62,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
|
||||
+2
-2
@@ -34,8 +34,8 @@ const (
|
||||
// monotonic reference time point
|
||||
var refTime time.Time = time.Now()
|
||||
|
||||
// currentMs returns current elasped monotonic milliseconds since program startup
|
||||
func currentMs() uint32 { return uint32(time.Now().Sub(refTime) / time.Millisecond) }
|
||||
// currentMs returns current elapsed monotonic milliseconds since program startup
|
||||
func currentMs() uint32 { return uint32(time.Since(refTime) / time.Millisecond) }
|
||||
|
||||
// output_callback is a prototype which ought capture conn and call conn.Write
|
||||
type output_callback func(buf []byte, size int)
|
||||
|
||||
+2
-11
@@ -18,12 +18,7 @@ func (s *UDPSession) defaultReadLoop() {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
continue
|
||||
}
|
||||
|
||||
if n >= s.headerSize+IKCP_OVERHEAD {
|
||||
s.packetInput(buf[:n])
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
s.packetInput(buf[:n])
|
||||
} else {
|
||||
s.notifyReadError(errors.WithStack(err))
|
||||
return
|
||||
@@ -35,11 +30,7 @@ func (l *Listener) defaultMonitor() {
|
||||
buf := make([]byte, mtuLimit)
|
||||
for {
|
||||
if n, from, err := l.conn.ReadFrom(buf); err == nil {
|
||||
if n >= l.headerSize+IKCP_OVERHEAD {
|
||||
l.packetInput(buf[:n], from)
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
l.packetInput(buf[:n], from)
|
||||
} else {
|
||||
l.notifyReadError(errors.WithStack(err))
|
||||
return
|
||||
|
||||
+1
-10
@@ -39,11 +39,6 @@ func (s *UDPSession) readLoop() {
|
||||
continue
|
||||
}
|
||||
|
||||
if msg.N < s.headerSize+IKCP_OVERHEAD {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
continue
|
||||
}
|
||||
|
||||
// source and size has validated
|
||||
s.packetInput(msg.Buffers[0][:msg.N])
|
||||
}
|
||||
@@ -95,11 +90,7 @@ func (l *Listener) monitor() {
|
||||
if count, err := xconn.ReadBatch(msgs, 0); err == nil {
|
||||
for i := 0; i < count; i++ {
|
||||
msg := &msgs[i]
|
||||
if msg.N >= l.headerSize+IKCP_OVERHEAD {
|
||||
l.packetInput(msg.Buffers[0][:msg.N], msg.Addr)
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
l.packetInput(msg.Buffers[0][:msg.N], msg.Addr)
|
||||
}
|
||||
} else {
|
||||
// compatibility issue:
|
||||
|
||||
+68
-81
@@ -35,9 +35,6 @@ const (
|
||||
// maximum packet size
|
||||
mtuLimit = 1500
|
||||
|
||||
// FEC keeps rxFECMulti* (dataShard+parityShard) ordered packets in memory
|
||||
rxFECMulti = 3
|
||||
|
||||
// accept backlog
|
||||
acceptBacklog = 128
|
||||
)
|
||||
@@ -155,7 +152,7 @@ func newUDPSession(conv uint32, dataShards, parityShards int, l *Listener, conn
|
||||
}
|
||||
|
||||
// FEC codec initialization
|
||||
sess.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||
sess.fecDecoder = newFECDecoder(dataShards, parityShards)
|
||||
if sess.block != nil {
|
||||
sess.fecEncoder = newFECEncoder(dataShards, parityShards, cryptHeaderSize)
|
||||
} else {
|
||||
@@ -216,7 +213,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
||||
return size, nil
|
||||
}
|
||||
|
||||
// if necessary resize the stream buffer to guarantee a sufficent buffer space
|
||||
// if necessary resize the stream buffer to guarantee a sufficient buffer space
|
||||
if cap(s.recvbuf) < size {
|
||||
s.recvbuf = make([]byte, size)
|
||||
}
|
||||
@@ -240,7 +237,7 @@ func (s *UDPSession) Read(b []byte) (n int, err error) {
|
||||
return 0, errors.WithStack(errTimeout)
|
||||
}
|
||||
|
||||
delay := s.rd.Sub(time.Now())
|
||||
delay := time.Until(s.rd)
|
||||
timeout = time.NewTimer(delay)
|
||||
c = timeout.C
|
||||
}
|
||||
@@ -311,7 +308,7 @@ func (s *UDPSession) WriteBuffers(v [][]byte) (n int, err error) {
|
||||
s.mu.Unlock()
|
||||
return 0, errors.WithStack(errTimeout)
|
||||
}
|
||||
delay := s.wd.Sub(time.Now())
|
||||
delay := time.Until(s.wd)
|
||||
timeout = time.NewTimer(delay)
|
||||
c = timeout.C
|
||||
}
|
||||
@@ -343,7 +340,6 @@ func (s *UDPSession) uncork() {
|
||||
}
|
||||
s.txqueue = s.txqueue[:0]
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Close closes the connection.
|
||||
@@ -655,22 +651,22 @@ func (s *UDPSession) notifyWriteError(err error) {
|
||||
|
||||
// packet input stage
|
||||
func (s *UDPSession) packetInput(data []byte) {
|
||||
dataValid := false
|
||||
if s.block != nil {
|
||||
decrypted := false
|
||||
if s.block != nil && len(data) >= cryptHeaderSize {
|
||||
s.block.Decrypt(data, data)
|
||||
data = data[nonceSize:]
|
||||
checksum := crc32.ChecksumIEEE(data[crcSize:])
|
||||
if checksum == binary.LittleEndian.Uint32(data) {
|
||||
data = data[crcSize:]
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
|
||||
}
|
||||
} else if s.block == nil {
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
}
|
||||
|
||||
if dataValid {
|
||||
if decrypted && len(data) >= IKCP_OVERHEAD {
|
||||
s.kcpInput(data)
|
||||
}
|
||||
}
|
||||
@@ -678,57 +674,58 @@ func (s *UDPSession) packetInput(data []byte) {
|
||||
func (s *UDPSession) kcpInput(data []byte) {
|
||||
var kcpInErrors, fecErrs, fecRecovered, fecParityShards uint64
|
||||
|
||||
if s.fecDecoder != nil {
|
||||
if len(data) > fecHeaderSize { // must be larger than fec header size
|
||||
fecFlag := binary.LittleEndian.Uint16(data[4:])
|
||||
if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2
|
||||
if len(data) >= fecHeaderSizePlus2 {
|
||||
f := fecPacket(data)
|
||||
if f.flag() == typeData || f.flag() == typeParity { // header check
|
||||
if f.flag() == typeParity {
|
||||
fecParityShards++
|
||||
}
|
||||
if f.flag() == typeParity {
|
||||
fecParityShards++
|
||||
}
|
||||
|
||||
// lock
|
||||
s.mu.Lock()
|
||||
recovers := s.fecDecoder.decode(f)
|
||||
if f.flag() == typeData {
|
||||
if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 {
|
||||
kcpInErrors++
|
||||
}
|
||||
// lock
|
||||
s.mu.Lock()
|
||||
// if fecDecoder is not initialized, create one with default parameter
|
||||
if s.fecDecoder == nil {
|
||||
s.fecDecoder = newFECDecoder(1, 1)
|
||||
}
|
||||
recovers := s.fecDecoder.decode(f)
|
||||
if f.flag() == typeData {
|
||||
if ret := s.kcp.Input(data[fecHeaderSizePlus2:], true, s.ackNoDelay); ret != 0 {
|
||||
kcpInErrors++
|
||||
}
|
||||
}
|
||||
|
||||
for _, r := range recovers {
|
||||
if len(r) >= 2 { // must be larger than 2bytes
|
||||
sz := binary.LittleEndian.Uint16(r)
|
||||
if int(sz) <= len(r) && sz >= 2 {
|
||||
if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 {
|
||||
fecRecovered++
|
||||
} else {
|
||||
kcpInErrors++
|
||||
}
|
||||
for _, r := range recovers {
|
||||
if len(r) >= 2 { // must be larger than 2bytes
|
||||
sz := binary.LittleEndian.Uint16(r)
|
||||
if int(sz) <= len(r) && sz >= 2 {
|
||||
if ret := s.kcp.Input(r[2:sz], false, s.ackNoDelay); ret == 0 {
|
||||
fecRecovered++
|
||||
} else {
|
||||
fecErrs++
|
||||
kcpInErrors++
|
||||
}
|
||||
} else {
|
||||
fecErrs++
|
||||
}
|
||||
// recycle the recovers
|
||||
xmitBuf.Put(r)
|
||||
} else {
|
||||
fecErrs++
|
||||
}
|
||||
|
||||
// to notify the readers to receive the data
|
||||
if n := s.kcp.PeekSize(); n > 0 {
|
||||
s.notifyReadEvent()
|
||||
}
|
||||
// to notify the writers
|
||||
waitsnd := s.kcp.WaitSnd()
|
||||
if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) {
|
||||
s.notifyWriteEvent()
|
||||
}
|
||||
|
||||
s.uncork()
|
||||
s.mu.Unlock()
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
// recycle the recovers
|
||||
xmitBuf.Put(r)
|
||||
}
|
||||
|
||||
// to notify the readers to receive the data
|
||||
if n := s.kcp.PeekSize(); n > 0 {
|
||||
s.notifyReadEvent()
|
||||
}
|
||||
// to notify the writers
|
||||
waitsnd := s.kcp.WaitSnd()
|
||||
if waitsnd < int(s.kcp.snd_wnd) && waitsnd < int(s.kcp.rmt_wnd) {
|
||||
s.notifyWriteEvent()
|
||||
}
|
||||
|
||||
s.uncork()
|
||||
s.mu.Unlock()
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InErrs, 1)
|
||||
}
|
||||
@@ -771,7 +768,6 @@ type (
|
||||
block BlockCrypt // block encryption
|
||||
dataShards int // FEC data shard
|
||||
parityShards int // FEC parity shard
|
||||
fecDecoder *fecDecoder // FEC mock initialization
|
||||
conn net.PacketConn // the underlying packet connection
|
||||
ownConn bool // true if we created conn internally, false if provided by caller
|
||||
|
||||
@@ -779,7 +775,6 @@ type (
|
||||
sessionLock sync.RWMutex
|
||||
chAccepts chan *UDPSession // Listen() backlog
|
||||
chSessionClosed chan net.Addr // session close queue
|
||||
headerSize int // the additional header to a KCP frame
|
||||
|
||||
die chan struct{} // notify the listener has closed
|
||||
dieOnce sync.Once
|
||||
@@ -795,43 +790,45 @@ type (
|
||||
|
||||
// packet input stage
|
||||
func (l *Listener) packetInput(data []byte, addr net.Addr) {
|
||||
dataValid := false
|
||||
if l.block != nil {
|
||||
decrypted := false
|
||||
if l.block != nil && len(data) >= cryptHeaderSize {
|
||||
l.block.Decrypt(data, data)
|
||||
data = data[nonceSize:]
|
||||
checksum := crc32.ChecksumIEEE(data[crcSize:])
|
||||
if checksum == binary.LittleEndian.Uint32(data) {
|
||||
data = data[crcSize:]
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
} else {
|
||||
atomic.AddUint64(&DefaultSnmp.InCsumErrors, 1)
|
||||
}
|
||||
} else if l.block == nil {
|
||||
dataValid = true
|
||||
decrypted = true
|
||||
}
|
||||
|
||||
if dataValid {
|
||||
if decrypted && len(data) >= IKCP_OVERHEAD {
|
||||
l.sessionLock.RLock()
|
||||
s, ok := l.sessions[addr.String()]
|
||||
l.sessionLock.RUnlock()
|
||||
|
||||
var conv, sn uint32
|
||||
convValid := false
|
||||
if l.fecDecoder != nil {
|
||||
isfec := binary.LittleEndian.Uint16(data[4:])
|
||||
if isfec == typeData {
|
||||
convRecovered := false
|
||||
fecFlag := binary.LittleEndian.Uint16(data[4:])
|
||||
if fecFlag == typeData || fecFlag == typeParity { // 16bit kcp cmd [81-84] and frg [0-255] will not overlap with FEC type 0x00f1 0x00f2
|
||||
// packet with FEC
|
||||
if fecFlag == typeData && len(data) >= fecHeaderSizePlus2+IKCP_OVERHEAD {
|
||||
conv = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2:])
|
||||
sn = binary.LittleEndian.Uint32(data[fecHeaderSizePlus2+IKCP_SN_OFFSET:])
|
||||
convValid = true
|
||||
convRecovered = true
|
||||
}
|
||||
} else {
|
||||
// packet without FEC
|
||||
conv = binary.LittleEndian.Uint32(data)
|
||||
sn = binary.LittleEndian.Uint32(data[IKCP_SN_OFFSET:])
|
||||
convValid = true
|
||||
convRecovered = true
|
||||
}
|
||||
|
||||
if ok { // existing connection
|
||||
if !convValid || conv == s.kcp.conv { // parity or valid data shard
|
||||
if !convRecovered || conv == s.kcp.conv { // parity data or valid conversation
|
||||
s.kcpInput(data)
|
||||
} else if sn == 0 { // should replace current connection
|
||||
s.Close()
|
||||
@@ -839,7 +836,7 @@ func (l *Listener) packetInput(data []byte, addr net.Addr) {
|
||||
}
|
||||
}
|
||||
|
||||
if s == nil && convValid { // new session
|
||||
if s == nil && convRecovered { // new session
|
||||
if len(l.chAccepts) < cap(l.chAccepts) { // do not let the new sessions overwhelm accept queue
|
||||
s := newUDPSession(conv, l.dataShards, l.parityShards, l, l.conn, false, addr, l.block)
|
||||
s.kcpInput(data)
|
||||
@@ -917,7 +914,7 @@ func (l *Listener) Accept() (net.Conn, error) {
|
||||
func (l *Listener) AcceptKCP() (*UDPSession, error) {
|
||||
var timeout <-chan time.Time
|
||||
if tdeadline, ok := l.rd.Load().(time.Time); ok && !tdeadline.IsZero() {
|
||||
timeout = time.After(tdeadline.Sub(time.Now()))
|
||||
timeout = time.After(time.Until(tdeadline))
|
||||
}
|
||||
|
||||
select {
|
||||
@@ -988,7 +985,7 @@ func Listen(laddr string) (net.Listener, error) { return ListenWithOptions(laddr
|
||||
//
|
||||
// 'block' is the block encryption algorithm to encrypt packets.
|
||||
//
|
||||
// 'dataShards', 'parityShards' specifiy how many parity packets will be generated following the data packets.
|
||||
// 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets.
|
||||
//
|
||||
// Check https://github.com/klauspost/reedsolomon for details
|
||||
func ListenWithOptions(laddr string, block BlockCrypt, dataShards, parityShards int) (*Listener, error) {
|
||||
@@ -1020,17 +1017,7 @@ func serveConn(block BlockCrypt, dataShards, parityShards int, conn net.PacketCo
|
||||
l.dataShards = dataShards
|
||||
l.parityShards = parityShards
|
||||
l.block = block
|
||||
l.fecDecoder = newFECDecoder(rxFECMulti*(dataShards+parityShards), dataShards, parityShards)
|
||||
l.chSocketReadError = make(chan struct{})
|
||||
|
||||
// calculate header size
|
||||
if l.block != nil {
|
||||
l.headerSize += cryptHeaderSize
|
||||
}
|
||||
if l.fecDecoder != nil {
|
||||
l.headerSize += fecHeaderSizePlus2
|
||||
}
|
||||
|
||||
go l.monitor()
|
||||
return l, nil
|
||||
}
|
||||
@@ -1042,7 +1029,7 @@ func Dial(raddr string) (net.Conn, error) { return DialWithOptions(raddr, nil, 0
|
||||
//
|
||||
// 'block' is the block encryption algorithm to encrypt packets.
|
||||
//
|
||||
// 'dataShards', 'parityShards' specifiy how many parity packets will be generated following the data packets.
|
||||
// 'dataShards', 'parityShards' specify how many parity packets will be generated following the data packets.
|
||||
//
|
||||
// Check https://github.com/klauspost/reedsolomon for details
|
||||
func DialWithOptions(raddr string, block BlockCrypt, dataShards, parityShards int) (*UDPSession, error) {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ type Snmp struct {
|
||||
RetransSegs uint64 // accmulated retransmited segments
|
||||
FastRetransSegs uint64 // accmulated fast retransmitted segments
|
||||
EarlyRetransSegs uint64 // accmulated early retransmitted segments
|
||||
LostSegs uint64 // number of segs infered as lost
|
||||
LostSegs uint64 // number of segs inferred as lost
|
||||
RepeatSegs uint64 // number of segs duplicated
|
||||
FECRecovered uint64 // correct packets recovered from FEC
|
||||
FECErrs uint64 // incorrect packets recovered from FEC
|
||||
|
||||
+3
@@ -1,3 +1,6 @@
|
||||
arch:
|
||||
- amd64
|
||||
- ppc64le
|
||||
language: go
|
||||
go:
|
||||
- 1.9.x
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
<img src="mux.jpg" alt="smux" height="120px" />
|
||||
|
||||
[1]: https://godoc.org/github.com/xtaci/smux?status.svg
|
||||
[2]: https://pkg.go.dev/github.com/xtaci/smux
|
||||
[2]: https://godoc.org/github.com/xtaci/smux
|
||||
[3]: https://img.shields.io/badge/license-MIT-blue.svg
|
||||
[4]: LICENSE
|
||||
[5]: https://travis-ci.org/xtaci/smux.svg?branch=master
|
||||
@@ -34,7 +34,7 @@ Smux ( **S**imple **MU**ltiple**X**ing) is a multiplexing library for Golang. It
|
||||
|
||||
## Documentation
|
||||
|
||||
For complete documentation, see the associated [Godoc](https://pkg.go.dev/github.com/xtaci/smux).
|
||||
For complete documentation, see the associated [Godoc](https://godoc.org/github.com/xtaci/smux).
|
||||
|
||||
## Benchmark
|
||||
```
|
||||
|
||||
+10
-5
@@ -17,6 +17,9 @@ type Config struct {
|
||||
// SMUX Protocol version, support 1,2
|
||||
Version int
|
||||
|
||||
// Disabled keepalive
|
||||
KeepAliveDisabled bool
|
||||
|
||||
// KeepAliveInterval is how often to send a NOP command to the remote
|
||||
KeepAliveInterval time.Duration
|
||||
|
||||
@@ -54,11 +57,13 @@ func VerifyConfig(config *Config) error {
|
||||
if !(config.Version == 1 || config.Version == 2) {
|
||||
return errors.New("unsupported protocol version")
|
||||
}
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return errors.New("keep-alive interval must be positive")
|
||||
}
|
||||
if config.KeepAliveTimeout < config.KeepAliveInterval {
|
||||
return fmt.Errorf("keep-alive timeout must be larger than keep-alive interval")
|
||||
if !config.KeepAliveDisabled {
|
||||
if config.KeepAliveInterval == 0 {
|
||||
return errors.New("keep-alive interval must be positive")
|
||||
}
|
||||
if config.KeepAliveTimeout < config.KeepAliveInterval {
|
||||
return fmt.Errorf("keep-alive timeout must be larger than keep-alive interval")
|
||||
}
|
||||
}
|
||||
if config.MaxFrameSize <= 0 {
|
||||
return errors.New("max frame size must be positive")
|
||||
|
||||
+5
-3
@@ -24,7 +24,7 @@ var (
|
||||
)
|
||||
|
||||
type writeRequest struct {
|
||||
prio uint64
|
||||
prio uint32
|
||||
frame Frame
|
||||
result chan writeResult
|
||||
}
|
||||
@@ -104,7 +104,9 @@ func newSession(config *Config, conn io.ReadWriteCloser, client bool) *Session {
|
||||
go s.shaperLoop()
|
||||
go s.recvLoop()
|
||||
go s.sendLoop()
|
||||
go s.keepalive()
|
||||
if !config.KeepAliveDisabled {
|
||||
go s.keepalive()
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -494,7 +496,7 @@ func (s *Session) writeFrame(f Frame) (n int, err error) {
|
||||
}
|
||||
|
||||
// internal writeFrame version to support deadline used in keepalive
|
||||
func (s *Session) writeFrameInternal(f Frame, deadline <-chan time.Time, prio uint64) (int, error) {
|
||||
func (s *Session) writeFrameInternal(f Frame, deadline <-chan time.Time, prio uint32) (int, error) {
|
||||
req := writeRequest{
|
||||
prio: prio,
|
||||
frame: f,
|
||||
|
||||
+5
-1
@@ -1,9 +1,13 @@
|
||||
package smux
|
||||
|
||||
func _itimediff(later, earlier uint32) int32 {
|
||||
return (int32)(later - earlier)
|
||||
}
|
||||
|
||||
type shaperHeap []writeRequest
|
||||
|
||||
func (h shaperHeap) Len() int { return len(h) }
|
||||
func (h shaperHeap) Less(i, j int) bool { return h[i].prio < h[j].prio }
|
||||
func (h shaperHeap) Less(i, j int) bool { return _itimediff(h[j].prio, h[i].prio) > 0 }
|
||||
func (h shaperHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
|
||||
func (h *shaperHeap) Push(x interface{}) { *h = append(*h, x.(writeRequest)) }
|
||||
|
||||
|
||||
+8
-2
@@ -272,6 +272,12 @@ func (s *Stream) waitRead() error {
|
||||
case <-s.chReadEvent:
|
||||
return nil
|
||||
case <-s.chFinEvent:
|
||||
// BUG(xtaci): Fix for https://github.com/xtaci/smux/issues/82
|
||||
s.bufferLock.Lock()
|
||||
defer s.bufferLock.Unlock()
|
||||
if len(s.buffers) > 0 {
|
||||
return nil
|
||||
}
|
||||
return io.EOF
|
||||
case <-s.sess.chSocketReadError:
|
||||
return s.sess.socketReadError.Load().(error)
|
||||
@@ -319,7 +325,7 @@ func (s *Stream) Write(b []byte) (n int, err error) {
|
||||
}
|
||||
frame.data = bts[:sz]
|
||||
bts = bts[sz:]
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, uint64(s.numWritten))
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, s.numWritten)
|
||||
s.numWritten++
|
||||
sent += n
|
||||
if err != nil {
|
||||
@@ -387,7 +393,7 @@ func (s *Stream) writeV2(b []byte) (n int, err error) {
|
||||
}
|
||||
frame.data = bts[:sz]
|
||||
bts = bts[sz:]
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, uint64(atomic.LoadUint32(&s.numWritten)))
|
||||
n, err := s.sess.writeFrameInternal(frame, deadline, atomic.LoadUint32(&s.numWritten))
|
||||
atomic.AddUint32(&s.numWritten, uint32(sz))
|
||||
sent += n
|
||||
if err != nil {
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !appengine
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
// Package subtle implements functions that are often useful in cryptographic
|
||||
// code but require careful thought to use correctly.
|
||||
|
||||
Generated
Vendored
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build appengine
|
||||
//go:build purego
|
||||
// +build purego
|
||||
|
||||
// Package subtle implements functions that are often useful in cryptographic
|
||||
// code but require careful thought to use correctly.
|
||||
+1
-1
@@ -32,7 +32,7 @@ import (
|
||||
// can get a derived key for e.g. AES-256 (which needs a 32-byte key) by
|
||||
// doing:
|
||||
//
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
// dk := pbkdf2.Key([]byte("some password"), salt, 4096, 32, sha1.New)
|
||||
//
|
||||
// Remember to get a good random salt. At least 8 bytes is recommended by the
|
||||
// RFC.
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
+118
-120
@@ -2,13 +2,14 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64,!appengine,!gccgo
|
||||
//go:build amd64 && !purego && gc
|
||||
// +build amd64,!purego,gc
|
||||
|
||||
// This code was translated into a form compatible with 6a from the public
|
||||
// domain sources in SUPERCOP: https://bench.cr.yp.to/supercop.html
|
||||
|
||||
// func salsa2020XORKeyStream(out, in *byte, n uint64, nonce, key *byte)
|
||||
// This needs up to 64 bytes at 360(SP); hence the non-obvious frame size.
|
||||
// This needs up to 64 bytes at 360(R12); hence the non-obvious frame size.
|
||||
TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVQ out+0(FP),DI
|
||||
MOVQ in+8(FP),SI
|
||||
@@ -17,10 +18,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVQ key+32(FP),R8
|
||||
|
||||
MOVQ SP,R12
|
||||
MOVQ SP,R9
|
||||
ADDQ $31, R9
|
||||
ANDQ $~31, R9
|
||||
MOVQ R9, SP
|
||||
ADDQ $31, R12
|
||||
ANDQ $~31, R12
|
||||
|
||||
MOVQ DX,R9
|
||||
MOVQ CX,DX
|
||||
@@ -32,116 +31,116 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL 0(R10),R8
|
||||
MOVL 0(DX),AX
|
||||
MOVL 16(R10),R11
|
||||
MOVL CX,0(SP)
|
||||
MOVL R8, 4 (SP)
|
||||
MOVL AX, 8 (SP)
|
||||
MOVL R11, 12 (SP)
|
||||
MOVL CX,0(R12)
|
||||
MOVL R8, 4 (R12)
|
||||
MOVL AX, 8 (R12)
|
||||
MOVL R11, 12 (R12)
|
||||
MOVL 8(DX),CX
|
||||
MOVL 24(R10),R8
|
||||
MOVL 4(R10),AX
|
||||
MOVL 4(DX),R11
|
||||
MOVL CX,16(SP)
|
||||
MOVL R8, 20 (SP)
|
||||
MOVL AX, 24 (SP)
|
||||
MOVL R11, 28 (SP)
|
||||
MOVL CX,16(R12)
|
||||
MOVL R8, 20 (R12)
|
||||
MOVL AX, 24 (R12)
|
||||
MOVL R11, 28 (R12)
|
||||
MOVL 12(DX),CX
|
||||
MOVL 12(R10),DX
|
||||
MOVL 28(R10),R8
|
||||
MOVL 8(R10),AX
|
||||
MOVL DX,32(SP)
|
||||
MOVL CX, 36 (SP)
|
||||
MOVL R8, 40 (SP)
|
||||
MOVL AX, 44 (SP)
|
||||
MOVL DX,32(R12)
|
||||
MOVL CX, 36 (R12)
|
||||
MOVL R8, 40 (R12)
|
||||
MOVL AX, 44 (R12)
|
||||
MOVQ $1634760805,DX
|
||||
MOVQ $857760878,CX
|
||||
MOVQ $2036477234,R8
|
||||
MOVQ $1797285236,AX
|
||||
MOVL DX,48(SP)
|
||||
MOVL CX, 52 (SP)
|
||||
MOVL R8, 56 (SP)
|
||||
MOVL AX, 60 (SP)
|
||||
MOVL DX,48(R12)
|
||||
MOVL CX, 52 (R12)
|
||||
MOVL R8, 56 (R12)
|
||||
MOVL AX, 60 (R12)
|
||||
CMPQ R9,$256
|
||||
JB BYTESBETWEEN1AND255
|
||||
MOVOA 48(SP),X0
|
||||
MOVOA 48(R12),X0
|
||||
PSHUFL $0X55,X0,X1
|
||||
PSHUFL $0XAA,X0,X2
|
||||
PSHUFL $0XFF,X0,X3
|
||||
PSHUFL $0X00,X0,X0
|
||||
MOVOA X1,64(SP)
|
||||
MOVOA X2,80(SP)
|
||||
MOVOA X3,96(SP)
|
||||
MOVOA X0,112(SP)
|
||||
MOVOA 0(SP),X0
|
||||
MOVOA X1,64(R12)
|
||||
MOVOA X2,80(R12)
|
||||
MOVOA X3,96(R12)
|
||||
MOVOA X0,112(R12)
|
||||
MOVOA 0(R12),X0
|
||||
PSHUFL $0XAA,X0,X1
|
||||
PSHUFL $0XFF,X0,X2
|
||||
PSHUFL $0X00,X0,X3
|
||||
PSHUFL $0X55,X0,X0
|
||||
MOVOA X1,128(SP)
|
||||
MOVOA X2,144(SP)
|
||||
MOVOA X3,160(SP)
|
||||
MOVOA X0,176(SP)
|
||||
MOVOA 16(SP),X0
|
||||
MOVOA X1,128(R12)
|
||||
MOVOA X2,144(R12)
|
||||
MOVOA X3,160(R12)
|
||||
MOVOA X0,176(R12)
|
||||
MOVOA 16(R12),X0
|
||||
PSHUFL $0XFF,X0,X1
|
||||
PSHUFL $0X55,X0,X2
|
||||
PSHUFL $0XAA,X0,X0
|
||||
MOVOA X1,192(SP)
|
||||
MOVOA X2,208(SP)
|
||||
MOVOA X0,224(SP)
|
||||
MOVOA 32(SP),X0
|
||||
MOVOA X1,192(R12)
|
||||
MOVOA X2,208(R12)
|
||||
MOVOA X0,224(R12)
|
||||
MOVOA 32(R12),X0
|
||||
PSHUFL $0X00,X0,X1
|
||||
PSHUFL $0XAA,X0,X2
|
||||
PSHUFL $0XFF,X0,X0
|
||||
MOVOA X1,240(SP)
|
||||
MOVOA X2,256(SP)
|
||||
MOVOA X0,272(SP)
|
||||
MOVOA X1,240(R12)
|
||||
MOVOA X2,256(R12)
|
||||
MOVOA X0,272(R12)
|
||||
BYTESATLEAST256:
|
||||
MOVL 16(SP),DX
|
||||
MOVL 36 (SP),CX
|
||||
MOVL DX,288(SP)
|
||||
MOVL CX,304(SP)
|
||||
MOVL 16(R12),DX
|
||||
MOVL 36 (R12),CX
|
||||
MOVL DX,288(R12)
|
||||
MOVL CX,304(R12)
|
||||
SHLQ $32,CX
|
||||
ADDQ CX,DX
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 292 (SP)
|
||||
MOVL CX, 308 (SP)
|
||||
MOVL DX, 292 (R12)
|
||||
MOVL CX, 308 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 296 (SP)
|
||||
MOVL CX, 312 (SP)
|
||||
MOVL DX, 296 (R12)
|
||||
MOVL CX, 312 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX, 300 (SP)
|
||||
MOVL CX, 316 (SP)
|
||||
MOVL DX, 300 (R12)
|
||||
MOVL CX, 316 (R12)
|
||||
ADDQ $1,DX
|
||||
MOVQ DX,CX
|
||||
SHRQ $32,CX
|
||||
MOVL DX,16(SP)
|
||||
MOVL CX, 36 (SP)
|
||||
MOVQ R9,352(SP)
|
||||
MOVL DX,16(R12)
|
||||
MOVL CX, 36 (R12)
|
||||
MOVQ R9,352(R12)
|
||||
MOVQ $20,DX
|
||||
MOVOA 64(SP),X0
|
||||
MOVOA 80(SP),X1
|
||||
MOVOA 96(SP),X2
|
||||
MOVOA 256(SP),X3
|
||||
MOVOA 272(SP),X4
|
||||
MOVOA 128(SP),X5
|
||||
MOVOA 144(SP),X6
|
||||
MOVOA 176(SP),X7
|
||||
MOVOA 192(SP),X8
|
||||
MOVOA 208(SP),X9
|
||||
MOVOA 224(SP),X10
|
||||
MOVOA 304(SP),X11
|
||||
MOVOA 112(SP),X12
|
||||
MOVOA 160(SP),X13
|
||||
MOVOA 240(SP),X14
|
||||
MOVOA 288(SP),X15
|
||||
MOVOA 64(R12),X0
|
||||
MOVOA 80(R12),X1
|
||||
MOVOA 96(R12),X2
|
||||
MOVOA 256(R12),X3
|
||||
MOVOA 272(R12),X4
|
||||
MOVOA 128(R12),X5
|
||||
MOVOA 144(R12),X6
|
||||
MOVOA 176(R12),X7
|
||||
MOVOA 192(R12),X8
|
||||
MOVOA 208(R12),X9
|
||||
MOVOA 224(R12),X10
|
||||
MOVOA 304(R12),X11
|
||||
MOVOA 112(R12),X12
|
||||
MOVOA 160(R12),X13
|
||||
MOVOA 240(R12),X14
|
||||
MOVOA 288(R12),X15
|
||||
MAINLOOP1:
|
||||
MOVOA X1,320(SP)
|
||||
MOVOA X2,336(SP)
|
||||
MOVOA X1,320(R12)
|
||||
MOVOA X2,336(R12)
|
||||
MOVOA X13,X1
|
||||
PADDL X12,X1
|
||||
MOVOA X1,X2
|
||||
@@ -191,8 +190,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X12
|
||||
PSRLL $14,X2
|
||||
PXOR X2,X12
|
||||
MOVOA 320(SP),X1
|
||||
MOVOA X12,320(SP)
|
||||
MOVOA 320(R12),X1
|
||||
MOVOA X12,320(R12)
|
||||
MOVOA X9,X2
|
||||
PADDL X7,X2
|
||||
MOVOA X2,X12
|
||||
@@ -207,8 +206,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X2,X3
|
||||
PSRLL $25,X12
|
||||
PXOR X12,X3
|
||||
MOVOA 336(SP),X2
|
||||
MOVOA X0,336(SP)
|
||||
MOVOA 336(R12),X2
|
||||
MOVOA X0,336(R12)
|
||||
MOVOA X6,X0
|
||||
PADDL X2,X0
|
||||
MOVOA X0,X12
|
||||
@@ -251,8 +250,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X1
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X1
|
||||
MOVOA 320(SP),X0
|
||||
MOVOA X1,320(SP)
|
||||
MOVOA 320(R12),X0
|
||||
MOVOA X1,320(R12)
|
||||
MOVOA X4,X1
|
||||
PADDL X0,X1
|
||||
MOVOA X1,X12
|
||||
@@ -267,8 +266,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X2
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X2
|
||||
MOVOA 336(SP),X12
|
||||
MOVOA X2,336(SP)
|
||||
MOVOA 336(R12),X12
|
||||
MOVOA X2,336(R12)
|
||||
MOVOA X14,X1
|
||||
PADDL X12,X1
|
||||
MOVOA X1,X2
|
||||
@@ -311,8 +310,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X1,X0
|
||||
PSRLL $14,X2
|
||||
PXOR X2,X0
|
||||
MOVOA 320(SP),X1
|
||||
MOVOA X0,320(SP)
|
||||
MOVOA 320(R12),X1
|
||||
MOVOA X0,320(R12)
|
||||
MOVOA X8,X0
|
||||
PADDL X14,X0
|
||||
MOVOA X0,X2
|
||||
@@ -327,8 +326,8 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X6
|
||||
PSRLL $25,X2
|
||||
PXOR X2,X6
|
||||
MOVOA 336(SP),X2
|
||||
MOVOA X12,336(SP)
|
||||
MOVOA 336(R12),X2
|
||||
MOVOA X12,336(R12)
|
||||
MOVOA X3,X0
|
||||
PADDL X2,X0
|
||||
MOVOA X0,X12
|
||||
@@ -378,14 +377,14 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PXOR X0,X2
|
||||
PSRLL $14,X12
|
||||
PXOR X12,X2
|
||||
MOVOA 320(SP),X12
|
||||
MOVOA 336(SP),X0
|
||||
MOVOA 320(R12),X12
|
||||
MOVOA 336(R12),X0
|
||||
SUBQ $2,DX
|
||||
JA MAINLOOP1
|
||||
PADDL 112(SP),X12
|
||||
PADDL 176(SP),X7
|
||||
PADDL 224(SP),X10
|
||||
PADDL 272(SP),X4
|
||||
PADDL 112(R12),X12
|
||||
PADDL 176(R12),X7
|
||||
PADDL 224(R12),X10
|
||||
PADDL 272(R12),X4
|
||||
MOVD X12,DX
|
||||
MOVD X7,CX
|
||||
MOVD X10,R8
|
||||
@@ -446,10 +445,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,196(DI)
|
||||
MOVL R8,200(DI)
|
||||
MOVL R9,204(DI)
|
||||
PADDL 240(SP),X14
|
||||
PADDL 64(SP),X0
|
||||
PADDL 128(SP),X5
|
||||
PADDL 192(SP),X8
|
||||
PADDL 240(R12),X14
|
||||
PADDL 64(R12),X0
|
||||
PADDL 128(R12),X5
|
||||
PADDL 192(R12),X8
|
||||
MOVD X14,DX
|
||||
MOVD X0,CX
|
||||
MOVD X5,R8
|
||||
@@ -510,10 +509,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,212(DI)
|
||||
MOVL R8,216(DI)
|
||||
MOVL R9,220(DI)
|
||||
PADDL 288(SP),X15
|
||||
PADDL 304(SP),X11
|
||||
PADDL 80(SP),X1
|
||||
PADDL 144(SP),X6
|
||||
PADDL 288(R12),X15
|
||||
PADDL 304(R12),X11
|
||||
PADDL 80(R12),X1
|
||||
PADDL 144(R12),X6
|
||||
MOVD X15,DX
|
||||
MOVD X11,CX
|
||||
MOVD X1,R8
|
||||
@@ -574,10 +573,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,228(DI)
|
||||
MOVL R8,232(DI)
|
||||
MOVL R9,236(DI)
|
||||
PADDL 160(SP),X13
|
||||
PADDL 208(SP),X9
|
||||
PADDL 256(SP),X3
|
||||
PADDL 96(SP),X2
|
||||
PADDL 160(R12),X13
|
||||
PADDL 208(R12),X9
|
||||
PADDL 256(R12),X3
|
||||
PADDL 96(R12),X2
|
||||
MOVD X13,DX
|
||||
MOVD X9,CX
|
||||
MOVD X3,R8
|
||||
@@ -638,7 +637,7 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL CX,244(DI)
|
||||
MOVL R8,248(DI)
|
||||
MOVL R9,252(DI)
|
||||
MOVQ 352(SP),R9
|
||||
MOVQ 352(R12),R9
|
||||
SUBQ $256,R9
|
||||
ADDQ $256,SI
|
||||
ADDQ $256,DI
|
||||
@@ -650,17 +649,17 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
CMPQ R9,$64
|
||||
JAE NOCOPY
|
||||
MOVQ DI,DX
|
||||
LEAQ 360(SP),DI
|
||||
LEAQ 360(R12),DI
|
||||
MOVQ R9,CX
|
||||
REP; MOVSB
|
||||
LEAQ 360(SP),DI
|
||||
LEAQ 360(SP),SI
|
||||
LEAQ 360(R12),DI
|
||||
LEAQ 360(R12),SI
|
||||
NOCOPY:
|
||||
MOVQ R9,352(SP)
|
||||
MOVOA 48(SP),X0
|
||||
MOVOA 0(SP),X1
|
||||
MOVOA 16(SP),X2
|
||||
MOVOA 32(SP),X3
|
||||
MOVQ R9,352(R12)
|
||||
MOVOA 48(R12),X0
|
||||
MOVOA 0(R12),X1
|
||||
MOVOA 16(R12),X2
|
||||
MOVOA 32(R12),X3
|
||||
MOVOA X1,X4
|
||||
MOVQ $20,CX
|
||||
MAINLOOP2:
|
||||
@@ -791,10 +790,10 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
PSHUFL $0X39,X3,X3
|
||||
PXOR X6,X0
|
||||
JA MAINLOOP2
|
||||
PADDL 48(SP),X0
|
||||
PADDL 0(SP),X1
|
||||
PADDL 16(SP),X2
|
||||
PADDL 32(SP),X3
|
||||
PADDL 48(R12),X0
|
||||
PADDL 0(R12),X1
|
||||
PADDL 16(R12),X2
|
||||
PADDL 32(R12),X3
|
||||
MOVD X0,CX
|
||||
MOVD X1,R8
|
||||
MOVD X2,R9
|
||||
@@ -855,16 +854,16 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
MOVL R8,44(DI)
|
||||
MOVL R9,28(DI)
|
||||
MOVL AX,12(DI)
|
||||
MOVQ 352(SP),R9
|
||||
MOVL 16(SP),CX
|
||||
MOVL 36 (SP),R8
|
||||
MOVQ 352(R12),R9
|
||||
MOVL 16(R12),CX
|
||||
MOVL 36 (R12),R8
|
||||
ADDQ $1,CX
|
||||
SHLQ $32,R8
|
||||
ADDQ R8,CX
|
||||
MOVQ CX,R8
|
||||
SHRQ $32,R8
|
||||
MOVL CX,16(SP)
|
||||
MOVL R8, 36 (SP)
|
||||
MOVL CX,16(R12)
|
||||
MOVL R8, 36 (R12)
|
||||
CMPQ R9,$64
|
||||
JA BYTESATLEAST65
|
||||
JAE BYTESATLEAST64
|
||||
@@ -874,7 +873,6 @@ TEXT ·salsa2020XORKeyStream(SB),0,$456-40 // frame = 424 + 32 byte alignment
|
||||
REP; MOVSB
|
||||
BYTESATLEAST64:
|
||||
DONE:
|
||||
MOVQ R12,SP
|
||||
RET
|
||||
BYTESATLEAST65:
|
||||
SUBQ $64,R9
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !amd64 appengine gccgo
|
||||
//go:build !amd64 || purego || !gc
|
||||
// +build !amd64 purego !gc
|
||||
|
||||
package salsa
|
||||
|
||||
|
||||
+2
-4
@@ -3,7 +3,6 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
/*
|
||||
|
||||
Package bpf implements marshaling and unmarshaling of programs for the
|
||||
Berkeley Packet Filter virtual machine, and provides a Go implementation
|
||||
of the virtual machine.
|
||||
@@ -21,7 +20,7 @@ access to kernel functions, and while conditional branches are
|
||||
allowed, they can only jump forwards, to guarantee that there are no
|
||||
infinite loops.
|
||||
|
||||
The virtual machine
|
||||
# The virtual machine
|
||||
|
||||
The BPF VM is an accumulator machine. Its main register, called
|
||||
register A, is an implicit source and destination in all arithmetic
|
||||
@@ -50,7 +49,7 @@ to extensions, which are essentially calls to kernel utility
|
||||
functions. Currently, the only extensions supported by this package
|
||||
are the Linux packet filter extensions.
|
||||
|
||||
Examples
|
||||
# Examples
|
||||
|
||||
This packet filter selects all ARP packets.
|
||||
|
||||
@@ -77,6 +76,5 @@ This packet filter captures a random 1% sample of traffic.
|
||||
// Ignore.
|
||||
bpf.RetConstant{Val: 0},
|
||||
})
|
||||
|
||||
*/
|
||||
package bpf // import "golang.org/x/net/bpf"
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
// +build aix darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm mips mipsle 386
|
||||
//go:build (arm || mips || mipsle || 386 || ppc) && linux
|
||||
// +build arm mips mipsle 386 ppc
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && linux
|
||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build linux
|
||||
|
||||
package socket
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
// +build solaris
|
||||
//go:build amd64 && solaris
|
||||
// +build amd64,solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+14
-3
@@ -2,13 +2,24 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package socket
|
||||
|
||||
type cmsghdr struct{}
|
||||
func controlHeaderLen() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
const sizeofCmsghdr = 0
|
||||
func controlMessageLen(dataLen int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
func controlMessageSpace(dataLen int) int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type cmsghdr struct{}
|
||||
|
||||
func (h *cmsghdr) len() int { return 0 }
|
||||
func (h *cmsghdr) lvl() int { return 0 }
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
import "golang.org/x/sys/unix"
|
||||
|
||||
func controlHeaderLen() int {
|
||||
return unix.CmsgLen(0)
|
||||
}
|
||||
|
||||
func controlMessageLen(dataLen int) int {
|
||||
return unix.CmsgLen(dataLen)
|
||||
}
|
||||
|
||||
func controlMessageSpace(dataLen int) int {
|
||||
return unix.CmsgSpace(dataLen)
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
// Copyright 2020 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package socket
|
||||
|
||||
func (h *cmsghdr) set(l, lvl, typ int) {
|
||||
h.Len = int32(l)
|
||||
h.Level = int32(lvl)
|
||||
h.Type = int32(typ)
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ioComplete checks the flags and result of a syscall, to be used as return
|
||||
// value in a syscall.RawConn.Read or Write callback.
|
||||
func ioComplete(flags int, operr error) bool {
|
||||
if flags&syscall.MSG_DONTWAIT != 0 {
|
||||
// Caller explicitly said don't wait, so always return immediately.
|
||||
return true
|
||||
}
|
||||
if operr == syscall.EAGAIN || operr == syscall.EWOULDBLOCK {
|
||||
// No data available, block for I/O and try again.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || windows || zos
|
||||
// +build aix windows zos
|
||||
|
||||
package socket
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
// ioComplete checks the flags and result of a syscall, to be used as return
|
||||
// value in a syscall.RawConn.Read or Write callback.
|
||||
func ioComplete(flags int, operr error) bool {
|
||||
if operr == syscall.EAGAIN || operr == syscall.EWOULDBLOCK {
|
||||
// No data available, block for I/O and try again.
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build darwin && go1.12
|
||||
// +build darwin,go1.12
|
||||
|
||||
// This exists solely so we can linkname in symbols from syscall.
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
|
||||
//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm mips mipsle 386
|
||||
//go:build (arm || mips || mipsle || 386 || ppc) && (darwin || dragonfly || freebsd || linux || netbsd || openbsd)
|
||||
// +build arm mips mipsle 386 ppc
|
||||
// +build darwin dragonfly freebsd linux netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
+3
-2
@@ -2,8 +2,9 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build arm64 amd64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd
|
||||
//go:build (arm64 || amd64 || loong64 || ppc64 || ppc64le || mips64 || mips64le || riscv64 || s390x) && (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || zos)
|
||||
// +build arm64 amd64 loong64 ppc64 ppc64le mips64 mips64le riscv64 s390x
|
||||
// +build aix darwin dragonfly freebsd linux netbsd openbsd zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-2
@@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build amd64
|
||||
// +build solaris
|
||||
//go:build amd64 && solaris
|
||||
// +build amd64,solaris
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+2
-1
@@ -2,7 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris
|
||||
//go:build !aix && !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd && !solaris && !zos
|
||||
// +build !aix,!darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd,!solaris,!zos
|
||||
|
||||
package socket
|
||||
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build !aix && !linux && !netbsd
|
||||
// +build !aix,!linux,!netbsd
|
||||
|
||||
package socket
|
||||
|
||||
+154
-16
@@ -2,29 +2,20 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || linux || netbsd
|
||||
// +build aix linux netbsd
|
||||
|
||||
package socket
|
||||
|
||||
import "net"
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type mmsghdrs []mmsghdr
|
||||
|
||||
func (hs mmsghdrs) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr) []byte) error {
|
||||
for i := range hs {
|
||||
vs := make([]iovec, len(ms[i].Buffers))
|
||||
var sa []byte
|
||||
if parseFn != nil {
|
||||
sa = make([]byte, sizeofSockaddrInet6)
|
||||
}
|
||||
if marshalFn != nil {
|
||||
sa = marshalFn(ms[i].Addr)
|
||||
}
|
||||
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr, error), hint string) error {
|
||||
for i := range hs {
|
||||
ms[i].N = int(hs[i].Len)
|
||||
@@ -40,3 +31,150 @@ func (hs mmsghdrs) unpack(ms []Message, parseFn func([]byte, string) (net.Addr,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// mmsghdrsPacker packs Message-slices into mmsghdrs (re-)using pre-allocated buffers.
|
||||
type mmsghdrsPacker struct {
|
||||
// hs are the pre-allocated mmsghdrs.
|
||||
hs mmsghdrs
|
||||
// sockaddrs is the pre-allocated buffer for the Hdr.Name buffers.
|
||||
// We use one large buffer for all messages and slice it up.
|
||||
sockaddrs []byte
|
||||
// vs are the pre-allocated iovecs.
|
||||
// We allocate one large buffer for all messages and slice it up. This allows to reuse the buffer
|
||||
// if the number of buffers per message is distributed differently between calls.
|
||||
vs []iovec
|
||||
}
|
||||
|
||||
func (p *mmsghdrsPacker) prepare(ms []Message) {
|
||||
n := len(ms)
|
||||
if n <= cap(p.hs) {
|
||||
p.hs = p.hs[:n]
|
||||
} else {
|
||||
p.hs = make(mmsghdrs, n)
|
||||
}
|
||||
if n*sizeofSockaddrInet6 <= cap(p.sockaddrs) {
|
||||
p.sockaddrs = p.sockaddrs[:n*sizeofSockaddrInet6]
|
||||
} else {
|
||||
p.sockaddrs = make([]byte, n*sizeofSockaddrInet6)
|
||||
}
|
||||
|
||||
nb := 0
|
||||
for _, m := range ms {
|
||||
nb += len(m.Buffers)
|
||||
}
|
||||
if nb <= cap(p.vs) {
|
||||
p.vs = p.vs[:nb]
|
||||
} else {
|
||||
p.vs = make([]iovec, nb)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *mmsghdrsPacker) pack(ms []Message, parseFn func([]byte, string) (net.Addr, error), marshalFn func(net.Addr, []byte) int) mmsghdrs {
|
||||
p.prepare(ms)
|
||||
hs := p.hs
|
||||
vsRest := p.vs
|
||||
saRest := p.sockaddrs
|
||||
for i := range hs {
|
||||
nvs := len(ms[i].Buffers)
|
||||
vs := vsRest[:nvs]
|
||||
vsRest = vsRest[nvs:]
|
||||
|
||||
var sa []byte
|
||||
if parseFn != nil {
|
||||
sa = saRest[:sizeofSockaddrInet6]
|
||||
saRest = saRest[sizeofSockaddrInet6:]
|
||||
} else if marshalFn != nil {
|
||||
n := marshalFn(ms[i].Addr, saRest)
|
||||
if n > 0 {
|
||||
sa = saRest[:n]
|
||||
saRest = saRest[n:]
|
||||
}
|
||||
}
|
||||
hs[i].Hdr.pack(vs, ms[i].Buffers, ms[i].OOB, sa)
|
||||
}
|
||||
return hs
|
||||
}
|
||||
|
||||
// syscaller is a helper to invoke recvmmsg and sendmmsg via the RawConn.Read/Write interface.
|
||||
// It is reusable, to amortize the overhead of allocating a closure for the function passed to
|
||||
// RawConn.Read/Write.
|
||||
type syscaller struct {
|
||||
n int
|
||||
operr error
|
||||
hs mmsghdrs
|
||||
flags int
|
||||
|
||||
boundRecvmmsgF func(uintptr) bool
|
||||
boundSendmmsgF func(uintptr) bool
|
||||
}
|
||||
|
||||
func (r *syscaller) init() {
|
||||
r.boundRecvmmsgF = r.recvmmsgF
|
||||
r.boundSendmmsgF = r.sendmmsgF
|
||||
}
|
||||
|
||||
func (r *syscaller) recvmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
||||
r.n = 0
|
||||
r.operr = nil
|
||||
r.hs = hs
|
||||
r.flags = flags
|
||||
if err := c.Read(r.boundRecvmmsgF); err != nil {
|
||||
return r.n, err
|
||||
}
|
||||
if r.operr != nil {
|
||||
return r.n, os.NewSyscallError("recvmmsg", r.operr)
|
||||
}
|
||||
return r.n, nil
|
||||
}
|
||||
|
||||
func (r *syscaller) recvmmsgF(s uintptr) bool {
|
||||
r.n, r.operr = recvmmsg(s, r.hs, r.flags)
|
||||
return ioComplete(r.flags, r.operr)
|
||||
}
|
||||
|
||||
func (r *syscaller) sendmmsg(c syscall.RawConn, hs mmsghdrs, flags int) (int, error) {
|
||||
r.n = 0
|
||||
r.operr = nil
|
||||
r.hs = hs
|
||||
r.flags = flags
|
||||
if err := c.Write(r.boundSendmmsgF); err != nil {
|
||||
return r.n, err
|
||||
}
|
||||
if r.operr != nil {
|
||||
return r.n, os.NewSyscallError("sendmmsg", r.operr)
|
||||
}
|
||||
return r.n, nil
|
||||
}
|
||||
|
||||
func (r *syscaller) sendmmsgF(s uintptr) bool {
|
||||
r.n, r.operr = sendmmsg(s, r.hs, r.flags)
|
||||
return ioComplete(r.flags, r.operr)
|
||||
}
|
||||
|
||||
// mmsgTmps holds reusable temporary helpers for recvmmsg and sendmmsg.
|
||||
type mmsgTmps struct {
|
||||
packer mmsghdrsPacker
|
||||
syscaller syscaller
|
||||
}
|
||||
|
||||
var defaultMmsgTmpsPool = mmsgTmpsPool{
|
||||
p: sync.Pool{
|
||||
New: func() interface{} {
|
||||
tmps := new(mmsgTmps)
|
||||
tmps.syscaller.init()
|
||||
return tmps
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type mmsgTmpsPool struct {
|
||||
p sync.Pool
|
||||
}
|
||||
|
||||
func (p *mmsgTmpsPool) Get() *mmsgTmps {
|
||||
return p.p.Get().(*mmsgTmps)
|
||||
}
|
||||
|
||||
func (p *mmsgTmpsPool) Put(tmps *mmsgTmps) {
|
||||
p.p.Put(tmps)
|
||||
}
|
||||
|
||||
+1
@@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build aix || darwin || dragonfly || freebsd || netbsd || openbsd
|
||||
// +build aix darwin dragonfly freebsd netbsd openbsd
|
||||
|
||||
package socket
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user